O Cortex M3 suporta um par útil de operações (comum em muitas outras máquinas) chamado "Load-Exclusive" (LDREX) e "Store-Exclusive" (STREX). Conceitualmente, a operação LDREX executa uma carga, também define algum hardware especial para observar se o local que foi carregado pode ser gravado por outra coisa. A execução de um STREX no endereço usado pelo último LDREX fará com que esse endereço seja gravado apenas se nada mais o tiver escrito primeiro . A instrução STREX carregará um registro com 0 se a loja ocorreu ou 1 se foi abortada.
Observe que o STREX geralmente é pessimista. Existem várias situações em que pode decidir não executar a loja, mesmo que o local em questão não tenha sido realmente tocado. Por exemplo, uma interrupção entre um LDREX e STREX fará com que o STREX assuma que o local que está sendo observado pode ter sido atingido. Por esse motivo, geralmente é uma boa ideia minimizar a quantidade de código entre o LDREX e o STREX. Por exemplo, considere algo como o seguinte:
inline void safe_increment (uint32_t * addr)
{
uint32_t novo_valor;
Faz
{
new_value = __ldrex (endereço) + 1;
} while (__ strex (novo_valor, endereço));
}
que compila para algo como:
; Suponha que R0 mantenha o endereço em questão; r1 lixeira
lp:
ldrex r1, [r0]
adicione r1, r1, # 1
strex r1, r1, [r0]
cmp r1, # 0; Teste se diferente de zero
bne lp
.. código continua
Na grande maioria das vezes que o código é executado, nada acontece entre o LDREX e o STREX para "perturbá-los"; portanto, o STREX terá êxito sem mais delongas. Se, no entanto, ocorrer uma interrupção imediatamente após a instrução LDREX ou ADD, o STREX não executará o armazenamento, mas o código retornará para ler o valor (possivelmente atualizado) de [r0] e calcular um novo valor incrementado com base nisso.
O uso do LDREX / STREX para formar operações como safe_increment possibilita não apenas gerenciar seções críticas, mas também em muitos casos, para evitar a necessidade delas.
while(STREXW(new_value, addr);
como podemos acreditar que o que você diz está correto se o seu código nem sequer é compilado?Parece que você precisa de alguns buffers circulares ou FIFOs no seu software MCU. Ao rastrear dois índices ou ponteiros na matriz para leitura e gravação, é possível que o primeiro plano e o segundo plano acessem o mesmo buffer sem interferência.
O código de primeiro plano pode ser gravado gratuitamente no buffer circular a qualquer momento. Ele insere dados no ponteiro de gravação e depois incrementa o ponteiro de gravação.
O código de plano de fundo (tratamento de interrupção) consome dados do ponteiro de leitura e incrementa o ponteiro de leitura.
Quando os ponteiros de leitura e gravação são iguais, o buffer fica vazio e o processo em segundo plano não envia dados. Quando o buffer está cheio, o processo em primeiro plano se recusa a gravar mais (ou pode sobrescrever dados antigos, dependendo de suas necessidades).
O uso de buffers circulares para dissociar leitores e gravadores deve remover a necessidade de desativar interrupções.
fonte
Não me lembro da localização exata, mas nas bibliotecas que vêm do ARM (não TI, ARM, ele deve estar no CMSIS ou algo assim, eu uso o ST, mas lembro de ler em algum lugar que esse arquivo veio do ARM, então você também deve tê-lo ) existe uma opção de desativação de interrupção global. É uma chamada de função. (Não estou no trabalho, mas amanhã procurarei a função exata). Gostaria de encerrar com um bom nome em seu sistema e desativar as interrupções, fazer suas coisas e ativar novamente. Dito isto, a melhor opção seria implementar um semáforo ou uma estrutura de filas em vez de desativar a interrupção global.
fonte