Macht die Loop eine Pause ?

Ich spiele gerade mit mit meinem Saleae Clone.
Funktioniert ohne Änderung des EEproms sofort mit der orginal Software, die Chinesen lernen auch dazu :wink:

Ein kleines simples Testprogramm:

void setup()
{
 DDRD |=  (1<<2);
}


void loop()
{
    
 PORTD |= (1<<2);

 PORTD &= ~(1<<2);
 
}

Bei diesem Scope, ist das Signal ist 0.125 us high und 0,875 us low.

Die Loop beginnt mit PORTD |= (1<<2); was das Bit setzt.
Dies setzt das bit dann zurück PORTD &= ~(1<<2);

Nach meinem Verständnis sollten aber die high und Low Zeiten hier in etwa identisch sein.
Oder macht die die main loop immer am Ende noch was anderes, was Zeit kostet ?

Mit einem PORTD ^= (1<<2); in der Loop sind die Ergebnisse fast identisch.

screenshot.png

rudirabbit: Oder macht die die main loop immer am Ende noch was anderes, was Zeit kostet ?

Was wirklich läuft ist das:

int main(void)
{
  init();
  initVariant();
  setup();
    
  for (;;) 
  {
    loop();
    if (serialEventRun) serialEventRun();
   }
        
  return 0;
}

Da geht also einiges an Zeit drauf für das Beenden der loop() Funktion und deren erneuten Aufruf

Mach mal selbst noch eine Endlosschleife in loop(). Der Compiler macht dann sehr wahrscheinlich einfach ein JMP daraus und es kosten dich nur 2-3 Takte.

Das ist dann quasi der Code ohne den Arduino Dialekt.

Wenn man es jetzt so macht wie es Arduino üblich ist, wird unnötig Zeit verbraten :smiling_imp:

Das ist genau der Code den die Arduino IDE im Hintergrund erzeugt und vor dir versteckt. Siehe \hardware\arduino\avr\cores\arduino\main.cpp

Mach mal das:

void loop()
{
   while(1)
   {
      PIND = (1 << 2);
      PIND = (1 << 2);
   }
}

Das ist glaube ich einen Takt kürzer für das reine Toggeln des Pins.

Eine Pause wird dann eben noch durch den Sprung nach oben entstehen.

Warum nicht dann gleich

PORTD ^= 1 << PIND2;

Das braucht einen Takt mehr weil man erst mal das Register auslesen muss :stuck_out_tongue:

http://www.billporter.info/2010/08/18/ready-set-oscillate-the-fastest-way-to-change-arduino-pins/

Serenifly:
Das braucht einen Takt mehr weil man erst mal das Register auslesen muss :stuck_out_tongue:

Ready, Set, Oscillate! The Fastest Way to Change Arduino Pins « The Mind of Bill Porter

Ja, aber die Zeiten sind gleich.
Zu den Zeiten des Orginalen Sketches:
0,125 nS sind 2 Takte bei einem 16MHz Arduino
0,875 nS sind 14 Takte.

Grüße Uwe

Wie vorgeschlagen, so schauts besser aus.
Ob man jetzt mit xor toggelt oder zwei Befehle ausführt sieht man nicht wirklich in den Zeiten.
Beides in etwa 0,2917us high 0,3333us low macht 1,6 mhz.

Es kommt nicht bei jeder Applikation auf Performance an, wenn man aber Wert darauf legt sollte man auf das Arduino Gedöns verzichten.

int main()

{
  
  DDRD |=  (1<<2); 
 while(1) 

{
  //PORTD ^= (1<<2);
 PORTD |= (1<<2);
PORTD &= ~(1<<2);
} 
  
  
  
return 1;  
}

Das die Arduino Portzugriffe langsam sind wußte ich ja schon vorher, aber das die Arduino Umsetzung setup und loop auch noch zusätzlich Zeit verbraucht war mir nicht bewußt.

Als digtalwrite etc. Ersatz könnte man sich auch macros PORTx |= (1<<z); usw. anlegen.

screenshot.png

Du kannst loop() schon verwenden. Allerdings dann in loop() einfach nochmal eine Endlosschleife machen. Dann wird die Funktion nie verlassen.

Funktionsaufrufe an sich kosten halt generell viel Zeit. Alleine durch die Verwendung des Stacks (push/pop). Das ist normal.

Allgemein für schnelle Pin-Zugriffe mit Arduino Nummern: https://code.google.com/p/digitalwritefast/ Wenn die Pins zur Compile-Zeit bekannt sind, ist das so schnell wie direkte Port-Adressierung

Wie kommt's dass in RudiRabbits ersten Beispiel der high-Puls 125 ns = 2 Takte dauerte nun (#7) aber 291 ns ??? Ausserdem dauert nun die low-Phase 333 ns. Im Bild sind es ca. 100+115 pixel. Das passt größenordnungsmässig dazu.

Ich nehme mal an, dieser Test lief immer noch auf einer 16 MHz Hardware.

Ich hätte vermutet, dass das Ergebnis 125 + 190 ns oder so wäre (2+3 Takte)

Kann jemand erklären, wieso 1. die Pulse nun so lang sind 2. der Unterschied so gering ist, bei einem Zeitquant von 62.5ns (1/16 µs)

???

Es handelt sich um einen Nano, also 16mhz.

Ich habe es gerade nochmal geprüft, die alte Version hat eine high Time von 125 ns. Die neue 291ns. Also unterschiedliche Zeiten für den gleichen Befehl. Die Anzahl der Takte sollte dort immer gleich sein. :o

Kann man den vom Compiler erzeugten asm Code in einem Temp Ordner irgendwo einsehen ?

rudirabbit: Kann man den vom Compiler erzeugten asm Code in einem Temp Ordner irgendwo einsehen ?

Du musst die elf Daten dis-assemblieren

  1. Kopiere x:\Arduino\hardware\tools\avr\bin\avr-objdump.exe irgendwo anders hin wo du bequem dran kommst

  2. Kopie die .elf Datei aus dem temporären Build Ordner (Win7: C:\Users\xxx\AppData\Local\Temp) auch dahin

  3. Öffne ein cmd Fenster, gehe in das Verzeichnis wo die exe liegt und mach das: avr-objdump -S Prog.cpp.elf > disasm.txt

Statt Prog.cpp.elf natürlich den entsprechenden Dateinamen einsetzen

Nachtrag: Oder Visual Micro verwenden. Da muss man sonst nichts machen: http://www.visualmicro.com/post/2012/08/24/Arduino-Memory-Usage-and-Disassembly-Reporting.aspx

Danke,

Aber der asm Code ist das wohl erwartete:

000000aa <loop>:
E:\Arduino-1.0.5\Arduino\Projekte\sketch_jan23a\sketch_jan23a.ino(28)

 

    PORTD |= (1<<2);
  aa:	5a 9a       	sbi	0x0b, 2	; 11
E:\Arduino-1.0.5\Arduino\Projekte\sketch_jan23a\sketch_jan23a.ino(29)
 PORTD &= ~(1<<2);
  ac:	5a 98       	cbi	0x0b, 2	; 11
E:\Arduino-1.0.5\Arduino\Projekte\sketch_jan23a\sketch_jan23a.ino(33)
 
   
 //
}
  ae:	08 95       	ret

Mit der while schleife in der Loop:

  aa:	5a 9a       	sbi	0x0b, 2	; 11
E:\Arduino-1.0.5\Arduino\Projekte\sketch_jan23a\sketch_jan23a.ino(30)
 PORTD &= ~(1<<2);
  ac:	5a 98       	cbi	0x0b, 2	; 11
  ae:	fd cf       	rjmp	.-6      	; 0xaa <loop>

Sehr seltsam, so langsam zweifle ich meine Meßergebnisse an :confused:

Das sieht nach einen Logik-Analyzer aus. Bist du sicher dass der mit so kurzen Zeit zurechtkommt?

Serenifly: Das sieht nach einen Logik-Analyzer aus. Bist du sicher dass der mit so kurzen Zeit zurechtkommt?

Ja ein Logik-Analyzer. Wie schon gesagt, es handelt sich um einen Saleae Clone mit 24mhz Bandbreite.

Btw: Ist es möglich asm Funktionen im C Code zu haben ? Und wie bekomme ich den Inhalt der Variablen in die Register und wieder zurück. Das es über den Stack via push und pop läuft ist klar, hast du kleines Beispiel parat ?

PS: Gerade habe ich in meine ws2811 Uhr die vorher nur mit DCF lief, optional meine NTP Timelib eingebaut, die dank deiner Unterstützung perfekt funktioniert. Bei dem Projekt (328p) wird so ziemlich alles an Ressouren knapp,als ich heute die Lib einbaut hatte, dachte ich schon das es nicht mehr funktioniert. Vor allen wegen dem S-Ram. Aber es funktioniert doch, bin echt happy. :grin:

Ist es möglich asm Funktionen im C Code zu haben ?

Natürlich: http://www.nongnu.org/avr-libc/user-manual/inline_asm.html http://rn-wissen.de/wiki/index.php/Inline-Assembler_in_avr-gcc

Außer NOPs zu machen kenne ich mich damit aber nicht aus