Grafik (PI5): Unterschied zwischen den Versionen
Die Seite wurde neu angelegt: „Die Grafik“ |
Keine Bearbeitungszusammenfassung |
||
| Zeile 1: | Zeile 1: | ||
Die Grafik | Vorab: Auf dem Raspberry Pi 5 hat sich in Sachen Grafik einiges geändert, was es für BareMetal-Entwickler schwieriger macht, die Grafik richtig zu programmieren. Dazu gab es bereits eine Diskussion auf GitHub: [https://github.com/raspberrypi/firmware/issues/1904 Raspberry Pi Firmware Issue #1904]. | ||
Diese Entwicklung oder Entscheidung gefällt mir nicht! | |||
Dennoch habe ich es geschafft, eine Anzeige auf dem Raspberry Pi 5 zu implementieren, die funktional ist. Im Gegensatz zu den Vorgängermodellen wird der Bildschirm in der config.txt Datei festgelegt und ist bereits vorhanden, wenn der erste Bootvorgang durchgeführt wird. | |||
Wir verwenden den Eintrag "framebuffer_depth=32" in der "config.txt" Datei. Dieser Eintrag erzeugt einen Framebuffer mit einer Tiefe von 32-Bit und einer Auflösung von 1920x1080 Pixeln. | |||
Im Raspberry Pi sind mehrere Prozessoren für verschiedene Aufgaben zuständig. So gibt es auch einen Prozessor (GPU), der die Grafik verwaltet. Interessant ist hierbei, dass genau dieser Prozessor auch für den ersten Start des Raspberry Pi zuständig ist. Nach der ersten Initialisierung übergibt er die Kontrolle an den ARM-Prozessor. | |||
Da jeder Prozessor für sich arbeitet, müssen wir einen Weg finden, damit diese Prozessoren miteinander kommunizieren können. Dazu wurde eine Art Postfach eingerichtet, in das wir per "Brief" mitteilen, was wir vom Grafikprozessor möchten. Bei einer Antwort verwendet der Grafikprozessor genau dieses Postfach wieder. Natürlich, wie in der Informatik üblich, ist der Aufbau des "Briefes" definiert. An diese Richtlinien müssen wir uns halten. | |||
=== Aufbau einer Mailbox-Nachricht === | |||
Eine TAG-Struktur beginnt immer mit einer 32-Bit Zahl, die die Länge der gesamten Struktur angibt. Danach folgt ein 32-Bit Puffer, um eventuell eine Antwort abzulegen, die bei einem Aufruf übermittelt wird. Anschließend kommen die einzelnen TAGs. Jeder TAG hat wieder eine Grundstruktur: zuerst wird der Name des TAGs übermittelt, gefolgt von der Anzahl der Werte in Bytes (32 Bit, entsprechend 4) und wieder ein Puffer für die Antwort. Danach folgen die Werte für den jeweiligen TAG. Die gesamte Struktur endet mit einem NULL-TAG. | |||
* Mailbox Länge | |||
* Mailbox AnfrageCode | |||
** TAG1 Name | |||
** TAG1 Länge | |||
** TAG1 Puffer | |||
*** TAG1 Wert1 | |||
*** TAG1 Wert2 | |||
*** ... | |||
** TAG2 Name | |||
** ... | |||
** TAGx NULL (End TAG) | |||
Weitere Infos kannst du auf [https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface GitHub] nachlesen. Wichtig ist, dass jeder einzelne TAG auf 32-Bit ausgerichtet sein muss. | |||
Im Gegensatz zu den Vorgängermodellen ist es beim Raspberry Pi 5 einfacher, die Speicheradresse der Grafik zu erhalten. Leider ist es jedoch nicht mehr möglich, eine gewünschte Anzeige zu konfigurieren, wie zum Beispiel die Bildschirmauflösung. Wir müssen das nutzen, was möglich ist und die Adresse des Grafikspeichers mit PROPTAG_ALLOCATE_BUFFER anfordern. | |||
Unsere Struktur für den Mailbox-Aufruf sieht nun wie folgt aus: | |||
<syntaxhighlight lang="asm"> | |||
//********************************************************** | |||
// Data | |||
//********************************************************** | |||
.section .data | |||
.align 16 | |||
pScreen: | |||
.int pScreen_end - pScreen | |||
.int CODE_REQUEST | |||
.int PROPTAG_ALLOCATE_BUFFER | |||
.int 8 | |||
.int 4 | |||
m_nBufferPtr: | |||
.int 0 | |||
m_nBufferSize: | |||
.int 0 | |||
.int PROPTAG_END | |||
pScreen_end: | |||
</syntaxhighlight> | |||
Wir werden der MailBox-Funktion, die wir noch schreiben, die Adresse dieser Struktur in x1 übermitteln und in w0 werden wir den MailBox-Kanal schreiben. Für die Kommunikation (ARM to VC) wird der Kanal 8 verwendet, den wir zuvor mit BCM_MAILBOX_PROP_OUT definiert haben. | |||
<syntaxhighlight lang="asm"> | |||
// boolean Init_Screen (void) | |||
.globl Init_Screen | |||
Init_Screen: | |||
stp x29, x30, [sp, -16]! | |||
mov x29, sp | |||
1: | |||
ldr w0,=BCM_MAILBOX_PROP_OUT // Kanal | |||
ldr x1,=pScreen // ScreenStruktur | |||
bl BcmMailBox_Write // Rufe die Mailbox auf | |||
ldr x0,=m_nBufferPtr // Lade die Speicheradresse | |||
ldr w0,[x0] | |||
cmp w0,#0 | |||
beq 1b | |||
and w0,w0,#0x3FFFFFFF // Passe die Adresse an | |||
ldr x1,=graphicsAddress // Und sichere sie | |||
str w0,[x1] | |||
ldp x29, x30, [sp], 16 | |||
ret | |||
</syntaxhighlight> | |||
In unserer Tag-Liste erhalten wir unter PROPTAG_ALLOCATE_BUFFER eine Rückantwort des Grafikchips, an welcher Adresse der Grafikspeicher liegt. Diese Position im Tag haben wir dem Label m_nBufferPtr gegeben, sodass wir direkt darauf zugreifen können. | |||
Wenn die Speicheradresse weiterhin einen Null-Wert hat, wissen wir, dass die Kommunikation entweder noch nicht erfolgt ist oder es einen Fehler gab. Wir rufen die Mailbox so lange auf, bis wir eine Antwort haben. | |||
Die Adresse, die wir zurückbekommen, ist die Adresse, wie sie der Grafikchip sieht. Da wir jedoch auf dem ARM-Prozessor arbeiten, müssen wir die Adresse an unseren Adressraum anpassen. Dies geschieht mit and w0,w0,#0x3FFFFFFF. Danach legen wir diese Adresse unter graphicsAddress ab, damit sie nicht verloren geht. | |||
Version vom 5. Juli 2024, 11:37 Uhr
Vorab: Auf dem Raspberry Pi 5 hat sich in Sachen Grafik einiges geändert, was es für BareMetal-Entwickler schwieriger macht, die Grafik richtig zu programmieren. Dazu gab es bereits eine Diskussion auf GitHub: Raspberry Pi Firmware Issue #1904.
Diese Entwicklung oder Entscheidung gefällt mir nicht!
Dennoch habe ich es geschafft, eine Anzeige auf dem Raspberry Pi 5 zu implementieren, die funktional ist. Im Gegensatz zu den Vorgängermodellen wird der Bildschirm in der config.txt Datei festgelegt und ist bereits vorhanden, wenn der erste Bootvorgang durchgeführt wird.
Wir verwenden den Eintrag "framebuffer_depth=32" in der "config.txt" Datei. Dieser Eintrag erzeugt einen Framebuffer mit einer Tiefe von 32-Bit und einer Auflösung von 1920x1080 Pixeln.
Im Raspberry Pi sind mehrere Prozessoren für verschiedene Aufgaben zuständig. So gibt es auch einen Prozessor (GPU), der die Grafik verwaltet. Interessant ist hierbei, dass genau dieser Prozessor auch für den ersten Start des Raspberry Pi zuständig ist. Nach der ersten Initialisierung übergibt er die Kontrolle an den ARM-Prozessor.
Da jeder Prozessor für sich arbeitet, müssen wir einen Weg finden, damit diese Prozessoren miteinander kommunizieren können. Dazu wurde eine Art Postfach eingerichtet, in das wir per "Brief" mitteilen, was wir vom Grafikprozessor möchten. Bei einer Antwort verwendet der Grafikprozessor genau dieses Postfach wieder. Natürlich, wie in der Informatik üblich, ist der Aufbau des "Briefes" definiert. An diese Richtlinien müssen wir uns halten.
Aufbau einer Mailbox-Nachricht
Eine TAG-Struktur beginnt immer mit einer 32-Bit Zahl, die die Länge der gesamten Struktur angibt. Danach folgt ein 32-Bit Puffer, um eventuell eine Antwort abzulegen, die bei einem Aufruf übermittelt wird. Anschließend kommen die einzelnen TAGs. Jeder TAG hat wieder eine Grundstruktur: zuerst wird der Name des TAGs übermittelt, gefolgt von der Anzahl der Werte in Bytes (32 Bit, entsprechend 4) und wieder ein Puffer für die Antwort. Danach folgen die Werte für den jeweiligen TAG. Die gesamte Struktur endet mit einem NULL-TAG.
- Mailbox Länge
- Mailbox AnfrageCode
- TAG1 Name
- TAG1 Länge
- TAG1 Puffer
- TAG1 Wert1
- TAG1 Wert2
- ...
- TAG2 Name
- ...
- TAGx NULL (End TAG)
Weitere Infos kannst du auf GitHub nachlesen. Wichtig ist, dass jeder einzelne TAG auf 32-Bit ausgerichtet sein muss.
Im Gegensatz zu den Vorgängermodellen ist es beim Raspberry Pi 5 einfacher, die Speicheradresse der Grafik zu erhalten. Leider ist es jedoch nicht mehr möglich, eine gewünschte Anzeige zu konfigurieren, wie zum Beispiel die Bildschirmauflösung. Wir müssen das nutzen, was möglich ist und die Adresse des Grafikspeichers mit PROPTAG_ALLOCATE_BUFFER anfordern.
Unsere Struktur für den Mailbox-Aufruf sieht nun wie folgt aus:
//**********************************************************
// Data
//**********************************************************
.section .data
.align 16
pScreen:
.int pScreen_end - pScreen
.int CODE_REQUEST
.int PROPTAG_ALLOCATE_BUFFER
.int 8
.int 4
m_nBufferPtr:
.int 0
m_nBufferSize:
.int 0
.int PROPTAG_END
pScreen_end:
Wir werden der MailBox-Funktion, die wir noch schreiben, die Adresse dieser Struktur in x1 übermitteln und in w0 werden wir den MailBox-Kanal schreiben. Für die Kommunikation (ARM to VC) wird der Kanal 8 verwendet, den wir zuvor mit BCM_MAILBOX_PROP_OUT definiert haben.
// boolean Init_Screen (void)
.globl Init_Screen
Init_Screen:
stp x29, x30, [sp, -16]!
mov x29, sp
1:
ldr w0,=BCM_MAILBOX_PROP_OUT // Kanal
ldr x1,=pScreen // ScreenStruktur
bl BcmMailBox_Write // Rufe die Mailbox auf
ldr x0,=m_nBufferPtr // Lade die Speicheradresse
ldr w0,[x0]
cmp w0,#0
beq 1b
and w0,w0,#0x3FFFFFFF // Passe die Adresse an
ldr x1,=graphicsAddress // Und sichere sie
str w0,[x1]
ldp x29, x30, [sp], 16
ret
In unserer Tag-Liste erhalten wir unter PROPTAG_ALLOCATE_BUFFER eine Rückantwort des Grafikchips, an welcher Adresse der Grafikspeicher liegt. Diese Position im Tag haben wir dem Label m_nBufferPtr gegeben, sodass wir direkt darauf zugreifen können.
Wenn die Speicheradresse weiterhin einen Null-Wert hat, wissen wir, dass die Kommunikation entweder noch nicht erfolgt ist oder es einen Fehler gab. Wir rufen die Mailbox so lange auf, bis wir eine Antwort haben.
Die Adresse, die wir zurückbekommen, ist die Adresse, wie sie der Grafikchip sieht. Da wir jedoch auf dem ARM-Prozessor arbeiten, müssen wir die Adresse an unseren Adressraum anpassen. Dies geschieht mit and w0,w0,#0x3FFFFFFF. Danach legen wir diese Adresse unter graphicsAddress ab, damit sie nicht verloren geht.