I'm using fstorage to store logged data in Flash. Works well, no problems there.
What I'd like to be able to do though, and haven't found a solution to, is to be able to place the fstorage space using symbols, that are defined in only one place. And to have the linker aware of where that flash storage space is, so that I can be sure that my code won't overflow into it as it continues to grow.
I'm using:
- nRF52840
- SES 4.40 with GNU linker (sections defined in flash_placement.xml)
- SDK 16.0.0
- SD S140
I'd like to allocate a sizeable chunk of the Flash for log storage, and have it remain in the same place, contents undisturbed, when the application code is updated. I.e. the location and size need to be fixed, not floating about.
The fstorage example sets up the start and end addresses with:
NRF_FSTORAGE_DEF(nrf_fstorage_t fstorage) = { /* Set a handler for fstorage events. */ .evt_handler = fstorage_evt_handler, /* These below are the boundaries of the flash space assigned to this instance of fstorage. * You must set these manually, even at runtime, before nrf_fstorage_init() is called. * The function nrf5_flash_end_addr_get() can be used to retrieve the last address on the * last page of flash available to write data. */ .start_addr = 0x3e000, .end_addr = 0x3ffff, };
It's easy to replace these with #define
'd symbols, say
#define FSTORAGE_START 0x80000 #define FSTORAGE_END 0xF7FFF
And I could then just assume that my code won't grow past say 0x80000, and from other questions and answers here, that seems to be the usual way that this is done. Or use BOOTLOADER_ADDRESS as the end address, and back calculate the start, based on a fixed fstorage space size. Either way, I'd have to continue to check that my code didn't grow past 0x80000.
That's not onerous, but I'd prefer to define (declare?) a memory section for the flash storage, by adding a line such as:
<ProgramSection alignment="4" keep="Yes" load="No" name=".storage_flash" start="0x80000" size="0x78000" address_symbol="__start_storage_flash" end_symbol="__stop_storage_flash" />
to flash_placement.xml.
That way, when I build the project, I can see the overall memory usage as e.g.
The flash storage is visible, I'm told accurately how much Flash is really "free" (ok, that example doesn't have the bootloader, but you get the idea), but more importantly the linker won't let me build the project if the application grows past the start of that flash storage region.
So that's what I'm doing at the moment, but I don't like having to enter, and maintain, that '0x80000' in two places. It would be better if there was a single source of truth. A symbol defined in one place, that could be referenced by both the linker and the compiler.
Now, in theory, that's what the address_symbol
and end_symbol
attributes in the ProgramSection
do, right? The Segger documentation seems to be quite light on this, but that seems to be what they are for.
We also have useful macros defined in nrf_section.h, which as far as I can see should allow me to write:
.start_addr = (uint32_t) NRF_SECTION_START_ADDR(storage_flash), .end_addr = (uint32_t) NRF_SECTION_END_ADDR(storage_flash)
However, if I try that, I get an "'__start_storage_flash' undeclared" error.
Yet as far as I can see, I have declared it. And with keep="Yes"
, which supposedly keeps the symbols around, even if the section isn't used. As I understand it, anyway.
Ok, so maybe I've misunderstood about symbols defined in flash_placement.xml being accessible, but if I substitute the start and end address definition with:
.start_addr = (uint32_t) NRF_SECTION_START_ADDR(log_const_data), .end_addr = (uint32_t) NRF_SECTION_END_ADDR(log_const_data)
It compiles ok. The start and end addresses are set to the location of the .log_const_data
section, as confirmed in the .map file.
Of course, I'd never want to actually overwrite that section with my application data, but it proves that the __start and __stop symbols are coming across and are visiible to the C compiler.
So - what's different about my flash storage declaration, last line in the fragment from flash_placement.xml below?
<ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_const_data" inputsections="*(SORT(.log_const_data*))" address_symbol="__start_log_const_data" end_symbol="__stop_log_const_data" /> <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_soc_observers" inputsections="*(SORT(.sdh_soc_observers*))" address_symbol="__start_sdh_soc_observers" end_symbol="__stop_sdh_soc_observers" /> <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_backends" inputsections="*(SORT(.log_backends*))" address_symbol="__start_log_backends" end_symbol="__stop_log_backends" /> <ProgramSection alignment="4" keep="Yes" load="Yes" name=".nrf_balloc" inputsections="*(.nrf_balloc*)" address_symbol="__start_nrf_balloc" end_symbol="__stop_nrf_balloc" /> <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections" address_symbol="__start_nrf_sections" /> <ProgramSection alignment="4" keep="Yes" load="Yes" name=".fs_data" inputsections="*(.fs_data*)" runin=".fs_data_run"/> <ProgramSection alignment="4" keep="Yes" load="Yes" name=".cli_sorted_cmd_ptrs" inputsections="*(.cli_sorted_cmd_ptrs*)" runin=".cli_sorted_cmd_ptrs_run"/> <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_dynamic_data" inputsections="*(SORT(.log_dynamic_data*))" runin=".log_dynamic_data_run"/> <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_filter_data" inputsections="*(SORT(.log_filter_data*))" runin=".log_filter_data_run"/> <ProgramSection alignment="4" load="Yes" name=".dtors" /> <ProgramSection alignment="4" load="Yes" name=".ctors" /> <ProgramSection alignment="4" load="Yes" name=".rodata" /> <ProgramSection alignment="4" load="Yes" name=".ARM.exidx" address_symbol="__exidx_start" end_symbol="__exidx_end" /> <ProgramSection alignment="4" load="Yes" runin=".fast_run" name=".fast" /> <ProgramSection alignment="4" load="Yes" runin=".data_run" name=".data" /> <ProgramSection alignment="4" load="Yes" runin=".tdata_run" name=".tdata" /> <ProgramSection alignment="4" keep="Yes" load="No" name=".storage_flash" start="0x80000" size="0x78000" address_symbol="__start_storage_flash" end_symbol="__stop_storage_flash" />
What have I missed? Why are the start/end symbols defined in the the earlier lines accessible from C, and the ones I added, not?