在cortex-m3上读取一个64位的volatile变量

ber*_*ing 5 arm atomic interrupt cortex-m3 stm32

我有一个32位的Cortex-M3 ARM控制器(STM32L1),其可以通过异步中断处理程序来修改在64位整数的变量。

volatile uint64_t v;
void some_interrupt_handler() {
    v = v + something;
}
Run Code Online (Sandbox Code Playgroud)

显然,我需要一种访问方式,以防止获取不一致的中途更新值。

这是第一次尝试

static inline uint64_t read_volatile_uint64(volatile uint64_t *x) {
    uint64_t y;
    __disable_irq();
    y = *x;
    __enable_irq();
    return y;
}
Run Code Online (Sandbox Code Playgroud)

该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;
}
Run Code Online (Sandbox Code Playgroud)

它仍然禁用中断,这是不希望的,因此我想知道是否有一种方法可以不诉诸cpsid。该权威指南的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;
}
Run Code Online (Sandbox Code Playgroud)

"=&r"用于解决ARM勘误表602117)

是否有一些可移植的库或内置函数呢?我已经试过atomic_load()stdatomic.h,但是失败了undefined reference to '__atomic_load_8'

Jer*_*en3 1

根据 ARMv7m 参考手册,LDRD 不保证原子性。(A3.5.1)

\n\n
The only ARMv7-M explicit accesses made by the ARM processor which exhibit single-copy atomicity are:\n\n\xe2\x80\xa2 All byte transactions\n\n\xe2\x80\xa2 All halfword transactions to 16-bit aligned locations\n\n\xe2\x80\xa2 All word transactions to 32-bit aligned locations\n\nLDM, LDC, LDRD, STM, STC, STRD, PUSH and POP operations are seen to be a sequence of 32-bit\ntransactions aligned to 32 bits. Each of these 32-bit transactions are guaranteed to exhibit single-copy\natomicity. Sub-sequences of two or more 32-bit transactions from the sequence also do not exhibit\nsingle-copy atomicity\n
Run Code Online (Sandbox Code Playgroud)\n\n

您可以做的是使用一个字节向 ISR 指示您正在读取它。

\n\n
non_isr(){\n    do{\n        flag = 1\n        foo = doubleword\n    while(flag > 1)\n    flag = 0\n}\n\nisr(){\n    if(flag == 1) \n        flag++;\n    doubleword = foo\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

来源(需要登录):\n http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0403e.b/index.html

\n\n

不需要登录:\n http://www.telecom.uff.br/~marcos/uP/ARMv7_Ref.pdf

\n