Ich will mit dem PiPico2 Frequenzen zählen. Das Ganze soll über die Periodendauermessung funktionieren, da ich eine möglichst schnelles Update der aktuellen Frequenz benötige.
Mein Testaufbau ist ein Frequenzgenerator mit 100kHz Rechteck an den Pin16 des PiPico geführt. So wie es aussieht, entstehen hier Fehler bis zu ca. 20%.
Kannst du den Fehler besser beschreiben? Ist für mich nicht klar ob du einen jitter hast oder nur falsche Anzeige. Kenne den Pico nicht, aber brauchst du unbedingt Variable-Typen inkl. double und print?
Ich will mit dem PiPico2 Frequenzen zählen. Das Ganze soll über die
Periodendauermessung funktionieren, da ich eine möglichst schnelles
Update der aktuellen Frequenz benötige.
Wenn es sowohl schnell, als auch genau und ohne CPU Belastung gehen soll, dann empfehle ich nachdrücklich den Schwenk auf die PIO.
Der Pico2 läuft (default) mit 150MHz,
dh. damit ist eine Auflösung von 6 2/3ns möglich.
Wer glatte Zahlen mag, bei 200MHz──▶5ns.
Kenne den Pico nicht, aber
brauchst du unbedingt Variable-Typen inkl. double und print?
Der Pico2 hat zwei FPUs, bei float Addition und Multiplikation innerhalb eines Taktzyklus, Division innerhalb max. acht (IIRC)
Double braucht mit dem CoPro etwas länger, was aber an der Stelle völlig egal ist.
Ich könnte mir vorstellen, dass der ganze multiple Arduiono Überbau/Abstraktion einer präzisen Messung nicht unbedingt zuträglich ist.
Die Anzeige funktioniert ziemlich sicher. Das Diagramm zeigt eher Ausreißer als Jitter. Klar, dass es so was bisweilen gibt. Manchmal auch durch Übertragungsfehlern. Der Screenshot ist vom Plotter der Arduino-IDE und das funktioniert stabil.
Die Ausreißer würde ich eher als Interrupt-Querschläger ansehen. Ich hätte da weniger erwartet, weil ich die Zeitmessung mit "setup1" ja auf den zweiten Kern des PiPico gelegt habe.
Norbert (der_norbert)
Wenn es sowohl schnell, als auch genau und ohne CPU Belastung gehen
soll, dann empfehle ich nachdrücklich den Schwenk auf die PIO.
Da wäre die Frage, ob es überhaupt mit der hohen Auflösung geht. Auch die PIO muss ja ein paar paar Instruktionen durchführen.
Vor allen Dingen scheint mir der Aufwand recht hoch:
Laut
Da wäre die Frage, ob es überhaupt mit der hohen Auflösung geht. Auch
die PIO muss ja ein paar paar Instruktionen durchführen.
Zur ersten Frage: Ja, geht es.
Die PIO arbeitet jede Instruktion innerhalb eines Taktzyklus ab.
Zählen braucht eine, springen braucht eine. (Wenn man's sauber macht)
Da man aber zwölf Statemachines zur Verfügung hat, kann man getrost zwei davon zeitversetzt das gleiche messen lassen.
Ich selbst habe ganz sicher schon tausende Zeilen PIO-Assembler geschrieben (nicht übertrieben) und nicht einmal auf einen Online-Gehgips zurück greifen müssen. Zwei Hände voll Instruktionen stellen jetzt lernmäßig nicht die Eiger Nordwand in den Schatten (Sorry für's Wortspiel)
So wie es aussieht, entstehen hier Fehler bis zu ca. 20%.
Das wundert nicht, da ohne richtige Synchronisierung von Eingangssignal und Referenztakt keine stabile Messungen möglich sind. Entweder verwendest Du externe D-FFs oder eine interne PIO + DMA.
Intern habe ich eine Lösung für den RP2040 auch für Arduino-IDE, die aber beim PicoPi2 wegen vermutlich wieder veränderter Arduino-Version nicht richtig compiliert wird. Beispiele kannst Du hier in der Codesammlung finden.
Läuft die serielle Kommunikation über USB? Dann unterbrechen oder
blockieren die USB-Interrupts sporadisch deinen GPIO-Interrupt, was dann
zu ungenauen Zeitmessungen führt.
Lässt du die Ausgabe der Ergebnisse über einen UART laufen, sollte das
nicht passieren.
Läuft die serielle Kommunikation über USB? Dann unterbrechen oder
blockieren die USB-Interrupts sporadisch deinen GPIO-Interrupt, was dann
zu ungenauen Zeitmessungen führt.
Ich habe das Programm noch mal umgeschrieben und Interrupt-frei gemacht. Es sind dann keine Ausreißer mehr sichtbar. Das Ganze läuft extra ohne alles auf dem zweiten Kern. Aber die maximale Abweichung liegt immer noch einiges über der anvisierten Nanosekundenauflösung (siehe Anhang, y-Achse: us).
Intern habe ich eine Lösung für den RP2040 auch für Arduino-IDE, die
aber beim PicoPi2 wegen vermutlich wieder veränderter Arduino-Version
nicht richtig compiliert wird.
Ich verwende das Early-Hill-Power Framework, das sollte recht stabil sein und besser als das originale Arduino PiPico mit MBed:
https://github.com/earlephilhower/arduino-pico
Dort kann man auch die nativen SDK-Funktionen benutzen (siehe oben im Code "gpio_get" statt digitalRead).
Wo genau kann ich deinen RP2040 Code finden?
Bei der 'Luxusversion' mit TDC gibt es die Ausführungen für IAR-EWARM, Segger-IDE und Arduino, die nahezu identisch sind. Die Messungen laufen alle über Interrupts im Hintergrund. Das bedingt wegen der standardmäßig bei Arduino vorhandenen USB-Schnittstelle auf der einen Seite, daß die Interruptvektoren ins RAM gelegt werden müssen. Auf der anderen Seite muß die 'RP2040.h' der beiden anderen IDEs für Arduino passen und darf nicht mit den dortigen *.h-Dateien kollidieren.
Für Arduino funktionierte das mit IDE V 2.3.2 package "Raspberry Pi Pico 3.7.0". Bei neueren Versionen sind unverständlicherweise die *.h-Dateien geändert/getauscht worden. Mir war es dann zu blöd, diesen Änderungen hinterher zu programmieren.
Im Anhang findest Du meine unvollendete Version, die eigentlich noch um serielle Befehle und Speicherung von Konstanten im FLASH-Speicher ergänzt werden sollte. Zur Datenübertragung wird USB benutzt.
DEF_F1_MESSZEIT (in ms) kannst Du ja auf den benötigten Wert verkleinern.
Ich hoffe, daß die Kommentare schon zur Verion passen.
Ich habe das Programm noch mal umgeschrieben und Interrupt-frei gemacht.
Es sind dann keine Ausreißer mehr sichtbar.
Sehr gut, dann lag es also tatsächlich an den Interrupts.
Aber die maximale Abweichung liegt immer noch einiges über der
anvisierten Nanosekundenauflösung
Mit welche Taktfrequenz läuft der Pico2? Glaubst du wirklich, man könne
damit 1ns auflösen?
(siehe Anhang, y-Achse: us).
Ich habe mal mit großer Anstrengung versucht, die Schwankungsbreite aus
deinem maximal schlecht skalierten Diagramm herauszulesen und komme auf
etwa ±46ns. Das ist besser als ich von einer Lösung mit Arduino ohne PIO
erwartet hätte.
Sind das Messungen? Wenn ja, dann sind sie verdächtig: 1 Bit
Quantisierungsfehler sollte immer drinn sein.
Das sind Messungen. Aber auf einem Controller.
PIO1 erzeugt die Frequenz auf GPIO16, PIO0 misst sie auf GPIO17.
Da muss man nicht so eine große Brücke bauen! ;-)
Also 100% synchron.
Aber du hast recht, wenn man etwas Externes messen würde, dann käme 1 cycle Unschärfe hinzu. (Plus die ppms der beteiligten Quarze)
So wie es aussieht, entstehen hier Fehler bis zu ca. 20%.
von Mi N. (msx)
08.10.2025 09:15
Das wundert nicht, da ohne richtige Synchronisierung von Eingangssignal
und Referenztakt keine stabile Messungen möglich sind. Entweder
verwendest Du externe D-FFs oder eine interne PIO + DMA.
Da ist mir nicht ganz klar, wie du das meinst. Eigentlich sollte der Jitter ja nur 1 Taktzyklus betragen. Wie oben gezeigt, schafft das Norbert ja mit 5ns Auflösung. Wenn man nicht mit einem synchronisiert, sollte das dann +-5ns sein.
Da ist mir nicht ganz klar, wie du das meinst. Eigentlich sollte der
Jitter ja nur 1 Taktzyklus betragen.
Ja, aber erst, wenn man auch die Verarbeitung der Ereignisse dem 2. Kern überträgt.
Mit "richtiger Synchronisierung" meine ich, daß man synchron zu einem Eingangsereignis dessen Zählerstand und auch des Referenzzählers einfriert ('capture') und später verarbeiten kann. Das war bei Deiner eingangs gezeigten Programmversion ja nicht der Fall. Loop() bei Arduino bedeutet, daß noch viele 'unsichtbare' Funktionen ausgeführt werden, die zeitlich nicht begrenzt sein müssen. Anders wäre es bei einer while()-Schleife, wo nur ISRs dazwischen funken können.
Damit bekommt man auch Frequenzmessungen auf 20 Stellen stabil :-)
Klar. Bin aber ein fauler Sack und hatte keine Lust einen Zweiten dran zu hängen. ;-)
Es ging aber auch nur um den Jitter, welcher bei dieser Kopplung aus verständlichen Gründen ›0‹ ist und bei Fremdfütterung max. 1 cycle beträgt.
Du bist ja auch Profi und hast keine Arduino-IDE benutzt!
Ich denke, er hat MicroPython benutzt.
Alles bis ein paar hundert MHz und wenige Nanosekunden lässt sich damit ja prima handeln.
Und für hundert Zeilen Code wirft man doch keinen C-Compiler an.
Allenfalls sollte man sich ueberlegen, was man genau will. Falls die Messung fuer einen visuellen Zahlen Display gedacht ist, bringen mehr wie 3-10 updates pro sekunde nichts. Die kann man nicht ablesen.
Falls man den Wert fuer eine Regelung will genuegt meist die Periodendauer in zufaelligen Einheiten, sprich der Zaehlerwert passt.