STM32L4: Flash Erase gibt HardFault

OP Persönliche Seite #7346816
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.

Gast #7346897
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

#7347110
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?

OP Persönliche Seite #7347277
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!

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren