2
votes

I am trying to write a bootloader application for STM32F030x8. I write the bin file to the controller via UART. when data is present on the UART RDR register, I put it in a globally declared buffer of 1Kb. Everytime the buffer is full, I am trying to write it to FLASH. After writing to FLASH, the app gives an acknowledge to the PC software and it is ready to accept a new 1Kb block. So the buffer isn't written to while accessed for writing to FLASH. when I try to write the global buffer to FLASH, the application goes into Hardfault handler.

But when I copy the buffer into a locally declared buffer of 1Kb using memcpy(), and try to write that buffer to FLASH, it gives no problem whatsoever.

Why can't I just write the globally declared buffer right to FLASH? Why is there no problem when the locally declared buffer is written to FLASH?

Thanks in advance!

EDIT:

uint32_t FLASH_If_Write(__IO uint32_t* FlashAddress, uint32_t* Data ,uint16_t DataLength)
{
  uint32_t i = 0;

  for (i = 0; (i < DataLength) && (*FlashAddress <= (USER_FLASH_END_ADDRESS-4)); i++)
  {
    /* the operation will be done by word */ 
    if (FLASH_Program(FLASH_TYPEPROGRAM_WORD, *FlashAddress, *(uint32_t*)(Data+i)) == 1)
    {
     /* Check the written value */
      if (*(uint32_t*)*FlashAddress != *(uint32_t*)(Data+i))
      {
        /* Flash content doesn't match SRAM content */
        return(2);
      }
      /* Increment FLASH destination address */
      *FlashAddress += 4;
    }
    else
    {
      /* Error occurred while writing data in Flash memory */
      return (1);
    }
  }

  return (0);
}

The Hardfault seems to happen when this function enters the for loop.

When in hardfault exception the LR register is 0xFFFFFFF9, SP = 0x200011E8

What's strange is that in the for loop, there isn't any reference to the buffer, so it's actually never accessed. But it does work when the buffer is copied into a local one. What am I missing here?

EDIT 2:

globally declared buffers:

in globals.c:
uint8_t rec_buffer_uart1[REC_BUFFER_SIZE] = {0};
uint8_t send_buffer_uart1[SEND_BUFFER_SIZE] = {0};

in globals.h:
#define REC_BUFFER_SIZE         1029
extern uint8_t rec_buffer_uart1[REC_BUFFER_SIZE];
#define SEND_BUFFER_SIZE        1031
extern uint8_t send_buffer_uart1[SEND_BUFFER_SIZE];

on buffer received event:

uint32_t flashdestination = APPLICATION_ADDRESS;
uint8_t *buf_ptr = &buf; // buf is locally declared buffer

// every time buffer is full:
{
    memcpy(buf_ptr, &rec_buffer_uart1[3], 1024);   
    // works:
    ramsource = (uint32_t)&buf;
    // generates Hardfault:
    ramsource = (uint32_t)&rec_buffer_uart1[3];

    /* Write received data in Flash */
    if (FLASH_If_Write(&flashdestination, (uint32_t*) ramsource , (uint16_t) 1024/4)  == 0)
    {
        // send acknowledge
    }
}
1
Do you get the hardfault as a direct result of the copy operation? Or is there possibly a scheduler (i.e., an OS) as part of your SW, that possibly switches to some other thread which then causes the hard fault? In fact, even without an OS, is it possibly that the hard fault occurs in one of your hw-interrupt handlers (ISR)? I suggest that you put a breakpoint in your hard fault interrupt handler, and check the values of PC and LR, just to make sure of that. Also, you might want to check the STM spec for other registers which may give you some more info on the source of the problem.barak manos
Show complete code - how you declare the buffer, how you pass it to the function, how you use it.Freddie Chopin
BTW - the code of the function you showed is a complete nonsense. If this code comes from ST its not really surprising, as whole HAL/SPL shows they have no idea about proper software development.Freddie Chopin
Thanks for your reply. Added the code.BertVano
Also, could you explain me why this code is nonsense? it is a function I copied from HAL libraries into my own lib.BertVano

1 Answers

8
votes

Note that the function operates on uint32_t, while you pass it a uint8_t buffer. ARM Cortex-M0 core (as found in STM32F0) does NOT support unaligned access and any attempt to do it will result in a fault.

It worked for local buffer only by coincidence - it was aligned to 4-byte boundary, while the global buffer was not. It could as well work with global buffer if it was aligned properly - again by pure coincidence.