Skip to main content
bnguy.1
Associate III
September 11, 2020
Question

How do I modify Linker Script for reserving one Flash Sector for user data? [STM32H7]

  • September 11, 2020
  • 2 replies
  • 3512 views

How do you modify the linker script to reserve a sector for user data... and such that this user sector won't get erased when re-programming/bootloading?

The dual-core STM32H7 has TWO 8-sector Banks (0x8000000-0x80FFFFF & 0x8100000-0x81FFFFF).. with linker scripts for *EACH* cpu (STM32H745XIHX_RAM.ld, STM32H745XIHX_FLASH.ld). I assume the CPUs can run from either bank/sector, including execute from the same.. so for now, I've tried modifying just the M7's STM32H745XIHX_FLASH.ld :

MEMORY
{
FLASH (xr) : ORIGIN = 0x08000000, LENGTH = 1920K
USER_FLASH (xrw) : ORIGIN = 0x081E0000, LENGTH = 128K ********
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 512K 
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
}
 
 
// Section must be 32-bytes aligned (size of a Flash Word)
 .NVM: ALIGN(0x10)
 {
 . = ALIGN(4);
 _NVM= .;
 . += NVM_SIZE ;
 } >USER_FLASH
 
main.c:
 
// 32-byte structure
typedef struct __packed {
 uint8_t val1;
 uint32_t val2[2]; // 8 bytes
 uint16_t val3;
 uint16_t val4;
 uint32_t val5[4]; // 16 bytes
 uint8_t val6[2]; // 2 bytes
 uint8_t val7;
} stNVM;
 
 
// Declare 32-byte variables inside USER_FLASH , should this be const??
__attribute__((__section__(".USER_FLASH"))) uint8_t NVM_user_data[16]; 
extern volatile stNVM _NVM;
 
void test ( void )
{
 // flash 32 bytes at a time.
	HAL_FLASH_Unlock();
 
	// Erase / Write 32-bytes
	FLASH_PageErase(0x081E0000);
	CLEAR_BIT (FLASH->CR, (FLASH_CR_PER));
	HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, 0x081E0000, NVM_user_data);
	CLEAR_BIT (FLASH->CR, (FLASH_CR_PG));
 
	// Erase / Write Next 32-bytes
	FLASH_PageErase(0x081E0000+32);
	CLEAR_BIT (FLASH->CR, (FLASH_CR_PER));
	HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, 0x081E0000+32, _NVM);
	CLEAR_BIT (FLASH->CR, (FLASH_CR_PG));
	HAL_FLASH_Lock();
}

However, not sure if its cache related, or linker script / variable declaration, but my program does not write to flash, and if I use CubeMxProgammer to manually put data in the USER_FLASH space, it will get wiped out when I re-pgrogram the application via the Bootloader.

This topic has been closed for replies.

2 replies

alister
Senior III
September 11, 2020

>How do you modify the linker script to reserve a sector for user data...

https://sourceware.org/binutils/docs/ld/index.html

USER_FLASH is already aligned.

Why is stNVM packed? It appears unnecessary. Doesn't the compiler know how to optimally align its members? Sectors are large and only a fraction of USER_FLASH will be used. It's increasing the code size and increasing its execution time.

Why is _NVM volatile? It appears unnecessary. Or is another thread going to erase and re-write it?

SECTIONS
{
 <snip>
 
 NVM (NOLOAD) :
 {
 *(NVM)
 } >USER_FLASH
}
 
 
typedef struct {
 uint8_t val1;
 uint32_t val2[2]; // 8 bytes
 uint16_t val3;
 uint16_t val4;
 uint32_t val5[4]; // 16 bytes
 uint8_t val6[2]; // 2 bytes
 uint8_t val7;
} stNVM;
 
const stNVM _NVM __attribute__ ((section ("NVM")));

>and such that this user sector won't get erased when re-programming/bootloading?

Your code decides when and whether a sector is erased.

You may write protect it too. That'd help protect against your not coding properly and/or circumstances you can't control.

The thing with details that appear unnecessary is a reader would have to assume (a) the developer doesn't know their craft or (b) the developer knows something they don't. If it's the latter, it's good practice to comment why.

bnguy.1
bnguy.1Author
Associate III
September 11, 2020

"The thing with details that appear unnecessary is a reader would have to assume (a) the developer doesn't know their craft or (b) the developer knows something they don't. If it's the latter, it's good practice to comment why."

Unfortunately, it's the former.. I don't have much experience, so my code is based on what I understand from the datasheet, and somewhat related questions I could find on the forum.

The NOLOAD appear to take.. however, if I call HAL_FLASH_Program with the desired flash address , can this linker section be removed all together? I.e. the linker section / NOLOAD is needed only if I want to map a variable directly to flash?

Tesla DeLorean
Guru
September 11, 2020

Ok, this is a muddled mess

The sectors are LARGE (128K), erased ONCE

FLASH_PageErase()?

Your HAL_FLASH_Program() function looks to try to overwrite the blank data with ITSELF, only writing 16-bits (2-bytes)

uint8_t NVM_user_data[16]; // this is 16 bytes, not 32

Linker script and __attribute__ stuff here is confused . The section would want to be NOLOAD so you don't write content into it.

Perhaps tell the linker not to use the memory, and then it won't use it?

You've shrunk the memory, this is all you need to keep the linker out of it

FLASH (xr) : ORIGIN = 0x08000000, LENGTH = 1920K

Consider using a POINTER with an casted assignment to the address you're using?

extern volatile stNVM *pNVM = (stNVM *)0x081E0000;

printf("%d\n", pNVM->val1);

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Tesla DeLorean
Guru
September 11, 2020
// ADDR_FLASH_SECTOR_7_BANK2 0x081E0000
 
{
 FLASH_EraseInitTypeDef EraseInitStruct = {0};
 uint32_t SECTORError = 0;
 
 HAL_FLASH_Unlock();
 
 /* Fill EraseInit structure*/
 EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
 EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
 EraseInitStruct.Banks = FLASH_BANK_2;
 EraseInitStruct.Sector = FLASH_SECTOR_7;
 EraseInitStruct.NbSectors = 1;
 
 if (HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) == HAL_OK)
 {
// Success
 }
 
 HAL_FLASH_Lock();
}

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..