Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

nvm.h

Committer:
mjr
Date:
2015-12-19
Revision:
35:e959ffba78fd
Child:
40:cc0d9814522b

File content as of revision 35:e959ffba78fd:

// NVM - Non-Volatile Memory
//
// This module handles the storage of our configuration settings
// and calibration data in flash memory, which allows us to
// retrieve these settings after each power cycle.


#ifndef NVM_H
#define NVM_H

#include "config.h"
#include "FreescaleIAP.h"


// Non-volatile memory (NVM) structure
//
// This structure defines the layout of our saved configuration
// and calibration data in flash memory.
//
// Hack alert!
// Our use of flash for this purpose is ad hoc and not supported
// by the mbed platform.  mbed doesn't impose a file system on the
// KL25Z flash; it simply treats the flash as a raw storage space
// and assumes that the linker output is the only thing using it.
// So if we want to use the flash, we basically have to do it on 
// the sly, by using space that the linker happens to leave unused.
// Fortunately, it's fairly easy to do this, because the flash
// is mapped in the obvious way, as a single contiguous block in 
// the CPU memory space, and the linker does the obvious thing, 
// storing its entire output in a single contiguous block starting
// at the lowest flash address.  This means that all flash memory
// from (lowest flash address + length of linker output) to
// (highest flash address) is unused and available for our sneaky
// system.  Unfortunately, there's no reliable way for the program
// to determine the length of the linker output, so we can't know 
// where our available region starts.  But we do know how much flash 
// there is overall, so we know where the flash ends.  We can 
// therefore align our storage region at the end of memory and hope 
// that it's small enough not to encroach on the linker space.  We
// can actually do a little better than hope: the mbed tools tell us 
// at the UI level how much flash the linker is using, even though it 
// doesn't expose that information to us programmatically, so we can 
// manually check that we have enough room.  As of this writing, the 
// configuration structure is much much smaller than the available 
// leftover flash space, so we should be safe indefinitely, barring 
// a major expansion of the configuration structure or code size.
//
// The boot loader seems to erase the entire flash space every time
// we load new firmware, so our configuration structure is lost
// when we update.  Furthermore, since we explicitly choose to put
// the config structure in space that isn't initialized by the linker,
// we can't specify the new contents stored on these erasure events.
// To deal with this, we use a signature and checksum to check the
// integrity of the stored data.  The erasure leaves deterministic
// values in memory unused by the linker, so we'll always detect
// an uninitialized config structure after an update.
//
struct NVM
{
public:
    // checksum - we use this to determine if the flash record
    // has been properly initialized
    uint32_t checksum;

    // signature and version reference values
    static const uint32_t SIGNATURE = 0x4D4A522A;
    static const uint16_t VERSION = 0x0003;
    
    // Is the data structure valid?  We test the signature and 
    // checksum to determine if we've been properly stored.
    int valid() const
    {
        return (d.sig == SIGNATURE 
                && d.vsn == VERSION
                && d.sz == sizeof(NVM)
                && checksum == CRC32(&d, sizeof(d)));
    }
    
    // save to non-volatile memory
    void save(FreescaleIAP &iap, int addr)
    {
        // update the checksum and structure size
        d.sig = SIGNATURE;
        d.vsn = VERSION;
        d.sz = sizeof(NVM);
        checksum = CRC32(&d, sizeof(d));
        
        // figure the number of sectors required
        int sectors = (sizeof(NVM) + SECTOR_SIZE - 1) / SECTOR_SIZE;
        for (int i = 0 ; i < sectors ; ++i)
            iap.erase_sector(addr + i*SECTOR_SIZE);

        // save the data
        iap.program_flash(addr, this, sizeof(*this));
    }
    
    // stored data (excluding the checksum)
    struct
    {
        // Signature, structure version, and structure size, as further
        // verification that we have valid data.
        uint32_t sig;
        uint16_t vsn;
        int sz;
        
        // configuration and calibration data
        Config c;
    } d;
};

#endif /* NVM_M */