ergodox-firmware/firmware/lib/eeprom.h

184 lines
7.3 KiB
C

/* ----------------------------------------------------------------------------
* Copyright (c) 2013 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (see "doc/licenses/MIT.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
/** description
* EEPROM interface
*
* Prefix: `eeprom__`
*
* Conventions:
* - Because the EEPROM must be shared between different parts of the entire
* program, there needs to be a way to define which blocks are to be used for
* which purposes. To that end, all blocks of the EEPROM that are being used
* must have their start and end addresses `#define`ed to two globally
* visible macros, of the form `OPT__EEPROM__[prefix]__START` and
* `OPT__EEPROM__[prefix]__END`, where "[prefix]" is the prefix usually given
* to public functions, etc., in that section of the code.
*
* Notes:
* - This is meant to be a replacement for the read, write, and update
* functions provided by `<avr/eeprom.h>`, and should be preferred for those
* operations. There are other things provided by that header that may be
* useful however, and it's likely that both will be needed.
*
* Implementation notes:
* - Writes generated by calls to `eeprom__write()` and `eeprom__copy()` should
* collectively execute in the order in which the calls were performed (i.e.
* all writes should be sequential, in the expected order, regardless of the
* function which generated them).
*/
#ifndef ERGODOX_FIRMWARE__LIB__EEPROM__H
#define ERGODOX_FIRMWARE__LIB__EEPROM__H
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
#include <stdint.h>
// ----------------------------------------------------------------------------
uint8_t eeprom__read (void * from);
uint8_t eeprom__write (void * to, uint8_t data);
uint8_t eeprom__fill (void * to, uint8_t data, uint8_t length);
uint8_t eeprom__copy (void * to, void * from, uint8_t length);
uint8_t eeprom__block_read (void * to, void * from, uint8_t length);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
#endif // ERGODOX_FIRMWARE__LIB__EEPROM__H
// ============================================================================
// === documentation ==========================================================
// ============================================================================
// ----------------------------------------------------------------------------
// functions ------------------------------------------------------------------
// ----------------------------------------------------------------------------
// === eeprom__read() ===
/** functions/eeprom__read/description
* Read and return the data at `from` in the EEPROM memory space
*
* Arguments:
* - `from`: The address of (i.e. a pointer to) the location from which to read
*
* Returns:
* - success: The data stored at `from` in the EEPROM memory space
* - failure: `0`
*/
// === eeprom__write() ===
/** functions/eeprom__write/description
* Schedule a regular 1 byte write to the EEPROM memory space
*
* Arguments:
* - `to`: The address of (i.e. a pointer to) the location to write to
* - `data`: The data to write
*
* Returns:
* - success: `0`
* - failure: [other]
*
* Notes:
* - Writes are scheduled (i.e. buffered) because writing to EEPROMs takes an
* enormous (relative to a microprocessor clock cycle) amount of time.
* - Due to the technology used, EEPROM bytes, when cleared, have a logical
* value of `1`. Interesting stuff, but I didn't read about it thoroughly
* enough to give my own explanation here.
*
* Implementation notes:
* - Undefined behavior will result if
* - `to` is not a valid address
* - This function should only modify when necessary; that is, when the data to
* be written is different than the data that's already there. This requires
* more processor time (to read the current value and compare), but it's
* better for the EEPROM (which has a limited write life), and will allow the
* operation to complete *much* more quickly in the event that the data has
* not changed.
* - Writing `0xFF` should clear the memory (without writing anything), and
* writing to a location currently set to `0xFF` should write without
* clearing first.
*/
// === eeprom__fill() ===
/** functions/eeprom__fill/description
* Fill a portion of the EEPROM with the given value
*
* Arguments:
* - `to`: The address of (i.e. a pointer to) the location to start writing to
* - `data`: The data to write
* - `length`: The number of times to sequentially write `data`, incrementing
* `to` each time
*
* Returns:
* - success: `0`
* - failure: [other]
*/
// === eeprom__copy() ===
/** functions/eeprom__copy/description
* Copy data from one location in the EEPROM memory space to another
*
* Arguments:
* - `to: The address of (i.e. a pointer to) the location to start writing to
* - `from`: The address of (i.e. a pointer to) the location to start copying
* from
* - `length`: The number of bytes to sequentially copy
*
* Returns:
* - success: `0`
* - failure: [other]
*
*
* Implementation notes:
*
* - If `to == from`, nothing should be done
* - If `to < from`, copying should start with the given addresses, and
* increment for `length - 1` bytes
* - If `to > from`, copying should start with the given addresses, and
* decrement for `length - 1` bytes
*
* - Undefined behavior will result if any address in the block of EEMEM you're
* copying from or the block of EEMEM you're copying to is invalid.
*/
// === eeprom__block_read() ===
/** functions/eeprom__block_read/description
* Read a block of data from the EEPROM into SRAM
*
* Arguments:
* - `to`: The location (in SRAM) to start writing the data to
* - `from`: The location (in EEMEM) to start reading the data from
* - `length`: The number number of bytes to read, incrementing `to` and `from`
* for each byte
*
* Returns:
* - success: `0`
* - failure: [other]
*
* Notes:
* - As one would expect, this read is performed sequentially, and all data is
* read in before returning. Delays due to the speed of the EEPROM are
* introduced *for every byte* whether one uses this function or reads each
* byte manually.
* - Because doing a "block_write" would be either unbearably slow or require
* us to work around the fact that the function would return before the data
* was actually written (so where would the data to be written be stored?
* we'd either have to copy it, or make an agreement with the calling
* functions to `malloc()` the data and let us `free()` it, or some such), we
* do not have any "block" functions that write to the EEPROM (except perhaps
* `eeprom__fill()`, which is a special case). Better to be careful with
* writes, and schedule them one at a time, using `eeprom__write()`.
*/