System Timer: Unterschied zwischen den Versionen

Aus C und Assembler mit Raspberry
Die Seite wurde neu angelegt: „System Timer“
 
 
(Eine dazwischenliegende Version desselben Benutzers wird nicht angezeigt)
Zeile 1: Zeile 1:
System Timer
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: [https://www.satyria.de/arm/source/kurs/3.1.zip 3.1.zip]
 
<syntaxhighlight lang="asm">
@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
</syntaxhighlight>
 
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.
 
<syntaxhighlight lang="asm">
/* 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}
</syntaxhighlight>
 
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.
 
<syntaxhighlight lang="asm">
/* 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
</syntaxhighlight>
 
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.
 
-----
 
{| style="width: 100%;
| 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: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) >