Forum: Mikrocontroller und Digitale Elektronik Portpin toggelt in Arduino zu langsam, warum?


von Daniel (Gast)


Lesenswert?

Hab mal paar "Experiemte" mit dem Arduino Mega gemacht.
Dabei interessierte mich, wie schnell ein Portpin in Software zu toggeln 
ist.

Ein einfacher "Sketch" brachte es auf 78,7 KHz.
Bei 16MHz viel zu wenig.

Vergleichsweise schafft man es in Assembler auf 2,6667MHz, in C ebenso.

Hier der Arduino "Pseudocode":

//Ardurino Pin 12 so schnell wie möglich in Software toggeln
int port = 12;

void setup() {
  pinMode(port, OUTPUT);
}
void loop() {
  digitalWrite(port, HIGH);
  digitalWrite(port, LOW);
}

Dafür braucht die CPU 630.400 Zyklen?????

In Assembler:

.INCLUDE "m2560def.inc"
  rjmp  main
main:
  ldi  R16,0xFF
  out  DDRB,R16

  ldi  R16,0xFF
  out  PORTB,R16

  sbi portb,6
  cbi portb,6
  rjmp PC-2

Ein Durchlauf benötigt 6 Zyklen.
Benutz man stattdessen in der Schleife nur "SBI PINB,6" (der Mega 2560 
kann das, dann sind es 8, also genau 2 MHz.

Was bremst den Arduino-Code so aus? Was macht "DigitalWrite" alles noch?

von g457 (Gast)


Lesenswert?

> Was bremst den Arduino-Code so aus?

Das SDK. Klücklicherweise muss man das nicht nutzen.

von Daniel (Gast)


Lesenswert?

Nachtrag:
andere Portpins schaffen es auf 100KHz..

von Lorstan (Gast)


Lesenswert?

Kuck doch einfach mal rein in digitalWrite(). Ist ja OpenSource.
Hatte es neulich gemacht. Kann mich noch dran erinnern, dass der Pin 
auch als PWM Pin und anderes benutzt werden kann.

von Karl H. (kbuchegg)


Lesenswert?

Daniel schrieb:

> Ein einfacher "Sketch" brachte es auf 78,7 KHz.
> Bei 16MHz viel zu wenig.

Nicht für einen Arduino.


> Was bremst den Arduino-Code so aus? Was macht "DigitalWrite" alles noch?

feststellen welcher Pin zu '12' gehört und den dann je nachdem ob du 
High oder Low haben willst, schalten.
Danach: den return aus loop() machen.
Beim Aufrufer dann die Buchhaltung durchführen, loop() wieder aufrufen 
und den nächsten digitalWrite machen.

: Bearbeitet durch User
von Timmo H. (masterfx)


Lesenswert?

1
void digitalWrite(uint8_t pin, uint8_t val)
2
{
3
        uint8_t timer = digitalPinToTimer(pin);
4
        uint8_t bit = digitalPinToBitMask(pin);
5
        uint8_t port = digitalPinToPort(pin);
6
        volatile uint8_t *out;
7
8
        if (port == NOT_A_PIN) return;
9
10
        // If the pin that support PWM output, we need to turn it off
11
        // before doing a digital write.
12
        if (timer != NOT_ON_TIMER) turnOffPWM(timer);
13
14
        out = portOutputRegister(port);
15
16
        uint8_t oldSREG = SREG;
17
        cli();
18
19
        if (val == LOW) {
20
                *out &= ~bit;
21
        } else {
22
                *out |= bit;
23
        }
24
25
        SREG = oldSREG;
26
}
Wen wundert es dass es länger dauert...

von Amateur (Gast)


Lesenswert?

... oder anders ausgedrückt: Die Wolle, der eierlegenden Wollmilchsau, 
ist nicht die Feinste und die Eier könnten etwas größer sein.

Auch ohne je in die Bibliotheken geschaut zu haben, sollte das obige 
Ergebnis eigentlich vorhersehbar sein - wenn auch vielleicht nicht in 
der aufgezeigten Größenordnung.

von Daniel (Gast)


Lesenswert?

Sind natürlich bei 78,8KHz "nur" ca 101 Zyklen für einen 
Umschaltvorgang. Das ist ja irre...

von Karl H. (kbuchegg)


Lesenswert?

Daniel schrieb:
> Sind natürlich bei 78,8KHz "nur" ca 101 Zyklen für einen
> Umschaltvorgang. Das ist ja irre...

Nö. Nicht für einen Umschaltvorgang.
Für einen kompletten Turnaround von einem Aufruf von loop() zum 
nächsten, vergehen 203 Takte.
Und das ist dann ein bischen was anderes.
Oder denkst du, dass du zb eine Systemuhr gratis kriegst?

: Bearbeitet durch User
von Daniel (Gast)


Lesenswert?

ein Umschaltvorgang ist doch von 0->1  oder umgekehrt. Dabei vergehen 
101 Take. 2 Umschaltvorgänge sind dann ein (kompletter)Zyklus.
Oder was meinst du mit Systemuhr?

von Amateur (Gast)


Lesenswert?

Wenn man aber von, oft sehr unrealistischen Megaherzphantasien 
herunterkommt: Ist das wirklich zu langsam?

Oder anders ausgedrückt: Wie realistisch ist die obige Schleife mit, 
völlig unrealistischen 6 bzw. 8 Taktzyklen?

Das Minimum der obigen Schleife enthält eine - wie auch immer geartete - 
Zählerabfrage. Also nix mit 6/8 Taktzyklen.

Meine Aktivitäten in Sachen Pin setzten folgten bisher immer dem Chema:

...
Grübel, grübel
Pin an
Grübel, grübel
Pin aus
...

Das Minimum war das Abholen von Messwerten und einfache Vergleiche. Das 
Maximum waren komplexe Rechnungen und Spaziergänge quer durch die 
Fließkommabibliotheken.
Irgendwann werden dann plötzlich zusätzliche 203 Takte zu einem Nichts, 
oder man stellt fest, dass der Prozessor ungeeignet ist.

von holger (Gast)


Lesenswert?

>Irgendwann werden dann plötzlich zusätzliche 203 Takte zu einem Nichts,

Mach mal ein Software SPI oder PWM. Dann wird ganz schnell klar
warum das nichts taugt.

von Daniel (Gast)


Lesenswert?

Mir ging es primär gar nicht darum irgendwelche MHz Orgien zu 
veranstalten.
Dafür gibt es Fast PWM & Co.
Wollte einfach nur wissen, ob der so unschuldig aussehende 
"DigitalWrite" Befehl wirklich nur den Pin - so wie im 
Assembler-Beispiel -  ohne weitere Verzögerung umschaltet. Tut er nicht, 
ok.
Damit ist er ungeeignet, wenn es mit dem Timing mal wirklich knapp 
zugeht. Möchte garn nicht wissen, was die anderen Adruino Makros so 
alles veranstalten.
Schon die kompilierte Codegröße hat mich stutzig gemacht.

von Amateur (Gast)


Lesenswert?

@Holger
>Mach mal ein Software SPI oder PWM. Dann wird ganz schnell klar
>warum das nichts taugt.

Stimmt, aber ...

@Daniel
>Damit ist er ungeeignet, wenn es mit dem Timing mal wirklich knapp
>zugeht. Möchte garn nicht wissen, was die anderen Adruino Makros so
>alles veranstalten.

Macht’s wie ich. Bisher habe ich drei Arduinos verwendet. Bei Zweien 
habe ich, wenn auch aus anderen Gründen, die Entwicklungsumgebung 
beiseitegeschoben und das "normale" Studio rangelassen. ISP bringt’s.

Ein Grund für den Arduino blieb nämlich: Es ist ein relativ günstiges 
und gut dokumentiertes Stück Elektronik, welches in zwei Fällen, die 
gesamte benötigte Elektronik enthielt. Im dritten Fall war der Micro 
ein, die gesamte Schaltung vereinfachendes, "IC".

von Axel S. (a-za-z0-9)


Lesenswert?

holger schrieb:
>>Irgendwann werden dann plötzlich zusätzliche 203 Takte zu einem Nichts,
>
> Mach mal ein Software SPI oder PWM. Dann wird ganz schnell klar
> warum das nichts taugt.

Warum sollte man SPI oder PWM mit digitalWrite() machen? Schließlich ist 
das ja eine der (har har) Stärken von Arduino, daß man SPI und PWM als 
Fertigteil bekommt, das man nur noch einstöpseln muß.

Dein Argument ist in etwa auf dem Niveau, daß sich Ytong-Steine schlecht 
als Bauklötze eignen, weil die damit gebauten Projekte so schlecht ins 
Kinderzimmer passen.


XL

von Karl H. (kbuchegg)


Lesenswert?

Daniel schrieb:
> ein Umschaltvorgang ist doch von 0->1  oder umgekehrt. Dabei vergehen
> 101 Take. 2 Umschaltvorgänge sind dann ein (kompletter)Zyklus.
> Oder was meinst du mit Systemuhr?

Nein. Ich meine, dass das Arduino System(!) im Hintergrund auch noch 
andere Sachen macht. Deine Endlosschleife ist eben nicht dasselbe, wie 
die Funktion loop(). Denn da gibt es auch noch einen Aufrufer, der 
loop() ständig aufruft und zwischen den Aufrufen auch noch Dinge 
erledigt. Ich würde durchaus soweit gehen und dem Arduino System bereits 
Eigenschaften eines kleines Betriebssystems zusprechen.

Kurz gesagt: du vergleichst in einem gewissen Sinne Äpfel mit Birnen.

: Bearbeitet durch User
von PittyJ (Gast)


Lesenswert?

Ist zwar langsam, dafür ist es einfach.
Wenn ich vergleiche, was da sonst für Bitfriemeleien notwendig sind, 
(30% der Post hier gehen ja um solche Probleme beim Ansprechen eines 
Ports)

So ist das halt im Leben:
-- schnell, und es wird hart
-- einfach, und es dauert eben.

Für die meisten Anwendungen reichen die 70 KHz doch aus.

von Stefan (Gast)


Lesenswert?

Meine Fresse, da ist ja sogar Java (ohne JIT Compiler) besser. Ich habe 
bisher noch nie mit der Arduino Software gearbeitet, aber spätestens 
jetzt ist sicher, dass ich es auch niemals tun werde.

Falls da mal ein Job-Angebot kommt: Nein Danke.

von Uwe (Gast)


Lesenswert?

> Meine Fresse, da ist ja sogar Java (ohne JIT Compiler) besser.
Dann lass mal Java auf ner 16MHz CPU laufen ...

von Peter D. (peda)


Lesenswert?

PittyJ schrieb:
> Ist zwar langsam, dafür ist es einfach.
> Wenn ich vergleiche, was da sonst für Bitfriemeleien notwendig sind,

Wenn man weiß wie, geht es auch schnell und einfach:

Beitrag "Re: Makros versus Funktionen"

von Peter D. (peda)


Lesenswert?

Timmo H. schrieb:
> void digitalWrite(uint8_t pin, uint8_t val)

Warum werden dann in den Arduino-Beispielen immer 16 Bit (int) 
übergeben?
Wozu diese Verschwendung auf nem 8-Bitter?

Timmo H. schrieb:
> uint8_t timer = digitalPinToTimer(pin);
>         uint8_t bit = digitalPinToBitMask(pin);
>         uint8_t port = digitalPinToPort(pin);
> ...
>         if (timer != NOT_ON_TIMER) turnOffPWM(timer);
>         out = portOutputRegister(port);

Schonmal 5 Unterfunktionsaufrufe, kein Wunder, daß da heftig Laufzeit 
zustande kommt.

von SE (Gast)


Lesenswert?

Da gibts aber noch mehr tücken beim Arduino Sketch:

kopiert von:
http://vpapanik.blogspot.gr/2012/08/arduino-thank-you-and-bye-bye.html

digitalWrite() takes 56 cycles to execute (well, I measured 400). At 
least it is easy to find out why and switch to direct port access (the 
second thing to change, after the IDE). Generally, Arduino is not very 
friendly for time-efficient coding.

You cannot (at least, easily) disable the default hardware serial 
library, in order to take over the TX and RX interrupts, no matter if it 
has been started or not !

There's a overflow timer ISR firing every 16K clock cycles in the 
background. This is for servicing millis() and micros() functions, even 
when they're not used at all !

An empty Arduino project takes 466 bytes on an Arduino UNO and 666 bytes 
on an Arduino Mega 2560. I dislike overheads a lot. I also dislike 
seeing warnings during compiling of the above.

von Quak (Gast)


Lesenswert?

Mal wieder viel Beitraege zu denen man nur sagen kann: "Wenn man keine 
Ahnung hat, einfach mal Fresse halten!". Immer wieder erschreckend, wie 
viel Energie in's Bashing und wie wenig in's KnowHow gesteckt wird.

von Stefan (Gast)


Lesenswert?

>> Meine Fresse, da ist ja sogar Java (ohne JIT Compiler) besser.
>Dann lass mal Java auf ner 16MHz CPU laufen ...

Bei Lego Mindstorms klappt das ganz gut mit 32Mhz.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.