Estoy codificando algo usando el control directo de GPIO, hay algunos buenos recursos para esto, como http://elinux.org/RPi_Low-level_peripherals#GPIO_hardware_hacking ; el proceso implica abrir ("/ dev / mem") y luego una operación de mmap mapea efectivamente la dirección física deseada en su espacio de dirección virtual. Luego, lea la sección 6 de este http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf para averiguar cómo se controlan las E / S.
Para cambiar a la función de un pin (entrada, salida o varias funciones especiales), modifique estos campos de 3 bits en los registros de E / S GPFSELx (000 = entrada, 001 = instancia de salida de enemigo). Estas operaciones de modificación se compilan en operaciones con carga y almacenamiento ordinarios (por ejemplo, para cambiar GPIO0 a input: * (regptr) & = ~ 7; que se compila en 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)
El problema es este: si se produce una interrupción entre la carga y el almacenamiento, y otro proceso o ISR modifica el mismo registro de E / S, la operación de almacenamiento (basada en una lectura obsoleta en r2) revertirá los efectos de esa otra operación. Por lo tanto, cambiar estos registros de E / S realmente debe hacerse con una operación atómica (bloqueada) de lectura / modificación / escritura. Los ejemplos que he visto no usan una operación bloqueada.
Dado que estos registros de E / S generalmente se cambian solo cuando se configura algo, es poco probable que ocurran problemas, pero 'nunca' siempre es mejor que 'improbable'. Además, si tiene una aplicación en la que está aplicando bit-bashing para emular una salida de colector abierto, entonces (por lo que puedo decir) esto implica programar la salida a 0 y luego cambiarla entre salida (para baja) o entrada ( para apagado / alto). Entonces, en ese caso, habría modificaciones frecuentes en estos registros de E / S, y las modificaciones inseguras tendrían muchas más probabilidades de causar un problema.
Entonces, probablemente haya una operación ARM 'compare and set' u operación similar que se puede usar aquí para hacer esto, ¿alguien puede señalarme eso y cómo hacer que eso suceda desde el código C?
[Tenga en cuenta que no se necesita nada especial cuando ha programado una E / S como salida y solo la cambia de 0 a 1 o viceversa; dado que hay un registro de E / S en el que escribe, para establecer los bits seleccionados en 1 y otro para borrar los bits seleccionados en 0. No se necesita lectura / escritura para esta operación, por lo que no hay peligro de interrupciones].
/dev/mem
parece que tu código es un código de espacio de usuario. No creo que en ningún sistema operativo moderno haya que tener cuidado con las interrupciones que cambian los valores de los registros en el código del espacio de usuario. Creo que esto no sería un problema incluso en el código de espacio del núcleo ya que Linux restaura todos los registros cuando el controlador de interrupciones finaliza su trabajo.