我在32位Cortex-M3 ARM控制器(STM32L1)上有一个64位整数变量,可以通过中断处理程序异步修改 .
volatile uint64_t v;
void some_interrupt_handler() {
v = v + something;
}
显然,我需要一种方法来访问它,以防止获得不一致的,中途更新的值 .
这是第一次尝试
static inline uint64_t read_volatile_uint64(volatile uint64_t *x) {
uint64_t y;
__disable_irq();
y = *x;
__enable_irq();
return y;
}
CMSIS内联函数 __disable_irq()
和 __enable_irq()
有一个不幸的副作用,强制编译器的内存障碍,所以我试图想出更细粒度的东西
static inline uint64_t read_volatile_uint64(volatile uint64_t *x) {
uint64_t y;
asm ( "cpsid i\n"
"ldrd %[value], %[addr]\n"
"cpsie i\n"
: [value]"=r"(y) : [addr]"m"(*x));
return y;
}
它仍然会禁用中断,这是不可取的,因此我无需借助 cpsid
就可以做到这一点 . Joseph Yiu的第三版ARM Cortex-M3和Cortex-M4处理器权威指南说
如果在处理器执行多周期指令(例如整数除法)时到达中断请求,则可以在中断处理程序完成后放弃并重新启动指令 . 此行为也适用于加载双字(LDRD)和存储双字(STRD)指令 .
这是否意味着只要写这个就可以了?
static inline uint64_t read_volatile_uint64(volatile uint64_t *x) {
uint64_t y;
asm ( "ldrd %[value], %[addr]\n"
: [value]"=&r"(y) : [addr]"m"(*x));
return y;
}
(使用 "=&r"
解决ARM勘误表602117)
是否有一些库或内置函数可以移植?我在 stdatomic.h
中尝试了 atomic_load()
,但它失败了 undefined reference to '__atomic_load_8'
.
1 回答
根据ARMv7m参考手册,LDRD不保证原子性 . (A3.5.1)
您可以做的是使用一个字节向ISR指示您正在阅读它 .
来源(需要登录):http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0403e.b/index.html
不需要登录:http://www.telecom.uff.br/~marcos/uP/ARMv7_Ref.pdf