You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32F411CEU6写入数组触发HardFault问题求助

Why Direct Assignment Triggers HardFault But Temporary Variable Doesn't on STM32F411CEU6

This boils down to memory alignment requirements for the Cortex-M4 FPU (Floating Point Unit)—a common pitfall in ARM embedded development. Let's break this down step by step:

Core Cause: FPU Memory Alignment Rules

The Cortex-M4 core (with FPU enabled, which is default for STM32F411) requires that single-precision float memory accesses (via FPU instructions like VLDR/VSTR) are 4-byte aligned. This means the target memory address must be a multiple of 4.

Your output_buff is a char array, which is 1-byte aligned. When you try to write to &output_buff[1], that address is not 4-byte aligned (e.g., if the array starts at 0x20000000, output_buff[1] is at 0x20000001). Directly using FPU instructions to write to this unaligned address triggers an alignment fault, which escalates to the HardFault_Handler.

Why the Two Approaches Behave Differently

1. Temporary Variable Works

When you store the SCL_calculate return value in a temporary float data variable:

  • The temporary variable is allocated on the stack, which the compiler guarantees is 4-byte aligned (stack memory follows ARM's alignment rules for primitive types).
  • The FPU first writes the return value to this aligned stack address using valid VSTR instructions.
  • Then, when copying to &output_buff[1], the compiler uses general-purpose register instructions (not FPU-specific) that allow unaligned access (since you're essentially doing byte-wise or word-wise copies via non-FPU ops). These don't trigger alignment faults.

2. Direct Assignment Triggers HardFault

When you write *( (float *) (&output_buff[1]) ) = SCL_calculate( );:

  • The compiler optimizes this to directly store the FPU register holding the return value into the unaligned &output_buff[1] address using an FPU VSTR instruction.
  • Since the target address isn't 4-byte aligned, the Cortex-M4's alignment trap (enabled by default via the UNALIGN_TRP bit in the CCR register) fires, sending the core into HardFault_Handler.

How to Fix This

You have a few safe, standards-compliant options:

Option 1: Align the Target Memory

Modify your output_buff to ensure the position where you write the float is 4-byte aligned. For example:

  • Add alignment attributes to the array:
    __attribute__((aligned(4))) char output_buff[9] = {0x0};
    
    This ensures the entire array starts at a 4-byte aligned address. If you need to write to index 1, you'd need to adjust the array layout (e.g., add padding bytes before the float position) to make that address aligned.

Option 2: Use memcpy for Safe Copying

Even if you can't align the memory, use memcpy to transfer the float value. Note that you still need a temporary variable (since you can't take the address of a function return value directly):

float temp = SCL_calculate(&Voltage);
memcpy(&output_buff[1], &temp, sizeof(float));

The compiler will handle the copy using non-FPU instructions that support unaligned access, avoiding the fault.

You can turn off the Cortex-M4's alignment trap by clearing the UNALIGN_TRP bit in the CCR register:

SCB->CCR &= ~SCB_CCR_UNALIGN_TRP_Msk;

However, this is not advised—it bypasses ARM's memory alignment rules, can degrade performance, and may cause unexpected behavior with other parts of your code or peripheral accesses.

Verify with Assembly

If you want to confirm this, check the compiled assembly code:

  • The direct assignment will show a VSTR instruction targeting the unaligned address.
  • The temporary variable approach will first use VSTR to the aligned stack address, followed by STRB/LDRB or general-purpose register transfers to the unaligned array position.

内容的提问来源于stack exchange,提问作者Electromosaw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 10:25:45