Reading a 64-bit volatile variable on Corex-m3

I have a 64-bit integer variable on a 32-bit controller of a Cortex-M3 ARM controller (STM32L1) that can be changed asynchronously using an interrupt handler.

volatile uint64_t v;
void some_interrupt_handler() {
    v = v + something;
}

Obviously, I need a way to access it in such a way as to prevent getting inconsistent, full updated values.

Here is the first attempt

static inline uint64_t read_volatile_uint64(volatile uint64_t *x) {
    uint64_t y;
    __disable_irq();
    y = *x;
    __enable_irq();
    return y;
}

CMSIS built-in functions __disable_irq()also __enable_irq()have an unpleasant side effect, causing a memory barrier in the compiler, so I tried to come up with something finer

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;
}

It still disables interrupts, which is undesirable, so I wonder if there is a way to do this without resorting to cpsid. The Ultimate Guide to ARM Cortex-M3 and Cortex-M4 Processors, Third Edition of Joseph Yiu Say

, , , . (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)

- , ? atomic_load() stdatomic.h, undefined reference to '__atomic_load_8'.

+5
2

LDRD ARMv7m. (A3.5.1)

The only ARMv7-M explicit accesses made by the ARM processor which exhibit single-copy atomicity are:

• All byte transactions

• All halfword transactions to 16-bit aligned locations

• All word transactions to 32-bit aligned locations

LDM, LDC, LDRD, STM, STC, STRD, PUSH and POP operations are seen to be a sequence of 32-bit
transactions aligned to 32 bits. Each of these 32-bit transactions are guaranteed to exhibit single-copy
atomicity. Sub-sequences of two or more 32-bit transactions from the sequence also do not exhibit
single-copy atomicity

, , ISR, .

non_isr(){
    do{
        flag = 1
        foo = doubleword
    while(flag > 1)
    flag = 0
}

isr(){
    if(flag == 1) 
        flag++;
    doubleword = foo
}

( ): 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

+1

64- (2 x 32-) system_tick, STM32L4xx (ARM Cortex M3). , "volatile uint64_t system_tick", LDRD, , , , .

IAR, , C11;

#include "stdatomic.h"
#ifdef __STDC_NO_ATOMICS__
static_assert(__STDC_NO_ATOMICS__ != 1);
#endif

volatile atomic_uint_fast64_t system_tick;
/**
* \brief Increment system_timer
* \retval none
*/
void HAL_IncTick(void)
{
    system_tick++;
}

/**
 * \brief Read 64-bit system_tick
 * \retval system_tick
 */
uint64_t HAL_GetSystemTick(void)
{
    return system_tick;
}

/**
 * \brief Read 32 least significant bits of system_tick
 * \retval (uint64_t) system_tick
 */
uint32_t HAL_GetTick(void)
{
    return (uint32_t)system_tick;
}

, , "".

8- , , , , , , , ISR. , IRQ, system_tick, IRQ, :

/**
 * \brief Read 64-bit system_tick
 * \retval system_tick
 */
uint64_t HAL_GetSystemTick(void)
{
    uint64_t tick;

    do {
        tick = system_tick;
    } while ((uint32_t)(system_tick >> 32) != (uint32_t)(tick >> 32));

    return tick;
}

, , 64- _ . HAL_IncTick() - , , .

0

Source: https://habr.com/ru/post/1671713/


All Articles