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.

CCS/MSP430FR2433: Variable that is #pragma PERSISTENT but not compile time initialized is NOT persistent and compiler should give error, not warning

Part Number: MSP430FR2433


Tool/software: Code Composer Studio

As noted in another post

#pragma PERSISTENT
int foo;

does not result in the variable foo being persistent in FRAM.  Instead, the compiler gives a warning "warning #1519-D: variable "foo" was declared persistent and should be explicitly initialized" and storage is allocated in .bss segment, i.e. RAM.

In my opinion the compiler should give an error message instead of a warning.    The compiler has failed the contract to put the variable in FRAM.  My analogy is if  I would declare a variable an int but the compiler only generated a byte storage.

I think there are valid reasons not to initialize FRAM variables:  I am going to initialize them at run-time on a power-on reset, or in other resets such as a software BOR reset (when I detect certain faults and must restart my app in its initial state.)  After that, I expect the variables to persist through other resets (namely LPM4.5 resets.)  Since I already have code to initialize the variables at run-time, it is more convenient not to write code to initialize them at compile time.  Especially if the variables are more complicated structs.

To some extent, I am venting, because this oddity bit me.

  • lloyd konneker said:
    In my opinion the compiler should give an error message instead of a warning.

    You can change compiler behavior regarding the handling of many diagnostics, including this one.  Because you build with the option --display_error_number, you see the ID of this diagnostic is 1519 ...

    lloyd konneker said:
    "warning #1519-D: variable "foo" was declared persistent and should be explicitly initialized"

    Build with the option --diag_error=1519 to cause this diagnostic to be an error instead of a warning.  For more information on changing how diagnostics are handled, please search the MSP430 compiler manual for the sub-chapter titled Understanding Diagnostic Messages.

    As for allocating uninitialized variables to FRAM ... Unfortunately, the solution is not as simple.  A more complicated (but not extremely complicated) solution exists that involves using the DATA_SECTION pragma and writing a bit of linker command file code.  Are you interested in that?

    Thanks and regards,

    -George

  • Changing diagnostics seems like a palliative, a work around.

    There is controversy about using pragmas in a compiler, quoting the GCC documents:   "It was basically a mistake to use #pragma for anything."  In this case, I am relying on the behavior (put the variable in FRAM) for correctness of my program.   Other pragmas are the same way, e.g. the pragma about ISR vectors, if the compiler doesn't load the code at the right address, the ISR won't work, the pragma is not just a suggestion that the compiler can ignore.   So IMO the CCS compiler has poorly implemented the pragma PERSISTENT.

    Maybe the solution is just in TI's documentation about FRAM compiler support, to reiterate that the pragma and the initialization clause are both required.  That's really what I am asking, I don't think said documentation has a statement "you must use the pragma, and also use an initialization clause on the variable."  (although the example code shows an initialization clause.)  That tidbit is only revealed in posts on this forum.

    No thanks for the loader scripts.  I found that even for a struct, any sort of initialization clause such as "= {0};" will compile and make the variable load into FRAM address, even though I am not sure the initialization clause is really initializing the struct properly.

  • lloyd konneker said:
    I don't think said documentation has a statement "you must use the pragma, and also use an initialization clause on the variable."

    Please search the MSP430 compiler manual for the sub-chapter titled The NOINIT and PERSISTENT Pragmas.  It states ...

    The PERSISTENT pragma is similar to the NOINIT pragma, except that it may only be used with statically-initialized variables.

    Please do not think the NOINIT pragma solves your problem.  NOINIT variables are allocated to RAM, and not FRAM.

    Thanks and regards,

    -George

  • OK, I was wrong, the document does say "The PERSISTENT pragma is similar to the NOINIT pragma, except that it may only be used with statically-initialized variables."

    Now I will argue that the statement is hard to understand and fuzzy.  

    How are the two pragmas similar? The statement lists one exception to the similarity, but omits another exception to the similarity, as you yourself have noted, and the document should say "AND except that the PERSISTENT pragma puts the variable in FRAM instead of RAM."

    That statement is poor technical writing, using the passive tense "may only be used."  If it said "If you use the pragma without an initialization, the variable will NOT be in FRAM."  

    To interpret the statement, one must first read about the NOINIT pragma, to figure out what it does so one can apply the differences noted in the "except for".  Most readers, like myself, are too hurried and will make mistakes.

    Now there are at least two posts in this forum about this issue.  Think how many people might have made the same mistake, read this forum, saw the post, and moved on without complaining. My hope is that when I give feedback, it will help others.  It is not just that I have a problem (since I have already solved it.)  It seems to me that TI doesn't always bump the feedback up the chain to the technical writers.

  • I agree the documentation is not clear that PERSISTENT variables go in FRAM, and NOINIT variables go in RAM.  So, I filed CODEGEN-5403 in the SDOWP system to change the manual so these details are more clear.  You are welcome to follow it with the SDOWP link below in my signature.

    Thanks and regards,

    -George

  • Another gotcha:  a static variable will not be in FRAM.

    So the example code in the documentation is very fragile, some changes to the example code might alter where the variable is stored:

    - adding static

    - omitting initialization

    To belabor my point, the implementation of the PERSISTENT pragma is what I would call a hack, in the sense that it is fragile, i.e. easy for a programmer to destroy the intent.  IMO a hack should be well documented (documentation should explain how it could be broken) or it shouldn't be a hack (change the compiler to give errors for the above cases.)

  • lloyd konneker said:
    Another gotcha:  a static variable will not be in FRAM.

    I cannot reproduce this result.

    Unless, you didn't initialize it.  In which case it is handled just like a normal PERSISTENT variable that is not initialized, i.e. it goes in RAM, as already discussed.

    Thanks and regards,

    -George

  • Yes, I could be wrong, I will attempt to provide a small test case.  The only evidence I have now is my full application, which seemed not to persist a variable declared static, and seemed to persist it (through LPM4.5 sleep) when it was not declared static.  I might be confused by the fact that a static variable does not appear in the .map file.  I will make a small test case, and set the flag so that static variables appear in the .map file.

  • I also can't duplicate in a small test case, so I was wrong. I am sorry. If you want to edit this thread to correct my wrong statements, feel free.

    As near as I can tell, my mistake was to declare and define a class with all static data and functions in a header file, and include that file from many other files. Then apparently, a separate persistent data member was allocated each time the header was included. So the call to read the data member and the call to set the data member were accessing different locations (both in FRAM.)

    I had to use the linker flag --mapfile_contents=sym_defs to see the problem.
  • Thanks for following up.  There is no need to change anything.  People learn from my mistakes all the time!

    -George