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.

Store variables in Flash on MSP430F5437A

Other Parts Discussed in Thread: MSP430F5437A

I need help figuring out how to store data in flash memory that my application can use.  I am using a MSP430F5437A device. 

What I want to do is store two types of data.  One is result data that I collect periodically (~every 2 sec) and the second is reference data that is updated occasionally (twice a year).  The reference data is read from the main application and is used to perform calculations.

I would like to map two variables to flash memory and read as if they were any other variable

I modified the .cmd file first by adding “MYDATA” as follows:

 

/****************************************************************************/

/* SPECIFY THE SYSTEM MEMORY MAP                                            */

/****************************************************************************/

 

MEMORY

{

    SFR                     : origin = 0x0000, length = 0x0010

    PERIPHERALS_8BIT        : origin = 0x0010, length = 0x00F0

    PERIPHERALS_16BIT       : origin = 0x0100, length = 0x0100

    RAM                     : origin = 0x1C00, length = 0x4000

    INFOA                   : origin = 0x1980, length = 0x0080

    INFOB                   : origin = 0x1900, length = 0x0080

    INFOC                   : origin = 0x1880, length = 0x0080

    INFOD                   : origin = 0x1800, length = 0x0080

    FLASH                   : origin = 0x5C00, length = 0xA380

   

    /* old line; keep as reference */

/*    FLASH2                  : origin = 0x10000,length = 0x35C00  */

    FLASH2                  : origin = 0x10000,length = 0x1AE00

    MYDATA                  : origin = 0x2AE00,length = 0x1AE00

    INT00                   : origin = 0xFF80, length = 0x0002

/****************************************************************************/

/* SPECIFY THE SECTIONS ALLOCATION INTO MEMORY                              */

/****************************************************************************/

 

SECTIONS

{

    .bss        : {} > RAM                /* GLOBAL & STATIC VARS              */

    .data       : {} > RAM                /* GLOBAL & STATIC VARS              */

    .sysmem     : {} > RAM                /* DYNAMIC MEMORY ALLOCATION AREA    */

    .stack      : {} > RAM (HIGH)         /* SOFTWARE SYSTEM STACK             */

 

    .text       : {}>> FLASH | FLASH2     /* CODE                              */

    .text:_isr  : {} > FLASH              /* ISR CODE SPACE                    */

    .cinit      : {} > FLASH              /* INITIALIZATION TABLES             */

    .const      : {} > FLASH | FLASH2     /* CONSTANT DATA                     */

    .cio        : {} > RAM                /* C I/O BUFFER                      */

 

    .pinit      : {} > FLASH              /* C++ CONSTRUCTOR TABLES            */

    .init_array : {} > FLASH              /* C++ CONSTRUCTOR TABLES            */

    .mspabi.exidx : {} > FLASH            /* C++ CONSTRUCTOR TABLES            */

    .mspabi.extab : {} > FLASH            /* C++ CONSTRUCTOR TABLES            */

    .mydata       : {} > MYDATA           /* custom data             */

 

In my source file I have the following functions to read and write flash data:

 

 

#define ARRY_SZ 5000

 

typedef struct _run_data

{

    unsigned long value;    // actual value

    unsigned int  time_ms;  // time in millisecond

} tRUN_DATA;

 

#pragma DATA_SECTION(flash_run_data, ".mydata");

#pragma DATA_ALIGN(flash_run_data, 1);

tRUN_DATA flash_run_data[ARRY_SZ];

 

#pragma DATA_SECTION(flash_reference, ".mydata");

#pragma DATA_ALIGN(flash_reference, 1);

tRUN_DATA flash_reference[ARRAY_SZ];

 

//--------------------------------------------------

void FLASH_Read(tRUN_DATA *data, int index)

{

  data->value = flash_run_data[index].value;

  data->time_ms = flash_run_data[index].time_ms;

}

 

 

 

//--------------------------------------------------

void FLASH_Write(tRUN_DATA data)

{

  FLASH_UNLOCK;

  flash_run_data[flash_index].value     = data.value;

  flash_run_data[flash_index].time_ms   = data.time_ms;

  FLASH_LOCK;

 

  flash_index++;

}

 

 

 

I am getting warnings during compile that I don’t understand.  They are:

#17003-D relocation from FLASH_Read” to symbol “flash_run_data” overflowed; the 18-bit relocated address 0x2ae00 is too large to  encode in the 16-bit filed

 

#10015-D output file “.out” cannot be loaded and run on a target system.

 

 

 

  • Hi,

    i think you need to active the large data model.

  • No change.  I feel I have something flawed in my basic concept.  First of all is it possible to store variables in flash?  If I can, is it correct to modify the .cmd file as I have done to create MYDATA?  Next, in my source file do I use “#pragma DATA_SECTION()” and  “#pragma DATA_ALIGN()”.  Once this is set up, I assume I can write and read to the variables defined.  Is this the correct approach?

  • Hi,

    I tested #pragma DATA_SECTION before, but i have never tried to use #pragma DATA_SECTION and #pragma DATA_ALIGN together.

    Could you try what happen if you don't use the #pragma DATA_ALIGN?

  • No change.  Am I creating .mydata section correctly in "lnk_msp430f5437a.cmd" file?

  • mrmrlarry said:
    First of all is it possible to store variables in flash?

    No.

    Flash is read-only memory. A variable is read/write (hence 'variable'). The linker will not place writable elements into flash area unless you deliberately instruct it to do so.
    OTOH, constants (which are read only too) are usually automatically placed in flash.

    Since you'll need specific code to change content in flash, you can define your storage area as constant data (so it is plaed in flash) and then pass the flash write function its pointer, along with the data to be written.

    However, writing to flash has some limitations. You can write to flash only if it has been erased before (you cannot overwrite a '0' with a '1'). And you can only erase it in chunks of 512 bytes. So storage is not as simple as x[i]=y;
    To change a single element in flash, you'll have to read the whole 512 bytes block it is in, erase the block, then write all 512 bytes (with the changed one) back.
    And it is slooow.

  • What is actually the implementation of your FLASH_UNLOCK and FLASH_LOCK?

  • #define FLASH_UNLOCK    FCTL3 = FWKEY; FCTL1 = FWKEY + WRT;

    #define FLASH_LOCK      FCTL1 = FWKEY; FCTL3 = FWKEY +  LOCK;

  • Hi,

    i am able to reproduce the problem.

    To fix this, just change the data type to "const tRUN_DATA" instead of only "tRUN_DATA". However i think you need to case your variable type when trying to write the data inside your Flash_write() function, and as JMG said above, not forget to erase the data first before writing new value (flash can be only written from 1->0"). 

    EDIT: here is my test code:

    /*
     * main.c
     */
    #include <msp430.h>
    
    #define ARRAY_SZ      (5000)
    
    typedef struct _run_data
    {
        unsigned long value;    // actual value
        unsigned int  time_ms;  // time in millisecond
    } tRUN_DATA;
    
    #define FLASH_UNLOCK    FCTL3 = FWKEY; FCTL1 = FWKEY + WRT;
    #define FLASH_LOCK      FCTL1 = FWKEY; FCTL3 = FWKEY +  LOCK;
    
    #pragma DATA_SECTION(flash_run_data, ".mydata");
    const tRUN_DATA flash_run_data[ARRAY_SZ];
    
    #pragma DATA_SECTION(flash_reference, ".mydata");
    const tRUN_DATA flash_reference[ARRAY_SZ];
    
    void FLASH_Read(tRUN_DATA *data, unsigned int index)
    {
      data->value = flash_run_data[index].value;
      data->time_ms = flash_run_data[index].time_ms;
    }
    
    void FLASH_Write(tRUN_DATA data)
    {
      static unsigned int flash_index = 0;
    
      FLASH_UNLOCK;
    
      ((tRUN_DATA*)flash_run_data)[flash_index].value     = data.value;
      ((tRUN_DATA*)flash_run_data)[flash_index].time_ms   = data.time_ms;
    
      FLASH_LOCK;
    
      flash_index++;
    
    }
    
    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;
      tRUN_DATA test_data;
      unsigned int i;
    
      while(1)
      {
        for(i=0 ; i<20 ; i++)
        {
          FLASH_Read(&test_data, i);
        }
      }
    }
    

  • I am still not sure I am creating the “.mydata” section correctly.  When I run my test app using “.infoA” instead of “.mydata”, it appears to work as expected.

    #pragma DATA_SECTION(flash_run_data, ".infoB");   // appears to work

    Instead of…

    #pragma DATA_SECTION(flash_run_data, ".mydata");   // does not work

     

  • I had the same issue with your test code.  I created a project for the MSP430F5437A in CCS v5.2, modified .cmd file to add MYDATA and get the same warnings.

  • I attached a zipped file containing the test project using CCS v5.2.  Is the .cmd file modified correctly?

    In file main.c, if I use the #pragma for "mydata" in lines 18 and 22, I get the warnings,  If I use the #pragma for "infoB" in lines 17 and 21, it compiles fine.  What is happening here and how can I get it to work properly?

    This is the message I get when compiling using #pragma in lines 18 and 22:

  • Here's the zipped project....6505.FlashTest.zip

  • Hi,

    i checked your project, you forget to enable the large data model i suggested above.

    here is the new project files:

    0550.FlashTest.zip

  • Got it.  Thanks.

  • Hello,

       I notice that this procedure doesn't work in CCs 5.5.0. In fact many errors are produced when I try to use --data_model = large, because free compiler version tries to build a library that doesn't work (and doesn't link).

    However a small tip appears when I pass with cursor onto combo box : this tip recommend the use of "restricted" model, that after a test work correctly!

    Finally, this is the code I wrote: 

    unsigned char *FPTR;
    FPTR = (unsigned char *) 0x1C400L; // Initialize Flash pointer

    ...

    FCTL3 = FWKEY; // Clear Lock bit
    FCTL1 = FWKEY+WRT; // Set WRT bit for write operation
    for(i = 0; i < 256; i++)
    {
    *FPTR = value; // Write a char to flash
    value = value - 1;
    FPTR++;
    }
    FCTL1 = FWKEY; // Clear WRT bit
    FCTL3 = FWKEY+LOCK; // Set LOCK bit

    Best regard,

    Massimo

**Attention** This is a public forum