Go Down

Topic: Warum hat digitalWrite disassembly so viel Overhead? (Read 754 times) previous topic - next topic

Helmuth

Mar 13, 2013, 10:30 pm Last Edit: Mar 13, 2013, 10:33 pm by Helmuth Reason: 1
Hi,

ich beziehe mich auf diesen Artikel hier: http://waitingforbigo.com/2013/02/19/introducing-fastpin-the-low-level-heart-of-fastspi_led2/

Ich stecke noch nicht tief genug in der Materie, um den disyssembly code von digitalWrite zu verstehen, aber warum ist er so viel länger, als die schnelle Version? Was passiert da alles und warum?


Doc_Arduino

Hallo,

Du meinst unten den Teil mit den vielen vielen Zeilen und drüber mit dem unverständlichen Code?
Das ist Assemblerprogrammierung. Assembler ist absolut Hardware nah. Näher gehts nicht. Der Compiler zeigt Dir für den Befehl die benötigten Takte an. Man weis also genau wieviel Zeit wofür benötigt wird. Wenn man das letzte aus dem µC rausquetschen muß oder will, dann eben Assembler. Nur weil das sehr schwierig zu programmieren ist wurden Hochsprachen wie C erfunden. Die vereinfachen vieles. Der kleine Nachteil von Hochsprachen das der Compiler das nicht ganz so perfekt übersetzt kann man glaube ich vernachlässigen. Die Hochsprachenkompiler heutzutage sind schon sowas von perfekt. Das das überhaupt immer so funktioniert erstaunt nicht immer wieder

Tschau
Doc Arduino

Helmuth

#2
Mar 14, 2013, 06:46 am Last Edit: Mar 14, 2013, 09:16 am by Helmuth Reason: 1
Ja Doc, dass das Assembler ist, war mir bereits aufgefallen...

Frage nochmal anders: Wenn es Daniel schafft, binnen 4 Takten ein Bit zu senden - warum ist digitalWrite dagegen so aufwendig und langsam?

MaFu

Dann schau Dir halt einfach mal an, was die Funktionen im Hintergrund so alles treiben.
In diesem Fall wäre es die Datei "hardware\arduino\cores\arduino\wiring_digital.c"

digitalWrite()
Code: [Select]
void digitalWrite(uint8_t pin, uint8_t val)
{
    uint8_t timer = digitalPinToTimer(pin);
    uint8_t bit = digitalPinToBitMask(pin);
    uint8_t port = digitalPinToPort(pin);
    volatile uint8_t *out;

    if (port == NOT_A_PIN) return;

    // If the pin that support PWM output, we need to turn it off
    // before doing a digital write.
    if (timer != NOT_ON_TIMER) turnOffPWM(timer);

    out = portOutputRegister(port);

    uint8_t oldSREG = SREG;
    cli();

    if (val == LOW) {
        *out &= ~bit;
    } else {
        *out |= bit;
    }

    SREG = oldSREG;
}
_______
Manfred

uwefed

#4
Mar 14, 2013, 08:44 am Last Edit: Mar 14, 2013, 08:52 am by uwefed Reason: 1

Ja Doc, dass das Assembler ist war mir bereits aufgefallen...

Frage nochmal anders: Wenn es Daniel schafft binnen 4 Takten ein Bit zu senden, warum ist digitalWrite dagegen so aufwendig und langsam?


Wenn Du Dich auf dies beziehst:
Quote
(for example, when bitbanging SPI output, the inner loop of the fast SPI code can push out a bit every 4 cycles – 2 to determine if the current bit is hi or lo, 2 to set the data line appropriately and strobe the clock)! 

Dann ist Deine Aussage falsch.
Um ein AusgangsPin zu setzen muß zuerst der Port gelesen werden, dann modifiziert und dann zurückgeschrieben werden um nur ein Bit zu ändern. Liest man den aktuellen Status nicht ein verändert man den Zustand möglicherweise für alle 6-8 Pins eines Ports.
Das ist nicht in 4 Taktzyklen zu machen. Wenn Du den Kode, den MaFu zeigt ansiehst, ist das Verändern des Portzustand nicht eine einfache Sache, sondern es muß unterschieden werden, ob der Pin auf HIGH zu setzen ist oder auf LOW.

Grüße Uwe

Helmuth

Hallo,

@MaFu: Danke für den Link zur Datei, ich hatte nicht auf dem Schirm, dass ich mir das ja alles selbst ansehen kann, was die Befehle eigentlich machen... Genau genommen habe ich mir, außer im Libraries Verzeichnis, noch keine einzige Datei im Arduinoordner angesehen *schäm*

@Uwe: Danke für die Richtigstellung.

Gruß Helmuth

Udo Klein

Quote

Um ein AusgangsPin zu setzen muß zuerst der Port gelesen werden, dann modifiziert und dann zurückgeschrieben werden um nur ein Bit zu ändern. Liest man den aktuellen Status nicht ein verändert man den Zustand möglicherweise für alle 6-8 Pins eines Ports.
Das ist nicht in 4 Taktzyklen zu machen.


Einspruch Euer Ehren. Das geht in 4 Takten. Der Grund warum digitalWrite das nicht schafft liegt daran, daß digitalWrite es erlaubt den Pin dynamisch zu bestimmen. In der genannten Library kann man sich jedoch sicher sein, daß immer der gleiche Pin angesprochen wird. Ob ein Bit auf High oder Low gesetzt wird beeinflusst die Ausführungszeit ebenfalls nicht. Wenn das allerdings nicht vorher bekannt ist, dann schon.

Mit anderen Worten: hart codierte Zugriffe sind schneller als etwas das erst zur Laufzeit bekannt ist. Auswege gibt es viele, nur bei der Arduino Zielgruppe ist Performance nicht wirklich sooo wichtig. Wenn es das wirklich wäre, dann würde man ja einen schnelleren Prozessor nehmen bzw. wenigstens den Takt hochdrehen.
Check out my experiments http://blog.blinkenlight.net

Go Up