This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

What is the best practice for programming a flash parameter block (for non-volatile device configuration parameters)?

Hi

I'm using a flash parameter block for device configuration. (LM4F120, LaunchPad, Code Composer Studio, C, Firmware development package Flash API)

I want my embedded device to ship with a' factory default' configuration which can later be modified in the field by the user.  Pretty standard stuff.

 

The parameter block is a big C struct.  I can initialize the struct in firmware to the 'factory default' values by assigning values to each element of the struct.  This is self-documenting, and easy to read and modify.

The initialization section of the firmware code can then write this struct containing these hard-coded values to flash .

The problem is the flash will be initialized every time the firmware initialization section is RUN, which is every time it is BOOTED or powered up.  This obviously defeats the whole purpose of flash. 

Clearly, I need the flash parameter block initialized only when the part is PROGRAMMED.

 

So, what is the 'right way' to do this in Code Composer Studio?

 

Thanks in advance for your help

-Adam

  • Hi Adam,

    I'm sorry, but I think I don't understand this question correctly!

    Adam Brailove said:

    The parameter block is a big C struct.  I can initialize the struct in firmware to the 'factory default' values by assigning values to each element of the struct.  This is self-documenting, and easy to read and modify.

    When you're talking about 'initializing' by firmware what do you mean? After power-up i.e.?

    Adam Brailove said:

    The initialization section of the firmware code can then write this struct containing these hard-coded values to flash .

    Why will you write some known data to flash after each power-up?

    I would do it this way:

    - Modify the linker control file that way that it gives a segment in the flash memory ( (i.e. named INITDATA) which is large enough to store the 'factory initialization data' (also needs to take the min. page size for a 'flash erase' = 1kbyte into account). This data is then accessed by using a 'big struct' during runtime

    - a constant table - representing the initialization data - will be placed (linked) into this segment

    Now, the user wants to change the data (default data). If your RAM memory is large enough you can load the whole constant table to RAM, let the application (i.e.User via terminal commands) change some of the parameters and then the application calls a functions which

     a) erases the INITDATA segment and

     b) writes new (custom) data to flash.

    So, does this szenario represents what you're trying to do?

    You may also want to have a look at this application note http://www.ti.com/mcu/docs/litabsmultiplefilelist.tsp?sectionId=96&tabId=1502&literatureNumber=spma030&docCategoryId=1&familyId=2940 . It covers EEPROM emulation on Stellaris MCUs.

    aBUGSworstnightmare

  • Hi,

    @aBUGSworstnightmare: I think he refers to the file utils/flash_pb.c...

    Petrei 

  • Sorry I was not clear.  Let me try to clarify:

    I am using utils/flash_pb.c, and it works great, but that is not a critical point, I think.  I am definitely able to setup, read, and write flash parameter block data from my C (firmware) code. 

    I decided to organize all the parameters using a C struct containing the many parameters: floats, ints chars arrays.  But that is not a critical point either.

    If I initialize the flash parameter block from C code, for example:

    myParameterBlockStruct.fParamX = 3.0;      // Initialize a variable in the struct to 'factory-default' value of 3.0

    FlashPBSave(&myParameterBlockStruct);    // Write the struct to flash

    then the flash parameter block gets re-initialized every time the microcontroller is booted up and this code is run.  This is quite useless, since the flash needs to retain the user-applied settings after every power-up.

    Obviously, the flash needs to be initialized only when the device is programmed, not every time it is booted up.  (I say 'obvoiusly', but actually it didn't ocurr to me at first.  It is obvoius to me now)

     

    So, aBUG's comments about using the linker and a 'constant table' are, I think, pointing me in the right direction (thank you) I just don't know exactly how to do it.(the CCS build settings are intimidating so I haven't touched them). 

    How/where do I make a 'constant table' ?

    Will I be able to manage the constants in a readable form, or just a big blob of hex?

    If it is a blob of hex, are there tools to help create/manage  the table?

    Exactly how do I tell the linker to write the table to flash?

    Can I control whether the the linker erases that section of flash when the device is programmed?

    etc.

     

    Thanks again !

    -Adam

     

     

     

     

  • Hi Adam,

    The typical way to do this is with some sort of checksum (simple or CRC).  The FlashPBIIsValid() function does a simple checksum on the parameter block.  Your start-up code could call this function and program the default values if the function returns 0 indicating that checksum is not valid or if all values are 0xff.  A benefit of this is that if the parameter block gets corrupted, then the defaults will be restored. 

    Note that the checksum here is a simple byte-wide check, so it has limitations.  A CRC-16 check would provide safer validation.

  • Hi Adam,

    I'm sorry, but I can't provide you a proven example for Stellaris! Here's an example how I did it on a MSP430 (modified for the Stellaris .cmd-file format). In principle it's the same on the Stellaris.

    1. Modify the linker command file (i.e. lm4f120h5qr.cmd for the LM4F120; the file is in your project folder by adding a new memory block and a section definition.

    MEMORY

    {

        FLASH (RX) : origin = 0x00000800, length = 0x00039200    

     CHANNEL0 (RX) : origin = 0x00039200, length = 0x0400

        CHANNEL1 (RX): origin = 0x00039600, length = 0x0400

        SRAM (RWX) : origin = 0x20000000, length = 0x00008000

    }

    This example will define 2 segemts in flash (CHANNEL0 and 1; located at the end of the available flash memory), each 1024bytes (0x400) large. You need to reduce the ammount of available flash (segment FLASH) respectivly (was 0x40000 --> now 0x39200) 

    Now, you need to add a new section (scroll down in the .cmd file):

    /* Section allocation in memory */

    SECTIONS

    {

        .intvecs:   > 0x00000000

        .text   :   > FLASH

        .const  :   > FLASH

        .cinit  :   > FLASH

        .pinit  :   > FLASH

        .channel0 :  > CHANNEL0 

       .channel1 :  > CHANNEL1

        .vtable :   > 0x20000000

        .data   :   > SRAM

        .bss    :   > SRAM

        .sysmem :   > SRAM

        .stack  :   > SRAM

    }

    This tells the linker were to place the data in.

    For details on the linker command file refer to the documentation please!

    2.) Initialize your constant table and tell the linker were to place it by using a #PRAGMA directive:

    #pragma DATA_SECTION (move0, ".channel0")

    const unsigned int move0[53] =

              {

                16,                  // Write value to flash   --> 17 position data sets

                // number in flash needs to be actual no of positions -1

                0,

                

    1430,

    160,

    50,

    1060,

    160,

    82,

    1785,

    160,

    50,

    1200,

    160,

    50,

    1628,

    160,

    67,

    1200,

    160,

    50,

    1500,

    160,

    71,

    1375,

    160,

    5,

    1505,

    160,

    43,

    1120,

    160,

    50,

    1800,

    160,

    30,

    1718,

    160,

    50,

    1175,

    160,

    172,

    1761,

    160,

    35,

    1430,

    160,

    12,

    1245,

    160,

    10,

    1550,

    160,

    50,

              };

    I only used constants for this example but you can initialize (and place) your structure the same way.

    A brief explaination:

    #pragma DATA_SECTION (move0, ".channel0")--> we're dealing with data and not op-code, the variable 'move0' will be placed in the section '.channel0' which is located in the memory SEGMENT CHANNEL0 (Flash memory).

    EDIT: You need to switch back to the default segment at the end of your definition; I think it's done by #pragma DEFAULT (but I'm not quite shure about this since I usually use a separate .c-file for each special segment).

    Access to your data is as usual; nothing to care about.

    aBUGSworstnightmare

  • Jonathan,

    your suggested method is elegant and it solved the problem.  Thanks.

     

    My code is based on the API in StellarisWare utils/flash_pb.c which handles checksum and fault tolerance etc very nicely.

    So I used FlashPBGet() which according to the docs:

     "Returns the address of the most recent parameter block, or NULL if there is no valid parameter blocks in flash"

     

    For reference, a code snippet (without error checking) is below:

     

    --------------------------  CODE SNIPPET ------------------------------------

    // ---- Flash Setup.  tFlashParams is a struct that holds all my parameters

    uLen = sizeof(tFlashParams); // Get length of parameter block struct

    FlashPBInit(0x3f800, 0x40000, 512);   // Set up parameter block of 512 bytes, in two erase pages starting at 0x3F800 (2 pages x 1024 byes/page)

    pucParamBlock = FlashPBGet();   // Attempt to get valid flash parameter block

    if(!pucParamBlock) { // If there is no valid flash parameter block then...

    FlashParamsDefaultInit();   // Initialize all the variables in global struct to their default values

    FlashPBSave((unsigned char*) &tFlashParams); // ...and write the struct with default values to flash

    }

    pucParamBlock = FlashPBGet();   // Now get the pointer to the parameter data from flash

    if(pucParamBlock) {   // If valid now, then ....

    memcpy(&tFlashParams, pucParamBlock, uLen);   // copy the contents of flash back into the struct

    }

  • Hi Adam, everybody,
    Firstly, thanks to all people in this community, it is a really information gold-source..

    I was using the Flash_PB library to write the Flash. I followed this and other examples.
    I am using the TM4C1294 connected launchpad, Windows 7, CCS V7, and TI 16.9.1 LTS compiler.
    I am just playing with flash, to store some permanent parameters. My struct is really simple: only 2 uint32_t variables.
    When the system powers-up, I init the Flash block:

    FlashPBInit(0x3F800,0x40000,512);
    tFlashParams.var1=0x01;
    tFlashParams.var2=0x02;

    after user pushes a push-button, this variables are increased and stored in the Flash:
    FlashParams.var1++;
    tFlashParams.var2++;
    FlashPBSave((unsigned char*)&tFlashParams); //write struct on flash

    Then, I get the values:
    pucParamBlock=FlashPBGet();
    memcpy(&tFlashParams,pucParamBlock,uLen);

    the problem, is that it works only 5 times... I wave no idea why. Maybe I am not understanding how the flash memory is used to store this, but I quite lost.

    Thanks!
    jordi
  • Adam,

    Just for the record, we have a library with a similar purpose, although we save it into eeprom. The general "logic" we implemented was:

    1- Always begin by applying the default values to the RAM strucuture

    2- Call a "Config_Initialization" function, which looks for a FingerPrint in a separate eeprom address. If the FP is there, it means the board had run before, hence copies eeprom struct into RAM. If not, copy the current RAM structure (which still has the defaults) to eeprom, and writes the FP.

    3- There are usually a few parameters that are hardcoded despite whatever was (or not) in eeprom before; these hardcoded things are again overwritten to RAM after phase two (ignore this if that's not your case, but I particularly refer, for example, to a firmware version stored in a macro).

    For the decision on step 2, besides finding a Fingerprint, we also use something like "EEPROM_OVERRIDE", that is handful if you need to erase the settings even if such FP was already stored.

    After some cleaning and optimization, it became our default library for general configuration of any new project. Of course, there are some other bells and whistles, and also we have learned that it works well for us to keep a common config structure for ALL of our arm projects, and a separate "project-specific" structure for each product.

    Hope that makes sense and is useful.

    Regards

    Bruno
  • A couple of other items to consider along Bruno's lines

    1. A version number of the structure. Lets you detect changes that leave the EE size the same but change meanings.
    2. Mirroring. Parameter writes can be interrupted. Keeping a mirrored copy lets you select a backup if one is corrupted

    I end up with multiple parameter block types

    • Checksumed and mirrored
    • Checksummed and not mirrored. These might be too large to mirror or easy to generate reasonable defaults.
    • Not checksummed or mirrored (usually faults or logs)

    Robert

  • Perhaps it should be noted that "Adam" was last seen/heard/read - these parts - more than FOUR Years past!

    Hovering over his name reveals "Recent Activity" - which notes such, "Four Year absence..."

  • And if you are interested in the next level of abstraction. I develop the structures in a spreadsheet (one tab per block) and generate any needed code from there.

    Robert

  • Ola Robert - that is SO GOOD that it (may) even cause "Adam" to reverse his abandonment of this forum...      (maybe)

  • cb1_mobile said:
    Perhaps it should be noted that "Adam" was last seen/heard/read - these parts - more than FOUR Years past!

    Hahaha, that's blushing! That fellow has probably given up EE and is now a resident in some hospital after so long!    :O

    Alright, poster "Jordi Nonell Canals48": PLEASE, DO create a new thread if you come across a similar situation, ok? Your question/issue is not the same as the original's thread title!

    When other people read a thread, there is a HUGE tendency to assume that the first post is the QUESTION, and all other are comments or further details, but not really a new completely different question.

    (Or at least, I MYSELF have that huge tendency...)

    Anyway, as far as your (Jordi's) question goes, I am not familiar with FlashPB library, and I suggest you use the Flash API's which are part of Tivaware. Create your own set of auxiliary functions for reading/writing your structure into flash memory using Tivaware calls.

    Bruno

  • I like this checksum story, Robert!
    I don't think we ever spotted a corrupt saved structure in our products - we just rely on reading the eeprom again after writing the structure, and comparing this second reading to the previous ram content. If they don't match, the function is allowed to try again a few more "timeout" times, but the bad-eeprom flag has not yet lit up in our toys...
    But still, it sounds like a nice touch of safety!
    The other related feature we plan to implement is a rotation of the eeprom location... It would force the application to scroll through the whole eeprom area until some sort of invalid FFFF's are found, and assume the previous block is good. Then, when the product is next shut down, the following block would be used. But it is just a thought here for the time being.
  • Bruno Saraiva said:
    I don't think we ever spotted a corrupt saved structure in our products - we just rely on reading the eeprom again after writing the structure

    I have and your test wouldn't catch most of them.

    Consider what happens if

    • You lose power part way through writing a block. Holdup may be feasible on an individual write but not necessarily for a full block
    • You get a reset part way through writing.
    • EMI induces a write before you write protect the EE. Note: my experience is the induced write could be anywhere.
    • The non-volatile memory isn't. Yes I've seen this happen. Had to add production tests to catch the faulty devices.

    One you are write protected it's pretty safe but before then there are multiple sources of interference.

    Your test catches the case where the write failed or the first read after the write failed. You will only notice the other failure mechanisms because of add side effects. And if you do get the case you are checking I'd venture the odds of the others happening is high.

    Robert

    Note: some standards require non-volatile parameters be secured by some sort of checksum.

  • Robert,
    Certainly all true! Thanks for the feedback.
    Good thing that all these protections can be added to the library itself (I hope), hence the application as is will still be able to simply read or write a "non-volatile" structure with no need for changes.
    I agree that none of your fault scenarios are too hard to happen - we were probably just lucky that our hardware are kind of designed in a way the those are very unlikely - but I now appreciate even more your input and will be moving this "non-volatile" protection implementation higher up on the (long) to-do-list.
    Cheers
    Bruno
  • Bruno Saraiva said:
    Good thing that all these protections can be added to the library itself (I hope), hence the application as is will still be able to simply read or write a "non-volatile" structure with no need for changes.

    Seems likely. You appear to have a good setup.

    Bruno Saraiva said:
    I agree that none of your fault scenarios are too hard to happen - we were probably just lucky that our hardware are kind of designed in a way the those are very unlikely

    Or you're unlikely enough that the failures are subtle enough that no one has attributed them to odd values in the EE :) To be fair a lot of the failures I observed were in a relatively high EMI environment.

    Bruno Saraiva said:
    will be moving this "non-volatile" protection implementation higher up on the (long) to-do-list.

    It only gets short once support is abandoned doesn't it? :)

    Robert

  • Bruno Saraiva said:
    will be moving this "non-volatile" protection implementation higher up on the (long) to-do-list.

    And - might that (long) "to-do-list" become (even) longer - as, poster "Adam" has, "(long) Fled the building..." 

    Somewhere (w/in past 90 days) electronic press compared/contrasted EE memory "w/in MCUs" vs. "stand alone ICs."       Hands down - stand alone ICs won - beware!

  • Interesting cb1. I can well believe that, particularly if the TM4Cs were included in the mix.

    External NV memory also allows optimizing size, performance and cost.

    Robert
  • cb1_mobile said:
    compared/contrasted EE memory "w/in MCUs" vs. "stand alone ICs."

    I wouldn't expect a different result. A dedicated part is usually, well, designed for the purpose.

    But still it appears to me that a well implemented eeprom library can fully achieve the published/datasheet eeprom functionalities, and the scenario of not having to add/route/procure/configure one extra circuit is attractive.

    I assume that almost every project that involves an M4 arm-based MCU demands some sort of non-volatile storage, and at least this basic need should be addressable without the need for external parts. Coming to think of it, I have recently looked at that other vendor's tenfold-more-popular processor, and the lack of internal eeprom was a fact that surprised me... 

    Low volume NV storage? Whenever cost allows, I'm a fan of F-RAM.

    Regards

    Bruno

  • You may note that (both) friend Robert and I advise posters,  Avoid, "Premature Optimization!"       (always have to "bear down/focus" when keying in that phrase...)

    All here must "note" (really note) that - as poster Bruno writes, "not having to add/route/procure/configure one extra circuit" has some appeal."    

    Yet - and significantly unsaid - is the EXTRA: "Time, Effort, Testing, Verification and very real RISK" which such "saving" admits.

    Perhaps better to employ KNOWN, SUPERIOR, More ROBUST external device (we too like Fram) until the "potential benefit" of such "saving" is very well established - thus proven.     (btw - that "proof" is rare - far better: SAFE, SECURE (via external device) than "Sorry" (via the MCU alone) as "kitchen sink" (Do everything - fairly poorly - at that.)

    I would add that - most always - the inclusion of, "SPI Bus and SPI ICs" avoids or at least minimizes "added" routing demands - and in fact is "Standard Practice" w/in our firm!       (we may chose "DNF" (Do Not Fill) should the fram not be required - yet its footprint & routing are ALWAYS there!         (thus ALL (earlier) objections to SAFE/SECURE/EXTERNAL Device dissolve...)