Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
nvm.h@59:94eb9265b6d7, 2016-05-12 (annotated)
- Committer:
- mjr
- Date:
- Thu May 12 05:57:53 2016 +0000
- Revision:
- 59:94eb9265b6d7
- Parent:
- 40:cc0d9814522b
- Child:
- 76:7f5912b6340e
Replaced library malloc with custom version that's slightly more efficient and makes more memory available overall
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 | 40:cc0d9814522b | 21 | // |
mjr | 35:e959ffba78fd | 22 | // Our use of flash for this purpose is ad hoc and not supported |
mjr | 40:cc0d9814522b | 23 | // by the mbed platform. mbed doesn't impose a file system (or any |
mjr | 40:cc0d9814522b | 24 | // other kind of formal structure) on the KL25Z flash; it simply |
mjr | 40:cc0d9814522b | 25 | // treats the flash as a raw storage space for linker output and |
mjr | 59:94eb9265b6d7 | 26 | // assumes that the linker is the only thing using it. So in order |
mjr | 59:94eb9265b6d7 | 27 | // to use the flash, we basically have to do it on the sly, by |
mjr | 59:94eb9265b6d7 | 28 | // using space that the linker happens to leave unused. |
mjr | 40:cc0d9814522b | 29 | // |
mjr | 40:cc0d9814522b | 30 | // Fortunately, it's fairly easy to do this, because the flash is |
mjr | 40:cc0d9814522b | 31 | // mapped in the obvious way, as a single contiguous block in the |
mjr | 59:94eb9265b6d7 | 32 | // CPU memory space, and because the mbed linker seems to do the |
mjr | 59:94eb9265b6d7 | 33 | // obvious thing, storing its entire output in a single contiguous |
mjr | 59:94eb9265b6d7 | 34 | // block starting at the lowest flash address. This means that all |
mjr | 59:94eb9265b6d7 | 35 | // flash memory from (lowest flash address + length of linker output) |
mjr | 59:94eb9265b6d7 | 36 | // to (highest flash address) is unused and available for our sneaky |
mjr | 35:e959ffba78fd | 37 | // system. Unfortunately, there's no reliable way for the program |
mjr | 35:e959ffba78fd | 38 | // to determine the length of the linker output, so we can't know |
mjr | 35:e959ffba78fd | 39 | // where our available region starts. But we do know how much flash |
mjr | 35:e959ffba78fd | 40 | // there is overall, so we know where the flash ends. We can |
mjr | 35:e959ffba78fd | 41 | // therefore align our storage region at the end of memory and hope |
mjr | 35:e959ffba78fd | 42 | // that it's small enough not to encroach on the linker space. We |
mjr | 35:e959ffba78fd | 43 | // can actually do a little better than hope: the mbed tools tell us |
mjr | 35:e959ffba78fd | 44 | // at the UI level how much flash the linker is using, even though it |
mjr | 35:e959ffba78fd | 45 | // doesn't expose that information to us programmatically, so we can |
mjr | 35:e959ffba78fd | 46 | // manually check that we have enough room. As of this writing, the |
mjr | 35:e959ffba78fd | 47 | // configuration structure is much much smaller than the available |
mjr | 35:e959ffba78fd | 48 | // leftover flash space, so we should be safe indefinitely, barring |
mjr | 35:e959ffba78fd | 49 | // a major expansion of the configuration structure or code size. |
mjr | 40:cc0d9814522b | 50 | // (And if we get to the point where we actually don't have space |
mjr | 40:cc0d9814522b | 51 | // for our ~1K structure, we'll be up against the limits of the |
mjr | 40:cc0d9814522b | 52 | // device anyway, so we'd have to rein in our ambitions or write |
mjr | 40:cc0d9814522b | 53 | // more efficient code for deeper reasons than sharing this tiny |
mjr | 40:cc0d9814522b | 54 | // sliver of memory.) |
mjr | 35:e959ffba78fd | 55 | // |
mjr | 35:e959ffba78fd | 56 | // The boot loader seems to erase the entire flash space every time |
mjr | 35:e959ffba78fd | 57 | // we load new firmware, so our configuration structure is lost |
mjr | 35:e959ffba78fd | 58 | // when we update. Furthermore, since we explicitly choose to put |
mjr | 35:e959ffba78fd | 59 | // the config structure in space that isn't initialized by the linker, |
mjr | 35:e959ffba78fd | 60 | // we can't specify the new contents stored on these erasure events. |
mjr | 35:e959ffba78fd | 61 | // To deal with this, we use a signature and checksum to check the |
mjr | 35:e959ffba78fd | 62 | // integrity of the stored data. The erasure leaves deterministic |
mjr | 35:e959ffba78fd | 63 | // values in memory unused by the linker, so we'll always detect |
mjr | 35:e959ffba78fd | 64 | // an uninitialized config structure after an update. |
mjr | 35:e959ffba78fd | 65 | // |
mjr | 35:e959ffba78fd | 66 | struct NVM |
mjr | 35:e959ffba78fd | 67 | { |
mjr | 35:e959ffba78fd | 68 | public: |
mjr | 35:e959ffba78fd | 69 | // checksum - we use this to determine if the flash record |
mjr | 35:e959ffba78fd | 70 | // has been properly initialized |
mjr | 35:e959ffba78fd | 71 | uint32_t checksum; |
mjr | 35:e959ffba78fd | 72 | |
mjr | 35:e959ffba78fd | 73 | // signature and version reference values |
mjr | 35:e959ffba78fd | 74 | static const uint32_t SIGNATURE = 0x4D4A522A; |
mjr | 35:e959ffba78fd | 75 | static const uint16_t VERSION = 0x0003; |
mjr | 35:e959ffba78fd | 76 | |
mjr | 35:e959ffba78fd | 77 | // Is the data structure valid? We test the signature and |
mjr | 35:e959ffba78fd | 78 | // checksum to determine if we've been properly stored. |
mjr | 35:e959ffba78fd | 79 | int valid() const |
mjr | 35:e959ffba78fd | 80 | { |
mjr | 35:e959ffba78fd | 81 | return (d.sig == SIGNATURE |
mjr | 35:e959ffba78fd | 82 | && d.vsn == VERSION |
mjr | 35:e959ffba78fd | 83 | && d.sz == sizeof(NVM) |
mjr | 35:e959ffba78fd | 84 | && checksum == CRC32(&d, sizeof(d))); |
mjr | 35:e959ffba78fd | 85 | } |
mjr | 35:e959ffba78fd | 86 | |
mjr | 35:e959ffba78fd | 87 | // save to non-volatile memory |
mjr | 35:e959ffba78fd | 88 | void save(FreescaleIAP &iap, int addr) |
mjr | 35:e959ffba78fd | 89 | { |
mjr | 35:e959ffba78fd | 90 | // update the checksum and structure size |
mjr | 35:e959ffba78fd | 91 | d.sig = SIGNATURE; |
mjr | 35:e959ffba78fd | 92 | d.vsn = VERSION; |
mjr | 35:e959ffba78fd | 93 | d.sz = sizeof(NVM); |
mjr | 35:e959ffba78fd | 94 | checksum = CRC32(&d, sizeof(d)); |
mjr | 35:e959ffba78fd | 95 | |
mjr | 35:e959ffba78fd | 96 | // figure the number of sectors required |
mjr | 35:e959ffba78fd | 97 | int sectors = (sizeof(NVM) + SECTOR_SIZE - 1) / SECTOR_SIZE; |
mjr | 35:e959ffba78fd | 98 | for (int i = 0 ; i < sectors ; ++i) |
mjr | 35:e959ffba78fd | 99 | iap.erase_sector(addr + i*SECTOR_SIZE); |
mjr | 35:e959ffba78fd | 100 | |
mjr | 35:e959ffba78fd | 101 | // save the data |
mjr | 35:e959ffba78fd | 102 | iap.program_flash(addr, this, sizeof(*this)); |
mjr | 35:e959ffba78fd | 103 | } |
mjr | 35:e959ffba78fd | 104 | |
mjr | 35:e959ffba78fd | 105 | // stored data (excluding the checksum) |
mjr | 35:e959ffba78fd | 106 | struct |
mjr | 35:e959ffba78fd | 107 | { |
mjr | 35:e959ffba78fd | 108 | // Signature, structure version, and structure size, as further |
mjr | 35:e959ffba78fd | 109 | // verification that we have valid data. |
mjr | 35:e959ffba78fd | 110 | uint32_t sig; |
mjr | 35:e959ffba78fd | 111 | uint16_t vsn; |
mjr | 35:e959ffba78fd | 112 | int sz; |
mjr | 35:e959ffba78fd | 113 | |
mjr | 35:e959ffba78fd | 114 | // configuration and calibration data |
mjr | 35:e959ffba78fd | 115 | Config c; |
mjr | 35:e959ffba78fd | 116 | } d; |
mjr | 35:e959ffba78fd | 117 | }; |
mjr | 35:e959ffba78fd | 118 | |
mjr | 35:e959ffba78fd | 119 | #endif /* NVM_M */ |