Micropython RP2040 Speed von Beispielcode

OP #7860789
Lesenswert?

Hallo,

nachdem Norbert (der_norbert) hier immer mal wieder beeindruckende Zahlen liefert, wie schnell den Micropython auf einem Raspberry Pi Pico läuft, bin ich auch mal neugierig geworden.

Ich habe mir Micropython nach dem PDF "Raspberry Pi Pico-series Python SDK" unter Linux installiert und die Runtime auf meinem Raspberry Pi Pico (ohne W und auch nicht der 2) geflasht.

Die Runtime meldet sich so bei mir:

1
MicroPython v1.25.0-preview.540.g0b3ad98ea on 2025-04-12; Raspberry Pi Pico with RP2040
2
Type "help()" for more information or .help for custom vREPL commands.

Läuft also. Ich kann per Console auf dem Board Code laufen lassen bzw. der Interpreter ist bedienbar.

Als IDE habe ich mir VS Code genommen. Dort habe ich MicroPico als Extension installiert und die Extensions die Autocompletion u.s.w. erledigen.

Dann habe ich ich den Code von hier (von Norbert) laufen lassen: Beitrag "Re: Micropython rp2040"

Das sind meine Ergebnisse:

1
CPU: 33 MHz     8093   9075   9463 FLOPS/core
2
CPU: 66 MHz    16159  18151  18926 FLOPS/core
3
CPU:133 MHz    32562  36577  38138 FLOPS/core
4
CPU:266 MHz    65126  73153  76276 FLOPS/core

Die von Norbert sind um den Faktor ~1.8 schneller:

1
CPU: 33 MHz    14390  17463  18938 FLOPS/core
2
CPU: 66 MHz    28665  35097  37680 FLOPS/core
3
CPU:133 MHz    57765  70724  75931 FLOPS/core
4
CPU:266 MHz   115990 140767 152656 FLOPS/core

Es ist dabei egal, ob ich den Code mit VSC starte oder mit dem mpremote tool.

Die Frage, woran liegst? Da der Beispielcode auch den CPU-Takt einstellt, kann es daran wohl nicht liegen.

Die Runtime sollte doch nicht soviel langsamer geworden sein?

Hat jemand eine Idee? Vielleicht liest Norbert ja mit und hat Lust seinen Test nochmal laufen zu lassen? Oder jemand anderes lässt ihn mal laufen?

Wo ist mein Denkfehler? Hat jemand einen Hinweis? Vielen Dank Euch.

900ss

Nachtrag: Vielleicht liegt der Trick auch im compilieren vom Code. Das hab ich noch nicht wirklich durchschaut weil die Anweisungen viper bzw native scheinbar auch vom Interpreter verstanden werden und der Code ohne diese Anweisungen langsamer läuft wie man an den Ergebnissen sieht.

Nachtrag2: picotool meldet vom Interpreter binary:

1
File ports/rp2/build-RPI_PICO/firmware.uf2:
2

3
Program Information
4
 name:            MicroPython
5
 version:         v1.25.0-preview.540.g0b3ad98ea
6
 features:        USB REPL
7
                  thread support
8
 frozen modules:  _boot_fat, rp2, _boot, asyncio, asyncio/core, asyncio/event, asyncio/funcs, asyncio/lock, asyncio/stream, uasyncio,
9
                  onewire, ds18x20, dht, neopixel
10
 binary start:    0x10000000
11
 binary end:      0x100519cc
12
 embedded drive:  0x100a0000-0x10200000 (1408K): MicroPython
13

14
Fixed Pin Information
15
 none
16

17
Build Information
18
 sdk version:       2.1.1
19
 pico_board:        pico
20
 boot2_name:        boot2_w25q080
21
 build date:        Apr 12 2025
22
 build attributes:  MinSizeRel
#7860795
Lesenswert?

900ss schrieb:

Vielleicht liest Norbert ja mit und hat Lust seinen Test nochmal laufen zu lassen?

Hab ich. Mit 1.24.1

1
CPU: 33 MHz     8356   9177   9483 FLOPS/core
2
CPU: 66 MHz    16713  18354  18966 FLOPS/core
3
CPU:133 MHz    33679  36986  38220 FLOPS/core
4
CPU:266 MHz    67358  73973  76440 FLOPS/core

Also wie bei dir. Direkt mal mit einer älteren 1.19.1 getestet: Und schon passen die alten Werte.

Da scheinen die Buben eine üble Regression in der FP Arithmetik eingebaut zu haben. Oder aus Versehen von float auf double gewechselt. Muss ich mir anschauen.

PS. Danke für den Hinweis. Werde in der nächsten Woche gleich die FP Arithmetik mit in den Testzyklus nehmen.

#7860825
Lesenswert?

Harald K. schrieb:

Norbert schrieb:

Aber so etwas darf man hier auf gar keinen Fall laut sagen.

Wieso das?

Weil's nicht die "richtige" Programmiersprache für µC ist. Das lassen ja eine nicht geringe Anzahl der hiesigen Forenteilnehmer gerne bei jeder unpassenden Gelegenheit heraus hängen. Das man manche Aufgaben noch nicht einmal in C schneller laufen lassen kann, macht's nur noch schlimmer. Bequem und schnell, das kann und darf nicht sein.

Und nach einem knappen halben Jahrhundert Programmierung in mehr Programmiersprachen als es einem gesunden Menschen gut tut, habe ich da einfach keine Lust mehr drauf. Zumal es genügend internationale Foren gibt, in denen sich die Teilnehmer erstaunlich zivilisiert verhalten.

#7860832
Lesenswert?

Norbert schrieb:

Das lassen ja eine nicht geringe Anzahl der hiesigen Forenteilnehmer gerne bei jeder unpassenden Gelegenheit heraus hängen.

Ich mag Python nicht besonders, da ich es für unübersichtlich halte, aber damit gehe ich nicht hausieren, und erst recht nicht würde ich anderen deswegen Vorhaltungen machen. Ich bin ja nicht der "C-Hater", der seinen Programmiersprachenhass sogar zum Namen machte.

Aber wenn jemand mit Python Probleme lösen kann, warum nicht?

#7860842
Lesenswert?

Norbert (der_norbert) 12.04.2025 21:24

Weil's nicht die "richtige" Programmiersprache für µC ist. Das lassen ja eine nicht geringe Anzahl der hiesigen Forenteilnehmer gerne bei jeder unpassenden Gelegenheit heraus hängen.

Das musst du ignorieren. Es gibt immer Leute die nur das verwenden wollen, was sie schon kennen. Und einige der Lautsprecher hier sind ja ziemlich konservativ und haben Schwierigkeiten, sich auf Neues einzustellen.

Das MC-Net hat über 10 Jahre gebraucht um halbwegs zu verstehen, was "Arduino" nicht gleichbedeutend mit "keine Ahnung" ist und dass "Einfachheit" auch im Professionellen Umfeld durchaus verwendet wird.

Hier der exemplarische Thread von 2013 (Arduino's gibt's seit ca. 2007):
Beitrag "Re: Arduino - bringt's das ?"

(Firma: Starfleet) #7860921
Lesenswert?

Ich habe mir Micropython nach dem PDF "Raspberry Pi Pico-series Python SDK" unter Linux installiert und die Runtime auf meinem Raspberry Pi Pico (ohne W und auch nicht der 2) geflasht.

Nachtrag: Vielleicht liegt der Trick auch im compilieren vom Code.

Nach oberflächlicher Recherche in diversen Entwicklerforen könnte es tatsächlich ein C-Problem (gcc) und kein Python-Problem sein.

Im Zusammenhang mit floating wird oft über die Nutzung/Verlinkung schneller (fast) gcc routinen für Soft-float und des ROM geschrieben.

Vielleicht klärt man auch, wie man die fürs floating-Point nötigen RAM-Tabellen flott zum Rechenwerk transferiert, resp. mit welchen Compiler/linker-Option man dafür sorgt das der erzeugte Interpreter flott auf alle nötigen Daten Zugreifen kann und nicht unnötig den Cache überschreibt.

https://github.com/orgs/micropython/discussions/14437

Änderungen im float-teil gab es mit V1.22, vielleicht testet man mal im Vergleich mit V1.21 .

Und gcc-Problem meint hier weniger einen Bug im Compiler als Unterschiede in den Compiler/Linker-Command-Line-Options die im build genutzt werden. Also weniger im C-Source stochern als in den (c)make-files/Aufrufen.

(Firma: Starfleet) #7860969
Lesenswert?

Mit dem RP2350:

1
> CPU: 33 MHz    33426  42691  48748 FLOPS/core
2
> CPU: 66 MHz    66219  85385  97497 FLOPS/core
3
> CPU:133 MHz   133439 172065 196473 FLOPS/core
4
> CPU:266 MHz   266880 344126 392944 FLOPS/core
5
>

Wer also nördlich einer halben Million FLOPS pro Sekunde braucht…

... nimmt einen Prozessor mit integrierter Hardware-Floating-Point-Unit wie den Pico 2 oder andere ...

Wobei man diese Menge floats erstmal aus den Sensoren saugen muß. Eher untypisch für üblich Pico-Anwendungen.

OP #7860981
Lesenswert?

Norbert schrieb:

Mit dem RP2350

Wie gut das letzte Woche einer mit der Post kam. Er ist erstmal in die Schublade gewandert aber nachher probiere ich den Test mal mit dem Teil. Bin noch nicht betriebsbereit ;)

Bradward B. schrieb:

Eher untypisch für üblich Pico-Anwendungen.

Ist auch eher nicht dass Thema hier. Was sinnvoll oder üblich ist oder auch nicht, bitte hier nicht diskutieren. Gibt nur Stress. ;)

(Firma: matzetronics) #7861140
Lesenswert?

Norbert schrieb:

Und nach einem knappen halben Jahrhundert Programmierung in mehr Programmiersprachen als es einem gesunden Menschen gut tut, habe ich da einfach keine Lust mehr drauf.

Da gehts mir ähnlich. Warum soll ich noch in Assembler programmieren, wenn der kleine Pico ganz bequem und interaktiv mit Micropython arbeitet. Und mit 6502 oder Z80 Assembler habe ich mich lange genug gequält, ganz zu schweigen von MCS51 oder MCS48...

#7861147
Lesenswert?

Matthias S. schrieb:

Da gehts mir ähnlich. Warum soll ich noch in Assembler programmieren,

Da habe ich mich missverständlich ausgedrückt. Was ich meinte war: Ich habe keine Lust mehr auf diese zuvor en passant erwähnten dümmlichen Diskussionen.

Scamp/65-/68- Assembler und noch einige mehr sind halt nun Thumb bzw. RISC-V gewichen. Wenn's denn mal richtig pressiert. Aber ich hab's nicht zu einer Religion erhoben, Basis ist eher gesunder Pragmatismus.

OP #7861230
Lesenswert?

Aus diesem Beitrag gelingt mir immerhin schon mal Fall 4 (Assembler, asymmetrisches Signal): Beitrag "Re: PiPico Multicore"

Allerdings hab ich an den Outputs wohl noch etwas falsch konfiguriert. Ich schaue mir das Signal mit dem Scope an und messe nicht mit dem anderen Core. Und das Signal ist eher ein verbogenes Dreieck-Signal.

Du schriebst ja, dass die Portpins das mitgehen können..... da muss ich wohl noch etwas üben ;)

Aber das in Python so schnell zu bekommen, da bin ich auch noch nicht soweit, da übe ich auch noch.

Edit: Wer misst misst Mist. :( Man sollte sein Scope auch richtig einstellen. Der Bandbreitenfilter war eingeschaltet. Und die Masse ist bei den Freqenzen auch nicht so unwichtig ;) Sieht schon besser aus.

OP #7861258
Lesenswert?

900ss schrieb:

Aber das in Python so schnell zu bekommen, da bin ich auch noch nicht soweit, da übe ich auch noch.

Hi Norbert, hast du bitte ein paar Stichwörter für mich? Ich bin Anfänger in Python und ich fürchte da fehlt mir Wissen. Ich nehme nicht an dass du eine Spezialität von Micropython nutzt. Vielleicht den direkten Registerzugriff (toggle).

#7861266
Lesenswert?

900ss schrieb:

Hi Norbert, hast du bitte ein paar Stichwörter für mich? Ich bin Anfänger in Python und ich fürchte da fehlt mir Wissen. Ich nehme nicht an dass du eine Spezialität von Micropython nutzt. Vielleicht den direkten Registerzugriff (toggle).

Klar. Zunächst, vergiss alles was mit der High Level Pin-Klasse zu tun hat. Da hört's schon sehr früh auf Spaß zu machen. Vergleichbar mit der Abstraktion der Abstraktion der Abstraktion eines GPIO bei Arduino. Für LEDs (und Buttons) aber Klasse! ;-)

Also, der @micropython. viper decorator erlaubt dir eine Beschleunigung um ein Vielfaches. Dafür migriert das (natürlich immer noch Python) Erscheinungsbild ein wenig in Richtung C. Des weiteren bekommt man direkte Registerzugriffe, in diesem speziellen Falle des SIO. Dort findet man einen Mechanismus, welcher es gestattet mit einen Befehl einen (oder mehrere) GPIOs zu setzen, zu löschen oder zu toggeln. Viper ist deswegen der Champion, weil man mit einem Python Statement ähnlich einem Pointer direkt auf eines dieser Register zugreifen kann. In nahezu Assembler Geschwindigkeit.

OP #7861274
Lesenswert?

Danke dir. Ok, den viper decorator habe ich benutzt (oder auch native) aber da muss ich mich nochmal mehr schlau machen, wie man damit das meiste herausholt.

Dass das über die Pin-Klasse nicht hinzubekommen ist in der Geschwindigkeit, das leuchtet mir wohl ein. In Assembler habe ich direkt auf die SIO (GPIO) Register geschrieben und dann "b( loop )".

"while true" scheint aber auch eine Schlafmütze zu sein.

OP #7861285
Lesenswert?

Norbert schrieb:

Sollte bei »while True:« aber eigentlich gleich sein.

Ok, jetzt bin ich weiter, am Scope werden ~16.6MHz angezeigt. Vorher kam ich über 280kHz nicht hinaus. Und ich nutze "while 1". Dein Testfall 1 ist erreicht :)

Unglaublich eigentlich. Mit einer Interpretersprache ohne eine Zeile Assembler zu kodieren. Cool!

Jetzt frag ich mich noch, wie du den Testfall 2 hinbekommen hast. Ist ja sogar schneller. wtf....

Edit: while True ist genauso schnell. War aber zu erwarten.

#7861290
Lesenswert?

900ss schrieb:

Unglaublich eigentlich. Mit einer Interpretersprache ohne eine Zeile Assembler zu kodieren. Cool!

Das ist ja das Gemeine! Wenn du eine Funktion in Viper schreibst, wird ein Objekt daraus. Dieses Objekt wird zur Ladezeit automagisch in Assembler kodiert. Man kann sich (mit ein wenig dunkler Magie) die Binäre Repräsentation aus dem Objekt ziehen und als eine Sequenz von Halfwords darstellen. Unter Zuhilfenahme des TR- und AR-Manuals kann man das Zeug in Maschinensprache dekodieren.

#7861301
Lesenswert?

900ss schrieb:

Gibt's irgendwo etwas wo das genauer beschrieben steht?

Tja, das ist die große Enttäuschung (war sie zumindest als ich begann) Doku, almost nada. Also alles Handarbeit.

Könnte mittlerweile – eventuell – mit viel Glück – etwas besser sein. Ganz sicher nicht bis zum Objekt auseinander pflücken und disassemblieren. Aber zumindest eine sanfte Viper Einführung inklusive all den Fallstricken.

OP #7861312
Lesenswert?

Norbert schrieb:

Könnte mittlerweile – eventuell – mit viel Glück – etwas besser sein.

Ich stöbere nochmal. Bisher ist mir nicht unter gekommen.

Alle 4 Testfälle laufen jetzt :) Ist wirklich sehr beeindruckend!

Fehlt nur noch, dass man debuggen kann ;) Aber man könnte den Code evtl. so schreiben, dass er auch auf dem PC läuft. Da kann man dann debuggen.

Danke für's Neugierde wecken und den Tips dazu :)

Edit: Falls du noch einen Tip hast, wie man die Kiste wieder anhält wenn eine loop mit viper oder native läuft, dass wäre schön. Mir gelang bisher nur Reset.

Edit2: das Anhalten wird wohl nur mit Reset funktionieren da sicher eine Maschinencodeschleife läuft und da sonst nichts mehr dazwischen kommt.

OP #7861474
Lesenswert?

@Christoph Dein Zitat ist ein Mix aus echtem Zitat und eigenem Text. Das ist schwer zu verstehen. Machst du aber oft so. Weshalb?

Nachtrag: Äh, sorry, das ist ein Fehler mit der Darstellung auf dem Smartphone. Da wird das Zitat und dann dein geschriebene Text als Zitat angezeigt. War mir bisher nicht aufgefallen. Vielleicht reicht eine Leerzeile zwischen Zitat und dann eigenem Text.

Wenn du mein letztes Posting vollständig gelesen hättest (oder auch den Thread), dann wüsstest du, daß es keine Fehler mehr gibt.

Mit den Hinweisen von Norbert hab ich alles lösen können.

Nachtrag: und ich wollte erstmal selbst graben und es selber zum Laufen bringen damit ich gezwungen bin zu lernen. Erst wenn ich selbst wirklich nicht mehr weiter gewusst hätte, dann würde ich schon den Code posten. Hinweise oder Stichworte sind mir erstmal viel hilfreicher.

OP #7861508
Lesenswert?

Matthias S. schrieb:

Habt ihr das jetzt schon mal mit einer PIO Routine verglichen?

Da ist für mich der Reiz nicht da. Dass die PIO das schafft, daran besteht ja kein Zweifel. Aber Pythoncode, immerhin eine Interpretersprache, der solch schnellen Code erzeugt, das ist schon sehr beeindruckend.

Man muss natürlich schon sehen, das durch viper erzeugter Code nicht überall möglich ist. Es funktioniert mit gewissen Konstrukten und Datentypen. Aber trotzdem kann man bei entsprechendem SW Design enorme Geschwindigkeiten bekommen. Wenn man dann noch die Möglichkeiten der HW richtig nutzt, dann kann man sicher sehr vieles auch in Micropython erledigen.

Ich hätte das nicht vermutet. Deshalb wollte ich das was Norbert im anfangs velinkten Thread gezeigt hat, auch mal nachvollziehen. Mir lässt es ein wenig die Kinnlade runter fallen ;)

#7861527
Lesenswert?

Matthias S. schrieb:

Habt ihr das jetzt schon mal mit einer PIO Routine verglichen?

900ss (900ss) 14.04.2025 08:41

Da ist für mich der Reiz nicht da. Dass die PIO das schafft, daran besteht ja kein Zweifel. Aber Pythoncode, immerhin eine Interpretersprache, der solch schnellen Code erzeugt, das ist schon sehr beeindruckend.

Naja, mit Viper wird's ja eine Art Inline-Asssembler und verliert dann auch viele der nützlichen Eigenschaften von Python (z.B. Float beim PiPico).

#7861530
Lesenswert?

Christoph M. schrieb:

verliert dann auch viele der nützlichen Eigenschaften von Python (z.B. Float beim PiPico).

Nein, nicht korrekt. Float Operationen werden lediglich nicht beschleunigt.

Matthias S. schrieb:

Habt ihr das jetzt schon mal mit einer PIO Routine verglichen? Wenns ums Pin toggeln geht, sollte man hier wohl ähnliche Ergebnisse bekommen, oder?

Nein, mit PIO kann man ½×F_CPU erreichen. Weit außerhalb dessen, was man mit Assembler zu erreichen vermag.

#7861536
Lesenswert?

Norbert schrieb:

Nein, mit PIO kann man ½×F_CPU erreichen. Weit außerhalb dessen, was man mit Assembler zu erreichen vermag.

Wie implementierst/entwickelst Du denn PIO-Abläufe unter Micropython? Gibt es dort einen PIO-Assembler? Vor einigen Jahren hatte ich mit µPython auf dem RP2040 herumgespielt, es aber doch wieder liegen lassen.

OP #7861538
Lesenswert?

Falls mal jemand Lust bekommt zu spielen, der Code im Anhang.

Bitte berücksichtigen, dass ich blutiger Anfänger in Python bin. Erst recht in MicroPython. Bis vor 2 Tagen hatte ich noch nie etwas mit gemacht.

Danke nochmal an Norbert für die Hilfe hier. Und für die Appetithäppchen die hier im Forum verstreut sind ;)

Angehängte Dateien:
#7861548
Lesenswert?

Mi N. schrieb:

Wie implementierst/entwickelst Du denn PIO-Abläufe unter Micropython? Gibt es dort einen PIO-Assembler?

Wurde ja zum teil schon beantwortet. Zusätzlich kann man ein PIO-Programm während der Laufzeit programmatisch generieren und den StateMachines verfügbar machen. Und zu guter Letzt ist es möglich (ebenfalls während der Laufzeit) PIO-Programme aus dem Dateisystem zu laden und nutzen.

OP #7861553
Lesenswert?

Norbert schrieb:

900ss schrieb:

Bitte berücksichtigen, dass ich blutiger Anfänger in Python bin. Erst recht in MicroPython.

Das vergiss mal schnell. Dein Code sieht schon verdammt gut aus.

Ich hab mir Mühe gegeben ;)

Es wäre nur nochmal interessant, woher die Laufzeitunterschiede zwischen V1.19.1 und der aktuellen Version kommen, die ich im Eingangspost beschrieben hatte.

Vielleicht sollte man mal einen Bugreport schreiben. Obwohl Bug ist es ja nicht aber der Unterschied ist signifikant. Evtl. hat das ja auch schon jemand erledigt. Hab nicht nachgesehen.

#7861562
Lesenswert?

900ss schrieb:

Es wäre nur nochmal interessant, woher die Laufzeitunterschiede zwischen V1.19.1 und der aktuellen Version kommen, die ich im Eingangspost beschrieben hatte.

Es sieht wohl so aus als wären die SDK basierten FP-Ops in gewissen Fällen nicht so präzise wie sie sein könnten. In nahezu allen praktischen Fällen hat das zwar wohl noch nie zu Problemen geführt, aber so wie ich das sehe ist nun ein anderes, langsameres jedoch präziseres Modell eingeführt worden.

Da ich – außer bei den speziellen Testprogrammen — noch nie diese Leistung gebraucht habe, ist es mir auch erst nach deinem frischen Test aufgefallen. Das ist OK (für mich) lieber höchstmögliche Präzision bei weniger Dampf. (Man kann µPy übrigens auch für »double« kompilieren)

Zumal ich weiß, wo ich bei Bedarf knapp 800kFlops her bekommen kann. ;-)

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