1

I'm trying to erase all bootloader from flash (2 pages of 2 KB, starting from address 0x08000000) in STM32F302RBT6, and as my code app starts from the 0x08001000 address should not be a problem to do it. The point is, after the erasing function returns, a hard fault it's generated with a memory fault IACCVIOL and never reaches the while(1).

public int main (void)
{
  HAL_Init();
  ClockInit();

  APP_MEM_EraseBootloaderSectorInFlash();
  while(1);
}

unsigned char APP_MEM_EraseBootloaderSectorInFlash(void) 
{
  unsigned char result = 0;

  __disable_irq();
  HAL_FLASH_Unlock();
  result = ErasePageinFlash(0x08000000);
  result = ErasePageinFlash(0x08000800);
  HAL_FLASH_Lock();
   __enable_irq();

  return result;
}

static unsigned char ErasePageinFlash(uint32_t page_address)
{
  unsigned char          result = 0;
  uint32_t               page_error;
  FLASH_EraseInitTypeDef erase_init;

  erase_init.TypeErase   = FLASH_TYPEERASE_PAGES;
  erase_init.NbPages     = 1u;
  erase_init.PageAddress = page_address;

  if (HAL_FLASHEx_Erase(&erase_init, &page_error) == HAL_OK)
  {
    result = 1;
  }

  return result;
}

PS. I've Already tried some things:

  1. If I erase two pages starting in 0x08003000 (not used by the application), it works fine, and no fault is generated.

  2. If I debug the code step by step, the problem doesn't occur. The code reaches the while(1).

  3. I've tried to reduce the clock and increment flash latency, but it didn't work.

  4. If I change the position of the while(1) from the main function and put it inside the APP_MEM_EraseBootloaderSectorInFlash function, it works fine, and no fault is generated.

This is the code of ClockInit:

static void ClockInit(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  //RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
  while (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    // TODO :: Fault behaviour
  }

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  while (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    // TODO :: Fault behaviour
  }
}

Fault Report

callstack

  • This might be a trivial question (and most likely not the issue) but are you sure that APP_MEM_BOOTLOADER_STARTING_ADDRESS + 0x800 is what you want? If the define is treated as a pointer to u32, than adding 0x800 would go 4 times the offset. – Fra93 Jun 15 '22 at 09:40
  • `If I debug the code step by step, the problem doesn't occur. The code reaches the while(1).` this is suspicious, can you check the program counter and see if the program resides at 0x8001000 even when you are debugging? Maybe the debugger runs code from somewhere else and it's not overwritten when erasing the flash. – Fra93 Jun 15 '22 at 09:44
  • Can you elaborate more on point (4)? Do you put it after the re enable of IRQs? Or somewhere else? – Fra93 Jun 15 '22 at 09:49
  • Side note: the return value of `ErasePageinFlash(APP_MEM_BOOTLOADER_STARTING_ADDRESS);` is ignored because `result` is unconditionally overwritten by the return value of `ErasePageinFlash(APP_MEM_BOOTLOADER_STARTING_ADDRESS + 0x800);` called after that. – MikeCAT Jun 15 '22 at 10:27
  • In case flash drivers work when you single step but don't work when you run, then the flash prescaler clock is a likely culprit. – Lundin Jun 15 '22 at 10:30
  • @Fra93 1) Regarding offset. I put the exact values that I wanted and it continues doesn't work (I edited the question to exactly what I did to test it) 2) I made a step by step debug, and the PC stayed restrict to addresses in range where my program is in the flash (from 0x08001000 to 0x08002610) 3) I put after the "__enable_irq();" – Leonardo Castilho Jun 15 '22 at 10:56
  • @Lundin, I thought that could be it. Then, I reduced the SYSCLK to 8 MHz and tried LATANCY_0, LATANCY_1, and LATANCY_2, but doesn't work too. The strange thing is, if I change the page address to 0x08003000 and 0x08003800, it works fine. – Leonardo Castilho Jun 15 '22 at 11:02
  • Erasing the first part of the flash will erase the interrupt vector, but no interrupt looks used in the code...? – MikeCAT Jun 15 '22 at 11:07
  • @MikeCAT I'm not using interrupts in my app. But I don't have access to the bootloader source code, which could use some interruptions for USART communications. Assuming it, I've disabled the interruptions and not enabled them again after erasing the page, and it worked properly, so I think you are right. After I erase the bootloader sector in memory, an interruption probably tries to point to a corrupted address (corrupted by me rsrsrs). Thank you (can you answer officially? then I can put the question as answered by you) – Leonardo Castilho Jun 15 '22 at 11:56
  • Cortex-M4 vector tables are relocatable. Ideally the bootloader should relocate the vector table to 0x8001000 (the application's table) then load the stack pointer and program-counter from the application vector table. If it is not doing that, you should relocate the vector table in the application before enabling interrupts. In the pre-main start-up code or very early in main(). – Clifford Jun 16 '22 at 00:02

1 Answers1

2

The first part of flash memory of STM series may be mapped to 0x00000000, which is used as the interrupt vector.

If this is the case, erasing the part will erase the interrupt vector and prevent interrupts from work correctly.

MikeCAT
  • 73,922
  • 11
  • 45
  • 70
  • 1
    Worth adding that in this case, the application at 0x8001000 should relocate the vector table _before_ enabling interrupts. – Clifford Jun 16 '22 at 00:05