Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
nvm.h@35:e959ffba78fd, 2015-12-19 (annotated)
- Committer:
- mjr
- Date:
- Sat Dec 19 06:37:19 2015 +0000
- Revision:
- 35:e959ffba78fd
- Child:
- 40:cc0d9814522b
Keyboard/Media Control interface working, but the extra interface confuses the DOF connector.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mjr | 35:e959ffba78fd | 1 | // NVM - Non-Volatile Memory |
mjr | 35:e959ffba78fd | 2 | // |
mjr | 35:e959ffba78fd | 3 | // This module handles the storage of our configuration settings |
mjr | 35:e959ffba78fd | 4 | // and calibration data in flash memory, which allows us to |
mjr | 35:e959ffba78fd | 5 | // retrieve these settings after each power cycle. |
mjr | 35:e959ffba78fd | 6 | |
mjr | 35:e959ffba78fd | 7 | |
mjr | 35:e959ffba78fd | 8 | #ifndef NVM_H |
mjr | 35:e959ffba78fd | 9 | #define NVM_H |
mjr | 35:e959ffba78fd | 10 | |
mjr | 35:e959ffba78fd | 11 | #include "config.h" |
mjr | 35:e959ffba78fd | 12 | #include "FreescaleIAP.h" |
mjr | 35:e959ffba78fd | 13 | |
mjr | 35:e959ffba78fd | 14 | |
mjr | 35:e959ffba78fd | 15 | // Non-volatile memory (NVM) structure |
mjr | 35:e959ffba78fd | 16 | // |
mjr | 35:e959ffba78fd | 17 | // This structure defines the layout of our saved configuration |
mjr | 35:e959ffba78fd | 18 | // and calibration data in flash memory. |
mjr | 35:e959ffba78fd | 19 | // |
mjr | 35:e959ffba78fd | 20 | // Hack alert! |
mjr | 35:e959ffba78fd | 21 | // Our use of flash for this purpose is ad hoc and not supported |
mjr | 35:e959ffba78fd | 22 | // by the mbed platform. mbed doesn't impose a file system on the |
mjr | 35:e959ffba78fd | 23 | // KL25Z flash; it simply treats the flash as a raw storage space |
mjr | 35:e959ffba78fd | 24 | // and assumes that the linker output is the only thing using it. |
mjr | 35:e959ffba78fd | 25 | // So if we want to use the flash, we basically have to do it on |
mjr | 35:e959ffba78fd | 26 | // the sly, by using space that the linker happens to leave unused. |
mjr | 35:e959ffba78fd | 27 | // Fortunately, it's fairly easy to do this, because the flash |
mjr | 35:e959ffba78fd | 28 | // is mapped in the obvious way, as a single contiguous block in |
mjr | 35:e959ffba78fd | 29 | // the CPU memory space, and the linker does the obvious thing, |
mjr | 35:e959ffba78fd | 30 | // storing its entire output in a single contiguous block starting |
mjr | 35:e959ffba78fd | 31 | // at the lowest flash address. This means that all flash memory |
mjr | 35:e959ffba78fd | 32 | // from (lowest flash address + length of linker output) to |
mjr | 35:e959ffba78fd | 33 | // (highest flash address) is unused and available for our sneaky |
mjr | 35:e959ffba78fd | 34 | // system. Unfortunately, there's no reliable way for the program |
mjr | 35:e959ffba78fd | 35 | // to determine the length of the linker output, so we can't know |
mjr | 35:e959ffba78fd | 36 | // where our available region starts. But we do know how much flash |
mjr | 35:e959ffba78fd | 37 | // there is overall, so we know where the flash ends. We can |
mjr | 35:e959ffba78fd | 38 | // therefore align our storage region at the end of memory and hope |
mjr | 35:e959ffba78fd | 39 | // that it's small enough not to encroach on the linker space. We |
mjr | 35:e959ffba78fd | 40 | // can actually do a little better than hope: the mbed tools tell us |
mjr | 35:e959ffba78fd | 41 | // at the UI level how much flash the linker is using, even though it |
mjr | 35:e959ffba78fd | 42 | // doesn't expose that information to us programmatically, so we can |
mjr | 35:e959ffba78fd | 43 | // manually check that we have enough room. As of this writing, the |
mjr | 35:e959ffba78fd | 44 | // configuration structure is much much smaller than the available |
mjr | 35:e959ffba78fd | 45 | // leftover flash space, so we should be safe indefinitely, barring |
mjr | 35:e959ffba78fd | 46 | // a major expansion of the configuration structure or code size. |
mjr | 35:e959ffba78fd | 47 | // |
mjr | 35:e959ffba78fd | 48 | // The boot loader seems to erase the entire flash space every time |
mjr | 35:e959ffba78fd | 49 | // we load new firmware, so our configuration structure is lost |
mjr | 35:e959ffba78fd | 50 | // when we update. Furthermore, since we explicitly choose to put |
mjr | 35:e959ffba78fd | 51 | // the config structure in space that isn't initialized by the linker, |
mjr | 35:e959ffba78fd | 52 | // we can't specify the new contents stored on these erasure events. |
mjr | 35:e959ffba78fd | 53 | // To deal with this, we use a signature and checksum to check the |
mjr | 35:e959ffba78fd | 54 | // integrity of the stored data. The erasure leaves deterministic |
mjr | 35:e959ffba78fd | 55 | // values in memory unused by the linker, so we'll always detect |
mjr | 35:e959ffba78fd | 56 | // an uninitialized config structure after an update. |
mjr | 35:e959ffba78fd | 57 | // |
mjr | 35:e959ffba78fd | 58 | struct NVM |
mjr | 35:e959ffba78fd | 59 | { |
mjr | 35:e959ffba78fd | 60 | public: |
mjr | 35:e959ffba78fd | 61 | // checksum - we use this to determine if the flash record |
mjr | 35:e959ffba78fd | 62 | // has been properly initialized |
mjr | 35:e959ffba78fd | 63 | uint32_t checksum; |
mjr | 35:e959ffba78fd | 64 | |
mjr | 35:e959ffba78fd | 65 | // signature and version reference values |
mjr | 35:e959ffba78fd | 66 | static const uint32_t SIGNATURE = 0x4D4A522A; |
mjr | 35:e959ffba78fd | 67 | static const uint16_t VERSION = 0x0003; |
mjr | 35:e959ffba78fd | 68 | |
mjr | 35:e959ffba78fd | 69 | // Is the data structure valid? We test the signature and |
mjr | 35:e959ffba78fd | 70 | // checksum to determine if we've been properly stored. |
mjr | 35:e959ffba78fd | 71 | int valid() const |
mjr | 35:e959ffba78fd | 72 | { |
mjr | 35:e959ffba78fd | 73 | return (d.sig == SIGNATURE |
mjr | 35:e959ffba78fd | 74 | && d.vsn == VERSION |
mjr | 35:e959ffba78fd | 75 | && d.sz == sizeof(NVM) |
mjr | 35:e959ffba78fd | 76 | && checksum == CRC32(&d, sizeof(d))); |
mjr | 35:e959ffba78fd | 77 | } |
mjr | 35:e959ffba78fd | 78 | |
mjr | 35:e959ffba78fd | 79 | // save to non-volatile memory |
mjr | 35:e959ffba78fd | 80 | void save(FreescaleIAP &iap, int addr) |
mjr | 35:e959ffba78fd | 81 | { |
mjr | 35:e959ffba78fd | 82 | // update the checksum and structure size |
mjr | 35:e959ffba78fd | 83 | d.sig = SIGNATURE; |
mjr | 35:e959ffba78fd | 84 | d.vsn = VERSION; |
mjr | 35:e959ffba78fd | 85 | d.sz = sizeof(NVM); |
mjr | 35:e959ffba78fd | 86 | checksum = CRC32(&d, sizeof(d)); |
mjr | 35:e959ffba78fd | 87 | |
mjr | 35:e959ffba78fd | 88 | // figure the number of sectors required |
mjr | 35:e959ffba78fd | 89 | int sectors = (sizeof(NVM) + SECTOR_SIZE - 1) / SECTOR_SIZE; |
mjr | 35:e959ffba78fd | 90 | for (int i = 0 ; i < sectors ; ++i) |
mjr | 35:e959ffba78fd | 91 | iap.erase_sector(addr + i*SECTOR_SIZE); |
mjr | 35:e959ffba78fd | 92 | |
mjr | 35:e959ffba78fd | 93 | // save the data |
mjr | 35:e959ffba78fd | 94 | iap.program_flash(addr, this, sizeof(*this)); |
mjr | 35:e959ffba78fd | 95 | } |
mjr | 35:e959ffba78fd | 96 | |
mjr | 35:e959ffba78fd | 97 | // stored data (excluding the checksum) |
mjr | 35:e959ffba78fd | 98 | struct |
mjr | 35:e959ffba78fd | 99 | { |
mjr | 35:e959ffba78fd | 100 | // Signature, structure version, and structure size, as further |
mjr | 35:e959ffba78fd | 101 | // verification that we have valid data. |
mjr | 35:e959ffba78fd | 102 | uint32_t sig; |
mjr | 35:e959ffba78fd | 103 | uint16_t vsn; |
mjr | 35:e959ffba78fd | 104 | int sz; |
mjr | 35:e959ffba78fd | 105 | |
mjr | 35:e959ffba78fd | 106 | // configuration and calibration data |
mjr | 35:e959ffba78fd | 107 | Config c; |
mjr | 35:e959ffba78fd | 108 | } d; |
mjr | 35:e959ffba78fd | 109 | }; |
mjr | 35:e959ffba78fd | 110 | |
mjr | 35:e959ffba78fd | 111 | #endif /* NVM_M */ |