cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F401 - Hard Fault while programmin FLASH - IAP

benjamin Gräf
Associate II

Hello!

I am working on a custom USB bootloader for a stm32F401VCT6.

The communicatio with the host PC over USB is working. Also the erasing of the Flash memory is working. I am using the HAL drivers by the way.

The bootlaoder sits in the first two sectors of the Flash memory.

The problem now is, when I want to write data to flash, it goes into a hard fault error. The point where the hard fault error occurs is in the function:

HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, startingAddress, dummy);

more specific, in this function another function is called:

status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);

this function is called 2 times in the HAL_Flash_Program function. the second time it causes an hard fault. The type of the hard fault is: Bus, memory management, or usage fault. more specific: Attempt to execute an undefined instruction

I tryed to disable the write protection. But still causes a hard fault when trying to write to flash.

My write to flash function:

static void Write(void)

{

uint32_t startingAddress = APPLICATION_START_ADDRESS;

int numBytes;

uint8_t i;

uint8_t diff = 0;

HAL_StatusTypeDef returnval;

/*

uint32_t error1 = FLASH_SR_PROGERR;

uint32_t error2 = FLASH_SR_PGAERR;

uint32_t error3 = FLASH_SR_PGSERR;

*/

// Receive the number of bytes to be written

WaitForUSBData(TIMEOUT_VALUE);

numBytes = pRxBuffer[0];

//FLASH_If_Init();

// Check checksum

if(CheckChecksum(pRxBuffer, 2) != 1)

{

// invalid checksum

Send_NACK();

return;

}

else

{

// valid checksum

if(numBytes == 32)

{

Send_ACK();

}

}

do

{

  // Receive the data, a maxiumum of 32 Bytes of data and 1 Byte of checksum can be received

WaitForUSBData(TIMEOUT_VALUE);

  i = 0;

  /*

  if(pRxBuffer[0] == 0 && pRxBuffer[1] == 0x80 && pRxBuffer[2] == 1){

  HAL_GPIO_TogglePin(GPIOD, LED2_Pin);

  HAL_Delay(150);

  HAL_GPIO_TogglePin(GPIOD, LED2_Pin);

HAL_Delay(150);

HAL_GPIO_TogglePin(GPIOD, LED2_Pin);

HAL_Delay(150);

HAL_GPIO_TogglePin(GPIOD, LED2_Pin);

  }

  */

HAL_FLASH_Unlock();

while(numBytes > 0)

  {

   // Program a double word (8 Byte) at once

// First bring it to the right Bit format

dummy = 0;

dummyH = 0;

dummyL = 0;

for(x = i; x < (i + 4); x++)

{

dummyL += pRxBuffer[x] << ((x - i) * 8);

dummyH += pRxBuffer[x + 4] << ((x - i) * 8);

}

dummy = (uint64_t) dummyH << 32;

dummy += (uint64_t) dummyL;

//If the last Doubleword is not complete, fill up the rest with 1

if(numBytes % 8 != 0)

{

shadowdummy = 1;

diff = 32 - numBytes;

for(x = 1; x < diff; x++)

{

shadowdummy += 1 << x;

}

dummy |= shadowdummy << (8 - diff);

}

//stuck here...

   returnval = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, startingAddress, dummy);

    if(returnval != HAL_OK)

    {

     //HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);

     Send_NACK();

     break;

    }

    /* Check the written value */

if (*(uint64_t*)startingAddress != dummy)

{

/* Flash content doesn't match received content */

//HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);

Send_NACK();

break;

}

    //startingAddress += 8;

    startingAddress += sizeof(uint64_t);

    i += sizeof(uint64_t);

    //CLEAR_BIT (FLASH->CR, (FLASH_CR_PG));

    numBytes -= 8;

  }

  HAL_FLASH_Lock();

  Send_ACK();

  // Receive the number of bytes to be written

  WaitForUSBData(TIMEOUT_VALUE);

  // Check checksum

  if(CheckChecksum(pRxBuffer, 2) != 1)

  {

   // invalid checksum

   Send_NACK();

   return;

  }

  else

  {

   // valid checksum

   Send_ACK();

  }

  numBytes = pRxBuffer[0];

}while(numBytes > 0);

Any ideas what could be wrong?

1 ACCEPTED SOLUTION

Accepted Solutions
Piranha
Chief II

RM0368 3.5.2 says that for a x64 program/erase parallelism size You neet to apply external high voltage to Vpp (BOOT0) pin. Without that in normal conditions (2.7-3.6 V) maximum parallelism size is x32. But my personal suggestion is to use x8 size parallelism, because it works in all power voltage range (1.7-3.6 V). For a things like bootloader, configuration and other storage You mostly need the safest not the fastest method. So You can get 61 KB/s in safest x8 mode or 244 KB/s in fastest x32 normal mode.

View solution in original post

6 REPLIES 6

Doesn't look like an alignment issue.

It is likely you increasing the address beyond the size limit of the flash array. Add a boundary check.​

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
benjamin Gräf
Associate II

Thank you for your answere.

What exectly do you mean by "limit of the flash array" The hard fault occures already at the first call of the HAL_FLASH_Program function. At this point the address is the starting address of sector 3 of flash where the user program is located.

You're going to need to instrument the code to output diagnostic information you can review.

I would make sure the address you are attempting to write is known, aligned and blank. Add sanity checks.

Make sure your stack is large enough and there is no corruption of the variables.

If you access outside the bounds of physical memory it will fault.

Unaligned 64-bit accesses will fault.

Unhandled interrupts can potential fault.

Have a proper Hard Fault Handler, and look at the faulting instructions, along with the registers to understand the specific objection.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Piranha
Chief II

RM0368 3.5.2 says that for a x64 program/erase parallelism size You neet to apply external high voltage to Vpp (BOOT0) pin. Without that in normal conditions (2.7-3.6 V) maximum parallelism size is x32. But my personal suggestion is to use x8 size parallelism, because it works in all power voltage range (1.7-3.6 V). For a things like bootloader, configuration and other storage You mostly need the safest not the fastest method. So You can get 61 KB/s in safest x8 mode or 244 KB/s in fastest x32 normal mode.

Ok this has fixed it. I tryed it with WORD programming now and it worked.

Strange, because I also wrote a bootloader for the STM32Lxx and there it worked with DOUBLEWORD programming just fine.

Thank you Clive and Piranha for your answeres !

have a nice day

benjamin Gräf
Associate II

Ok very strange scenario.

I finished the bootloader and it worked the first time I used it to program a hex file into flash .

Then jumped to the main application address and the main program ran fine.

After that I wanted to try it again but the microcontroller did not respond anymore and I was not able to communicate with it over USB or even with the ST-Link Debugger.

I can not reset the STM32 since its a custom PCB with no Reset Pin and the ST Link V2 gives the error:

Failed to reset ST-Link device

Failed to Perform System reset of ST-Link device

Error in initializing ST-Link device.

Reason: Failed to reset target.

I am using Atollic TrueSTUDIO for STM32. Basically I cannot communicate with the microcontroller anymore and it also does not run the bootloader anymore if I restart it. I know this because the signal LED is not blinking as it is supposed to do.

Any ideas?