1
\$\begingroup\$

Getting hard fault when assigning this 32 bit value to the shown variable(val_32);

  uint32_t val_32 = *((uint32_t *)( &buffer[0] + length - 4));
  
  or

  uint32_t val_32 = *((uint32_t *)( &buffer[length - 4] ));

Same thing but tried:

  uint32_t val_32 = *((uint32_t *)(buffer + length - 4));

Declarations of the variables used;

uint8_t buffer[200];

uint8_t length;

System:

MCU = STM32F072C8T6

Keil v5.23

When i debugging, hardfault occurs at stepping over this code. Though without stepping over i put that code to the watch window and get the result i expected. Dont know what is my mistake or how to fix it. Thanks for the help.

\$\endgroup\$
2
  • \$\begingroup\$ Can you please share all the code? I don't think the problem is in here. \$\endgroup\$
    – emre iris
    Mar 9, 2021 at 7:36
  • \$\begingroup\$ Sorry i cant share but i intentionally cause the problem again and solved it by changing my style to get 32 bit value from uint8_t values ( by unions , sliding bytes, memcpy etc.) \$\endgroup\$
    – U.Sim
    Mar 10, 2021 at 13:28

2 Answers 2

6
\$\begingroup\$

This looks like an unaligned access, which causes hard faults on Cortex M0 cores. M3 & M4 cores can handle this with some performance penalties.

Basically, when you try to access a memory location using a uint32_t pointer, the compiler generates a 32 bit word access instruction. This word address must be aligned to a 4 byte address boundary. In other words, the address must be divisible by 4.

Your uint8_t buffer may or may not be aligned to 4 byte boundary. Actually, unless they are in structs, compilers seem to align all variables on word boundaries. Of course you can't count on that, so it's better to demand it explicitly. In GCC, you can align variables like below:

uint8_t buffer[200] __attribute__ ((aligned (4)));

Unfortunately, this kind of alignment won't solve your problem in your situation. Because even if the start of the buffer is aligned, you are using uint8_t pointers to access it. So unless the length is divisible by 4, you will still cause unaligned access faults.

You may need to reconsider your memory layout. Or you can manually extract uint32_t from the buffer. memcpy() function is a well known and easy to use solution in these situations.

#include <string.h>
uint32_t val32;
memcpy(&val32, buffer + length - 4, sizeof(val32));
\$\endgroup\$
3
  • \$\begingroup\$ Thanks, I just answered that I wasn't sure of the STM32 behaviour… some architectures really dislike unaligned accesses (and need to emulate them in the fault handler, if needed) \$\endgroup\$ Mar 9, 2021 at 7:40
  • \$\begingroup\$ Thanks for your time and help. Have a good day. \$\endgroup\$
    – U.Sim
    Mar 9, 2021 at 7:51
  • 1
    \$\begingroup\$ sizeof val32 might be better than sizeof (uint32_t). Or at least worth considering. \$\endgroup\$
    – user57037
    Mar 9, 2021 at 7:55
0
\$\begingroup\$

Uhmm this seems like a buffer overflow/uninitialized variable issue.

What is the value of length at the fault time? If you didn't initialize it and it's a local variable then it's a random value.

Also assuming length < 4 you would try to access before the buffer, which is illegal.

Another thing, but I don't know if the STM32 is affected, is that some CPU can't store unaligned words; for example a 32 bit value in some architectures can't be stored on addresses which are not multiple or 4 (this simplifies the internal architecture)

\$\endgroup\$
1
  • \$\begingroup\$ More like bad array element access. \$\endgroup\$
    – emre iris
    Mar 9, 2021 at 7:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.