2020-09-10 05:54 PM
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.
2020-09-10 06:56 PM
>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.
2020-09-10 07:01 PM
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);
2020-09-10 07:14 PM
// 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();
}
2020-09-11 01:34 PM
Thanks, I understand the 128KB sector size is huge compared to the few bytes of data I need to store.. but the only other place would be use the OPTION BYTE area, byte I rather not mess with that for fear of bricking. I'll need to write to erase/flash quite frequently , hopefully the 10k number of write cycles won't be an issue.
I fixed the test code to erase only once, I've also expanded FLASH_PageErase to show what it's doing.. and simplified the source buffer, to just be an array of 32-bit data. It seems like it's writing now, but still seems there's a pesky issue with the source pointer math.
uint32_t ulDATA_TO_WRITE [ 128 ];
void test ( void )
{
static FLASH_EraseInitTypeDef EraseInitStruct;
uint32_t SECTORError;
int sofar=0;
HAL_FLASH_Unlock();
// Erase
uint32_t StartSector = GetSector(0x081E0000);
uint32_t EndSectorAddress = StartSectorAddress + numberofwords*4;
uint32_t EndSector = GetSector(EndSectorAddress);
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
EraseInitStruct.Sector = StartSector;
EraseInitStruct.NbSectors = (EndSector - StartSector) + 1;
HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError);
//CLEAR_BIT (FLASH->CR, (FLASH_CR_PER)); // Flush needed DCRST / ICRST?
// Write
int numberofwords = (strlen(ulDATA_TO_WRITE)/4) + ((strlen(ulDATA_TO_WRITE) % 4) != 0);
while (sofar<numberofwords)
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, StartSectorAddress, ulDATA_TO_WRITE[sofar]) == HAL_OK)
{
StartSectorAddress += 4; // 2 // 8
sofar++;
}
}
//CLEAR_BIT (FLASH->CR, (FLASH_CR_PG));
HAL_FLASH_Lock();
}
:
2020-09-11 01:36 PM
"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?
2020-09-14 06:25 PM
Is there an issue with writing to the same 32-byte flash word repeatedly with the same data?
I'm using a 32-byte buffer, initialized with 0xFFs
uint32_t buffer [ 8 ] = {
0xFFFFFFFFL , 0xFFFFFFFFL , 0xFFFFFFFFL , 0xFFFFFFFFL , 0xFFFFFFFFL , 0xFFFFFFFFL , 0xFFFFFFFFL , 0xFFFFFFFFL};
so every time I want to write to flash, I use the next index.. so essentially, I'm always writing the same 32-bytes except for the 32-bit word I'm writing.
It's seems random, but every couple writes or so, I'll get a hard fault when verifying the data in the flash.