Hallo, ich flansche derzeit ein ILI9341 (SPI) an einen kleinen uC an und schreibe die dazu nötigen Routinen selbst, allerdings nach Vorlage aus einer Lib, zb die Inits des Displays und die Kommandos zur Darstellung. Damit will ich mich nicht befassen, das Rad gibt es ja schon. Nun zum mir bisher noch geheimnisvollen DMA Zugriff: Was würde mir der bringen, bezogen auf das Display und wie müsste ich ihn realisieren? Die Display Befehle sind unterschiedlich lang, es wird nur geschrieben, nie gelesen. Derzeit muss die CPU so lange warten, bis die SPI eben fertig ist. Müsste eigentlich nicht sein. Wie schreibe ich das nun um? Eine typische Display Sequenz für den Aufbau eines Graphen sind hunderte Display Kommndos und Bytes, die ich genausogut in einen Puffer schreiben könnte. Also die jetzige SPI Routine schreibt nicht in die SPi sondern in einen Puffer. Und wenn das Bild fertig ist müsste nur ein "Trigger" dafür sorgen, dass der DMA los rattert und alle Bytes ins Display schiebt. Natürlich mit den richtigen CE Takten. Soweit theoretisch, da gibt es aber noch den Chip Select und einen weiteren Steuerpin. Und den kennt DMA ja nicht. Wie würde es denn richtig gemacht?
Hallo, ist zwar für den F4, aber das Prinzip ist das Gleiche. Die Initialisierung wie bisher und zum übertragen der Pixeldaten schaltest Du in den window/page Modus. Dann gibt es keine störenden Steuersignale mehr und dem DMA steht nichts im Wege. http://www.requiem-projects.com/en/ili9341-lcd-driver-stm32f4-dma/
hp-freund schrieb: > ist zwar für den F4, aber das Prinzip ist das Gleiche. Für den f4 habe ich das alles schon aber der 100 ist schon etwas anders, ich musste viel umstricken da die Lib andere Namen hat, die Peripherie an anderen Bussen hängt usw. Allerdings werde ich mir diesen Code wohl schnappen und Stück für Stück umarbeiten, daran wird wohl kein Weg dran vorbei führen.
Eigentlich meinte ich mit dem Prinzip nur den window/page Modus mit DMA. Den einschalten und Datenblock marsch :)
Für exakt solche Fälle schreib ich immer eine Queue, in der die Befehle nach FIFO abgearbeitet werden. Eine "addTask" Funktion, in der neue Befehle reingeladen werden und an deren Ende geprüft wird ob der DMA bereits läuft. Läuft er nicht -> aufdrehen. Läuft er bereits -> nix tun, den neuen Task haben wir eh schon hinzugefügt. Innerhalb des DMA Interrupts wird dann geprüft, ob noch Befehle in der Queue liegen und der DMA gegebenenfalls neu initialisiert. Die Befehle selbst liegen in einer simplen Struktur, etwa so
1 | struct |
2 | {
|
3 | struct |
4 | { uint8_t buf[SIZE_DISPLAY_BUF];
|
5 | uint8_t nbyte; |
6 | //uint8_t* src; |
7 | } buf_t[NUMBER_OF_TASKS]; |
8 | uint8_t qwrite; |
9 | uint8_t qread; |
10 | } disp_t; |
qwrite und qread sind die aktuellen Indizes für "Task hinzufügen" und "Task bearbeitet". Mit einer modulo Funktion kann man die schön überrollen lassen, ohne sich irgendwelche Gedanken über deren Größe machen zu müssen. Wenn man garantieren kann dass die Wunschdaten auch nach hinzufügen eines Tasks noch erhalten bleiben, kann man theoretisch auch einen Pointer in die Queue schmeißen, statt dem Buffer... aber keine Ahnung wie viel RAM du hast? Wer sauber programmiert darf den nötigen Platz wohl auch allokieren.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.