Da ja mittlerweile verschiedene MCUs durch die Arduino IDE unterstützt
werden, möchte ich mal wissen, wie schnell die Peripherie damit ist.
Hier mal der erste Test mit einem Arduino Uno:
digitalWrite speed benchmark
=============================
number of tries: 100000 duration [us]: 519212 ==> speed
[megaSamples/second] : 0.19
analogRead speed benchmark
=============================
number of tries: 100000 duration [us]: 11200052 ==> speed
[kiloSamples/second] : 8.93
Knapp 9kHz für den ADC ist fast ein wenig langsam. Jetzt bin ich mal
gespannt, wie schnell so was auf einem STM wird.
Wenn du die Register direkt ansprichst, geht es VIEL schneller.
Genau genommen hast du da nicht die Performance des µC getestet, sondern
die Performance des Arduino Frameworks.
Markus schrieb:> Knapp 9kHz für den ADC ist fast ein wenig langsam.
Die Ergebnisse sollten einem motivieren mal ins "richtige"
Programmieren überzugehen.
>Die Ergebnisse sollten einem motivieren mal ins "richtige">Programmieren überzugehen.
Stell Dir mal vor, wenn Du den Job seit 30 Jahren machst ( so wie ich )
und zig Prozessorarchitekturen hinter Dir hast wird es irgendwann mal
langweilig und zu umständlich sich mit jeder zusätzlich hinzu kommenden
Architektur zu befassen.
Wenn Du dann einfach nur Problem lösen willst, kommt die Zeit der
Software Frameworks die eine platformunabhängige und einfache
Programmierung erlauben.
Mach es einfach mal lange genug, dann wirst Du schlauer.
>Wenn du die Register direkt ansprichst, geht es VIEL schneller.>Genau genommen hast du da nicht die Performance des µC getestet, sondern>die Performance des Arduino Frameworks.
Weiß ich. Das war genau die Absicht: Der Test des Gesamtsystems.
Markus schrieb:> Knapp 9kHz für den ADC ist fast ein wenig langsam. Jetzt bin ich mal> gespannt, wie schnell so was auf einem STM wird.
Selbst 190khz beim digitalWrite ist eigentlich mehr als lächerlich, was
macht das Framework?! Startet der für jeden Pin-Change den µC neu oder
warum ist das so miserabel?!
>Selbst 190khz beim digitalWrite ist eigentlich mehr als lächerlich, was>macht das Framework?! Startet der für jeden Pin-Change den µC neu oder>warum ist das so miserabel?!
Es abstrahiert den Pin-Zugriff durch eine Pin-Nummer, damit die Software
auf Boards mit verschiedenen MCUs läuft. Man kann z.B. einen Arduino
Uno mit Atmega328 und einen Arduino Due mit ARM-MCU austauschen:
https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/wiring_digital.c
( Zeile 138 )
Es gibt schnellere Versionen mittels C++ Templates, aber die wurden
leider nie in den Main-Zweig aufgenommen.
Hier das Ergebnis mit einem der Arduino-Frameworks auf dem Nucleo-64 (
STM32L476 ):
digitalWrite speed benchmark
=============================
number of tries: 100000 duration [us]: 39651 ==> speed
[megaSamples/second] : 2.52
analogRead speed benchmark
=============================
number of tries: 100000 duration [us]: 3258145 ==> speed
[kiloSamples/second] : 30.69
Der Pin Zugriff ist hier deutlich schneller, aber der ADC mit
~30kSamples/s nicht so richtig überzeugend.
Jörg schrieb:> Dann wären die Ergebnisse vergleich- und nachvollziebar.
Wenn ich weiss dass ich beim AVR im direkten Programmieren
den Faktor 10 beim DigialWrite erreichen kann brauch ich
kein Testprogramm mehr um irgendwas nachzuvollziehen.
Your mileage may vary. Sagte schon immer der Franzose.
Ist halt so, Arduino kostet.
Aber wie viel konkret ist nicht nur von der Plattform, sondern auch von
der Implementierung abhängig.
Und von dem was man da gerade macht.
Das Bild ist für den Code hier:
1
digitalWrite(D8, LOW);
2
digitalWrite(D4, LOW);
Also im Grunde messe ich da wie lange es dauert einen Pin zu setzen.
Das läuft da gerade auf einem ESP8266 mit 80MHz, die 438ns sind also nur
35 Taktzyklen was für Arduino schon am unteren Ende der Skala sein
dürfte.
Andererseits messe ich auch das hier:
1
SPI.transfer(0x55);
2
SPI.transfer(0x55);
Damit sehe ich auf dem Scope zwischen dem Ende des ersten Transfers und
dem Anfang des nächsten Transfers eine Lücke von 2,3µs, das sind 184
Taktzklen für was auch immer.
Zusammen sieht das so aus:
1
digitalWrite(D8, LOW);
2
digitalWrite(D4, LOW);
3
SPI.transfer(0x55);
4
SPI.transfer(0x55);
5
digitalWrite(D8, HIGH);
6
digitalWrite(D4, HIGH);
Zwischen Low für D4 und der ersten Flanke auf SCK vergehen 1,7µs, es
werden also 136 Taktzyklen benötigt um die Daten auf den SPI zu werfen
und nach dem Transfer noch mal schlapp 50 Zyklen um wieder zurück zu
kommen.
Ich würde mal vermuten, dass da noch Potential für Optimierungen ist.
Alles nicht schlimm, muss man nur mit rechnen.
Und durch verschiedene Implementierungen auch nicht unbedingt
vergleichbar.
In Deinem Oszi Bild steht 1/dt=2.28Mhz
Das ist relativ nahe an den 2.52 MSPs aus meinem Benchmark.
Du könntest auch einfach mal den Benchmark laufen lassen.
Markus schrieb:> tell Dir mal vor, wenn Du den Job seit 30 Jahren machst ( so wie ich )> und zig Prozessorarchitekturen hinter Dir hast wird es irgendwann mal> langweilig und zu umständlich sich mit jeder zusätzlich hinzu kommenden> Architektur zu befassen.> Wenn Du dann einfach nur Problem lösen willst, kommt die Zeit der> Software Frameworks die eine platformunabhängige und einfache> Programmierung erlauben.> Mach es einfach mal lange genug, dann wirst Du schlauer.
Ja, ich finde die Frameworks auch nicht schlecht. Bei vielen einfachen
Aufgaben kommt man so schnell zum Ziel.
Leider kommt man auch schnell an die Grenzen und kann mit Framework die
gewünschte Performance oder den gewünschten niedrigen Energiebedarf
nicht erreichen.
Weiterhin führen die Frameworks dazu, dass fast jeder ohne
Expertenwissen schnell zum Ziel kommen kann. Dies wiederum führt in
einigen Fällen zu einer schlechten Performance, da nicht nur das
notwendige, sondern das Framework in der Software mitgeschleppt wird.
Man sieht es bei ganz vielen Anwendungen: Ein
Klick/Tastendruck/Tipp/Wisch und das Warten geht los. Zügige
Datenverarbeitung, schnelle Datenanzeige und gutes Reaktionsvermögen auf
Benutzereingaben schließen sich bei manchen System quasi gegenseitig
aus.
Zusätzlich lassen Frameworks natürlich aufgrund ihrer einfachen
Handhabbarkeit auch eine gewisse Betriebsblindheit und eine gewisse
Faulheit zu. Daher sollte man wachsam bei der Benutzung solcher
Frameworks sein um nicht nur eine Lösung, sondern auch eine gute Lösung
zu finden.
Alles in Allem: Frameworks sind eine gute Sache, dennoch sollte man in
manchen Fällen auf sie verzichten können. Dazu ist es leider notwendig,
sich in verschiedene Architekturen einzuarbeiten, sofern man für
verschiedene Architekturen Software schreibt.
number of tries: 100000 duration [us]: 96273 ==> speed [megaSamples/second] : 1.04
4
5
analogRead speed benchmark
6
=============================
7
8
Soft WDT reset
9
10
ctx: cont
11
sp: 3ffef280 end: 3ffef4c0 offset: 01b0
Tja, nun. :-)
Gibt der "Benchmark" die Zeit für Pin-Wechsel und zurück an? Also 0-1-0?
Gemessen habe ich ja nur 1-0.
Und Watchdog-Reset, tja, mehr als ein paar hundert ms sollte die loop()
nicht laufen.
Ein freundliches "ESP.wdtDisable();" im Code hat gar nichts bewirkt.
Also weniger Durchläufe:
1
digitalWrite speed benchmark
2
=============================
3
number of tries: 10000 duration [us]: 9648 ==> speed [megaSamples/second] : 1.04
4
5
analogRead speed benchmark
6
=============================
7
number of tries: 10000 duration [us]: 1064127 ==> speed [kiloSamples/second] : 9.40
Rudolph schrieb:> Ein freundliches "ESP.wdtDisable();" im Code hat gar nichts bewirkt.
Das darf dich nicht wundern!
Der WDT ist nicht abschaltbar.
Ganz so, wie es bei einem WDT auch sein sollte.
Danke ;-)
>Gibt der "Benchmark" die Zeit für Pin-Wechsel und zurück an? Also 0-1-0?
Eigentlich nicht, es sind 8 digitalWrite in der "unrolled loop":
https://www.mikrocontroller.net/attachment/highlight/327826
Seltsam ....
Gerade eben habe ich eine Template Library für die AVR-Arduinos
gefunden, die ist extrem gut dokumentiert und sehr schnell: Sie erreicht
die maximal mögliche Geschwindigkeit für AVR-Prozessoren.
https://github.com/mmarchetti/DirectIO
Leider nur für AVR, die ARMS wären schön ...
Arduino F. schrieb:>> Ein freundliches "ESP.wdtDisable();" im Code hat gar nichts bewirkt.> Das darf dich nicht wundern!> Der WDT ist nicht abschaltbar.> Ganz so, wie es bei einem WDT auch sein sollte.
Warum darf mich das nicht wundern wenn die Funktion genau für sowas in
das Framework mit eingebaut wurde?
Aber egal, ich benötige die sicher nicht.
Markus schrieb:> Eigentlich nicht, es sind 8 digitalWrite in der "unrolled loop":> https://www.mikrocontroller.net/attachment/highlight/327826>> Seltsam ....
Tja, aber da glaube ich lieber meinem Oszi. :-)
Wenn das der Overhead durch die Schleife ist, dürfte das auf einem AVR
auch noch mehr ausmachen.
Markus schrieb:> Knapp 9kHz für den ADC ist fast ein wenig langsam.
Ein Blick ins Datenblatt verrät, die Wandlerfrequenz muß im Bereich
50..200kHz liegen und eine Wandlung dauert 13 Takte.
Damit ergibt sich eine Wandlerrate von 3,8 ... 15kHz.
Der ADC-Teiler kann nur binare Schritte. Wenn also der Quarz unglücklich
gewählt wurde und es kämen 201kHz raus, mußt Du die nächste Teilerstufe
nehmen, d.h. 100,5kHz (Wandlerrate = 7,7kHz).
Für 15kHz bräuchtest Du einen 12,8MHz Quarz.
Rudolph schrieb:> Warum darf mich das nicht wundern wenn die Funktion genau für sowas in> das Framework mit eingebaut wurde?
Ein Blick in den Quellkot offenbart wundersames:
1
voidEspClass::wdtDisable(void)
2
{
3
/// Please don't stop software watchdog too long (less than 6 seconds),
4
/// otherwise it will trigger hardware watchdog reset.
5
system_soft_wdt_stop();
6
}
Du kannst mit der Funktion also nur den Software WDT abschalten.
Den Hardware WDT tangiert das nicht.
Peter D. schrieb:> Wenn also der Quarz unglücklich> gewählt wurde und es kämen 201kHz raus, mußt Du die nächste Teilerstufe> nehmen,
Das ist wie beim Yoghurt:
Wenn nachts um 0:00 Uhr das Verfallsdatum eintritt fängt der
sofort spontan das schimmeln an.
Peter D. schrieb:> Ein Blick ins Datenblatt verrät, die Wandlerfrequenz muß im Bereich> 50..200kHz liegen und eine Wandlung dauert 13 Takte.> Damit ergibt sich eine Wandlerrate von 3,8 ... 15kHz.
Mit 15kHz kriegst du aber nicht mehr die 10bit Auflösung
Markus schrieb:> Knapp 9kHz für den ADC ist fast ein wenig langsam
Ist in etwa die maximale Samplingrate für den ADC...
Markus schrieb:> Es abstrahiert den Pin-Zugriff durch eine Pin-Nummer
Schlimmer noch, die Pinnummer einer ganz bestimmten Bauform eines ganz
bestimmten AVR-Typs. Es ist also ein Unterschied, ob der MC im PDIP,
TQFP oder MLF-Gehäuse ist. Mal ist PD0 Pin 2, 30 oder 26.
Wenn man dann den MC in einer echten Schaltung einbaut und aber im
Framework irgendwelche Fantasie-Pinnummern findet, kann man sich nur
noch die Karten legen.
Beim Arduino Framework beziehen sich die Pin-Namen auf die Stiftleisten.
Genau dafür taugt das sehr gut.
Wer kein Arduino Board verwendet, kann sich ja sein eigenes Mapping
definieren.
Arduino F. schrieb:> Ein Blick in den Quellkot offenbart wundersames:void> EspClass::wdtDisable(void)> {> /// Please don't stop software watchdog too long (less than 6> seconds),> /// otherwise it will trigger hardware watchdog reset.> system_soft_wdt_stop();> }>> Du kannst mit der Funktion also nur den Software WDT abschalten.> Den Hardware WDT tangiert das nicht.
Na okay, auch schön, es gibt also zwei Watchdogs und wenn man den einen
mit dieser Funktion abschaltet hat man ungefähr sechs Sekunden bis der
andere anspringt.
Ein Aufruf mit 50.000 statt 100.000 könnte also gerade noch so drin
sein, so zusätzlich zu dem was sonst noch in der loop() ist.
Peter Dannegger
>Schlimmer noch, die Pinnummer einer ganz bestimmten Bauform eines ganz>bestimmten AVR-Typs.
Stefan Us
>>Beim Arduino Framework beziehen sich die Pin-Namen auf die Stiftleisten.>>Genau dafür taugt das sehr gut.
Um das noch mal etwas besser zu verdeutlichen hier zwei Bilder mit dem
Arduino Uno und dem Nucleo-64 Board.
Die Pin-Nummern bezeichnen die Nummern des Arduino-Standart Headers.
Auf dem Nucleo steht zwar D0, D1 .. usw meint aber digital Pin 0,1 ...
Markus schrieb:> Stell Dir mal vor, wenn Du den Job seit 30 Jahren machst ( so wie ich )> und zig Prozessorarchitekturen hinter Dir hast wird es irgendwann mal> langweilig und zu umständlich sich mit jeder zusätzlich hinzu kommenden> Architektur zu befassen.> Wenn Du dann einfach nur Problem lösen willst, kommt die Zeit der> Software Frameworks die eine platformunabhängige und einfache> Programmierung erlauben.
"seit 30 Jahren" macht den Unterschied! Zu der Zeit hatte ich den
68HC805 im Einsatz und in Assembler Zyklen gezählt, weil ich
Zeitprobleme hatte.
Ganz sicher hast Du über die Zeit ein Gefühl entwickelt, welche
Geschwindigkeit wirklich notwendig ist.
Du kannst abschätzen, ob Arduino für Deine konkrete Anwendung
ausreichend Geschwindigkeit bietet oder nicht.
Du weißt, dass Du "Fußpilzebene" könntest und hast es nicht nötig, über
die Bastler herzuziehen oder den xxx zu verlängern, weil Du per
Assemblercode länger auf Ereignisse warten kannst.
Jetzt erzeugst Du Benchmarks und schätzt den Gesamtaufwand ab, ob ein
größerer µC mit Arduino oder ein kleiner in Assembler sinnvoller wäre.
Also: Gute Vorgehensweise, ich habe nichts auszusetzen :-)
>"Fußpilzebene"
loll :-)
>Ist in etwa die maximale Samplingrate für den ADC...
Harspalterisch könnte ich mich jetzt darauf versteifen, dass der ATMEGA
ADC auch auf 150kHz übertackted werden kann. Das funktioniert in der
Praxis gar nicht so schlecht.
Auf was ich eher hinaus wollte war aber, dass der schnellste ADC des
STM32L467 eigentlich 5MSPs kann ( wenn ichs in den Specs richtig
überflogen habe ) aber im Benchmark nur 30kSps erreicht werden.
Aber vielleicht haben sie sich ja auch am Arduino-Uno grob orientiert.
Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.
Wichtige Regeln - erst lesen, dann posten!
Groß- und Kleinschreibung verwenden
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang