Forum: Mikrocontroller und Digitale Elektronik STM32L4: Flash Erase gibt HardFault


von Max G. (l0wside) Benutzerseite


Lesenswert?

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.

: Bearbeitet durch User
von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Warum align(4) und nicht (8)? Was sagt der Debugger?

von Max G. (l0wside) Benutzerseite


Lesenswert?

align(8) ist natürlich plausibel, du hast Recht. Hat das Problem aber 
auch nicht gelöst (und war auch vorher schon, ziemlich unglücklich, 
durch das __attribute__((aligned(64))) erschlagen).

Was genau meinst du mit "was sagt der Debugger"?

von pegel (Gast)


Lesenswert?

~/STM32Cube/Repository/STM32Cube_FW_L4_V1.17.2/Projects/NUCLEO-L452RE/Ex 
amples/FLASH

Vielleicht hilft das zur Orientierung.

von Michael F. (Firma: IAR Systems) (michael_iar)


Lesenswert?

Max G. schrieb:
> In CFSR steht IACCVIOL auf 1 - access violation, aber wo und
> warum???

Moin,

laut Arm Cortex-M4 User Guide sollte bei IACCVIOL die verursachende 
Adresse des Program Counters gespeichert werden:
1
1 = the processor attempted an instruction fetch from a location that does not permit execution. This fault occurs on any access to an XN region, even when the MPU is disabled or not present. When this bit is 1, the PC value stacked for the exception return points to the faulting instruction.

Steht was plausibles in LR / R14?

Gruß,
Michael

von Jim M. (turboj)


Lesenswert?

Löschen geht doch nur für ganze Pages, die 11 Bits benötigen ein 
Alignment von 2048 Byte - jedenfalls sieht das für mich so aus.

Wenn Du Teile Deines Programms mit löschst sind Hard Faults die logische 
Folge. Hast Du mal den Flash komplett ausgelesen und mit dem Programm 
(binary/hex) verglichen?

von Max G. (l0wside) Benutzerseite


Lesenswert?

Jim M. schrieb:
> Wenn Du Teile Deines Programms mit löschst sind Hard Faults die logische
> Folge. Hast Du mal den Flash komplett ausgelesen und mit dem Programm
> (binary/hex) verglichen?
Auch wenn ich den ersten Teil deines Beitrags nicht so recht verstanden 
habe (die Pages werden mit ihrer Nummer, nicht mit der Adresse 
angesprochen, daher der Rechtsshift), hast du mich auf die richtige Spur 
gebracht.

Das Linker-File sieht nun wie so aus:
1
MEMORY
2
{
3
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 160K
4
  RAM2    (xrw)    : ORIGIN = 0x10000000,   LENGTH = 32K
5
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH = 510K
6
  EEPROM   (rx)    : ORIGIN = 0x807F800,   LENGTH = 2K
7
}
8
[...]
9
  persist :
10
  {
11
    KEEP(*(persist))
12
    . = ALIGN(8);
13
    *(.persist)
14
    . = ALIGN(8);
15
  } > EEPROM

In der ursprünglichen Version war die section irgendwo am Ende des 
Bootcodes gelandet, so dass die Löschaktion den Bootcode mit entsorgt 
hat. Das hat wenig erstaunlich den Hardfault verursacht.
Sieht aus, als wäre es nun i.O.

Danke allen Helfern!

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.