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.

MSP430FR5969: GCC v5.3.0.219 using persistent attribute

Part Number: MSP430FR5969

Hi,

I'm trying to place some persistent variables into FRAM on the MSP430FR5969 using the current GCC compiler. I am using a make file to build the project. I do NOT use CCS ide. I have checked that the linker script has a .PERSISTENT section declared, but am unable to get the variable to change. For example:

void myFunction(void)

{

__attribute__ ((persistent)) uint8_t count = 0;

printf("The count:%u", count++);

}

when I call myFunction(), count does not increment. Everything compiles ok, and there is a .persistent. segment reported by the linker.

Any ideas as to why I can't get count to increment?

Thanks,

Peter Philippa.

  • Hi Peter,

    The persistent attribute has more to do with where the variables are stored in memory and initialized at startup as compared to how the variable is updated. Please view Section 5 of SLAA628 for more information: www.ti.com/.../slaa628.pdf

    Your code needs to use a static variable as compared to automatic, please refer to the the answer of this forum post: stackoverflow.com/.../difference-between-static-auto-global-and-local-variable-in-the-context-of-c-a

    Regards,
    Ryan
  • Hi Ryan,

    Many thanks for taking the time to reply to my problem. My apologies as it appears that I have not explained the problem correctly.

    My mind thinks that replacing a static modifier with persistent would be enough change to give the effect I need - so, in effect, removing the 'auto' behaviour of the variable. What I expected was that if the variable is persistent, it lives forever - even between machine resets; yet, if its auto, it only lives during scope of the function. My mind also believes that needing to have static behaviour of the variable in addition to persistent is counter-intuitive. The omission of a compiler warning doesn't really bother me, though.

    When I do add static and persistent to the declaration for count, then the behaviour is that count will increment, but is reinitialised with each reset (i.e. just like any static object).

    My reading indicates my goal may be achieved with the persistent modifier and that each compiler (IAR, CCS and GCC) does this in a different way. I haven't yet found a document or web site that concisely explains how to do this with a current GCC compiler.

    I will attempt the code changes in the recommended slaa628.pdf but I have reservations about success of the changes, as the document omits discussing the GCC compiler. I shall report back so that anyone following this post may short-cut their problem resolution time.

    Many thanks,

    Peter

  • Peter Philippa said:
    When I do add static and persistent to the declaration for count, then the behaviour is that count will increment, but is reinitialised with each reset (i.e. just like any static object).

    I have been investigating the behavior of __attribute__ ((persistent)) using the msp430-gcc-5.3.0.224_win32 compiler installed from the CCS 7 App Center, which is the version of the GCC MSP430 compiler maintained by SOMMIUM Technologies Limited.

    I used a standalone program containing only code in main() for a MSP430FR5969.

    Different combinations of variables were tested:

    1) Attempting to use __attribute__ ((persistent)) on a variable with automatic storage:

    #include <msp430.h>
    #include <stdint.h>
    #include <stdio.h>
    
    int main(void)
    {
        __attribute__ ((persistent)) uint8_t count   = 0;
    
        WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    
        count++;
        printf("The count:%u\n", count);
        return 0;
    }

    The result is that count is allocated on the stack, and thus isn't persistent. The GCC compiler doesn't report a warning that the __attribute__ ((persistent)) is being ignored when used on a variable with automatic storage, even when -Wall is used.

    Note that with the same program the TI v16.9.0.LTS MSP430 compiler does report the warning:

    "../main.c", line 7: warning #1524-D: PERSISTENT can only be applied to definitions of symbols that have static storage, not "count" (declared at line 7)

    2) Attempting to use __attribute__ ((persistent)) on a global variable initialized to zero:

    #include <msp430.h>
    #include <stdint.h>
    #include <stdio.h>
    
    __attribute__ ((persistent)) uint8_t count = 0;
    
    int main(void)
    {
    
        WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    
        count++;
        printf("The count:%u\n", count);
        return 0;
    }

    The result is that the count variable is persistent, in that count is set to zero when the program is downloaded and count then retains its value across a Hard Reset.

    3) Attempting to use __attribute__ ((persistent)) on a file static global variable initialized to zero:

    #include <msp430.h>
    #include <stdint.h>
    #include <stdio.h>
    
    static __attribute__ ((persistent)) uint8_t count = 0;
    
    int main(void)
    {
    
        WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    
        count++;
        printf("The count:%u\n", count);
        return 0;
    }

    The result is that the count variable isn't persistent, since it is re-initialized to zero by the run-time start up code. Inspecting the GCC linker map file shows the count variable has been placed in the .bss section rather than the .persistent section.

    4) Attempting to use __attribute__ ((persistent)) on a file static global variable initialized to one:

    #include <msp430.h>
    #include <stdint.h>
    #include <stdio.h>
    
    static __attribute__ ((persistent)) uint8_t count = 1;
    
    int main(void)
    {
    
        WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    
        count++;
        printf("The count:%u\n", count);
        return 0;
    }

    The result is that the count variable is persistent, in that count is set to one when the program is downloaded and count then retains its value across a Hard Reset.

    5) Attempting to use __attribute__ ((persistent)) on a function static variable initialized to zero:

    #include <msp430.h>
    #include <stdint.h>
    #include <stdio.h>
    
    
    int main(void)
    {
        static __attribute__ ((persistent)) uint8_t count = 0;
    
        WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    
        count++;
        printf("The count:%u\n", count);
        return 0;
    }

    The result is that the count variable isn't persistent, since it is re-initialized to zero by the run-time start up code. Inspecting the GCC linker map file shows the count variable has been placed in the .bss section rather than the .persistent section.

    6) Attempting to use __attribute__ ((persistent)) on a function static variable initialized to one:

    #include <msp430.h>
    #include <stdint.h>
    #include <stdio.h>
    
    
    int main(void)
    {
        static __attribute__ ((persistent)) uint8_t count = 1;
    
        WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    
        count++;
        printf("The count:%u\n", count);
        return 0;
    }

    The result is that the count variable is persistent, in that count is set to one when the program is downloaded and count then retains its value across a Hard Reset.

    In summary:

    a) In case 1 I can understand why the variable isn't persistent, but the GCC compiler could be improved by producing a warning why the __attribute__ ((persistent)) is ignored (as the TI compiler already does).

    b) In cases 3 and 5 it seems their might be a GCC compiler bug whereby the use of __attribute__ ((persistent)) on variable which otherwise would be placed in the .bss segment gets ignored.

    For reference I have attached the CSS project used, which contains the final code for test 6). Note that due to the MSP430FR5969 only containing 2K of RAM the default CCS msp430fr5969.ld had to be changed to place the stack and heap in the HIFRAM rather than RAM, to give sufficient heap space to allow printf() to be used.MSP430FR5969_GCC_persistent.zip

  • Hi Chester,

    BIG thanks for your comprehensive cover of persistent using GCC and for attaching your project files. I confirm your findings using your project files.

    When I tried each of your test cases in my project, an error message was reported by the compiler:

    main.c:101:(.text+0x9c): relocation truncated to fit: R_MSP430X_ABS16 against symbol `count' defined in .persistent section in main.o

    in your test cases 2), 4) & 6).

    After a few modifications to my makefile I discovered that the error was generated when I built my project without the -mlarge option.

    This leads me to believe that the memory model MUST be large to use persistent variables. A large memory model then created casting warnings to be emitted from macros defined in the msp430fr5969.h file (that comes with the compiler).

    Could you confirm that a large memory model MUST be used with persistent variables? And/or, do you know a way to use persistent with the small memory model?

    Thanks again,

    Peter

  • Peter Philippa said:
    Could you confirm that a large memory model MUST be used with persistent variables? And/or, do you know a way to use persistent with the small memory model?

    The default msp430fr5969.ld linker script with CCS 7 was placing the .persistent section in the HIFRAM region:

      /* This section contains data that is initialised during load
         but not on application reset.  */  
      .persistent :
      {
        . = ALIGN(2);
        PROVIDE (__persistent_start = .);
        *(.persistent)
        . = ALIGN(2);
        PROVIDE (__persistent_end = .);
      } > HIFRAM

    Where the HIFRAM region starts at 0x10000 which is why the large memory model was required to access the persistent variables.

    By changing the linker script to place the .persistent section on the ROM region, which is FRAM in the lower 64K of address space, allows persistent variables with the small memory model:

      /* This section contains data that is initialised during load
         but not on application reset.  */  
      .persistent :
      {
        . = ALIGN(2);
        PROVIDE (__persistent_start = .);
        *(.persistent)
        . = ALIGN(2);
        PROVIDE (__persistent_end = .);
      } > ROM

    My updated example project with this change for persistent variables and a small memory model is attached. 8360.MSP430FR5969_GCC_persistent.zip

    [I also changed the stack and heap to be allocated in FRAM in the first 64K of address space]

  • Chester Gillon said:
    b) In cases 3 and 5 it seems their might be a GCC compiler bug whereby the use of __attribute__ ((persistent)) on variable which otherwise would be placed in the .bss segment gets ignored.

    When the -save-temps option was used to inspect the generated assembler, in cases 3 and 5 the count variable was handled as a common symbol as indicated by .comm for test case 3:

    	.local	count
    	.comm	count,1,1

    And test case 5 :

    	.local	count.3248
    	.comm	count.3248,1,1

    Looking at the source code for msp430-gcc-5.3.0.224, in the msp430_data_attr() function in msp430-gcc-5.3.0.224_source-full\gcc\gcc\config\msp430\msp430.c there is the following block:

      /* If this var is thought to be common, then change this.  Common variables
         are assigned to sections before the backend has a chance to process them.  */
      if (DECL_COMMON (* node))
        DECL_COMMON (* node) = 0;

    What might be happening is that common variables bypass the logic in the msp430_select_section() function which checks for the presence of the persistent attribute to select the data section to be used, although I haven't attempted to study the msp430-gcc-5.3.0.224 source code in detail to prove this.

    As an alternative, changed the test cases to use __attribute__ ((section (".persistent"))), instead of __attribute__ ((persistent)), to directly specify the .persistent section to be used for persistent variables.

    1) Attempting to use __attribute__ ((section (".persistent"))) on a variable with automatic storage:

    #include <msp430.h>
    #include <stdint.h>
    #include <stdio.h>
    
    int main(void)
    {
        __attribute__ ((section (".persistent"))) uint8_t count = 0;
    
        WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    
        count++;
        printf("The count:%u\n", count);
        return 0;
    }

    The result is that the compiler reports an error due to attempting to set the data section for a variable with automatic storage:

    ../main.c: In function 'main':
    ../main.c:7:55: error: section attribute cannot be specified for local variables
         __attribute__ ((section (".persistent"))) uint8_t count = 0;

    i.e. the compiler now traps an invalid attempt to make a variable with automatic storage persistent.

    2) Attempting to use __attribute__ ((section (".persistent"))) on a global variable initialized to zero:

    #include <msp430.h>
    #include <stdint.h>
    #include <stdio.h>
    
    __attribute__ ((section (".persistent"))) uint8_t count = 0;
    
    int main(void)
    {
    
        WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    
        count++;
        printf("The count:%u\n", count);
        return 0;
    }

    The result is that the count variable is persistent, in that count is set to zero when the program is downloaded and count then retains its value across a Hard Reset.

    3) Attempting to use __attribute__ ((section (".persistent"))) on a file static global variable initialized to zero:

    #include <msp430.h>
    #include <stdint.h>
    #include <stdio.h>
    
    static __attribute__ ((section (".persistent"))) uint8_t count = 0;
    
    int main(void)
    {
    
        WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    
        count++;
        printf("The count:%u\n", count);
        return 0;
    }

    The result is that the count variable is persistent, in that count is set to zero when the program is downloaded and count then retains its value across a Hard Reset.

    4) Attempting to use __attribute__ ((section (".persistent"))) on a file static global variable initialized to one:

    #include <msp430.h>
    #include <stdint.h>
    #include <stdio.h>
    
    static __attribute__ ((section (".persistent"))) uint8_t count = 1;
    
    int main(void)
    {
    
        WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    
        count++;
        printf("The count:%u\n", count);
        return 0;
    }

    The result is that the count variable is persistent, in that count is set to one when the program is downloaded and count then retains its value across a Hard Reset.

    5) Attempting to use __attribute__ ((section (".persistent"))) on a function static variable initialized to zero:

    #include <msp430.h>
    #include <stdint.h>
    #include <stdio.h>
    
    
    int main(void)
    {
        static __attribute__ ((section (".persistent"))) uint8_t count = 0;
    
        WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    
        count++;
        printf("The count:%u\n", count);
        return 0;
    }

    The result is that the count variable is persistent, in that count is set to zero when the program is downloaded and count then retains its value across a Hard Reset.

    6) Attempting to use __attribute__ ((section (".persistent"))) on a function static variable initialized to one:

    #include <msp430.h>
    #include <stdint.h>
    #include <stdio.h>
    
    
    int main(void)
    {
        static __attribute__ ((section (".persistent"))) uint8_t count = 1;
    
        WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer
    
        count++;
        printf("The count:%u\n", count);
        return 0;
    }

    The result is that the count variable is persistent, in that count is set to one when the program is downloaded and count then retains its value across a Hard Reset.

    The conclusion is that __attribute__ ((section (".persistent"))) is a more reliable way to make a variable persistent, as opposed to using __attribute__ ((persistent)).

  • Hi Chester,

    Brilliant! Many thanks. The combination of your last few postings has resolved the problem for me. I really appreciate you taking the time to give a comprehensive reply. I trust that 2017 is a great year for you, too!

    Cheers,

    Peter

**Attention** This is a public forum