Baudraten für PIPico über stdio.usb einstellen

OP #8100223
Lesenswert?
• ▲
▼

Hallo, ich bin dabei die Baudraten für PiPIco in C++ zu programmieren. Die Verbindung läuft über die USB-Buchse mit den stdio-funktionen. Da gibt es aber keine Möglichkeit die Baudrate zu programmieren. Man kann nur dazu eine #def machen:

1
#define         PICO_DEFAULT_UART_BAUD_RATE     9600

Der Compiler sagt nichts dazu. Aber leider bemerke ich keine Veränderungen der Übertragungsdauern. Mit den Oszi messe ich immer nur ca.150ns für die kürzesten Impulse, egal was ich definiere.
Es gibt ja auch noch die UARTs 0 und 1 beim Pico. Die laufen aber nicht über die USB-Buchse, oder?
Zur Not würden mir auch die 115200 reichen, lieber wäre mir aber schneller.

#8100227
Lesenswert?
• ▲
▼

Rudi schrieb:

Es gibt ja auch noch die UARTs 0 und 1 beim Pico. Die laufen aber nicht über die USB-Buchse, oder? Zur Not würden mir auch die 115200 reichen, lieber wäre mir aber schneller.

Fangen wir hinten an, die UARTs unterstützen knapp 8 MBaud bei den Standard-genutzten 125MHz (genau: CPU_FREQ/16) Kann man auch schön mit einem UART-USB Kabel testen. (mein PL2303 schafft 4MBaud in den PC hinein) Zwei Picos kann man aber bequem mit maximaler Geschwindigkeit quatschen lassen. Bei der Geschwindigkeit empfiehlt es sich DMA zu nutzen.

Die ACM hat im Grunde genommen gar keine Baud Rate, die Geschwindigkeit wird durch die USB-Geschwindigkeit bestimmt. Hast du da D+ und D- gemessen?

Bin jetzt nicht 100% sicher, aber ich meine mich zu erinnern, dass entweder pro Millisekunde oder alle 125µs je 64 Bytes übertragen werden können. Da sind die PiPicos übrigens deutlich langsamer als zB. die STM32F4.

: Bearbeitet durch User
#8100241
Lesenswert?
• ▲
▼

Norbert schrieb:

Bin jetzt nicht 100% sicher, aber ich meine mich zu erinnern, dass entweder pro Millisekunde oder alle 125µs je 64 Bytes übertragen werden können.

Pro Millisekunde, der RP2040 etc. ist nur ein Full-Speed-Device (12 MBit/sec). Microframes alle 125 µsec gibt es erst ab High-Speed (480 MBit/sec).

Die 64 Byte beziehen sich aber auf den Inhalt eines Pakets ("Transfer"). Pro Frame können mehere Pakete ("Transfers") übertragen werden. Bei 64 Byte Nutzdaten pro Paket sind das maximal 13 Pakete pro Frame, d.h. 832 Byte.

Und damit liegt die maximale Nutzdatenrate bei etwa 832 kByte/sec.

#8100256
Lesenswert?
• ▲
▼

Harald K. schrieb:

Die 64 Byte beziehen sich aber auf den Inhalt eines Pakets ("Transfer"). Pro Frame können mehere Pakete ("Transfers") übertragen werden. Bei 64 Byte Nutzdaten pro Paket sind das maximal 13 Pakete pro Frame, d.h. 832 Byte. Und damit liegt die maximale Nutzdatenrate bei etwa 832 kByte/sec.

Hmmm, habe ich noch nie durch das Ding bekommen. Noch nicht einmal ansatzweise. Vielleicht eine Limitierung des tinyUSB im SDK. Muss gelegentlich mal einen Blick hinein werfen.

#8100281
Lesenswert?
• ▲
▼

Norbert schrieb:

Hmmm, habe ich noch nie durch das Ding bekommen. Noch nicht einmal ansatzweise.

Setzt "bulk" transfer voraus. Früher(tm) gab es USB-IDE-Adapter, die nur Fullspeed konnten (weil es damals Highspeed noch gar nicht gab), mit denen lag' man bei eben jenen 800 kByte/sec.

Einer der wenigen USB-SCSI-Adapter (Adaptec USBConnect 2000) stammt auch aus der Vor-2.0-Zeit und liefert entsprechende Datenraten. Gemütlich, sehr gemütlich.

So sieht das Ding aus: https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQh0-06yFS-401_PGBjnMACkD4rwgcbSLFMuBlaQKwFGotfq_pHXYJxIwam&s=10

OP #8100282
Lesenswert?
• ▲
▼

Also, über USB weiß ich wohl zuwenig. Was ich hier lese, gibt es einen großen Unterschied zu seriell. Wenn ich nun mit meinen PiPico Daten an einen PC senden will, muß ich praktischer Weise über USB gehen. Da nützten mir die 2 Uarts im PiPico wohl auch nichts.

Harald K. schrieb:

Und damit liegt die maximale Nutzdatenrate bei etwa 832 kByte/sec

Wenn es aber so schnell geht, warum kommt der gesendete Text am Teminal Putty so langsam an, dass man fast mitlesen kann?

#8100310
Lesenswert?
• ▲
▼

Rudi schrieb:

Also, über USB weiß ich wohl zuwenig. Was ich hier lese, gibt es einen großen Unterschied zu seriell. Wenn ich nun mit meinen PiPico Daten an einen PC senden will, muß ich praktischer Weise über USB gehen. Da nützten mir die 2 Uarts im PiPico wohl auch nichts.

Wenn du richtig heftigen Datendurchsatz brauchst, UART-USB Kabel (hatte ich oben schon geschrieben) damit schaffst du 4MBaud also ca. 400kByte/s. Mit einem der schnellen FTDI Adapter soll dem Vernehmen nach noch mehr möglich sein.

Wenn es aber so schnell geht, warum kommt der gesendete Text am Teminal Putty so langsam an, dass man fast mitlesen kann?

Selbst µPy mit tinyUSB schafft > 50KByte/s mit 'nem Dreizeiler.

#8100316
Lesenswert?
• ▲
▼

Norbert schrieb:

Mit dem Standard-SDK und tinyUSB?

Hab's mir einfach gemacht und das Arduino-Framework mit earlephilhower Core verwendet. Müsste Pico-SDK-USB verwenden, was m.W. auch eine TinyUSB-Portierung ist.

Norbert schrieb:

Hast du mal den tatsächlichen Durchsatz gemessen?

Nur sehr grob abgeschätzt... Für ca. 10 Sekunden screen ein Logfile schreiben lassen, das war dann 3½ MB groß.

Ist nur als PoC für mausbedienbare Userinterfaces über die Serielle gedacht, nicht als Bandbreiten-Test.

#8100320
Lesenswert?
• ▲
▼

Εrnst B. schrieb:

Für ca. 10 Sekunden screen ein Logfile schreiben lassen, das war dann 3½ MB groß.

Danke, das ist verdammt schnell. Also muss ich wohl mal in den sauren Apfel…

Hier mal eine Standard Terminalausgabe über /dev/ttyACM0:

1
#!/micropython
2
# vim: fileencoding=utf-8: ts=4: sw=4: expandtab:
3
ch = ''.join([chr(n) for n in range(33,127)]*2)
4
for z in range(1000):
5
    a = z % 64
6
    print(f'{z:4}', ch[a:a+80])

Und:

1
$ picorun Durchsatz.py | pv > /dev/null
2
^C14MiB 0:00:10 [ 118KiB/s] [           <=>     ]
Angehängte Dateien:
#8100323
Lesenswert?
• ▲
▼

Norbert schrieb:

Danke, das ist verdammt schnell.

Gib nicht zuviel auf meine Schätzung, keine Ahnung ob screen das Logfile 1:1 schreibt, und die Zeit war so nach Gefühl.

Mit "pv" gemessen komm ich auch auf 124KiB/s.

und das fast unverändert mit und ohne diesem FPS-Limit in der loop:

1
  const unsigned long now = millis();
2
  if (now - lastFrame < 50) {
3
    return;
4
  }
5
  lastFrame = now;

Insofern bin ich mit meinem Code wohl auch am Bandbreitenlimit, und muss mir was Besseres als "jedes Frame alle Widgets neu zeichnen" überlegen

#8100497
Lesenswert?
• ▲
▼

Norbert schrieb:

Vielleicht sind's auch nur die nach innen gerichteten App-Buffer.

Davon geh ich auch aus, in den Buffer laufen die Buchstaben rein, und sollten dann in 64-Byte-Häppchen rausgesendet werden, im Default also bis zu 4 hintereinander bevor der Buffer leer läuft.

Sollte also eigentlich für mehr Bandbreite reichen, wenn der tud_task() oft genug läuft, und der PC genug URBs sendet.

und zumindest der Linux cdc_acm - Treiber sollte eigentlich genug URBs raussenden:

1
  for (i = 0; i < acm->rx_buflimit; ++i) {
2
    res = acm_submit_read_urb(acm, i, mem_flags);

default für das rx_buflimit sollten 16 sein, "#define ACM_NR" in der cdc-acm.h.

Deswegen wollte ich das mit 1024 in der tusb_config.h versuchen, dann passt die Anzahl der URBs, die der Kernel-Treiber raussendet zur max. Menge an URBs, die TinyUSB direkt hintereinander beantworten kann.

#8100569
Lesenswert?
• ▲
▼

Kurze Statusmeldung:

CFG_TUD_CDC_TX_BUFSIZE vergrößern hat nichts gebracht, aber mit der CPU auf 200MHz laufen 170KiB/s über ttyACM.

Und mit dem zweiten Core aktiv, der nur "tud_task()" ausführt, 180-200 KiB/s. Ist so natürlich nicht optimal, weil beide Cores am USB werkeln. Den ganzen USB-Teil auf den zweiten Kern zu schieben wäre vermutlich mit etwas Aufwand möglich...

Eher interessiert mich, warum das hochtakten was bringt. Ist ja nicht so als wäre der vorher CPU-Limitiert gewesen für die 125 KiB/sec..

#8100627
Lesenswert?
• ▲
▼

Super, Danke Ernst.
Ja wenn ›Taktrate erhöhen‹ zu einem höheren Durchsatz führt, dann ist es mMn. ein Problem des USB Stacks. Wäre man Politiker, könnte man auch sagen, da ist noch Optimierungspotential vorhanden.

Vielleicht hat's ja einige Abstraktionsschichten zu viel. Sieht dann zwar schön aus, wie aus dem Lehrbuch, erinnert aber an einen Traktor mit Heckspoiler.

Wenn ich dazu komme, werde ich das mal Taktweise ein wenig hoch peitschen und 'ne Tabelle bauen.

Ad: Die Tabelle ist 'ne flache Linie. Bis 400MHz gleichbleibender Durchsatz. Bei 48MHz geringfügig niedriger. Aber alles mit µPy, da mag die Idle Loop einfach nicht schnell genug sein. Obwohl, bei mehr als dreifacher Frequenz…

: Bearbeitet durch User
#8100636
Lesenswert?
• ▲
▼

Εrnst B. schrieb:

Eher interessiert mich, warum das hochtakten was bringt. Ist ja nicht so als wäre der vorher CPU-Limitiert gewesen für die 125 KiB/sec..

Könnte sein, dass der kooperative Aufruf von "tud_task()" kostspielig ist und man bei höheren Frequenzen eine Art aligning auf die darunter liegende USB req./resp. Struktur bekommt. Aber alles Spekulatius. Bin mir nicht sicher, ob ich mir das Durchforsten des tinyUSB code antun möchte. Vielleicht im Winter.

: Bearbeitet durch User
#8100931
Lesenswert?
• ▲
▼

Moin Ernst,

alles zurück auf Anfang. Bin bei meinen Messungen zur Geschwindigkeit einem Fehler aufgesessen.
Anscheinend bremst das dazwischen liegende simple Terminal die Datenrate. Ist mir erst aufgefallen, als ich einen ungewöhnlich hohen CPU Wert auf einem Kern des PCs gesehen hatte.

Als Erklärung, nicht Entschuldigung, muss ich anführen, dass bei älteren Firmware Revisionen wirklich eine Limitierung vorlag. Deshalb war ich bei den fehlerhaften neuen Messungen auch nicht sonderlich verblüfft. Mit der aktuellen 1.29 Firmware (auf RP2040) bin ich es nun aber! ;-)

Hier die korrekten Messungen mit µPy bei µC Frequenzen von 48MHz bis 400MHz.

1
    $ pv -rav </dev/ttyACM0 >/dev/null
2
    
3
48MHz: [328KiB/s] ( 328KiB/s)
4
rate min/avg/max/mdev = 334743.309/336805.767/338799.935/985.888 B/s
5

6
100MHz: [499KiB/s] ( 499KiB/s)
7
rate min/avg/max/mdev = 511653.501/512008.337/513115.745/404.530 B/s
8

9
200MHz: [659KiB/s] ( 660KiB/s)
10
rate min/avg/max/mdev = 674488.465/676007.634/677014.416/796.126 B/s
11

12
300MHz: [674KiB/s] ( 665KiB/s)
13
rate min/avg/max/mdev = 646164.050/681648.275/691998.152/11315.737 B/s
14

15
400MHz: [703KiB/s] ( 702KiB/s)
16
rate min/avg/max/mdev = 718162.983/719908.444/721057.894/782.333 B/s
#8100996
Lesenswert?
• ▲
▼

Und nur der Vollständigkeit halber, nun die Messungen für
PICO2 RP2350:

1
/tmp/norbert$ pv -F"    48 MHz: %a %r %b"    </dev/ttyACM0 >/dev/null
2
^C  48 MHz: [ 507KiB/s] [ 507KiB/s] 10,4MiB
3
/tmp/norbert$ pv -F"   100 MHz: %a %r %b"    </dev/ttyACM0 >/dev/null
4
^C 100 MHz: [ 750KiB/s] [ 750KiB/s] 10,3MiB
5
/tmp/norbert$ pv -F"   200 MHz: %a %r %b"    </dev/ttyACM0 >/dev/null
6
^C 200 MHz: [ 906KiB/s] [ 906KiB/s] 10,6MiB
7
/tmp/norbert$ pv -F"   300 MHz: %a %r %b"    </dev/ttyACM0 >/dev/null
8
^C 300 MHz: [ 976KiB/s] [ 986KiB/s] 10,5MiB
9
/tmp/norbert$ pv -F"   400 MHz: %a %r %b"    </dev/ttyACM0 >/dev/null
10
^C 400 MHz: [1006KiB/s] [1011KiB/s] 10,8MiB

Scheint, als ob die USB Engine beim Neuen etwas flotter agiert.
Ich denke, sehr viel mehr wird da jetzt bei USB-FS wohl nicht mehr gehen… ;-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren