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.

How to correctly declare initialized data into FLASH using C/C++

Other Parts Discussed in Thread: EK-TM4C123GXL

Hi all, 

I've got a strange problems while trying to define some initialized data directly into FLASH, not in SRAM. General idea behind all these tricks was to enable program modules to be easily included or excluded from build process much like linux kernel modules do. Similar to linux I need to register some data as an array of pointers. To do this I defined macros which declare pointers to be placed in specific data section:

struct command cmd_x = {
    .name = "command x",
    .id = 123,
    // etc
};

#define CMD_PTR(x) \ _Pragma("DATA_SECTION(\".commands\")") \ _Pragma("RETAIN") \ struct command *cmd_##x##_ptr = &cmd_##x;

Then I added section '.commands' to linker command file, to put all pointers into solid array with labeled begin and end margins.  Actual data is constants so it is desirable to locate both real structures and their pointers into FLASH.

The problem arises when I try to put section .commands into ROM. Compiler sees that data is defined as modifiable and it places actual initialization to .cinit, just like if the section was going into SRAM. But linker places the section into FLASH accoring to my .cmd file. All this give me wrong data in runtime, all data is actually 0xff, since flash was erased and not updated from .cinit section.

Then I tried to force compiler to consider my data as read only, to eliminate initialisation bia .cinit. I tried to play with const keyword placing it around pointer declaration. But it does not work. Once I write something like

#pragma DATA_SECTION(".commands")
#pragma RETAIN
  struct command *const cmd_reset_ptr = &cmd_reset;


I see the cmd_reset_ptr symbol is removed from .map file at all. Section becomes empty and is removed from output file. The only working solution for now is placement data into SRAM and initialization from .cinit. But this wastes SRAM resources!

How can I place initialized data into FLASH without wasting SRAM?

  • Vladimir Dashevsky said:
    How can I place initialized data into FLASH without wasting SRAM?

    The attached project, created in CCSv6 with TI ARM compiler v5.1.6, in an example for a EK-TM4C123GXL which demonstrates this. 6215.TIVA_const_flash_commands.zip

    Every definition which is intended to be stored in flash needs to marked as const. i.e. each command definition:

    const command_def cmd_a =
    {
    	.name = "command_a",
    	.id = 1,
    	.init_func = command_a_init
    };
    

    And each command pointer needs to have a constant pointer pointing to constant data:

    #define STRINGIFY(s) #s
    #define CMD_PTR_SYMBOL(x) cmd_##x##_ptr
    #define CMD_PTR(x) \
    	_Pragma(STRINGIFY (DATA_SECTION( CMD_PTR_SYMBOL(x) ,".commands"))) \
    	_Pragma(STRINGIFY (RETAIN( CMD_PTR_SYMBOL(x) ))) \
        const command_def *const CMD_PTR_SYMBOL(x) = &cmd_##x;
    

    In the linker command file the .command section was set to be stored in flash, with symbols defined for its start and end:

        .commands: > FLASH, START(command_ptrs_start), END(command_ptrs_end)
    

    The main function was then able to iterate over the list of command pointers stored in flash:

    extern const command_def *command_ptrs_start[];
    extern const command_def *command_ptrs_end[];
    
    int main(void) {
    	const command_def **command_ptrs;
    	const command_def *command;
    
    	for (command_ptrs = command_ptrs_start; command_ptrs != command_ptrs_end; command_ptrs++)
    	{
    		command = *command_ptrs;
    		printf ("Calling initialisation for name=%s ID=%d\n", command->name, command->id);
    		(*command->init_func) ();
    	}
    	
    	return 0;
    }