Cortex-M双核系统中断中atomic自增未按预期工作问题排查
问题原因分析与解决方案
1. 共享内存段链接脚本配置错误
如果counter2未被正确分配到跨核共享内存区域,M4的写入实际操作的是本地私有内存,M7读取的共享内存地址自然始终为初始值0。
- 检查M4的链接脚本(如
M4.ld):确认counter2所属的原子变量是否被放入指定的共享内存段(需对应RT1176的物理共享内存地址,例如0x20200000起始的区域)。 - 验证变量地址:在M4和M7代码中分别打印
&counter2,确保两者地址完全一致。若不一致,说明链接脚本配置有误,变量未被分配到共享内存。
2. C++原子操作的内存序与编译选项不匹配
GCC 9.3.1对Cortex-M4的fetch_add实现依赖正确的编译选项和内存序参数:
- 默认的
memory_order_seq_cst在裸机M4环境下可能被编译器优化出问题,尝试显式指定宽松内存序:counter2.fetch_add(1, std::memory_order_relaxed); - 检查M4编译参数:确保包含
-mthumb -march=armv7e-m -mtune=cortex-m4(若使用FPU需加上-mfloat-abi=hard),这些参数是GCC生成正确Cortex-M4原子指令的必要条件。缺少参数可能导致fetch_add被编译为非原子操作甚至无效指令。
3. RT1176共享内存缓存一致性配置问题
RT1176的M7和M4核缓存配置可能导致共享内存访问不一致:
- 确认共享内存区域被配置为非缓存(Non-cacheable)或缓存一致性(Cache-coherent):若M4的写入被缓存但未同步到物理内存,M7读取的物理内存会是初始值0。而
counter1的store+load可能因编译器生成的指令触发了缓存回写,因此表现正常。 - 修改M4的MPU/MMU配置,将共享内存区域设置为非缓存属性。
4. GCC 9.3.1的C++原子操作实现缺陷
GCC 9.3.1在Cortex-M4裸机环境下的std::atomic实现存在已知问题,尤其是32位整数的fetch_add:
- 尝试用ARM汇编实现原子自增,绕过标准库:
在定时器中断中调用inline void atomic_inc(std::atomic<uint32_t>& val) { __asm__ volatile ( "ldrex r0, [%0]\n" "add r0, r0, #1\n" "strex r1, r0, [%0]\n" "cmp r1, #0\n" "bne .-12\n" : "+r"(&val) : : "r0", "r1", "memory" ); }atomic_inc(counter2)替代fetch_add。
内容的提问来源于stack exchange,提问作者Lucan de Groot
相关产品推荐
相关产品推荐

