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.

FRAM memory segmentation

Other Parts Discussed in Thread: MSP430FR5739

I'm a little confused on the memory segmentation scheme for the new MSP430FR devices. I understand how to define the individual segments, but how do I tell the compiler that I want my program's execution code to reside in Segment 1 (i.e. main( ) and all of my own functions), read-only variables in Segment 2 (for configuration), and read/write variables in Segment 3 (data storage and logging of events)?

Note: Using C code in CCSv4 (please be gentle with the software, my specialty is more towards hardware)

  • I do not use c and do not know how to use CCS. But I think the Linker in CCS only needs to know the physical address range of R/O memory vs R/W memory. For MS430FR, R/O memory must be FRAM whereas R/W memory can be either SRAM or FRAM. You only need to specify this in the Linker Command File.

  • Hi Eric,

    this is hanndled by the linker command file. See the extract from lnk_msp430fr5739.cmd below:


    SECTIONS
    {
        GROUP(ALL_FRAM)
        {
           GROUP(READ_WRITE_MEMORY): ALIGN(0x0200) RUN_START(fram_rw_start)
           {
              .bss    : {}                   /* GLOBAL & STATIC VARS              */
              .cio    : {}                   /* C I/O BUFFER                      */
              .sysmem : {}                   /* DYNAMIC MEMORY ALLOCATION AREA    */
              .stack  : {}                   /* SOFTWARE SYSTEM STACK             */
           }

           GROUP(READ_ONLY_MEMORY): ALIGN(0x0200) RUN_START(fram_ro_start)
           {
              .cinit  : {}                   /* INITIALIZATION TABLES             */
              .pinit  : {}                   /* C++ CONSTRUCTOR TABLES            */
              .const  : {}                   /* CONSTANT DATA                     */
           }

           GROUP(EXECUTABLE_MEMORY): ALIGN(0x0200) RUN_START(fram_rx_start)
           {
              .text   : {}                   /* CODE                              */
           }
        } > FRAM

    ...

    This will place op-code (incl. all your functions) in executable_memory, const data (read only) in read_only_memory and all your variables in read_write_memory.
    This .cmd-file does not make use of RAM!

    If you want to have your own, custom segments, you can define them in the .cmd-file as usual (make a new segment definition). If you want to have them at a certain address, you will have to make a full-curtom linker-command-file.
    Also find some details on how to place data/code in specific segments in the i.e. C Compiler Users Guide (http://www.ti.com/litv/pdf/slau132e).

    Rgds
    aBUGSworstnightmare

  • Eric Jonardi said:
    how do I tell the compiler that I want my program's execution code to reside in Segment 1

    COmpiler and linker are usually built together. So the compiler knows what standard segments are defined in the linker command file. And it automatically pics the proper standard segment based on the type of code/data it generates.
    If you define your own segments, then you have to specifiy for each element where it has to go to.

    It is possible to tell the compiler to put a R/W variable into flash or a function into volatile ram if you want. But it will most likely not give the desired result :)

    How ou can tell the compiler to put something into a different than the standard segment, depends on the compiler. Some use a #pragma directive, some an attribute modifier, some a compiler-specific keyword.

    I don't mknow the CCS syntax, as I'm MSPGCC user. There it would be
    const char __attribute__ ((section(".fartext"))) fardata[128]={9,8,7,6,5,4,3,2,1,0};
    to put fardata in a self-defined segment .fartext

  • Based on the C compiler guide from your link, it seems that the MPU operates completely transparent to the normal user:

    4.3.4 Initialization of the FRAM Memory Protection Unit said:
    The linker supports initialization of the FRAM memory protection unit (MPU). The linker uses a boot routine that performs MPU initialization based on the definition of certain symbols. The TI provided linker command files that are used by default for different devices define the necessary symbols so MPU initialization happens automatically. Code and data sections are automatically given the correct access permissions. If you want to manually adjust how the MPU is initialized you can modify the __mpuseg and __mpusam definitions in the linker command file. The MPU-specific boot routine is used when these two symbols are defined and it sets the value of the MPUSEG and MPUSAM registers based on these values. If you do not want the MPU initialized you can remove these definitions from the linker command file.


    While this simplifies having to deal with organizing the memory myself, it leaves me with two questions:

    1.) I need to be able to store data (for event logging) between system resets, with no predictability and limited/zero warning as to when these resets will occur. Normally this might be suited to an external EEPROM or FRAM chip, but now that I have on-chip FRAM I would like to leverage it as much as possible. Ideally this quasi-permanent data will be an array (info memory will be to small for this). How would I reserve space for and access this data?

    2.) I plan to initiate software BORs often alongside the occasional external reset, to ensure that all active code/variables/registers are uncorrupted. The device will be in a cubesat (VERY tiny satellite), so RAM corruption due to radiation soft errors is a significant risk. Based on my understanding (correct me if I'm wrong), the configuration information placed at the beginning of main( ) and all other execution code will be loaded from the FRAM correctly each time, even if the code that had been active in the RAM and the control registers was indeed corrupted. (also, if you feel this strategy is unwise/unnecessary, please feel free to voice your constructive criticism)

  • Eric,

    I would like to add some comments...

    1) The way CCS is setup today - based on the linker command file that was shown in a post above - all the global variables are already placed in FRAM and the SRAM does not get used at all.  The disadvantage to this approach is that you may taking up valuable code space - to store variables that may not need storing, also FRAM accesses are higher power than SRAM. So if you have some variables that dont need to be non-volatile dont waste power by storing them in FRAM.

    2) Yes the calibration/ configuration information that is essential for device functionality is accessed by the boot code (in ROM) and is rewritten afer a power cycle. I am not sure what you are referring to when you say "control registers". If the device hasn't been through an actual power cycle but only a software BOR, the SRAM contents will likely be retained. If this is not wanted, it can be re-initalized at startup.

    Overall if you are looking for flexibility in terms of code Vs data storage I would recommend looking into customizing the linker command file (the Help section in CCS has useful documents). Split up your memory into 1) volatile data - SRAM 2) NV data (FRAM) and 3) Code FRAM. I will also recommend using the memory protection unit to specify read/ write and execute permissions between the sections.

    If I havent answered your question please let me know,

    -Priya

  • Priya,

    Thanks for taking the time to answer my long winded questions.

    1.) How would I go about reserving space for and then later accessing non-volative data on internal FRAM between power cycles? (if I can do this in C code only without modifying the linker file, then all the better)

    Side note: since the SRAM is not used, and the FRAM is immune to radiation soft-errors, would the the only parts of the device's operation susceptible to radition soft errors be the core lore logic (PC, ALU), or is there something else that I'm forgetting?

    2.) I would probably re-intialize to ensure the validity of the active code.

    Also, isn't the MPU initialized by default by the C compiler?

    4.3.4 Initialization of the FRAM Memory Protection Unit said:
    TI provided linker command files that are used by default for different devices define the necessary symbols so MPU initialization happens automatically.

    -Eric

  • CCS dos not set uninitialized data to 0. That's different from a normal C compiler behavior, which will put all non.initialized variables into a segment hat has been erased before, but is handy here. Just do not initialize a variable and it will have the value at startup that was oon its memory location on power-on.
    You can define a guard variable that is not initialized too , but triggers a manual initialization of your variables (where needed) on the very first start. Then set this variable to the guard value and on subsequent starts the init loop will not be executed. You'll have to program this on your own, it is not a compiler feature.

    Eric Jonardi said:
    Also, isn't the MPU initialized by default by the C compiler?

    I think the cides part refers to the fact that the startup code will automatically get the information about which part of FRAM is variable and must be R/W and which part is code and will stay RO.
    Also, the stack is initialized by this code.
    If your project is plain assembly language, there i sno statup code and yo'll have to take care of it yourself.

    P.s.: if radiation soft errors on SRAM aren't an issue, I'd put the stack onto SRAM. Since the MSP doesn't keep its processor status on a reset (or power-off), the stack content can be volatile too. - you cannot recover anyway. And if the core is subject to radiationerrors too, then it makes no difference at all. So why wasting energy and time to put the stack contents on FRAM.

**Attention** This is a public forum