DigitalWriteFast() schneller mit Literalen als Instanzvariablen!!!?

Hallo, mir ist gestern aufgefallen, dass digitalWriteFast(pin,Level) je nach Pin-Definition unterschiedlich schnell ist. So ist digitalWriteFast() ca. 3 mal langsamer wenn man Instanzvariablen benutzt anstatt direkt Literal für den Pin. z.B.

class Pins {
public: 
    int8_t testPin; 
    Pins(int8_t pin) { testPin = pin; }
};
Pins pins = Pins(3);

void loop(){
    unsigned long startTime = micros();
    digitalWriteFast(3, HIGH);
    digitalWriteFast(3, LOW);
    Serial.println("Time Literal (uSec.): " + String(micros() - startTime));
    startTime = micros();
    digitalWriteFast(pins.testPin, HIGH);
    digitalWriteFast(pins.testPin, LOW);
    Serial.println("Time Instanzvariable (uSec.): " + String(micros() - startTime));
}

[u]Augabe:[/u] Time Literal (uSec.): 4 Time Instanzvariable (uSec.): 12

In meinem Projekt verwaltet jedes Objekt seine eigenen Pins in den Instanzvariablen. Heißt, es ist unmöglich diese Variablen durch statics, Literale etc. zu ersetzen. Gibt es trotzdem eine Möglichkeit mit Instanzvariablen die Geschwindigkeit wie mit Literalen bei digitalWriteFast() zu erreichen? Da letztendlich Schrittmotoren angesteuert werden sollen spielt mittlerweile jede Mikrosekunde eine Rolle :S

P.S. Woran liegt dieser Geschwindigkeitsunterschied eigentlich? Legt der Arduino Uno die Objekte in einem sehr langsamen Speicher ab wodurch Zugriffe auf Instanzvariablen ewig brauchen?

Gibt es trotzdem eine Möglichkeit mit Instanzvariablen die Geschwindigkeit wie mit Literalen bei digitalWriteFast() zu erreichen?

Der Compiler optimiert.

Konstanten kann er bis in den Programmcode tragen.

Variable Werte müssen mindestens geholt werden, evtl. noch geschoben usw. Das braucht Takte.

Die klare logische Antwort heißt darum: NEIN!

Das steht in der Beschreibung der Library dabei. Der Pin muss zur Compile-Zeit bekannt sein. Sonst geht das Makro nicht. Wenn er ist zur Laufzeit bekannt ist wird nur das normale digitalWrite() gemacht:

#ifndef digitalWriteFast
#define digitalWriteFast(P, V) \
do {                       \
if (__builtin_constant_p(P) && __builtin_constant_p(V))   __atomicWrite__(digitalPinToPortReg(P),P,V) \
else  digitalWrite((P), (V));         \
}while (0)
#endif

Wenn wir schon beim Eingemachten sind, kann mir jemand erklären wofür die do Schleife gut sein soll? IMO sollte da das Klammerpärchen { ... } alleine schon reichen.

Damit man das Makro in einem if/else Block wie eine Funktion verwenden kann

Wenn du sowas hast:

if (...)
   MACRO(...);
else
  function();

Wenn du dann ein mehrzeiliges Makro mit nur einem Scope-Block hast expandiert das so:

if (...)
{
   ...
}
;
else
  function();

Das compiliert nicht. Wegen dem Semikolon am Ende. Die while-Schleife wird durch das Semikolon beendet wodurch man korrekten Code hat

Danke, jetzt habe ich noch einen Punkt mehr, warum ich C nicht mag :frowning:

Danke, Serenifly. Ist jedenfalls eine einleuchtende Erklärung. Manchmal macht ein Semikolon mehr oder weniger einen gravierenden Unterschied.