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.

Variable with persistent attribute

Other Parts Discussed in Thread: MSP430FR5969, ENERGIA

I'm working with the MSP430FR5969 and my goal is to have some variables in FRAM that retain their value through a chip reset, that is, they are only initialized when the program is loaded.

I'm working on an Energia project in CCS6.1, so the GCC compiler is used.  My CCS project options show that I have 2 choices for compiler:

1)  GNU v4.9.1 (Red Hat), and

2) GNU v4.6.3 (MSPGCC)

Is there a "persistent" variable attribute supported by these compilers that can be used in a C/CPP module so it can be linked with the Energia code?  

I already tried this in a C file withing the Energia project:

int __attribute__((persistent)) myVar;

but I got a message saying the attribute was ignored.

Alternatively, is it a viable option to use the "persistent" pragma in the TI compiler and link it with the Energia project?   Any other possibilities?

Thanks,

John Wygonski

  • The persistent attribute was added in gcc 5.3.0.

    If you're using an earlier version, you have to manually put the variables into a section that is put into lower or upper FRAM (try .rodata.persistent or .upper.rodata.persistent).

  • Thanks very much for getting me on the right track.   I tried:

    int __attribute__((section(".rodata.persistent"))) varPersistent = 1; //

    int __attribute__((section(".upper.rodata.persistent"))) varPersistent2 = 2; //

    and found that varPersistent1 gets located in FRAM and behaves as desired, while varPersistent2 gets located in RAM.

    Thankas again,

    John Wygonski

  • Apparently, your older gcc also has an older linker script without .upper.rodata. Try section(".far.text.persistent") instead. If that does not work, please show your version of msp430fr5969.ld.
  • I get the same result using section(".far.text.persistent") -- placed in RAM.

    Here's the contents of the memory.x file in my Energia installation under ...\ldscripts\msp430fr5969:

    MEMORY {
      sfr              : ORIGIN = 0x0000, LENGTH = 0x0010 /* END=0x0010, size 16 */
      peripheral_8bit  : ORIGIN = 0x0010, LENGTH = 0x00f0 /* END=0x0100, size 240 */
      peripheral_16bit : ORIGIN = 0x0100, LENGTH = 0x0100 /* END=0x0200, size 256 */
      bsl              : ORIGIN = 0x1000, LENGTH = 0x0800 /* END=0x1800, size 2K as 4 512-byte segments */
      infomem          : ORIGIN = 0x1800, LENGTH = 0x0200 /* END=0x1a00, size 512 as 4 128-byte segments */
      infod            : ORIGIN = 0x1800, LENGTH = 0x0080 /* END=0x1880, size 128 */
      infoc            : ORIGIN = 0x1880, LENGTH = 0x0080 /* END=0x1900, size 128 */
      infob            : ORIGIN = 0x1900, LENGTH = 0x0080 /* END=0x1980, size 128 */
      infoa            : ORIGIN = 0x1980, LENGTH = 0x0080 /* END=0x1a00, size 128 */
      ram (wx)         : ORIGIN = 0x1c00, LENGTH = 0x0800 /* END=0x2400, size 2K */
      rom (rx)         : ORIGIN = 0x4400, LENGTH = 0xbb80 /* END=0xff80, size 48000 */
      signature        : ORIGIN = 0xff80, LENGTH = 0x0010 /* END=0xff90, size 16 as 1 16-byte segments */
      vectors          : ORIGIN = 0xff80, LENGTH = 0x0080 /* END=0x10000, size 128 as 64 2-byte segments */
      far_rom          : ORIGIN = 0x00010000, LENGTH = 0x00004000 /* END=0x00014000, size 16K */
      /* Remaining banks are absent */
      ram2 (wx)        : ORIGIN = 0x0000, LENGTH = 0x0000
      ram_mirror (wx)  : ORIGIN = 0x0000, LENGTH = 0x0000
      tinyram (wx)     : ORIGIN = 0x0000, LENGTH = 0x0000
      usbram (wx)      : ORIGIN = 0x0000, LENGTH = 0x0000
    }
    REGION_ALIAS("REGION_TEXT", rom);
    REGION_ALIAS("REGION_DATA", ram);
    REGION_ALIAS("REGION_FAR_ROM", far_rom); /* Legacy name, no longer used */
    REGION_ALIAS("REGION_FAR_TEXT", far_rom);
    REGION_ALIAS("REGION_FAR_DATA", ram2);
    PROVIDE (__info_segment_size = 0x80);
    PROVIDE (__infod = 0x1800);
    PROVIDE (__infoc = 0x1880);
    PROVIDE (__infob = 0x1900);
    PROVIDE (__infoa = 0x1980);

    It's not clear to me how section(".rodata.persistent") results in locating the variable correctly in FRAM.   Also, curiously, section(".rom.persistent') locates the variable in RAM.   Is there an additional parent linker control file that is used along with the chip-specific one?

  • There should be a linker script file somewhere, probably just called msp430.ld. (It's named msp430fr5969.ld when using the gcc support files, but apparently Energia does things differently.)

    Your memory.x file names the upper FRAM "far_rom". To put a section into that, there should be a declaration similare to the following:

      .upper.rodata :
      {
        *(.upper.rodata.* .upper.rodata)     /* but yours has other names here */
      } > far_rom

    The important part is the "> far_rom" at the end.

  • Yes, I found the linker script msp430.x in the Energia folder with the following content:

    /* Default linker script, for normal executables */
    OUTPUT_FORMAT("elf32-msp430")
    OUTPUT_ARCH("msp430")
    INCLUDE memory.x
    INCLUDE periph.x
    SECTIONS
    {
      /* Read-only sections, merged into text segment.  */
      .hash            : { *(.hash)          }
      .dynsym          : { *(.dynsym)        }
      .dynstr          : { *(.dynstr)        }
      .gnu.version     : { *(.gnu.version)   }
      .gnu.version_d   : { *(.gnu.version_d) }
      .gnu.version_r   : { *(.gnu.version_r) }
      .rel.init      : { *(.rel.init)  }
      .rela.init     : { *(.rela.init) }
      .rel.fini      : { *(.rel.fini)  }
      .rela.fini     : { *(.rela.fini) }
      .rel.text      : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)        }
      .rela.text     : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)     }
      .rel.rodata    : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)    }
      .rela.rodata   : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
      .rel.data      : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)        }
      .rela.data     : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)     }
      .rel.bss       : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)          }
      .rela.bss      : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)       }
      .rel.ctors     : { *(.rel.ctors)  }
      .rela.ctors    : { *(.rela.ctors) }
      .rel.dtors     : { *(.rel.dtors)  }
      .rela.dtors    : { *(.rela.dtors) }
      .rel.got       : { *(.rel.got)    }
      .rela.got      : { *(.rela.got)   }
      .rel.plt       : { *(.rel.plt)    }
      .rela.plt      : { *(.rela.plt)   }
      .text :
      {
         . = ALIGN(2);
         KEEP(*(.init .init.*))
         KEEP(*(.init0))  /* Start here after reset.               */
         KEEP(*(.init1))  /* User definable.                       */
         KEEP(*(.init2))  /* Initialize stack.                     */
         KEEP(*(.init3))  /* Initialize hardware, user definable.  */
         KEEP(*(.init4))  /* Copy data to .data, clear bss.        */
         KEEP(*(.init5))  /* User definable.                       */
         KEEP(*(.init6))  /* C++ constructors.                     */
         KEEP(*(.init7))  /* User definable.                       */
         KEEP(*(.init8))  /* User definable.                       */
         KEEP(*(.init9))  /* Call main().                          */
         KEEP(*(.fini9))  /* Falls into here after main(). User definable.  */
         KEEP(*(.fini8))  /* User definable.                           */
         KEEP(*(.fini7))  /* User definable.                           */
         KEEP(*(.fini6))  /* C++ destructors.                          */
         KEEP(*(.fini5))  /* User definable.                           */
         KEEP(*(.fini4))  /* User definable.                           */
         KEEP(*(.fini3))  /* User definable.                           */
         KEEP(*(.fini2))  /* User definable.                           */
         KEEP(*(.fini1))  /* User definable.                           */
         KEEP(*(.fini0))  /* Infinite loop after program termination.  */
         KEEP(*(.fini .fini.*))
         . = ALIGN(2);
         __ctors_start = . ;
         KEEP(*(.ctors))
         __ctors_end = . ;
         __dtors_start = . ;
         KEEP(*(.dtors))
         __dtors_end = . ;
         . = ALIGN(2);
        *(.text .text.* .gnu.linkonce.t.*)
         . = ALIGN(2);
      }  > REGION_TEXT
      .rodata   :
      {
         . = ALIGN(2);
        *(.rodata .rodata.* .gnu.linkonce.r.*)
         . = ALIGN(2);
      }  > REGION_TEXT
       _etext = .; /* Past last read-only (loadable) segment */
      .data   :
      {
         . = ALIGN(2);
         PROVIDE (__data_start = .) ;
        *(.data .data.* .gnu.linkonce.d.*)
         . = ALIGN(2);
         _edata = . ;  /* Past last read-write (loadable) segment */
      }  > REGION_DATA AT > REGION_TEXT
       PROVIDE (__data_load_start = LOADADDR(.data) );
       PROVIDE (__data_size = SIZEOF(.data) );
      .bss   :
      {
         PROVIDE (__bss_start = .) ;
        *(.bss .bss.*)
        *(COMMON)
         . = ALIGN(2);
         PROVIDE (__bss_end = .) ;
      }  > REGION_DATA
       PROVIDE (__bss_size = SIZEOF(.bss) );
      .noinit   :
      {
         PROVIDE (__noinit_start = .) ;
        *(.noinit .noinit.*)
         . = ALIGN(2);
         PROVIDE (__noinit_end = .) ;
      }  > REGION_DATA
       . = ALIGN(2);
       _end = . ;   /* Past last write (loadable) segment */
      .infomem   :
      {
        *(.infomem)
         . = ALIGN(2);
        *(.infomem.*)
      }  > infomem
      .infomemnobits   :
      {
        *(.infomemnobits)
         . = ALIGN(2);
        *(.infomemnobits.*)
      }  > infomem
      .infoa   :
      {
        *(.infoa .infoa.*)
      }  > infoa
      .infob   :
      {
        *(.infob .infob.*)
      }  > infob
      .infoc   :
      {
        *(.infoc .infoc.*)
      }  > infoc
      .infod   :
      {
        *(.infod .infod.*)
      }  > infod
      .vectors  :
      {
         PROVIDE (__vectors_start = .) ;
        KEEP(*(.vectors*))
         _vectors_end = . ;
      }  > vectors
      .fartext :
      {
         . = ALIGN(2);
        *(.fartext)
         . = ALIGN(2);
        *(.fartext.*)
         _efartext = .;
      }  > REGION_FAR_ROM
      /* Stabs for profiling information*/
      .profiler 0 : { *(.profiler) }
      /* Stabs debugging sections.  */
      .stab 0 : { *(.stab) }
      .stabstr 0 : { *(.stabstr) }
      .stab.excl 0 : { *(.stab.excl) }
      .stab.exclstr 0 : { *(.stab.exclstr) }
      .stab.index 0 : { *(.stab.index) }
      .stab.indexstr 0 : { *(.stab.indexstr) }
      .comment 0 : { *(.comment) }
      /* DWARF debug sections.
         Symbols in the DWARF debugging sections are relative to the beginning
         of the section so we begin them at 0.  */
      /* DWARF 1 */
      .debug          0 : { *(.debug) }
      .line           0 : { *(.line) }
      /* GNU DWARF 1 extensions */
      .debug_srcinfo  0 : { *(.debug_srcinfo) }
      .debug_sfnames  0 : { *(.debug_sfnames) }
      /* DWARF 1.1 and DWARF 2 */
      .debug_aranges  0 : { *(.debug_aranges) }
      .debug_pubnames 0 : { *(.debug_pubnames) }
      /* DWARF 2 */
      .debug_info     0 : { *(.debug_info) *(.gnu.linkonce.wi.*) }
      .debug_abbrev   0 : { *(.debug_abbrev) }
      .debug_line     0 : { *(.debug_line) }
      .debug_frame    0 : { *(.debug_frame) }
      .debug_str      0 : { *(.debug_str) }
      .debug_loc      0 : { *(.debug_loc) }
      .debug_macinfo  0 : { *(.debug_macinfo) }
      /* DWARF 3 */
      .debug_pubtypes 0 : { *(.debug_pubtypes) }
      .debug_ranges   0 : { *(.debug_ranges) }
       PROVIDE (__stack = ORIGIN(ram) + LENGTH(ram));
       PROVIDE (__data_start_rom = _etext);
       PROVIDE (__data_end_rom   = _etext + SIZEOF (.data));
    }
    

    and now I can see how .rodata gets located in FRAM.

    Thanks for your help with this.

  • With this linker script, the only way to put stuff into upper FRAM is to use some ".fartext" section.

**Attention** This is a public forum