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.

RE: msp430fr6989 write in FRAM

Other Parts Discussed in Thread: MSP430FR69891

Original thread: https://e2e.ti.com/support/microcontrollers/msp430/f/166/p/485532/2272339#2272339

Hi Katie,

Thanks very much for posting this information.

I'm having a similar problem trying to use the FRAM as RAM for variable storage (e.g. logging).  I'm using the MSP430FR69891, and CCS 7.2.0, with the MSP430 C Compiler v16.9.4.LTS.  I noticed in one of the links you provided in your answer that the compiler was the newer 17.6.0.STS.  Maybe the compiler version is the issue here?

I'm using the #pragma PERSISTENT feature, and the variable (a buffer) is placed in RAM, not in FRAM.  However, when I place the buffer in a specific FRAM location (e.g.  #pragma location = 0x4400) then the buffer is placed in FRAM.  However, this obviously steps on the code, since now the code crashes.

Thanks in advance for any help with this issue.

Thanks,
Adam

  • Hi Adam,

    Can you please post a code snippet showing how you are setting up the buffer?

    Regards,
    Katie
  • Hi Katie,

    Thanks for your reply.

    Here's how it's being setup:

    #pragma NOINIT(FRAM_write)
    #pragma PERSISTENT( FRAM_write )
    //#pragma location = 0x4400;
    unsigned long FRAM_write[ 128 ];


    Then in main(), the first thing it does:

    memset( FRAM_write, 0xA5, sizeof( FRAM_write ) );


    The FRAM_write variable ends up being in RAM, as seen from the following map file:

    This places FRAM_write in RAM, as seen from the memory map:

    output attributes/
    section page origin length input sections
    -------- ---- ---------- ---------- ----------------
    .bss 0 00001c00 0000059a UNINITIALIZED
    00001c00 00000200 (.common:FRAM_write)



    When I use the #pragma location feature, then it goes in FRAM. Here's that code:

    #pragma NOINIT(FRAM_write)
    #pragma PERSISTENT( FRAM_write )
    #pragma location = 0x4400;
    unsigned long FRAM_write[ 128 ];

    And the map file:

    .TI.bound:FRAM_write
    * 0 00004400 00000200 UNINITIALIZED
    00004400 00000200 main.obj (.TI.bound:FRAM_write)


    Thanks,
    Adam
  • Hi Adam,

    I think that #pragma NOINIT and #pragma PERSISTENT should not be used together. Is CCS throwing any warning message when you build?

    For PERSISTENT, it actually needs to have an initialization value, e.g.

    #pragma PERSISTENT( FRAM_write )
    unsigned long FRAM_write[ 128 ] = {0};

    This conflicts with NOINIT because that would require you NOT to have an initialization value. It sounds like NOINIT is overriding PERSISTENT in this case, so let's get rid of it.

    I would recommend using PERSISTENT alone, as shown in my example above. I just tried this with your compiler version and it appeared to work correctly. The value set for the initialization will only be set when you first load code to the part, but the compiler will make it so the c-startup code does not re-initialize the area at every startup. That way your FRAM values will not be wiped away by c-startup code and will be retained through a power cycle or reset of the code. PERSISTENT is also what is used for the automatic MPU handling by the MPU tool.

    Regards,

    Katie

  • Hi Katie,

    Thank you very much for your quick responses. It's very much appreciated!

    For the version of code I sent you I had both PERSISTENT and NOINIT together, but I've also tried them apart, with no difference. I've tried all permutations (but only sent you one of them), and none of them have worked.

    But, your suggestion of giving it an initialization value, solves the problem! That is something I hadn't done.

    This works:
    #pragma PERSISTENT( FRAM_write )
    unsigned long FRAM_write[ 128 ] = {0};

    This doesn't work:
    #pragma NOINIT( FRAM_write )
    unsigned long FRAM_write[ 128 ] = {0};

    So, it looks like the only option is to use the PERSISTENT pragma for FRAM placement. The NOINIT pragma will not work. I just added this for clarity, for myself. You didn't suggest the NOINIT technique.

    Thanks again Katie for your help. You've been very helpful!

    Adam
  • Hi Katie,

    This brings up an additional question.

    Is there a way to lock down the location of a variable in FRAM, from build to build? So in other words, rev. A of the firmware gets released into the field, and then rev. B comes along, but now that FRAM variable has been moved by the linker, due to things shifting around in the build. I realize that there's the #pragma location feature, and maybe that's the way to do it.

    Thanks in advance for your help with this.

    And, thanks again for your help with the previous FRAM questions.

    Thanks,
    Adam
  • Hi Adam,

    If you always reference the FRAM variable as a variable instead of trying to write to a hard-coded address with pointers, then it truly should not matter where the linker places the variable. So my question is basically why do you want to lock down a specific address for the FRAM variable - what is the use-case? There are ways to do it, but you would end up not using the automatic linker handling of your MPU initialization in this case and also would need a custom linker file. So if you can instead just access the FRAM like a variable, array, etc instead of using statements to write to a hard-coded address, this will be much much easier long term for you.

    Using PERSISTENT, the default linker files place all read + write variables at the beginning of the FRAM on the part. But if you add/remove/change size of the variables they may end up within slightly different addresses within that grouping. But as I said there are very few use-cases where you would need to actually set a specific absolute address - the beauty of using a variable/array though is that you don't need to know the absolute address.

    Regards,

    Katie

  • Hi Katie,

    Thanks for your reply.

    As an example, the firmware has a set of system parameters living in FRAM, which need to persist across power cycles. For example, the Front Panel LCD contrast setting, which lives at FRAM address 0x4400. So, for rev. A firmware, this setting is at 0x4400. Now for rev. B, some changes were made in the code, and things got shifted around, and now the LCD contrast setting lives at a slightly different FRAM address 0x4410. This obviously won't work, since when rev. B firmware got installed, it will look at address 0x4410, for the LCD contrast setting, but it actually lives at address 0x4400, resulting in the setting not getting applied correctly (e.g. a garbage value gets applied).

    Hopefully this example makes sense.

    I'm agreeing with you that a custom linker file is needed. So, I'll need to explore that option some more.

    Thanks for your help. It's much appreciated.

    Adam
  • Hi Adam,

    How is the custom linker file method working for you - do you need any guidance to get that up and running?

    Regards,
    Katie
  • Hi Katie,

    The custom linker file is working out well.  Now that I've created a custom linker file, defining a section in FRAM for Persistent Storage, and giving it the property that it isn't initialized automatically to zero on power-up, it is working exactly as is needed.  This is the solution I was looking for, and the only way to get there is with the custom linker file.  I've done the same thing with other processors in the past, so it makes complete sense that this is the way to do it with the MSP430.  I really like TI's documentation regarding the linker file format.  It is very thorough, which I very much appreciate.

    Thanks for your help with this.

    Adam

  • Great! I'm glad to hear everything worked out for you.

    Regards,

    Katie

**Attention** This is a public forum