Hallo,
ich verwende das picoboard RP2040 mit arduino framework.
Weiss jemand ob man ähnlich wie bei Atmega, Attiny Serie den GPIO
Port/Pin direkt per Register ansprechen kann wie z.B.?
Vanye R. schrieb:> Ja, kann man machen. Liess das Datenblatt da stehen die> Register drin.
und wie findet man den Layer wo diese Register benannt sind? Und sonst,
wie sieht das aus? Irgendwie 0x0000xxx = 0x0000xxx;
Sorry das geht mir zu tief, bzw. weiss nicht wo anfangen...
Beispiele wären cool, da kommt man dann schnell rein.
Epi K. schrieb:> und wie findet man den Layer wo diese Register benannt sind? Und sonst,> wie sieht das aus? Irgendwie 0x0000xxx = 0x0000xxx;>> Sorry das geht mir zu tief, bzw. weiss nicht wo anfangen...> Beispiele wären cool, da kommt man dann schnell rein.
Du suchst im Datenblatt nach SIO (Single-cycle IO)
bzw. Atomic Register Access.
Umschalten eines Portpins dauert bei 125MHz dann lediglich 8ns.
Epi K. schrieb:> geht das so?:>> 0x40014000 = 0x1000 //bit13 setzen,
Nö. Es gibt sicher Headerfiles im Compiler vom Arduino, wo die Register
per Namen ansprechbar sind.
> Dann ist GPIO0 als Ausgang definiert :-D ?
Wozu glaubst du, das tun zu müssen? Gerade auf dem Raspberry PI Pico ist
das setzen der IOs so schnell, da kann man in den allermeisten Fällen
das einfache digitalWrite() bzw. pinMode() nehmen. Das dauert vermutlich
weniger als 1 us.
Epi K. schrieb:> geht das so?:>> 0x40014000 = 0x1000 //bit13 setzen,>> Dann ist GPIO0 als Ausgang definiert :-D ?
Nein.
So aber vielleicht:
*((unsigned int *)0x40014000) = 0x1000;
Wenn da wirklich ein Register liegt die auch mit 32 bit beschreibbar ist
und man keine Speicher oder Register Protektion aktiv hat (wenn es auf
dem Ding sowas gibt) dann müsste das klappen.
Epi K. schrieb:>> Umschalten eines Portpins dauert bei 125MHz dann lediglich 8ns.>> ne glaube ich nicht, bei ca. 400..500KHz ist Schluss....
Sagt wer? Du?
Epi K. schrieb:> Norbert schrieb:>> Umschalten eines Portpins dauert bei 125MHz dann lediglich 8ns.>> ne glaube ich nicht, bei ca. 400..500KHz ist Schluss....
Das Glauben überlassen wir doch besser den Klerikern.
Die haben Jahrhunderte lange Übung im alles Glauben und nichts Wissen.
Uns reicht da schon ein Blick auf's Oszilloskop. ;-)
Epi K. schrieb:>> Sagt wer? Du?>> ja, hatte ich mit gpio_put() getestet... irgendwie sehr lahm, aber wohl> dem MUX geschuldet..
Wer viel mißt, mißt Mist.
Sooo, mal wieder wurden die urban legends widerlegt. Siehe Anhang. Als
zufälliger Besitzer eines RP2040 hab ich einfach mal gemessen.
Pin wackeln in Endlosschleife. Laut Arduino-IDE läuft die CPU mit 133
MHz.
digitalWrite() ~ 800kHz
Register set/clr ~33MHz(!)
Register togl ~ 22MHz(!)
Sollte reichen. Da kommt mein olles DS1052 schon an seine Grenzen!
Falk B. schrieb:> digitalWrite() ~ 800kHz> Register set/clr ~33MHz(!)> Register togl ~ 22MHz(!)
Mach das mal mit Assembler. Da ist noch ne gewaltige Menge Luft nach
oben.
In einer Endlosschleife addieren sich die Zeit des str[hb] Befehls auf
die SIO (XOR) und der branch Befehl. Wenn du die Flash-delays raus
haben möchtest, dann noch im RAM laufen lassen.
Da war selbst mein 50MHz anal. Philips überfordert.
Konnte nur im time x10 etwas sehen.
Norbert schrieb:>> digitalWrite() ~ 800kHz>> Register set/clr ~33MHz(!)>> Register togl ~ 22MHz(!)>> Mach das mal mit Assembler. Da ist noch ne gewaltige Menge Luft nach> oben.
Nö. Die 2. Version braucht 4 (VIER) CPU-Takte für die gesamte Schleife!
> In einer Endlosschleife addieren sich die Zeit des str[hb] Befehls auf> die SIO (XOR) und der branch Befehl. Wenn du die Flash-delays raus> haben möchtest, dann noch im RAM laufen lassen.> Da war selbst mein 50MHz anal. Philips überfordert.
Genau, anal. Voll für den Arsch! ;-)
Falk B. schrieb:> Nö. Die 2. Version braucht 4 (VIER) CPU-Takte für die gesamte Schleife!
33% zu viel!
Laut Datasheet braucht der str[bh] Befehl nur einen Takt für SIO
Operationen und der unconditional branch nur zwei. Macht Drei. Also 41
2/3 MHz. (bei 125)
Wenn man den branch mal vergisst, im Sinne eines Loop unroll, dann kann
man also mit einem Taktzyklus toggeln. Ergo 8ns.
Ps. Man sieht's auf dem Scope, man kann's messen, sieht nur nicht mehr
so schön aus. ;-)
ziemlich sinnfrei diese ständigen Pintoggle Rekorddiskussionen. Der
RP2040 hat die PIO, für schnelle Spezialaufgaben macht es mehr Sinn sich
damit zu beschäfftigen.
Epi K. schrieb:> Weiss jemand ob man ähnlich wie bei Atmega, Attiny Serie den GPIO> Port/Pin direkt per Register ansprechen kann wie z.B.?
Ich weiß es ;-)
Zunächst müssen einige Initialisierungen passieren, ob Eingang oder
Ausgang, Pullup oder Pulldown, ggf. Stromstärke oder Schmitttrigger.
Dafür kannst Du wohl die Arduino-Befehle verwenden.
Um sehr schnell einen Ausgang zu setzen oder zu löschen, gibt es
spezielle Adressen, die ein atomares SET, CLEAR oder XOR durchführen.
Diesen Adressen haben einen Offset zur Basisadresse und man findet sie
beispielsweise in RP2040.h. Im Datenblatt findet sich eine kurze
Beschreibung auf Seite 18, Kapitel 2.1.2
Beispiel-Code hätte ich auch zu bieten, wenn es notwendig sein sollte.
Mi N. schrieb:> Beispiel-Code hätte ich auch zu bieten, wenn es notwendig sein sollte.
Schon mal die anderen Beiträge gelesen? Du bist Stunden zu spät,
außerdem ohne Substanz (Beispiele).
J. S. schrieb:> ziemlich sinnfrei diese ständigen Pintoggle Rekorddiskussionen.> Der> RP2040 hat die PIO, für schnelle Spezialaufgaben macht es mehr Sinn sich> damit zu beschäfftigen.
Nein, finde ich gar nicht.
Hier geht es einzig und allein darum,
falsche von richtigen Informationen zu trennen.
Und während ich ausgesprochen gerne die PIO Statemachines nutze, alles
kann man mit den zwei mal 32 Instruktionen auch nicht erledigen.
Kleine Ergänzung. Die Funktionen aus der Doku des RP2040
1
staticinlineboolgpio_get(uintgpio);
2
staticinlinevoidgpio_set_mask(uint32_tmask);
3
staticinlinevoidgpio_clr_mask(uint32_tmask);
4
staticinlinevoidgpio_put(uintgpio,boolvalue);
gibt es schon in den Untiefen der Includes im gcc für den RP2040. Kann
man ohne zusätzliche #include nutzen. Mit konstanten Argumenten wird das
auch so weit optimiert, daß der einzige Registerzugriff übrig bleibt,
die Schleife ist so schnell wie der Test 2 mit den direktem
Registerzugriff!
1
#if TEST_NR == 4
2
// toggle test, direct register access via non-Arduino function
3
gpio_put(TEST_LED,HIGH);
4
gpio_put(TEST_LED,LOW);
5
#endif
Wenn man mit variablen Argumenten arbeitet, was ich hier mal mit einer
volatile Varible erzwungen habe, wird es langsamer, aber immer noch SEHR
flott! Umschaltfrequenz ~11MHz, d.h. ein Funktionsaufruf dauert ca.
40ns!
1
volatileuintpin=TEST_LED;
2
3
...
4
5
#if TEST_NR == 5
6
// toggle test, direct register access via non-Arduino function
Falk B. schrieb:> Epi K. schrieb:>>> Sagt wer? Du?>>>> ja, hatte ich mit gpio_put() getestet... irgendwie sehr lahm, aber wohl>> dem MUX geschuldet..>> Wer viel mißt, mißt Mist.
Ich hätte erwähnen sollen, dass es mir darum geht mehrere Pins
gleichzeitig zu toggeln (oder min. 10pins).
Mit gpio_put_all habe ich nur paar 100KHz erreicht. Messung kann ich
ggf. am Nachmittag nachreichen.
Epi K. schrieb:> Ich hätte erwähnen sollen, dass es mir darum geht mehrere Pins> gleichzeitig zu toggeln (oder min. 10pins).
Tja, und schon wieder versagt Gen-Z kläglich. Schon mal über die
Wirkungsweise der Funktionen gpio_set_mask(uint32_t mask) nachgedacht?
> Mit gpio_put_all habe ich nur paar 100KHz erreicht.
Tja . . .
Epi K. schrieb:> Mit gpio_put_all habe ich nur paar 100KHz erreicht.
Kann ich nicht bestätigen. Bei mir sind es mit deinem Code in einer
while(true) um die 13.8MHz bei Debug und ca. 31.25MHz mit Release (siehe
Anhang).
Verwendeter Code:
Geb dir mal den CLK_SYS an einem Pin aus. Hier ein Beispiel am PIN21
(Achtung, da geht nicht jeder Pin). Geteilt durch 10.0f damit man es
besser messen kann.
Bei mir messe ich dann 12.5MHz, also 125MHz als Sys-Clock. Was
anscheinend Default ist. Die Zeiten vom Anhang werden also noch leicht
schneller sein wenn man auf die erlaubten 133MHz erhöht.
Und wie schon oben gesagt: Soll es noch schneller sein nimm eine PIO.
Das hier duerfte so ziemlich die Minimalversion sein:
https://github.com/dwelch67/raspberrypi-pico/tree/main/blinker00
Und ja, es ist natuerlich schon schoener wenn man sich ein Headerfile
mit den Registern besorgt. .-)
Was leider fuer Anfaenger etwas verwirrend ist das ist dieser
zweistufige Bootprozess mit Pruefsumme.
Deshalb schaut euch das was dwelch67 da gemacht hat genau an. Das
erleichtert den Einstieg ernorm.
Vanyo
Vanye R. schrieb:> Und ja, es ist natuerlich schon schoener wenn man sich ein Headerfile> mit den Registern besorgt. .-)
Einen habe ich noch übrig.
N. M. schrieb:> Und wie schon oben gesagt: Soll es noch schneller sein nimm eine PIO.
Nicht unbedingt schneller aber auf jeden Fall komplizierter.
Mi N. schrieb:> rp2040.h (2,38 MB)>> Und ja, es ist natuerlich schon schoener wenn man sich ein Headerfile>> mit den Registern besorgt. .-)>> Einen habe ich noch übrig.
Ja, einen an der Waffel. Keiner braucht dein 2,4MB Headerfile, da ist
bei jedem Compiler schon dabei.
N. M. schrieb:> Epi K. schrieb:>> Mit gpio_put_all habe ich nur paar 100KHz erreicht.>> Kann ich nicht bestätigen. Bei mir sind es mit deinem Code in einer> while(true) um die 13.8MHz bei Debug und ca. 31.25MHz mit Release (siehe> Anhang).
Vielen Dank für diese Hinweise. Ich verwende platformIO / Arduino mit
folgendem Setup, und im Anhang die Messung. Das Signal ist komisch, aber
immerhin jetzt mehr als paar 100kHz, d.h.:
gpio_put_all: unsymetrisches Signal ca. 7.3MHz
sio_hw->gpio_set u. clr: unsymetrisches Signal ca. 6.9Mhz
sio_hw->gpio_togl: symetrisches Signal ca. 3.6MHz
Epi K. schrieb:> void loop() {> gpio_put_all(0xffffffff);> gpio_put_all(0x00000000);> //sio_hw->gpio_set = mask;> //sio_hw->gpio_clr = mask;> //sio_hw->gpio_togl = mask;> }
Hier ist dein Fehler. Loop wird zwar dauerhaft ausgeführt, ist aber eine
Funktion, die aufgerufen wird. Ein while(1) {} ist da schneller.
Falk B. schrieb:> Hier ist dein Fehler. Loop wird zwar dauerhaft ausgeführt, ist aber eine> Funktion, die aufgerufen wird. Ein while(1) {} ist da schneller.
Tatsächlich, Signal ist immer noch nicht schön symetrisch aber jetzt bei
31 Mhz mit put_all....
Tolle Sache :-)
Hier mal eine gescheite HF-Messung des IO-Pins. Gemessen mit einem
nagelneuen LeCroy Wavesurfer 4054HD (500MHz, 5 Gs/s, 12Bit) und einem
selbstgebauten Z0-Tastkopf mit 1k Eingangswiderstand. Die IOs sind
RATTENSCHNELL! Dargestellte Anstiegszeit ca. 1ns, davon sind aber ca.
0,7ns schon das Oszi! (toszi~0,35/f3dB).
tr = Wurzel (tg^2 - toszi^2) = Wurzel (1ns^2-0,7ns^2) = 0,7ns
Alter Schalter!
Die beiden ersten Messungen wurden mit interner Terminierung mit 50 Ohm
gemacht, da hat man schon eine sehr gute Signalqualität. Die dritte
Messung mit externer Terminierung an einem T-Stück und Oszi auf 1M
Eingangswiderstand. Das ist DEUTLICH schlechter! Ob das am schon etwas
älteren, leicht oxidierten T-Stück oder dem Oszi liegt, ist unklar.
Epi K. schrieb:> Tatsächlich, Signal ist immer noch nicht schön symetrisch aber jetzt bei> 31 Mhz mit put_all....
Wenn Du 100 MHz brauchst, lass den RP2040 mit 4xx MHz laufen.
Ich denke, jetzt ist der Zeitpunkt gekommen, zu sagen, was das ganze
überhaupt soll.