Ich codiere etwas mithilfe der direkten Steuerung von GPIO. Dafür gibt es einige gute Ressourcen, z. B. http://elinux.org/RPi_Low-level_peripherals#GPIO_hardware_hacking . Der Prozess beinhaltet open ("/ dev / mem") und dann ordnet eine mmap-Operation die gewünschte physische Adresse effektiv Ihrem virtuellen Adressraum zu. Dann lesen Sie Abschnitt 6 dieser http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf , um herauszufinden, wie die E / A gesteuert werden.
Um zur Funktion eines Pins (Eingabe oder Ausgabe oder verschiedene Sonderfunktionen) zu wechseln, ändern Sie diese 3-Bit-Felder in den GPFSELx-E / A-Registern (000 = Eingabe, 001 = Ausgabe der Feindinstanz). Diese Änderungsoperationen werden zu Operationen mit normalem Laden und Speichern kompiliert (z. B. um GPIO0 in Eingabe zu ändern: * (regptr) & = ~ 7;, was zu so etwas kompiliert wird
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)
Das Problem ist folgendes: Wenn ein Interrupt zwischen Laden und Speichern auftritt und ein anderer Prozess oder ISR dasselbe E / A-Register ändert, werden durch die Speicheroperation (basierend auf einem veralteten Einlesen in r2) die Auswirkungen dieser anderen Operation zurückgesetzt. Das Ändern dieser E / A-Register muss also wirklich mit einer atomaren (gesperrten) Lese- / Änderungs- / Schreiboperation erfolgen. Die Beispiele, die ich gesehen habe, verwenden keine gesperrte Operation.
Da diese E / A-Register im Allgemeinen nur beim Einrichten geändert werden, ist es unwahrscheinlich, dass Probleme auftreten, aber "nie" ist immer besser als "unwahrscheinlich". Wenn Sie eine Anwendung haben, in der Sie Bit-Bashing durchführen, um einen Open-Collector-Ausgang zu emulieren, müssen Sie (soweit ich das beurteilen kann) den Ausgang auf 0 programmieren und dann zwischen Ausgang (für niedrig) oder Eingang (für niedrig) umschalten. für aus / hoch). In diesem Fall würden diese E / A-Register häufig geändert, und unsichere Änderungen würden mit größerer Wahrscheinlichkeit ein Problem verursachen.
Es gibt also wahrscheinlich eine ARM-Operation zum Vergleichen und Setzen oder eine ähnliche Operation, die hier verwendet werden kann. Kann mich jemand darauf hinweisen und wie kann dies mit C-Code geschehen?
[Beachten Sie, dass nichts Besonderes erforderlich ist, wenn Sie eine E / A als Ausgabe programmiert haben und sie nur von 0 auf 1 oder umgekehrt ändern. Da es ein E / A-Register gibt, in das Sie schreiben, um ausgewählte Bits auf 1 und ein anderes, um ausgewählte Bits auf 0 zu setzen, ist für diesen Vorgang kein Lesen / Schreiben erforderlich, daher besteht keine Gefahr durch Interrupts.
/dev/mem
, scheint es, dass Ihr Code Userspace-Code ist. Ich denke nicht, dass man in einem modernen Betriebssystem vorsichtig sein muss, wenn Interrupts die Registerwerte im Userspace-Code ändern. Ich glaube, dass dies selbst im Kernel-Space-Code kein Problem wäre, da Linux alle Register wiederherstellt, wenn der Interrupt-Handler seinen Job beendet.