8 UART's mit asm_pio PIO DMA / Micropython auf dem PI PICO Worum geht es hier ? Der PI PICO verfügt von Haus aus über 2 integrierte UART-Schnittstellen, von denen eine meist für die Programmierung genutzt wird. Mit den PIO's kann man bis zu 8 zusätzliche UART-Schnittstellen (alternativ als Transmitter oder Receiver) an frei wählbaren Pins des PI PICO einrichten - zusätzlich zu den vorhandenen beiden Schnittstellen. Es folgen drei Versionen der Schnittstelle, die ersten beiden entstanden bereits im Zusammenhang mit meinen "Spielereien mit asm_pio + Micropython auf dem PI PICO". Hier ging es darum auszuprobieren, was man mit den PIO's anstellen kann. Die dritte und neue Version nutzt DMA für den Datentransfer mit den PIO's. Version 1 sendet bis zu 9 Byte nonblocking. Der Empfang wird per Interrupt abgewickelt: nach jedem empfangenen Byte wird eine ISR ausgeführt, die das empfangene Byte abholt. Die Software muss selbst erkennen, wann ein Datentransfer abgeschlossen ist. Eine weitere Variante erkennt das Übertragungsende (am Ausbleiben eines weiteren Startbits). Das Problem dieses Konzeptes ist, dass viele Interrupts ausgelöst werden. Micropython kann diese aber bei höheren Baud-Raten nicht mehr schnell genug bedienen, so dass irgendwann Datenverluste drohen und auch das laufende Programm ausgebremst wird. Für moderate Baud-Raten und wenig zeitkritische Anwendungen funktoniert das aber zufrieden stellend. Ansatz der 2. Version war, die 32-Bit-Fifos der Statemachines als Puffer zum Senden und Empfangen besser zu nutzen und damit die Anzahl der erforderlich Interrupts zu reduzieren. Die Beschränkung liegt hier im 32-Byte-Limit. Der asm_pio-Code des Receivers belegt das gesamt Insturktion-Memory. Und die Nachbereitung der empfangenen Daten ist etwas mühsam. Zwischenzeitlich gibt es diverse Beiträge im Web, die aufzeigen, wie PICO's DMA auch unter Micropython nutzbar ist. DMA bietet den Vorteil, dass nicht nur die Statemachines, sondern auch der Datentransfer im Hintergrund ablaufen.. Der Programmcode sieht auf den ersten Blick aufwändiger aus - aber das täuscht. Wenn Interesse besteht - weitere Erläuterung gibt's in der Anlage in der readme.pdf. Michael S.
Hier noch ein kleiner Nachtrag: Es hatte mich einen guten ganzen Tag gekostet, ein unerwartetes Verhalten der Statemachines zu beseitigen, leider zunächst ohne die Ursache zu verstehen: Immer dann, wenn mehrere Instanzen eines Receivers gestartet werden sollten, arbeitete nie mehr als eine einzige Instanz auf jedem PIO-Block. Das heißt, manchmal schon - aber nicht mehr nach einem Reset. Ein Blick in die Register zeigte merkwürdige Unterschied in den Registern - SMx_ADDR Register - SMx_INSTR Register Bei den nicht funktionierenden Statemachines waren die Register nicht gesetzt. Kopieren der Registerinhalte von der arbeitenden SM auf die anderen brachte keine Veränderung. Erst durch den Vergleich des Programmcodes mit meinen funktionierenden Beispielen in den "Spielereien" entpuppte sich am Ende als Verursacher das "statemachine.restart()". Ohne selbiges funktionierte alles wie erwartet. Ich habe mir das heute noch einmal genauer angesehen und das restart() ohne Micropython durch Setzen der entsprechenden Bits in den Controll-Registern ausgeführt. Das funktioniert. Sollte da ein Bug im "restart()" stecken ? Den Programmcode meines Testes füge ich mal an Anlage bei. Michael S. 23.07.2022
Michael S. schrieb: > Der PI PICO verfügt von Haus aus über 2 integrierte UART-Schnittstellen, > von denen eine meist für die Programmierung genutzt wird. Ähem, nein, warum sollte man das tun? Es gibt doch SWD. Darüber kann man dann auch debuggen und nicht nur programmieren.
Interssantes Projekt. Leider gibt es hier immer zu wenig Leute, die sich für ein spezielles Thema interessieren. An deiner Stelle würde ich es auf GitHub hochladen, dann kannst du auch sehen, wie viele Zugriffe es gibt. Das gab es hier im Forum auch mal, aber leider haben sie es abgestellt.
Noch ein letzter Nachtrag zu den UART-DMA-Varianten. Mit dem Inline-Assembler hatte ich bislang noch nicht gearbeitet - und so ist mir anfangs nicht aufgefallen, dass man in einigen Instruktionen Konstanten verwenden kann (z.B. beim Shiften und Addieren). Damit werden einige mov's überflüssig. Bei der Gelegenheit habe ich auch die DMA_BASE-Adressen, die bislang per Parameter übergeben wurden, direkt in den Programmcode eingebaut. Die (interne) Funktion "bit_reverse_8()" unterscheidet zwischen Source- und Targetadresse. Das Wechseln zwischen zwei unterschiedlichen Empfangsarrays kann dadurch entfallen. Diese Änderungen betreffen nur Objekt-Interna, nach außen bleibt alles gleich. Michael S. 25.07,2022
Hallo, häufig denkt man komplizierter als erforderlich. So war meine schlaue Überlegung gewesen: Will man ein empfangenes Byte in ein Register der Statemachine schreiben, dann shiftet man es normalerweise von links nach rechts rein.
1 | 8-Bit 32-Bit Register |
2 | 8765_4321 -> 8765_4321-0000_0000-0000_0000-0000_0000 |
Um die Daten per DMA abzuholen, benöitgt man daher ein Array aus 32-Bit Variablem. Das ist wenig effizient. Um Platz zu sparen, habe ich die Bits von rechs nach links in das niedrigstweritige Byte geshiftet - und konnte es so mit 8-Bit Variablen auslesen:
1 | 32-Bit Register 8-Bit |
2 | 0000_0000-0000_0000-0000_0000-1234_5678 <- 1234_5678 |
Dummerweise wird dabei die Bit-Reihenfolge verdreht. Das musste eine Inline-Assembler-Routine richten. Dabei geht es viel einfacher. Die Statemachine kennt keine direkte Instruktion zum Shiften. Aber man kann aus einer beliebigen Quelle Bits ins ISR shiften. Ausgangspunkt (8 Bit empfangen):
1 | 8-Bit 32-Bit Register |
2 | 8765_4321 -> 8765_4321-0000_0000-0000_0000-0000_0000 |
Mit "in_(x, 24)" werden 24 (zufällige) Bits z.B, aus dem X-Register hinterher geschoben - und schon passt die Byte-Position und die Bit-Reihenfolge.
1 | -> 24 Bit -> xxxx_xxxx-xxxx_xxxx-xxxx_xxxx-8765_4321 |
Was im "x" steht, das interessiert nicht, es wird ja nicht ausgelesen. Mit Hilfe von "autopush" bleibt sogar die Anzahl der benötigten Instruktionen unverändert. Und das Invertieren der Bitreihenfolge entfällt. Einfach ist eben einfach einfacher. Michael S. 04.08.2022
> Dabei geht es viel einfacher. Ja, z.B. mit einen ARM aus der TI TIVA Serie. Die haben von Haus aus max. 8 serielle Schnittstellen.
Cooles Projekt, das wunderbar zeigt, wie MicroPython, ARM- und PIO-Assembler zusammenarbeiten. Habe eine Menge gelernt aus Deinem Programm.
Interessantes Projekt! Ich hatte bisher den PI pico als "Spielzeug" abgetan. Nachdem ich mich nun genauer mit deinen Quelldateien und dem Datenblatt beschäftigt habe wird mir dieser immer sympathischer. Es kann gut sein, dass wir unsere STM32F0 durch den PI pico ersetzen. Vor allem sind diese lieferbar.
Wenn etwas in der heutigen Zeit im Status:
> Vor allem sind diese lieferbar.
ist, wuerde ich eher von einer gewissen "Zurueckhaltung"
bei der Verwendung ausgehen.
Der Bastlermarkt macht den Kohl eben nicht fett.
Und in der Industrie scheint er, aus was fuer Gruenden auch immer,
nicht anzukommen.
Cartman schrieb: > Und in der Industrie scheint er, aus was fuer Gruenden auch immer, > nicht anzukommen. Mag noch kommen – und sei’s eben nur aufgrund der Marktlage. Die interessante Frage ist: sollte das kommen, können sie dann die Nachfrage bedienen? Was jetzt zu haben ist, ist ja nur deswegen zu haben, weil es [noch] keine große Nachfrage aus dem kommerziellen Bereich gibt, in dem ordentliche Mengen umgesetzt werden.
Cartman schrieb: > Und in der Industrie scheint er, aus was fuer Gruenden auch immer, > nicht anzukommen. Liegt vermutlich am nicht integrierten FLASH. Das war bei mir bisher der Grund. Der vermeintliche Nachteil kann aber auch vorteilhaft sein. Erstens ist externer QSPI-Speicher in der Regel günstiger und es müssen nicht verschiedene µC-Derivate vorgehalten werden. Es wird einfach der benötigte FLASH dazu bestückt. Der interne RAM ist bei PI pico eher üppig.
Cartman schrieb: > Und in der Industrie scheint er, aus was fuer Gruenden auch immer, > nicht anzukommen. Oh' doch. Aber Entwicklung braucht halt Zeit, insbesondere, wenn man von einer unnötig fetten MCU-Sau mit lausig hingerotzter "mir gehört die Welt"-Software auf was Schlankeres migrieren muss. Zu "alten Zeiten" war sowas nicht durchsetzbar. Jetzt werden die BWLer durch die Umstände dazu gezwungen, auch über sowas nachzudenken. Naja, und auf einmal geht dann doch was. Worauf sich die BWLer aber noch nicht so richtig eingestellt haben, ist die wenig überraschende Tatsache, dass der Entwicklungsaufwand deutlich hochgeht, wenn die Resourcen knapp werden. Aber: noch'n Winter und auch die kommen dahinter...
Michael S. schrieb: > Der PI PICO verfügt von Haus aus über 2 integrierte UART-Schnittstellen, > von denen eine meist für die Programmierung genutzt wird. Falsch. Beide UARTs sind frei, die Programmierung erfolgt auf separatem Wege über USB. Transputer schrieb: > Ich hatte bisher den PI pico als "Spielzeug" abgetan Naja, Micropython in seinem aktuellen Status würde ich diesen Status durchaus verpassen. Das Zeug läuft trotz vieler guter Ansätze zeitverschwenderisch code-interpretierend, meist single-threaded und noch lange nicht ausgereift und robust.
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.