System Timer: Unterschied zwischen den Versionen

Aus C und Assembler mit Raspberry
KKeine Bearbeitungszusammenfassung
 
Zeile 73: Zeile 73:


{| style="width: 100%;
{| style="width: 100%;
| style="width: 33%;" | [[General Purpose I/O (GPIO) (2)|< Zurück (General Purpose I/O (GPIO) (2))]]
| style="width: 33%;" | [[General Purpose I/O|< Zurück (General Purpose I/O (GPIO) (2))]]
| style="width: 33%; text-align:center;" | [[Hauptseite|< Hauptseite >]]
| style="width: 33%; text-align:center;" | [[Hauptseite|< Hauptseite >]]
| style="width: 33%; text-align:right;" | [[UART|Weiter (UART) >]]
| style="width: 33%; text-align:right;" | [[UART|Weiter (UART) >]]
|}
|}

Aktuelle Version vom 22. August 2024, 12:00 Uhr

Der Raspberry Pi besitzt einen Timer, den er selbstständig taktet. Damit können Zeitgesteuerte Funktionen erstellt werden. In der originalen Dokumentation wird dies im Kapitel 10 auf Seite 175 beschrieben.

Neue Wait-Funktion

Wie ich bereits im vorherigen Kapitel erzählt habe, werden wir unsere "wait"-Funktion etwas besser machen. Eine Schleife, die keine Kontrolle der Zeit verfügt, macht keinen Sinn. Dazu löschen wir den jetzigen Inhalt unserer "time.h" Datei und schreiben einen neuen Code. Zunächst erweitern wir aber unsere "base.inc" Datei, um die Werte, die der Timer benötigt. Den Sourcecode gibt es wieder hier: 3.1.zip

@Timer registers
.equ TIMER_BASE, RPI_BASE + 0x003000
.equ TIMER_CS, TIMER_BASE + 0x00 @clock status
.equ TIMER_CLO, TIMER_BASE + 0x04 @ clock low 32 bytes
.equ TIMER_CHI, TIMER_BASE + 0x08 @ clock high 32 bytes

.equ MICROS_PER_SECOND, 1000000 @ Microseconds per second
.equ MICROS_PER_MILLISECOND, 1000 @ Microseconds per millisecond

.equ T1_CLOCK_SECOND, MICROS_PER_SECOND @ RPi is microseconds

Laut Dokumentation liegen die Register ab der Position 0x3000 vor und die weiteren Register folgend. Für unseren Code werden wir aber nur "TIMER_CLO" verwenden. Dies ist das untere Zeitregister, was für unsere Zwecke ausreichend ist.

In der time.h Datei erzeugen wir erstmal eine Funktionen “GetTimeStamp”. Diese wird die aktuelle Zeit herauslesen.

/* int r0 GetTimeStamp (void)
*/
GetTimeStamp:
   push {lr}

   ldr r0,=TIMER_CLO    @Address of the lower system timer counter
   ldr r0,[r0]          @Get the current value

   pop {pc}

Diese Funktion erwartet keinen Wert und gibt die aktuelle Zeit in r0 zurück. Vom Grunde funktioniert es wie zuvor, wenn wir aus einem Register Daten lesen. Zunächst wird die Adresse von "TIMER_CLO" nach r0 geladen und anschließend der Inhalt nach r0 kopiert.

Nachdem wir dies haben, erstellen wir unsere wait-Funktion.

/* void wait (int r0)
   the milliseconds are specified in r0
*/

wait:
   push {lr}
   
   mov r2,r0            @copy r0 to r2

   bl GetTimeStamp      @transfer time to r0
   mov r3,r0            @and copy to r3

   wait_loop$:
      bl GetTimeStamp   @transfer time to r0
      sub r1,r0,r3      @Subtract the stored value from r0 and write it into r1
      cmp r1,r2         @Compare the difference with the handover
      bls wait_loop$    @If less than or equal, then wait

   pop {pc}             @Wait end

Diese Funktion erwartet nun in r0 die Zeit, die in Millisekunden vergehen soll, bis er wieder zurückkehrt. Sie wird keinen Wert zurückgeben.

Zunächst sichern wir die Übergabe in r2. Anschließend holen wir den aktuellen Zeitstempel und sichern ihn in r3. In der Warteschleife wird wieder die aktuelle Zeit geholz, Subtrahier den alten Wert und vergleicht ihn mit dem Rückgabewert. Solange der unterschied kleiner ist, wird diese Schleife wiederholt.

Das war es schon.


< Zurück (General Purpose I/O (GPIO) (2)) < Hauptseite > Weiter (UART) >