Arduino Due PIO

Hallo,
Bin gerade dabei erste Versuche mit dem Due zu starten.

Sind auch hier (beim Due) die Arduino Pin Zugriffunktionen auch einem Performance Defizit unterworfen wie bei den AVR ?

Wenn man das ARM Datenblatt anschaut, ist der direkte Portzugriff nicht so einfach wir bei den AVR.

Sind etliche Register mehr, aber auch interessante Dinge dabei.
Input Filter Register zum Beispiel.

Grüße Rudi

Hallo Rudi,

kann jetzt nur auf das antworten, was ich so mit bekommen hab. Hab bis auf ein paar LCD Ansteuerung noch nichts in der ganzen Zeit gemacht. Liegt immer nur in der Ecke.

Die Perfomance der AVR GPIO Ansteuerung dürfte deutlich effizienter sein, wenn auch nicht gut. Beim Due wurde viel getrickst, damit das ganze von Aussen sich nicht wesentlich unterscheidet, wie man es bei den AVR in der Arduino IDE kannte.

Das ganze braucht einen verhältnismäßig großen Overhead.

Es gab einen Test im Elektor, der das Timeing zum direkten Zugriff vergleicht.

Das ist aber ca. 1 Jahr her.
Damals war der Unterschied noch richtig krass.
Meine aber gelesen zu haben das dies inzwischen nicht mehr so gravierend ist.

Entweder findet sich noch jemand der was sagen kann, oder ich muss meinen alten Hamek anwerfen.

Der Elektor Testcode sah so aus:

//*********************************
//Speed-Test 2.0 with Arduino Due
//*********************************
#include „arduino.h“
//
//
const int LED1 = 13;
int LED2 = 12;
int LED3 = 11;
int TP1 = 7; //Testpin
#define Direct
void setup()
{
/* add setup code here */
// set the digital pin as output:
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
pinMode(TP1, OUTPUT);
// set output low
digitalWrite(LED1,0);
digitalWrite(LED2,0);
digitalWrite(LED3,0);
digitalWrite(TP1,0);
}
void loop() {
// put your main code here, to run repeatedly:
#ifdef Direct
//x= state of PIO_SODR with bit 23 = 1
int x = PIOC->PIO_SODR | 1<<23;
while (1){ //Only for testpurposes, don‘t exit this loop
PIOC->PIO_SODR = x;
PIOC->PIO_CODR = x;
}
#else
digitalWrite(TP1,1);
digitalWrite(TP1,0);
#endif
}

Ich habe für den direkten Zugriff noch diese beiden Funktionen gefunden.

inline void digitalWriteDirect(int pin, boolean val){
  if(val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
  else    g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
}

inline int digitalReadDirect(int pin){
  return !!(g_APinDescription[pin].pPort -> PIO_SODR & g_APinDescription[pin].ulPin);
}

Das Funktioniert auch. Am WE werde ich die Timeing im Vergleich mit Arduino digitalWrite etc. testen.

Ich nutze aber ungern Code den ich nicht ganz verstehe.
DIe Funktionen der PIO_SODR/ PIO_SODR/PIO_SODR sind mir inzwischen klar. Steht ja im Datenblatt.

1:
Wo ist das hier definiert: g_APinDescription[pin].pPort ?

2:
Bei der Lesefunktion der Rückgabewert mit return !!
Was ist das ? , 2 mal not macht keinen Sinn für mich.

Bei der Lesefunktion der Rückgabewert mit return !!
Was ist das ? , 2 mal not macht keinen Sinn für mich.

Eine Typeumwandlung zu bool, für Schreibfaule.

Das sind zwei Negationen hintereinander. Ein altes C Idiom, da es da noch keinen richtigen bool Typ gab Genauso wie man auch auf dem Arduino lange Zeit dummerweise einfach ein typedef auf unsigned char genommen hat. Bool begrenzt den Wert automatisch auf 0 oder 1 egal was man übergibt. Integer-Typen tun das nicht.

!! macht aus allem was größer 0 ist eine 1.

Wenn der Wert 0 ist: 0 -> 1 -> 0
Wenn der Wert > 0 ist: 100 (z.B.) -> 0 -> 1

P.S.:
Täusche ich mich oder ist der Code der Write Funktion für beide Zweige gleich?

Danke euch beiden, also ein Typcast auf bool.

[/code]

Serenifly:
Täusche ich mich oder ist der Code der Write Funktion für beide Zweige gleich?

Nein du hast recht, es war ein Copy and Paste Fehler meinerseits als ich das ins Forum gepostet habe.
So ist es richtig.. PIO_CODR

inline void digitalWriteDirect(int pin, boolean val){
  if(val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
  else    g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
}

inline int digitalReadDirect(int pin){
  return !!(g_APinDescription[pin].pPort -> PIO_PDSR & g_APinDescription[pin].ulPin);
}

Warum gibt wird der Rückgabewert der Readfunktion nicht gleich als bool definiert ?
z.b so

inline bool  digitalReadDirect(int pin){

Ein bool braucht zwar auch 8Bit (verschwendung, geht nicht anders ) , ein Int braucht aber hier 32Bit !

rudirabbit:
Ein bool braucht zwar auch 8Bit (verschwendung, geht nicht anders ) , ein Int braucht aber hier 32Bit !

Auf einem 32-Bit System ist das aber egal, da der Datenbus sowieso 32 Bit breit ist und auf Assembler Ebene generell mit 32 Bit gearbeitet wird.

Du sparst dir aber das Anpassen des Wertes. Das ist wichtig bei den Abfragen, da der Wert nur 0/1 sein darf wenn man explizit mit LOW/HIGH vergleicht.

Ich habe Speedtests mit Digitalwrite gemacht.

void loop() 
 {
               while(1)  
                {
                  
                digitalWrite(X_STEP_PIN,HIGH);
                digitalWrite(X_STEP_PIN,LOW);
             }


}

Hier habe ich eine Periodedauer von ca. 6us

Wenn ich das hier mache;

PIOB->PIO_SODR = PIO_PB25;
PIOB->PIO_CODR = PIO_PB25;

Kann dies mein alter Hamek nicht mehr so darstellen, das man eine Periodendauer rauslesen könnte.
Das selbe gilt für die digitalWriteDirect Funktionen aus dem Fred hier.
Das muss zwar etwas langsamer sein, weil ein paar Takte mehr gebraucht werden, ich kann es mit meinen Mitteln nicht mehr messen.

Mein Fazit: Wenn man wirklich schnelle Zugriffe auf die Pins haben will, ist es besser die digitalWriteDirect oder sowas PIOB->PIO_SODR = PIO_PB25; zu machen.

Letzteres ist etwas sperriger zu Programmieren, man braucht das Pinmapping als Referenz dazu.

Also wie beim AVR auch, verbraucht Digitalwrite auch beim ARM doch relativ viel Zeit.
In einer ISR z.b.sehr ungünstig.

Also ich kann gerne, wenn gewünscht mal mit einem Logikanalyser testen, wie sich digitalWrite im Vergleich zum direkten Pinansprechen verhält. Habe hier den Zero sowie Due herumliegen. Müsste nur ggf. die Geschwindkeit beim Due anpassen, da diese doch deutlich über 24MHz liegt. Des weiteren müsste ich sehen, dass ich den Takt vom Zero evtl. noch etwas in der Arduino IDE heruntersetze, damit ich die Zeiten messen kann.

Das ist bei den AVRs nie das Problem gewesen, da der Takt um ein vielfaches geringer war.

sschultewolter:
Also ich kann gerne, wenn gewünscht mal mit einem Logikanalyser testen ...

Du bringst mich auf eine Idee, habe einen Saleae Nachbau rumliegen.
Fast vergessen das ich sowas auf Lager habe :confused:

Werde ich Testen, vor allem der Unterschied von der digitalWriteDirect Funktion und dem wirklich direkten Zugriff interessiert mich.

PS:
Warum mache ich das ?
Will mit dem Due eine Steuerung für einen Laserplotter realisieren, mein Selbstbau Code läuft schon auf einem AVR ganz gut. Allerdings auf einem sehr kleinem Tisch.

Plane nun einen Umbau auf 1000x500 mit Servomotoren.
Will also meinen AVR Code auf den Due teilweise portieren.
Bin etwas ein Pedant geworden, will es möglichst perfekt haben.
Deshalb auch die Tests bei den Portzugiffen.

Also mit dem Logikanalyser getestet.

Bei der Directfunktion oder auch Pio Zugriff brauchte es ein paar Nop's
Sonst hatte ich kein Signal, das ist wohl dem ARM zu schnell.
Mit Aruduino Digitalwrite ohne Nops.

Der Performanceunterschied zu Arduino Digitalwrite ist mehr als deutlich.
Denke die Directfunktion ist einfach zu handeln und nur wenig langsamer als über den Pio.

void loop() {
               while(1)  
                {
          
// digitalWriteDirect(X_STEP_PIN    , HIGH);
               PIOB->PIO_SODR = PIO_PB25;
               
                   NOP; NOP;NOP; NOP;NOP; NOP;NOP;NOP;NOP;
//   digitalWriteDirect(X_STEP_PIN    , LOW);
                PIOB->PIO_CODR = PIO_PB25;
                    NOP; NOP;NOP; NOP;NOP; NOP;NOP;NOP;NOP;
                 }
 

}