Estou codificando algo usando o controle direto do GPIO, existem alguns bons recursos para isso, como http://elinux.org/RPi_Low-level_peripherals#GPIO_hardware_hacking ; o processo envolve aberto ("/ dev / mem") e, em seguida, uma operação mmap efetivamente mapeia o endereço físico desejado em seu espaço de endereço virtual. Em seguida, leia a seção 6 deste http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf para descobrir como as E / S são controladas.
Para mudar para a função de um pino (entrada, saída ou várias funções especiais), você modifica esses campos de 3 bits nos registros de E / S GPFSELx (000 = entrada, 001 = instância de saída). Essas operações de modificação são compiladas para operações com carga e armazenamento comuns (por exemplo, para alterar GPIO0 para entrada: * (regptr) & = ~ 7; que compila para algo como
ldr r2, [r3, #0] ; r = *ptr (load r2 from I/O register)
bic r2, r2, #7 ; r2 &= ~7
str r2, [r3, #0] ; *ptr = r2 (store r2 to I/O register)
O problema é o seguinte: se ocorrer uma interrupção entre a carga e a loja, e outro processo ou ISR modificar o mesmo registro de E / S, a operação de armazenamento (com base em uma leitura obsoleta em r2) reverterá os efeitos dessa outra operação. Portanto, a alteração desses registros de E / S realmente precisa ser feita com uma operação de leitura / modificação / gravação atômica (bloqueada). Os exemplos que eu vi não usam uma operação bloqueada.
Como esses registros de E / S geralmente são alterados apenas ao configurar algo, é improvável que ocorram problemas, mas 'nunca' é sempre melhor do que 'improvável'. Além disso, se você tiver um aplicativo no qual você está fazendo um bit-bashing para emular uma saída de coletor aberto, (tanto quanto eu sei), isso envolve programar a saída para 0 e alterná-la entre saída (baixa) ou entrada ( para off / high). Portanto, nesse caso, haveria modificações frequentes nesses registros de E / S, e as modificações inseguras teriam muito mais probabilidade de causar um problema.
Portanto, provavelmente existe uma operação de comparação e configuração do ARM ou similar que pode ser usada aqui para fazer isso, alguém pode me indicar isso e como fazer isso acontecer com o código C?
[Observe que nada de especial é necessário quando você programa uma E / S como saída e apenas a altera de 0 para 1 ou vice-versa; como existe um registro de E / S no qual você escreve, para definir os bits selecionados como 1 e outro para limpar os bits selecionados como 0. Nenhuma leitura / gravação é necessária para esta operação, portanto, não há risco de interrupções].
/dev/mem
, parece que seu código é código do espaço do usuário. Eu não acho que em qualquer sistema operacional moderno seja necessário ter cuidado com as interrupções na alteração dos valores dos registros no código do espaço do usuário. Eu acredito que isso não seria um problema, mesmo no código de espaço do kernel, pois o Linux restaura todos os registros quando o manipulador de interrupções termina seu trabalho.