arm interrupt atomic stm32 cortex-m3

arm - leyendo una variable volátil de 64 bits en cortex-m3



interrupt atomic (1)

La atomicidad no está garantizada en LDRD según el manual de referencia 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

Lo que puedes hacer es usar un byte para indicar al ISR que lo estás leyendo.

non_isr(){ do{ flag = 1 foo = doubleword while(flag > 1) flag = 0 } isr(){ if(flag == 1) flag++; doubleword = foo }

Fuente (se requiere iniciar sesión): http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0403e.b/index.html

No es necesario iniciar sesión: http://www.telecom.uff.br/~marcos/uP/ARMv7_Ref.pdf

Tengo una variable entera de 64 bits en un controlador ARM Cortex-M3 de 32 bits (STM32L1), que puede ser modificado asincrónicamente por un controlador de interrupción.

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

Obviamente, necesito una forma de acceder a ella de una manera que evite obtener valores inconsistentes y actualizados a medias.

Aquí está el primer intento

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

Las funciones en línea de __disable_irq() y __enable_irq() tienen un desafortunado efecto secundario, forzando una barrera de memoria en el compilador, así que he tratado de encontrar algo más refinado

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

Todavía desactiva las interrupciones, lo cual no es deseable, así que me pregunto si hay alguna manera de hacerlo sin recurrir a cpsid . La guía definitiva de los procesadores ARM Cortex-M3 y Cortex-M4, tercera edición de Joseph Yiu, dice:

Si llega una solicitud de interrupción cuando el procesador está ejecutando una instrucción de ciclos múltiples, como una división de enteros, la instrucción podría abandonarse y reiniciarse después de que el manejador de interrupciones finalice. Este comportamiento también se aplica para cargar instrucciones de doble palabra (LDRD) y almacenar palabras dobles (STRD).

¿Significa que estaré bien simplemente escribiendo esto?

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

(Usando "=&r" para trabajar con ARM errata 602117)

¿Hay alguna biblioteca o función incorporada que haga lo mismo de forma portátil? He intentado atomic_load() en stdatomic.h , pero falla con undefined reference to ''__atomic_load_8'' .