I am trying to implement NVM3 driver into project based on EFR32BG22 Silabs microcontroller. As I noticed in the documentation, I need to add new section into SECTIONS command in linker script so I made one, and it seems to work. But I am not sure, if it is correctly implemented, and if it wont fail in runtime.
I've read few documentations of NVM3, but still there comes questions stated below. Here is the linker script:
/***************************************************************************//**
* GCC Linker script for Silicon Labs devices
*******************************************************************************
* # License
* <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
MEMORY
{
FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x7e000
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x8000
}
ENTRY(Reset_Handler)
SECTIONS
{
.text :
{
linker_vectors_begin = .;
KEEP(*(.vectors))
linker_vectors_end = .;
__Vectors_End = .;
__Vectors_Size = __Vectors_End - __Vectors;
linker_code_begin = .;
*(.text*)
linker_code_end = .;
KEEP(*(.init))
KEEP(*(.fini))
/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)
*(.rodata*)
*(.eh_frame*)
} > FLASH
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;
__etext = .;
/* Start placing output sections which are loaded into RAM */
. = ORIGIN(RAM);
.stack ALIGN(8) (NOLOAD):
{
__StackLimit = .;
KEEP(*(.stack*))
. = ALIGN(4);
__StackTop = .;
PROVIDE(__stack = __StackTop);
} > RAM
.noinit . (NOLOAD):
{
*(.noinit*);
} > RAM
.data . : AT (__etext)
{
. = ALIGN(4);
__data_start__ = .;
*(vtable)
*(.data*)
. = ALIGN (4);
PROVIDE(__ram_func_section_start = .);
*(.ram)
PROVIDE(__ram_func_section_end = .);
. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/* finit data */
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
/* All data end */
__data_end__ = .;
} > RAM
.bss . :
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > RAM
.heap (COPY):
{
__HeapBase = .;
__end__ = .;
end = __end__;
_end = __end__;
KEEP(*(.heap*))
. = ORIGIN(RAM) + LENGTH(RAM);
__HeapLimit = .;
} > RAM
__heap_size = __HeapLimit - __HeapBase;
__main_flash_end__ = 0x0 + 0x7e000;
/* This is where we handle flash storage blocks. We use dummy sections for finding the configured
* block sizes and then "place" them at the end of flash when the size is known. */
.internal_storage (DSECT) : {
KEEP(*(.internal_storage*))
} > FLASH
.nvm (DSECT) : {
KEEP(*(.simee*))
} > FLASH
linker_nvm_end = __main_flash_end__;
linker_nvm_begin = linker_nvm_end - SIZEOF(.nvm);
linker_nvm_size = SIZEOF(.nvm);
linker_storage_end = linker_nvm_begin;
linker_storage_begin = linker_storage_end - SIZEOF(.internal_storage);
linker_storage_size = SIZEOF(.internal_storage);
__nvm3Base = linker_nvm_begin;
//That part has been added by me
NVM3 (LENGTH(FLASH) - 0x6000) (NOLOAD):
{
*(nvm3Data1_section)
}
//
}
My question are:
- Why is main_flash_end symbol equal to 0x7e000 instead of 0x80000? Is it in order to provide 8kB of FLASH for user usage?
- What are the .internal_storage and .nvm sections? Do i need to worry about these sections? What is the DSECT section?
- How can I be sure, that the NVM section will not collide with any other data stored in FLASH?
- Does new NVM3 section overwrite before stated sections (that are stated to 0x7e000)?
- Are there any limitations of assigning FLASH memory as NVM3 memory?
- Do I need to change attribute of FLASH memory from rx to rwx in order to use part of it as NVM3? If not, why? Thanks in advance.