GPIO Programmierung: Unterschied zwischen den Versionen

Aus C und Assembler mit Raspberry
Die Seite wurde neu angelegt: „GPIO-Programmierung mit ARM64-Bit-Assembler In diesem Kapitel werden wir uns mit der GPIO-Programmierung (General Purpose Input/Output) auf dem Raspberry Pi beschäftigen. Dazu besprechen wir: Grundlagen der GPIO-Programmierung Direkte Steuerung der GPIO-Pins Besondere Register und Konfiguration Grundlagen der GPIO-Programmierung GPIO steht für "General Purpose Input/Output" und bezieht sich auf die universell einsetzbaren Pins auf dem Raspberry Pi, d…“
 
KKeine Bearbeitungszusammenfassung
 
(5 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
GPIO-Programmierung mit ARM64-Bit-Assembler
In diesem Kapitel werden wir uns mit der GPIO-Programmierung (General Purpose Input/Output) auf dem Raspberry Pi beschäftigen. Dazu besprechen wir:


In diesem Kapitel werden wir uns mit der GPIO-Programmierung (General Purpose Input/Output) auf dem Raspberry Pi beschäftigen. Dazu besprechen wir:
* Grundlagen der GPIO-Programmierung
* Direkte Steuerung der GPIO-Pins
* Besondere Register und Konfiguration
* Grundlagen der GPIO-Programmierung


Grundlagen der GPIO-Programmierung
== Grundlagen der GPIO-Programmierung ==
Direkte Steuerung der GPIO-Pins
Besondere Register und Konfiguration
Grundlagen der GPIO-Programmierung


GPIO steht für "General Purpose Input/Output" und bezieht sich auf die universell einsetzbaren Pins auf dem Raspberry Pi, die zur Kommunikation mit der Außenwelt verwendet werden können. Diese Pins können als Eingang oder Ausgang konfiguriert werden und sind nützlich für eine Vielzahl von Projekten, wie das Ansteuern von LEDs, das Lesen von Sensorwerten oder die Kommunikation mit anderen Geräten.
GPIO steht für "General Purpose Input/Output" und bezieht sich auf die universell einsetzbaren Pins auf dem Raspberry Pi, die zur Kommunikation mit der Außenwelt verwendet werden können. Diese Pins können als Eingang oder Ausgang konfiguriert werden und sind nützlich für eine Vielzahl von Projekten, wie das Ansteuern von LEDs, das Lesen von Sensorwerten oder die Kommunikation mit anderen Geräten.
Zeile 12: Zeile 12:
Einige häufige Anwendungen von GPIOs umfassen:
Einige häufige Anwendungen von GPIOs umfassen:


Steuern von Leuchtdioden (LEDs)
* Steuern von Leuchtdioden (LEDs)
Lesen von Tasterzuständen
* Lesen von Tasterzuständen
Ansteuern von Relais
* Ansteuern von Relais
Kommunikation mit anderen Mikrocontrollern oder Sensoren
* Kommunikation mit anderen Mikrocontrollern oder Sensoren
Direkte Steuerung der GPIO-Pins
== Direkte Steuerung der GPIO-Pins ==


Die direkte Steuerung der GPIO-Pins erfolgt durch Schreiben in bestimmte Register, die die Funktion und den Zustand der GPIOs festlegen. Auf dem Raspberry Pi gibt es spezielle Speicheradressen, die diesen Registern entsprechen. Diese Register beinhalten beispielsweise die GPIO Function Select Register (GPFSEL), die GPIO Set Register (GPSET) und die GPIO Clear Register (GPCLR).
Die direkte Steuerung der GPIO-Pins erfolgt durch Schreiben in bestimmte Register, die die Funktion und den Zustand der GPIOs festlegen. Auf dem Raspberry Pi gibt es spezielle Speicheradressen, die diesen Registern entsprechen. Diese Register beinhalten beispielsweise die GPIO Function Select Register (GPFSEL), die GPIO Set Register (GPSET) und die GPIO Clear Register (GPCLR).


Die Base-Adresse des GPIO-Registers für den Raspberry Pi 4/5 ist 0xFE000000, wobei die GPIO-Register bei einem Offset von 0x200000 beginnen, also 0xFE200000.
Die Base-Adresse des GPIO-Registers für den Raspberry Pi 4 ist 0xFE000000, wobei die GPIO-Register bei einem Offset von 0x200000 beginnen, also 0xFE200000.


Besondere Register und Konfiguration
Für andere Raspberry Pi Varianten gibt es unter [[Basisadressen der Modelle]] eine Übersicht der Base-Adresse. 
 
== Besondere Register und Konfiguration ==


Die wichtigen Register zur Steuerung der GPIOs umfassen:
Die wichtigen Register zur Steuerung der GPIOs umfassen:


GPFSEL (GPIO Function Select Register):
=== GPFSEL (GPIO Function Select Register) ===


Diese Register konfigurieren, ob ein GPIO-Pin als Eingang, Ausgang oder einer alternativen Funktion arbeitet.
Diese Register konfigurieren, ob ein GPIO-Pin als Eingang, Ausgang oder einer alternativen Funktion arbeitet.
Zeile 33: Zeile 35:
Beispiel:
Beispiel:


GPFSEL0: Steuerung der Pins 0-9
* GPFSEL0: Steuerung der Pins 0-9
GPFSEL1: Steuerung der Pins 10-19
* GPFSEL1: Steuerung der Pins 10-19
GPFSEL4: Steuerung der Pins 40-49 (z.B., GPIO 42)
* GPFSEL4: Steuerung der Pins 40-49 (z.B., GPIO 42)


GPSET (GPIO Set Register):
=== GPSET (GPIO Set Register) ===


Diese Register setzen bestimmte GPIO-Pins auf High.
Diese Register setzen bestimmte GPIO-Pins auf High.
GPSET0 setzt die Pins 0-31, GPSET1 setzt die Pins 32-57.
GPSET0 setzt die Pins 0-31, GPSET1 setzt die Pins 32-57.


GPCLR (GPIO Clear Register):
=== GPCLR (GPIO Clear Register) ===


Diese Register setzen bestimmte GPIO-Pins auf Low.
Diese Register setzen bestimmte GPIO-Pins auf Low.
GPCLR0 setzt die Pins 0-31, GPCLR1 setzt die Pins 32-57.
GPCLR0 setzt die Pins 0-31, GPCLR1 setzt die Pins 32-57.


Hinweis: Die Base-Adresse der GPIO-Register lautet 0xFE200000:
Hinweis: Wenn die Base-Adresse der GPIO-Register lautet 0xFE200000:
* GPFSEL0 bei 0xFE200004, GPSET1 bei 0xFE200020, GPCLR1 bei 0xFE20002C.


GPFSEL0 bei 0xFE200004, GPSET1 bei 0xFE200020, GPCLR1 bei 0xFE20002C.
== Beispiel: Interne LED steuern ==
Beispiel: Interne LED steuern


Um die interne LED des Raspberry Pi über einen GPIO-Pin zu steuern (typischerweise GPIO 42), können wir die folgenden Schritte ausführen:
Um die interne LED des Raspberry Pi über einen GPIO-Pin zu steuern (typischerweise GPIO 42 bei Raspberry Pi 4), können wir die folgenden Schritte ausführen:


Konfigurieren des GPIO-Pins 42 als Ausgang
Konfigurieren des GPIO-Pins 42 als Ausgang
Zeile 59: Zeile 63:


Beispiel in Assembler:
Beispiel in Assembler:
 
<syntaxhighlight lang="asm">
.section .text
.section .text
.global _start
.global _start
Zeile 95: Zeile 99:
     // Loop indefinitely
     // Loop indefinitely
     b _start
     b _start
 
</syntaxhighlight>


Erklärung:
Erklärung:


Der GPIO-Pin 42 wird als Ausgang konfiguriert, indem das GPIO Function Select Register (GPFSEL4) entsprechend gesetzt wird.
* Der GPIO-Pin 42 wird als Ausgang konfiguriert, indem das GPIO Function Select Register (GPFSEL4) entsprechend gesetzt wird.
Der GPIO-Pin 42 wird auf High gesetzt (LED an), indem das GPIO Set Register (GPSET1) verwendet wird.
* Der GPIO-Pin 42 wird auf High gesetzt (LED an), indem das GPIO Set Register (GPSET1) verwendet wird.
Eine einfache Wartezeit für eine Verzögerung wurde implementiert.
* Eine einfache Wartezeit für eine Verzögerung wurde implementiert.
Der GPIO-Pin 42 wird wieder auf Low gesetzt (LED aus), indem das GPIO Clear Register (GPCLR1) verwendet wird.
* Der GPIO-Pin 42 wird wieder auf Low gesetzt (LED aus), indem das GPIO Clear Register (GPCLR1) verwendet wird.
Eine weitere Wartezeit für eine Verzögerung wurde hinzugefügt.
* Eine weitere Wartezeit für eine Verzögerung wurde hinzugefügt.
Das Programm springt schließlich zurück zum Anfang und wiederholt den Prozess.
* Das Programm springt schließlich zurück zum Anfang und wiederholt den Prozess.
Verweis auf Dokumentation
== Verweis auf Dokumentation ==


Für eine umfassende Liste von GPIO-Registers und deren Funktionen, konsultieren Sie die offizielle Dokumentation des Raspberry Pi oder andere technische Referenzen.
Für eine umfassende Liste von GPIO-Registers und deren Funktionen, konsultieren Sie die offizielle Dokumentation des Raspberry Pi oder andere technische Referenzen.
<!--
== GPIO über Syscalls ansteuern ==
Die Pins werden wie Dateien behandelt. Der Dateipfad ist: /sys/class/gpio
Es wird einfach ein String, der den PIN angibt nach /sys/class/gpio/export geschrieben.
Der Treiber erstellt dann vier Dateien:
* /sys/class/gpio/gpio17/direction: Wird verwendet, um anzugeben, ob der Pin für Eingabe oder Ausgabe ist
* /sys/class/gpio/gpio17/value: Wird verwendet, um den Wert des Pins festzulegen oder zu lesen
* /sys/class/gpio/gpio17/edge: Wird verwendet, um einen Interrupt festzulegen, um Wertänderungen zu erkennen
* /sys/class/gpio/gpio17/active_low: Wird verwendet, um die Bedeutung von 0 und 1 umzukehren
!!!GPIO17 ändern!!!!!!!!!!!!! und testen
Nach dem Beenden wird das Gerät mit dem File "/sys/class/gpio/unexport" und dem String des PINs geschlossen.
.text
nanosleep:
  ldr x0,=timespec
  ldr x1,=timespec
  mov x8,#162 //#define __NR_nanosleep 162
  svc 0
.data
  timespec:
  timespec_tv_sec:  .dword 0
  timespec_tv_nsec: .dword 100000000
*PIN Öffnen:
.text
  mov x0,#-100
  ldr x1,=gpioexp
  mov x2,#1 //#define O_WRONLY 00000001
  mov x3,#666  //Dateirechte (Jeder darf alles...)
  mov x8,#323 //#define __NR_openat 323
  svc 0 
  mov x10,x0  //File Descriptor
  ldr x1,=pin
  mov x2,#2
  mov x8,#4 //#define __NR_write   4
  svc 0
  mov x0,x10
  mov x8,#118 //#define __NR_fsync 118
  svc 0
  mov x0,x10
  mov x8,#6 //#define __NR_close   6
  svc 0
.data
gpioexp: .asciz "/sys/class/gpio/export"
pin: .asciz "17" //Ändern!!!!!!!!!!!!!
GPIODirectionOut pin17:
Muss ich probieren! Seite 180 im Buch
Doku: https://www.satyria.de/arm/sources/doku/RaspberryPiAssemblyLanguageProgramming.pdf
fileio.s:
@ Various macros to perform file I/O
@ The fd parameter needs to be a register.
@ Uses R0, R1, R7.
@ Return code is in R0.
.include "unistd.s"
.equ O_RDONLY, 0
.equ O_WRONLY, 1
.equ O_CREAT, 0100
.equ S_RDWR, 0666
.macro openFile fileName, flags
ldr r0, =\fileName
mov r1, #\flags
mov r2, #S_RDWR @ RW access rights
mov r7, #sys_open
svc 0
.endm
.macro readFile fd, buffer, length
mov r0, \fd @ file descriptor
ldr r1, =\buffer
mov r2, #\length
mov r7, #sys_read
svc 0
.endm
.macro writeFile fd, buffer, length
mov r0, \fd @ file descriptor
ldr r1, =\buffer
mov r2, \length
mov r7, #sys_write
svc 0
.endm
.macro flushClose fd
@fsync syscall
mov r0, \fd
mov r7, #sys_fsync
svc 0
@close syscall
mov r0, \fd
mov r7, #sys_close
svc 0
.endm
@ Various macros to access the GPIO pins
@ on the Raspberry Pi.
@
@ R8 - file descriptor.
@
.include "fileio.s"
@ Macro nanoSleep to sleep .1 second
@ Calls Linux nanosleep service which is funct 162.
@ Pass a reference to a timespec in both r0 and r1
@ First is input time to sleep in secs and nanosecs.
@ Second is time left to sleep if interrupted
.macro nanoSleep
ldr r0, =timespecsec
ldr r1, =timespecsec
mov r7, #sys_nanosleep
svc 0
.endm
.macro GPIOExport pin
openFile gpioexp, O_WRONLY
mov r8, r0 @ save the file desc
writeFile r8, \pin, #2
flushClose r8
.endm
.macro GPIODirectionOut pin
@ copy pin into filename pattern
ldr r1, =\pin
ldr r2, =gpiopinfile
add r2, #20
ldrb r3, [r1], #1 @ load pin and post incr
strb r3, [r2], #1 @ store to filename and post incr
ldrb r3, [r1]
strb r3, [r2]
openFile gpiopinfile, O_WRONLY
mov r8, r0 @ save the file descriptor
writeFile r8, outstr, #3
flushClose r8
.endm
.macro GPIOWrite pin, value
@ copy pin into filename pattern
ldr r1, =\pin
ldr r2, =gpiovaluefile
add r2, #20
ldrb r3, [r1], #1 @ load pin and post increment
strb r3, [r2], #1 @ store to filename and
post increment
ldrb r3, [r1]
strb r3, [r2]
openFile gpiovaluefile, O_WRONLY
mov r8, r0 @ save the file descriptor
writeFile r8, \value, #1
flushClose r8
.endm
.data
timespecsec: .word 0
timespecnano: .word 100000000
gpioexp: .asciz "/sys/class/gpio/export"
gpiopinfile: .asciz "/sys/class/gpio/gpioxx/direction"
gpiovaluefile: .asciz "/sys/class/gpio/gpioxx/value"
outstr: .asciz "out"
.align 2 @ save users of this file having
to do this.


Mit diesen Grundlagen und Beispielen sollten Anfänger in der Lage sein, GPIO-Pins auf dem Raspberry Pi zu steuern und für verschiedene Projekte zu nutzen.
Listing 8-2. Main program to flash the LEDs
@
@ Assembler program to flash three LEDs connected to
@ the Raspberry Pi GPIO port.
@
@ r6 - loop variable to flash lights 10 times
@
.include "gpiomacros.s"
.global _start @ Provide program starting
address to linker
_start: GPIOExport pin17
GPIOExport pin27
GPIOExport pin22
nanoSleep
GPIODirectionOut pin17
GPIODirectionOut pin27
GPIODirectionOut pin22
@ set up a loop counter for 10 iterations
mov r6, #10
loop: GPIOWrite pin17, high
nanoSleep
GPIOWrite pin17, low
GPIOWrite pin27, high
nanoSleep
GPIOWrite pin27, low
GPIOWrite pin22, high
nanoSleep
GPIOWrite pin22, low
@decrement loop counter and see if we loop
@ Subtract 1 from loop register
@ setting status register.
subs r6, #1
@ If we haven't counted down to 0 then loop
bne loop
_end: mov R0, #0 @ Use 0 return code
mov R7, #1 @ Command code 1 terminates
svc 0 @ Linux command to terminate
pin17: .asciz "17"
pin27: .asciz "27"
pin22: .asciz "22"
low: .asciz "0"
high: .asciz "1"
-->

Aktuelle Version vom 9. April 2025, 19:44 Uhr

In diesem Kapitel werden wir uns mit der GPIO-Programmierung (General Purpose Input/Output) auf dem Raspberry Pi beschäftigen. Dazu besprechen wir:

  • Grundlagen der GPIO-Programmierung
  • Direkte Steuerung der GPIO-Pins
  • Besondere Register und Konfiguration
  • Grundlagen der GPIO-Programmierung

Grundlagen der GPIO-Programmierung

GPIO steht für "General Purpose Input/Output" und bezieht sich auf die universell einsetzbaren Pins auf dem Raspberry Pi, die zur Kommunikation mit der Außenwelt verwendet werden können. Diese Pins können als Eingang oder Ausgang konfiguriert werden und sind nützlich für eine Vielzahl von Projekten, wie das Ansteuern von LEDs, das Lesen von Sensorwerten oder die Kommunikation mit anderen Geräten.

Einige häufige Anwendungen von GPIOs umfassen:

  • Steuern von Leuchtdioden (LEDs)
  • Lesen von Tasterzuständen
  • Ansteuern von Relais
  • Kommunikation mit anderen Mikrocontrollern oder Sensoren

Direkte Steuerung der GPIO-Pins

Die direkte Steuerung der GPIO-Pins erfolgt durch Schreiben in bestimmte Register, die die Funktion und den Zustand der GPIOs festlegen. Auf dem Raspberry Pi gibt es spezielle Speicheradressen, die diesen Registern entsprechen. Diese Register beinhalten beispielsweise die GPIO Function Select Register (GPFSEL), die GPIO Set Register (GPSET) und die GPIO Clear Register (GPCLR).

Die Base-Adresse des GPIO-Registers für den Raspberry Pi 4 ist 0xFE000000, wobei die GPIO-Register bei einem Offset von 0x200000 beginnen, also 0xFE200000.

Für andere Raspberry Pi Varianten gibt es unter Basisadressen der Modelle eine Übersicht der Base-Adresse.

Besondere Register und Konfiguration

Die wichtigen Register zur Steuerung der GPIOs umfassen:

GPFSEL (GPIO Function Select Register)

Diese Register konfigurieren, ob ein GPIO-Pin als Eingang, Ausgang oder einer alternativen Funktion arbeitet. Für jeden GPIO-Pin sind 3 Bits vorhanden (000 für Eingang, 001 für Ausgang, andere Werte für Alternativfunktionen).

Beispiel:

  • GPFSEL0: Steuerung der Pins 0-9
  • GPFSEL1: Steuerung der Pins 10-19
  • GPFSEL4: Steuerung der Pins 40-49 (z.B., GPIO 42)

GPSET (GPIO Set Register)

Diese Register setzen bestimmte GPIO-Pins auf High.

GPSET0 setzt die Pins 0-31, GPSET1 setzt die Pins 32-57.

GPCLR (GPIO Clear Register)

Diese Register setzen bestimmte GPIO-Pins auf Low.

GPCLR0 setzt die Pins 0-31, GPCLR1 setzt die Pins 32-57.

Hinweis: Wenn die Base-Adresse der GPIO-Register lautet 0xFE200000:

  • GPFSEL0 bei 0xFE200004, GPSET1 bei 0xFE200020, GPCLR1 bei 0xFE20002C.

Beispiel: Interne LED steuern

Um die interne LED des Raspberry Pi über einen GPIO-Pin zu steuern (typischerweise GPIO 42 bei Raspberry Pi 4), können wir die folgenden Schritte ausführen:

Konfigurieren des GPIO-Pins 42 als Ausgang Umschalten des GPIO-Pins 42 auf High (LED an) Umschalten des GPIO-Pins 42 auf Low (LED aus)

Beispiel in Assembler:

.section .text
.global _start

_start:
    // Set GPIO42 as output
    ldr x0, =0xFE200010    // GPFSEL4 (GPIO Function Select Register 4)
    ldr x1, [x0]           // Lade den aktuellen Wert von GPFSEL4
    bic x1, x1, #(0x7 << 6) // Lösche die Bits 6-8 (funktion für GPIO42 wählen)
    orr x1, x1, #(0x1 << 6) // Setze GPIO42 als Ausgang (001 << 6)
    str x1, [x0]           // Schreibe den neuen Wert zurück in GPFSEL4

    // Turn GPIO42 on (LED an)
    ldr x0, =0xFE200020    // GPSET1 (GPIO Set Register 1)
    mov x1, #(1 << 10)     // Setze Bit 10 (GPIO42)
    str x1, [x0]

    // Warte (einfache Schleife für Verzögerung)
    mov x2, #1000000
wait:
    subs x2, x2, #1
    bne wait

    // Turn GPIO42 off (LED aus)
    ldr x0, =0xFE20002C    // GPCLR1 (GPIO Clear Register 1)
    mov x1, #(1 << 10)     // Lösche Bit 10 (GPIO42)
    str x1, [x0]

    // Warte (einfache Schleife für Verzögerung)
    mov x2, #1000000
wait2:
    subs x2, x2, #1
    bne wait2
    
    // Loop indefinitely
    b _start

Erklärung:

  • Der GPIO-Pin 42 wird als Ausgang konfiguriert, indem das GPIO Function Select Register (GPFSEL4) entsprechend gesetzt wird.
  • Der GPIO-Pin 42 wird auf High gesetzt (LED an), indem das GPIO Set Register (GPSET1) verwendet wird.
  • Eine einfache Wartezeit für eine Verzögerung wurde implementiert.
  • Der GPIO-Pin 42 wird wieder auf Low gesetzt (LED aus), indem das GPIO Clear Register (GPCLR1) verwendet wird.
  • Eine weitere Wartezeit für eine Verzögerung wurde hinzugefügt.
  • Das Programm springt schließlich zurück zum Anfang und wiederholt den Prozess.

Verweis auf Dokumentation

Für eine umfassende Liste von GPIO-Registers und deren Funktionen, konsultieren Sie die offizielle Dokumentation des Raspberry Pi oder andere technische Referenzen.