Guten Morgen zusammen,
der Versuch, auf einem Nucleo STM32L452 eine Page des Flash zu
beschreiben, endet regelmäßig im HardFault - und ich verstehe den Grund
nicht. In CFSR steht IACCVIOL auf 1 - access violation, aber wo und
warum???
In main.c wird die Clock angeschaltet:
1 | RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN | RCC_AHB1ENR_FLASHEN;
|
Die Struktur im Flash, in die ich schreiben will, ist wie folgt
deklariert:
1 | typedef struct {
|
2 | uint16_t ofs_x;
|
3 | uint32_t scale_x;
|
4 | uint16_t ofs_y;
|
5 | uint32_t scale_y;
|
6 | } touch_calibration_t;
|
7 |
|
8 | touch_calibration_t touch_calibration __attribute__ ((section("persist"))) __attribute__((aligned(64)));
|
Im Linker File steht:
1 | persist :
|
2 | {
|
3 | KEEP(*(persist))
|
4 | . = ALIGN(4);
|
5 | *(.persist)
|
6 | . = ALIGN(4);
|
7 | } > FLASH
|
Das Alignment scheint auch zu funktionieren, jedenfalls liegt das an
0x08052A40 - 64-bit Alignment passt also.
Im Moment wäre ich schon froh, wenn ich unfallfrei löschen könnte. Beide
Varianten unten führen zum HardFault.
Irritierenderweise ist das Flash SR nach dem Löschen völlig unauffällig
(EOP gesetzt, sonst alles 0). Die Page ist auch gelöscht, jedenfalls
laut Debugger.
1 | uint32_t write_persist (uint32_t StartPageAddress, uint32_t *data, uint16_t numberofwords)
|
2 | {
|
3 |
|
4 | static FLASH_EraseInitTypeDef EraseInitStruct;
|
5 | uint32_t PAGEError;
|
6 | int sofar=0;
|
7 | __disable_irq();
|
8 | /* Unlock the Flash to enable the flash control register access *************/
|
9 | uint32_t acr_backup = FLASH->ACR;
|
10 | FLASH->ACR = FLASH_ACR_LATENCY_4WS; /* disable caches, set to maximum wait states */
|
11 | while(FLASH->SR & FLASH_SR_BSY);
|
12 | HAL_FLASH_Unlock();
|
13 |
|
14 | /* Erase the user Flash area*/
|
15 | uint32_t StartPage = (StartPageAddress - FLASH_BASE) >> 11;
|
16 | uint32_t EndPageAdress = StartPageAddress + numberofwords*4;
|
17 | uint32_t EndPage = (EndPageAdress - FLASH_BASE) >> 11;
|
18 |
|
19 | /* Fill EraseInit structure*/
|
20 | EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
|
21 | EraseInitStruct.Page = StartPage;
|
22 | EraseInitStruct.NbPages = ((EndPage - StartPage)/FLASH_PAGE_SIZE) +1;
|
23 |
|
24 | if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
|
25 | {
|
26 | /*Error occurred while page erase.*/
|
27 | __enable_irq();
|
28 | return HAL_FLASH_GetError ();
|
29 | }
|
30 | FLASH->ACR = acr_backup;
|
31 | HAL_FLASH_Lock();
|
32 |
|
33 | __enable_irq();
|
34 | }
|
1 | uint32_t write_persist (uint32_t StartPageAddress, uint32_t *data, uint16_t numberofwords)
|
2 | {
|
3 |
|
4 | static FLASH_EraseInitTypeDef EraseInitStruct;
|
5 | uint32_t PAGEError;
|
6 | int sofar=0;
|
7 | __disable_irq();
|
8 | /* Unlock the Flash to enable the flash control register access *************/
|
9 | uint32_t acr_backup = FLASH->ACR;
|
10 | FLASH->ACR = FLASH_ACR_LATENCY_4WS; /* disable caches, set to maximum wait states */
|
11 | while(FLASH->SR & FLASH_SR_BSY);
|
12 | HAL_FLASH_Unlock();
|
13 |
|
14 | /* Erase the user Flash area*/
|
15 | while(FLASH->SR & FLASH_SR_BSY);
|
16 | uint16_t page = (((uint32_t)&touch_calibration) - FLASH_BASE) >> 11;
|
17 | FLASH->CR = FLASH_CR_PER | (page << FLASH_CR_PNB_Pos) | FLASH_CR_STRT | FLASH_CR_EOPIE;
|
18 | while(FLASH->SR & FLASH_SR_BSY);
|
19 | FLASH->CR &= ~(FLASH_CR_PER | FLASH_CR_PNB_Msk | FLASH_CR_EOPIE);
|
20 | FLASH->ACR = acr_backup;
|
21 | HAL_FLASH_Lock();
|
22 |
|
23 | __enable_irq();
|
24 | }
|
Der Rechtsshift um 11 bit dient der Division durch 2048 - die Page Size
im Flash.
Der HardFault tritt erst dann auf, wenn ich einen Reset versuche. Am
nachfolgenden Code kann es aber nicht liegen, denn den Effekt habe ich
auch dann, wenn als nächster Aufruf while(1) folgt.
Any ideas? Inzwischen sind mir die Ideen ausgegangen.