El Cortex M3 admite un par de operaciones de operaciones útiles (comunes en muchas otras máquinas también) llamadas "Load-Exclusive" (LDREX) y "Store-Exclusive" (STREX). Conceptualmente, la operación LDREX realiza una carga, también establece un hardware especial para observar si la ubicación que se cargó podría estar escrita por otra cosa. Realizar un STREX en la dirección utilizada por el último LDREX hará que esa dirección se escriba solo si nada más la escribió primero . La instrucción STREX cargará un registro con 0 si la tienda se llevó a cabo, o 1 si se canceló.
Tenga en cuenta que STREX es a menudo pesimista. Hay una variedad de situaciones en las que podría decidir no realizar la tienda, incluso si la ubicación en cuestión no hubiera sido tocada. Por ejemplo, una interrupción entre un LDREX y un STREX hará que el STREX asuma que la ubicación que se está viendo podría haber sido golpeada. Por esta razón, generalmente es una buena idea minimizar la cantidad de código entre LDREX y STREX. Por ejemplo, considere algo como lo siguiente:
inline void safe_increment (uint32_t * addr)
{
uint32_t new_value;
hacer
{
nuevo_valor = __ldrex (addr) + 1;
} while (__ strex (nuevo_valor, addr));
}
que compila algo como:
; Suponga que R0 contiene la dirección en cuestión; r1 destrozado
lp:
ldrex r1, [r0]
agregue r1, r1, # 1
strex r1, r1, [r0]
cmp r1, # 0; Prueba si no es cero
bne lp
.. el código continúa
La gran mayoría de las veces que se ejecuta el código, nada sucederá entre LDREX y STREX para "perturbarlos", por lo que STREX tendrá éxito sin más preámbulos. Sin embargo, si ocurre una interrupción inmediatamente después de la instrucción LDREX o ADD, STREX no realizará el almacenamiento, sino que el código volverá a leer el valor (posiblemente actualizado) de [r0] y calculará un nuevo valor incrementado basado en eso.
El uso de LDREX / STREX para formar operaciones como safe_increment hace posible no solo administrar secciones críticas, sino también, en muchos casos, evitar la necesidad de ellas.
while(STREXW(new_value, addr);
¿cómo podemos creer que lo que usted dice es correcto si su código ni siquiera se compila?Parece que necesita algunos búferes circulares o FIFO en su software MCU. Al rastrear dos índices o punteros en la matriz para lectura y escritura, puede tener acceso tanto en primer plano como en segundo plano al mismo búfer sin interferencia.
El código de primer plano es libre de escribir en el búfer circular en cualquier momento. Inserta datos en el puntero de escritura, luego incrementa el puntero de escritura.
El código de fondo (manejo de interrupciones) consume datos del puntero de lectura e incrementa el puntero de lectura.
Cuando los punteros de lectura y escritura son iguales, el búfer está vacío y el proceso en segundo plano no envía datos. Cuando el búfer está lleno, el proceso en primer plano se niega a escribir más (o puede sobrescribir datos antiguos, según sus necesidades).
El uso de buffers circulares para desacoplar lectores y escritores debería eliminar la necesidad de deshabilitar las interrupciones.
fuente
No puedo recordar la ubicación exacta, pero en las bibliotecas que provienen de ARM (no TI, ARM, debería estar bajo CMSIS o algo así, utilizo ST pero recuerdo haber leído en alguna parte que este archivo proviene de ARM, por lo que también debería tenerlo ) hay una opción de desactivación de interrupción global. Es una llamada a la función. (No estoy en el trabajo pero mañana buscaré la función exacta). Lo terminaría con un buen nombre en su sistema y deshabilitaría las interrupciones, haría lo suyo y habilitaría de nuevo. Dicho esto, la mejor opción sería implementar un semáforo o una estructura de cola en lugar de la desactivación de interrupción global.
fuente