184 lines
7.3 KiB
C
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()`.
|
|
*/
|
|
|