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.

MSP430G - storing data in small section of flash/ROM

Other Parts Discussed in Thread: MSP430G2553

Hello E2E forum!

We are using the MSP430G2553 part with 16 KB of ROM and we would like to store some data in non-volatile flash/ROM, ( ~ 1k in size).  We have already used the Information area and now have to use area otherwise allocated for code.  

Is there any example code of this being done?

I realize that we will have to change the linker file in either TICC or IAR to make this work. Examples of this would be helpful.

Any feedback or input is welcomed and appreciated!

Thanks again!

Paul

  • For IAR, make and use a modified private copy of the linker command file lnk430g2553.xcl

    (1) First search all occurrence of "C000", you probably will find the following lines:

    // Read-only memory (FLASH):       C000-FFFF

    -Z(CODE)CSTART,ISR_CODE,CODE_ID=C000-FFDF

    -P(CODE)CODE=C000-FFDF

    -J2,crc16,,,CHECKSUM,,#0xFFFF=C000-FFBF

    (2) Chang all those "C000" into "C400"

    (3) And also insert lines such as:

    -Z(DATA)MYINFO=C000-C3FF

    -Z(CONST)MYINFOA=C200-C3FF

    -Z(CONST)MYINFOB=C000-C1FF

    You know have 2 private Sectors (i.e., 1KB) of Flash Memory called MYINFOA and MYINFOB for your private use.

  • With IAR, no need to edit the linker file really as that is always a pain as it never uses a local copy of it (without you changing that)

    I just did this in IAR and seems to work just fine with the standard linker file as it is. 
    __no_init static char storage[1024] @ 0xc000;

    You have to use an example some were in your code like: char  qwert = storage[0];
    for the compiler to really include it as without being referenced it will skip it, until you use it for real like in the flash write routine etc
    The good part is that 1Kb storage is now an actual array for C.

  • Thanks very much!

    We are using code composer.  Attached is my linker file. Do I have to do anything in the SECTIONS part of the file?

    Also, I assume to write this area I have to go through similar procedures as for the info areas – correct?

    Typically we do something like this:

    static void dataflash_access( unsigned char *seg_ptr )

    {

       while(BUSY & FCTL3);

      

       const unsigned char erase_flag = seg_ptr != NULL;

       FCTL1 = FWKEY + (erase_flag ? ERASE : 0);

       FCTL3 = FWKEY + (erase_flag ? 0     : LOCK);

       if( erase_flag ) {

          *seg_ptr = 0;

       }

    }

    static void dataflash_write( unsigned char *dst1, unsigned char *src1, unsigned char size1 )

    {

       dataflash_access( dst1 );

       FCTL1 = FWKEY + WRT;

       memcpy( dst1, src1, size1 );

       dataflash_access( NULL );

    }

     

    Where the seg_ptr would be like 0XC000

    We set the flash speed early in our code

      //set the internal clocks to 16 MHz

       BCSCTL1 = CALBC1_16MHZ; //0x1089;

       BCSCTL3 |= XCAP_3; //add so load capacitance //remove on real board

       DCOCTL  = CALDCO_16MHZ;

    //set the flash clock register for writing/erasing information memory

       FCTL2 = FWKEY + FSSEL_1 + FN0 + FN5;

    lnk_msp430g2553.txt
    /* ============================================================================ */
    /* Copyright (c) 2014, Texas Instruments Incorporated                           */
    /*  All rights reserved.                                                        */
    /*                                                                              */
    /*  Redistribution and use in source and binary forms, with or without          */
    /*  modification, are permitted provided that the following conditions          */
    /*  are met:                                                                    */
    /*                                                                              */
    /*  *  Redistributions of source code must retain the above copyright           */
    /*     notice, this list of conditions and the following disclaimer.            */
    /*                                                                              */
    /*  *  Redistributions in binary form must reproduce the above copyright        */
    /*     notice, this list of conditions and the following disclaimer in the      */
    /*     documentation and/or other materials provided with the distribution.     */
    /*                                                                              */
    /*  *  Neither the name of Texas Instruments Incorporated nor the names of      */
    /*     its contributors may be used to endorse or promote products derived      */
    /*     from this software without specific prior written permission.            */
    /*                                                                              */
    /*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" */
    /*  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,       */
    /*  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR      */
    /*  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR            */
    /*  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,       */
    /*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,         */
    /*  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; */
    /*  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,    */
    /*  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR     */
    /*  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,              */
    /*  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                          */
    /* ============================================================================ */
    
    /******************************************************************************/
    /* lnk_msp430g2553.cmd - LINKER COMMAND FILE FOR LINKING MSP430G2553 PROGRAMS     */
    /*                                                                            */
    /*   Usage:  lnk430 <obj files...>    -o <out file> -m <map file> lnk.cmd     */
    /*           cl430  <src files...> -z -o <out file> -m <map file> lnk.cmd     */
    /*                                                                            */
    /*----------------------------------------------------------------------------*/
    /* These linker options are for command line linking only.  For IDE linking,  */
    /* you should set your linker options in Project Properties                   */
    /* -c                                               LINK USING C CONVENTIONS  */
    /* -stack  0x0100                                   SOFTWARE STACK SIZE       */
    /* -heap   0x0100                                   HEAP AREA SIZE            */
    /*                                                                            */
    /*----------------------------------------------------------------------------*/
    /* Version: 1.159                                                             */
    /*----------------------------------------------------------------------------*/
    
    /****************************************************************************/
    /* 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 = 0x0200, length = 0x0200
        INFOA                   : origin = 0x10C0, length = 0x0040
        INFOB                   : origin = 0x1080, length = 0x0040
        INFOC                   : origin = 0x1040, length = 0x0040
        INFOD                   : origin = 0x1000, length = 0x0040
        FLASH_WAT               : origin = 0xC000, length = 0x0400
        FLASH                   : origin = 0xC400, length = 0x3BE0
        INT00                   : origin = 0xFFE0, length = 0x0002
        INT01                   : origin = 0xFFE2, length = 0x0002
        INT02                   : origin = 0xFFE4, length = 0x0002
        INT03                   : origin = 0xFFE6, length = 0x0002
        INT04                   : origin = 0xFFE8, length = 0x0002
        INT05                   : origin = 0xFFEA, length = 0x0002
        INT06                   : origin = 0xFFEC, length = 0x0002
        INT07                   : origin = 0xFFEE, length = 0x0002
        INT08                   : origin = 0xFFF0, length = 0x0002
        INT09                   : origin = 0xFFF2, length = 0x0002
        INT10                   : origin = 0xFFF4, length = 0x0002
        INT11                   : origin = 0xFFF6, length = 0x0002
        INT12                   : origin = 0xFFF8, length = 0x0002
        INT13                   : origin = 0xFFFA, length = 0x0002
        INT14                   : origin = 0xFFFC, length = 0x0002
        RESET                   : origin = 0xFFFE, length = 0x0002
    }
    
    /****************************************************************************/
    /* Specify the sections allocation into memory                              */
    /****************************************************************************/
    
    SECTIONS
    {
        .bss        : {} > RAM                  /* Global & static vars              */
        .data       : {} > RAM                  /* Global & static vars              */
        .TI.noinit  : {} > RAM                  /* For #pragma noinit                */
        .sysmem     : {} > RAM                  /* Dynamic memory allocation area    */
        .stack      : {} > RAM (HIGH)           /* Software system stack             */
    
        .text       : {} > FLASH                /* Code                              */
        .cinit      : {} > FLASH                /* Initialization tables             */
        .const      : {} > FLASH                /* 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            */
    
        .infoA     : {} > INFOA              /* MSP430 INFO FLASH Memory segments */
        .infoB     : {} > INFOB
        .infoC     : {} > INFOC
        .infoD     : {} > INFOD
    
        /* MSP430 Interrupt vectors          */
        TRAPINT      : { * ( .int00 ) } > INT00 type = VECT_INIT
        .int01       : {}               > INT01
        PORT1        : { * ( .int02 ) } > INT02 type = VECT_INIT
        PORT2        : { * ( .int03 ) } > INT03 type = VECT_INIT
        .int04       : {}               > INT04
        ADC10        : { * ( .int05 ) } > INT05 type = VECT_INIT
        USCIAB0TX    : { * ( .int06 ) } > INT06 type = VECT_INIT
        USCIAB0RX    : { * ( .int07 ) } > INT07 type = VECT_INIT
        TIMER0_A1    : { * ( .int08 ) } > INT08 type = VECT_INIT
        TIMER0_A0    : { * ( .int09 ) } > INT09 type = VECT_INIT
        WDT          : { * ( .int10 ) } > INT10 type = VECT_INIT
        COMPARATORA   : { * ( .int11 ) } > INT11 type = VECT_INIT
        TIMER1_A1    : { * ( .int12 ) } > INT12 type = VECT_INIT
        TIMER1_A0    : { * ( .int13 ) } > INT13 type = VECT_INIT
        NMI          : { * ( .int14 ) } > INT14 type = VECT_INIT
        .reset       : {}               > RESET  /* MSP430 Reset vector         */ 
    }
    
    /****************************************************************************/
    /* Include peripherals memory map                                           */
    /****************************************************************************/
    
    -l msp430g2553.cmd
    
    

     

    Thanks again!

    Paul

     

  • Hi Paul,

      This wiki should give you some tips on how to modify your linker file.

    Also, these are the functions that I've used to write/erase to memory (very similar to what you have):

    FlashState_T Flash_Erase (uint8_t segment)
    {
    	uint16_t locCounter = 1;
    
    	Flash_ptr = (uint8_t *) ((0xffff - ((segment + 1) * 512)) + 1);
    	FCTL1 = FWKEY + ERASE;                   // Set Erase bit
    	FCTL3 = FWKEY;                           // Clear Lock bit
    	*Flash_ptr = 0;                          // Dummy write to erase Flash segment
    
    	/* operation ongoing -> wait until ready */
    	while( ( ( FCTL3 & BUSY ) == BUSY ) && ( locCounter++ ) );
    	FCTL3 = FWKEY + LOCK;                    // Set LOCK bit
    
    	if (locCounter != 0)
    	{
    		return (OK);
    	}
    	else
    	{
    		return (ERROR);
    	}
    }
    
    /***********************************************************
      Function: Flash_Write
    */
    FlashState_T Flash_Write(uint8_t *Src_address_ptr, uint16_t Dest_address, uint8_t byte_count)
    {
    	uint8_t index;
    	uint16_t locCounter;
    	FlashState_T locStatus = OK;
    
    	FCTL3 = FWKEY;                                 // Clear Lock bit
    	Flash_ptr = (uint8_t *) Dest_address; 	           // Initialize Destination Flash pointer
    
    	FCTL1 = FWKEY + WRT;                           // Set WRT bit for write operation
    
    	for (index = 0; index < byte_count; index++)
    	{
    		*Flash_ptr++ = Src_address_ptr[index];     // Write value to flash
    
    		locCounter = 1;
    
    		/* operation ongoing -> wait until ready */
    		while( ( ( FCTL3 & BUSY ) == BUSY ) && ( locCounter++ ) );
    
    		if (locCounter == 0)
    		{
    			locStatus = ERROR;
    			break;
    		}
    	}
    	FCTL1 = FWKEY;                                 // Clear WRT bit
    	FCTL3 = FWKEY + LOCK;                          // Set LOCK bit
    
    	return (locStatus);
    }


    Paul Schoenke said:
    Do I have to do anything in the SECTIONS part of the file?

    Yes, for example:

    MEMORY
    {
        SFR                     : origin = 0x0000, length = 0x0010
        PERIPHERALS_8BIT        : origin = 0x0010, length = 0x00F0
        PERIPHERALS_16BIT       : origin = 0x0100, length = 0x0100
        RAM                     : origin = 0x1100, length = 0x1000
        INFOA                   : origin = 0x1080, length = 0x0080
        INFOB                   : origin = 0x1000, length = 0x0080
        FLASH                   : origin = 0x2100, length = 0xDEC0
        FLASH3                  : origin = 0x1e000,length = 0x2000
    ...
    
    SECTIONS
    {
        .bss        : {} > RAM                  /* Global & static vars              */
        .data       : {} > RAM                  /* Global & static vars              */
        .TI.noinit  : {} > RAM                  /* For #pragma noinit                */
        .sysmem     : {} > RAM                  /* Dynamic memory allocation area    */
        .stack      : {} > RAM (HIGH)           /* Software system stack             */
    
        .text       : {}>> FLASH       /* Code                              */
        .text_test  : {} > FLASH3
        .text:_isr  : {} > FLASH                /* ISR Code space                    */
        .cinit      : {} > FLASH                /* Initialization tables             */
        .const      : {} > FLASH       /* Constant data                     */
        .cio        : {} > RAM        
    
    ....
    
    #pragma CODE_SECTION(testFunction,".text_test")
    void testFunction(void)
    {
        while(1);
    }
    

    Hopefully this helps.

      Regards,

        David

  • Thanks so much for the great feedback!

    Do you have to wait after writing every byte to flash for the busy flag?

    Thanks again!

    Paul

  • Hi Paul,

    Yes it does. Please take a look at section 7.3.4 Flash Memory Access During Write or Erase of the users guide (www.ti.com/.../slau144j.pdf).

    Best regards,

    David
  • DavidL said:
    Hi Paul,

    Yes it does. Please take a look at section 7.3.4 Flash Memory Access During Write or Erase of the users guide (www.ti.com/.../slau144j.pdf).

    Best regards,

    David

    1. That section starts with: "When any write or any erase operation is initiated from RAM...". Are we initiate those operations form RAM?
    2. The uint16_t locCounter is initially set to 1. It will take exactly 65535 ++ operation to make locCounter == 0. Is there any situation this may happen? If so, what is that situation?
    -- OCY
  • Thanks very much!  After reading that section it appears to make the distinction between writing from RAM and writing from flash. I interpret this as whether your code is being executed out of RAM (such as a boot loader) vs. out of program memory. If this is true, it appears from my reading that you only have to check that bit after every word write if you are running out of RAM. The discussion in that section implies  that when running out of flash, the flash memory controller blocks the CPU to ensure you don't have a memory access violation.

    This seems to indicate this is done without intervention, automatically, and therefore the need to check that bit after every write is unnecessary.

    Please let me know if my reading is incorrect. I also looked at a couple of examples online and most did not have that check in there.

    Thanks again very much!

    Paul

  • Now, your reading is correct.

    For MSP430 with more than one "Bank" of Flash memory, if the Erase or Write operation for Flash in one Bank is initiated from code in a different Bank, waiting for the Busy-bit is needed. The User's Guide did not mention this.
  • "For MSP430 with more than one "Bank" of Flash memory, if the Erase or Write operation for Flash in one Bank is initiated from code in a different Bank, waiting for the Busy-bit is needed."
    On some MSPs (including the 5438 non-A), initiating bank erase form a different bank will crash the CPU. On a write operation, BUSY is not needed to be checked, multi-banked MSPs behave like the normal ones for the write (CPU jumps on place by fetching $3FFF). It's only the bank erase that allows continuing reading from other flash banks.

    But back to the original post:
    If there is plenty of flash space left, there is another way of reserving space in flash without touching the linker script:
    define an area that is 511 bytes larger than your required storage space.
    const char reserved[size+511];
    char * storage_start = (reserved+511)&0xFE00;
    This ensures that you will find a complete 512 bytes flash segment where no code or other constants are stored and where you can safely store your data. The drawback is that its position may move with each code change, and it is part of the written code, so you cannot preserve it across firmware updates. And it wastes 511 bytes of flash.
    But this method is 100% portable across different devices as well as different compilers.

**Attention** This is a public forum