AVR ohne Loop

Antworten
Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

AVR ohne Loop

Beitrag von Mathias »

Was passiert in einem AVR, wen es kein Loop hat ?
In folgendem Beispiel, reagiert nicht mal mehr der Timer.
Passiert da irgend etwas undefiniertes ?

Code: Alles auswählen

begin
  DDRB := %00100000; // Pin 13 Output
 
  // Timer 2
  TCCR2A := %00;               // Normaler Timer
  TCCR2B := %111;              // Clock / 1024
  TIMSK2 := (1 shl TOIE2);     // Enable Timer2 Interrupt.
 
  asm sei end;                 // Interrupts einschalten.
 
//  repeat
//  until 1 = 2;
end
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: AVR ohne Loop

Beitrag von Timm Thaler »

Der Controller rennt einfach weiter. Sprich der Programmzähler wird weiter erhöht und auch die im Flash stehenden Befehle ausgeführt. Üblicherweise ist das 0xFF FF. Welchem Befehl das entspricht, darfst Du im instruction set selber rausfinden.

Allerdings können da auch Daten stehen, so schreibt glaube ich der FPC Compiler seine Versionsinfo ans Ende des Programms. Und diese Daten werden gnadenlos als Code interpretiert. Der Controller macht also irgendwas, bestenfalls geht er in eine Endlosschleife, springt wild hin und her oder setzt sich selber in den Sleepmode, schlimmstenfalls aktiviert er irgendwelche Pins und schießt Deine Hardware ab.

Dann kann der Controller bis ans Ende des Flash rennen, wo er vielleicht einen Bootloader findet. Der wird dann aktiv, und wartet entweder auf einen Programmupload oder macht nach einiger Zeit ein Reset.

Kommt der Controller trotz dieser Widrigkeiten am Ende des Flash an, läuft der Programmzähler über und der Controller startet von Anfang an. Bei 32kByte Flash sind das 16k Befehlsworte, bei 8MHz dauert das also gerade mal 2 Millisekunden, wenn der Controller ungebremst durchrennen kann.

tl;dr: Man macht das einfach nicht!

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: AVR ohne Loop

Beitrag von Mathias »

tl;dr: Man macht das einfach nicht!
In der Regel nicht, aber wi eschnell hat man Project/Neu gemacht und F9 gedrückt. :mrgreen:
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

FPK
Beiträge: 65
Registriert: Mi 21. Mai 2008, 19:38
Wohnort: Erlangen

Re: AVR ohne Loop

Beitrag von FPK »

Timm Thaler hat geschrieben:Der Controller rennt einfach weiter. Sprich der Programmzähler wird weiter erhöht und auch die im Flash stehenden Befehle ausgeführt. Üblicherweise ist das 0xFF FF. Welchem Befehl das entspricht, darfst Du im instruction set selber rausfinden.

Allerdings können da auch Daten stehen, so schreibt glaube ich der FPC Compiler seine Versionsinfo ans Ende des Programms. Und diese Daten werden gnadenlos als Code interpretiert. Der Controller macht also irgendwas, bestenfalls geht er in eine Endlosschleife, springt wild hin und her oder setzt sich selber in den Sleepmode, schlimmstenfalls aktiviert er irgendwelche Pins und schießt Deine Hardware ab.


Nach dem Ende des Hauptprogramms schickt FPC den Controller in eine Endlosschleife, um genau solche Dinge zu verhindern.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: AVR ohne Loop

Beitrag von Mathias »

Nach dem Ende des Hauptprogramms schickt FPC den Controller in eine Endlosschleife, um genau solche Dinge zu verhindern.

wen das so wäre, das müsste doch der Timer-Interrupt weiter laufen ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: AVR ohne Loop

Beitrag von Timm Thaler »

FPK hat geschrieben:Nach dem Ende des Hauptprogramms schickt FPC den Controller in eine Endlosschleife, um genau solche Dinge zu verhindern.


Mit Compileroption -al kann man sich ja die Assemblerlistings der einzelnen Units ausgeben lassen.

Da fehlen allerdings noch die Sachen, die der Compiler drumrum baut. Wie zum Beispiel die Initialisierung oder auch sowas wie die Endlosschleife am Ende.

Gibt es eine Compileroption, mit der man sich das komplette Assemblerlisting ausgeben lassen kann? Ohne das Hexfile durch den Disassembler laufen lassen zu müssen? Letzteres ist doch recht mühsam.

FPK
Beiträge: 65
Registriert: Mi 21. Mai 2008, 19:38
Wohnort: Erlangen

Re: AVR ohne Loop

Beitrag von FPK »

Timm Thaler hat geschrieben:
FPK hat geschrieben:Nach dem Ende des Hauptprogramms schickt FPC den Controller in eine Endlosschleife, um genau solche Dinge zu verhindern.


Mit Compileroption -al kann man sich ja die Assemblerlistings der einzelnen Units ausgeben lassen.

Da fehlen allerdings noch die Sachen, die der Compiler drumrum baut. Wie zum Beispiel die Initialisierung oder auch sowas wie die Endlosschleife am Ende.

Gibt es eine Compileroption, mit der man sich das komplette Assemblerlisting ausgeben lassen kann? Ohne das Hexfile durch den Disassembler laufen lassen zu müssen? Letzteres ist doch recht mühsam.


Nur mit -al wenn die Unit gerade compiliert wird, dem Compiler liegt ja ansonsten auch nur ein Object-File (Binärdaten) vor. Oder eben gleich den Quelltext anschauen: https://svn.freepascal.org/cgi-bin/view ... iew=markup

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: AVR ohne Loop

Beitrag von Timm Thaler »

FPK hat geschrieben:Oder eben gleich den Quelltext anschauen: https://svn.freepascal.org/cgi-bin/view ... iew=markup


Ja, würd ich gern, aber ich tue mich schwer, darin was zu finden.

Zum Beispiel baut mir der Compiler bei manchen Multiplikationen ein call fpc_mul_longint ein. Welches erheblich länger dauert wie eine native Multiplikation mittels Hardware-mul. Nun hätte ich mir gern mal angesehen, wie dieses fpc_mul_longint aufgebaut ist, aber ich habe es in den Sourcen nicht gefunden.

Aber danke, anhand des Beispiels hab ich den Befehl

Code: Alles auswählen

avr_cli;
gefunden, der direkt ein CLI einbaut, ohne den Umweg eine Prozedur aufzurufen. Und passend gibt es noch

Code: Alles auswählen

avr_sei();
Die Unit intrinsics muss eingebunden werden.

Wo findet man weitere solche "Geheimbefehle"?

FPK
Beiträge: 65
Registriert: Mi 21. Mai 2008, 19:38
Wohnort: Erlangen

Re: AVR ohne Loop

Beitrag von FPK »

Timm Thaler hat geschrieben:
FPK hat geschrieben:Oder eben gleich den Quelltext anschauen: https://svn.freepascal.org/cgi-bin/view ... iew=markup


Ja, würd ich gern, aber ich tue mich schwer, darin was zu finden.

Zum Beispiel baut mir der Compiler bei manchen Multiplikationen ein call fpc_mul_longint ein. Welches erheblich länger dauert wie eine native Multiplikation mittels Hardware-mul. Nun hätte ich mir gern mal angesehen, wie dieses fpc_mul_longint aufgebaut ist, aber ich habe es in den Sourcen nicht gefunden.


Ich verwende in solchen Fällen einfach die "Suchen in Dateien"-Funktion von Lazarus mit $(ProjPath)\..\ als Suchpfad. In dem Fall mit dem embedded-Projekt für die rtl (fpc/rtl/embedded/buildrtl.lpi, lässt sich nicht übersetzen, ist aber zum RTL bearbeiten etc. geeignet)


Aber danke, anhand des Beispiels hab ich den Befehl

Code: Alles auswählen

avr_cli;
gefunden, der direkt ein CLI einbaut, ohne den Umweg eine Prozedur aufzurufen. Und passend gibt es noch

Code: Alles auswählen

avr_sei();
Die Unit intrinsics muss eingebunden werden.

Wo findet man weitere solche "Geheimbefehle"?


Wahrscheinlich noch nirgends, ist noch zu neu, ist sicher noch nicht im wiki. Ansonsten eben in der Unit intrinsics.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: AVR ohne Loop

Beitrag von Mathias »

Wo findet man weitere solche "Geheimbefehle"?

Wen man der Cursor auf "intrinsics" und Ctrl+Enter drückt, kommt folgendes:

Code: Alles auswählen

    procedure avr_cli;[INTERNPROC: in_avr_cli];
    procedure avr_sei;[INTERNPROC: in_avr_sei];
    procedure avr_wdr;[INTERNPROC: in_avr_wdr];
    procedure avr_sleep;[INTERNPROC: in_avr_sleep];
    procedure avr_nop;[INTERNPROC: in_avr_nop];

Anscheinend gibt es sogar ein Nop und Sleep.
Aber was wdr ist, kann ich nicht sagen. Weis das sonst wer ?

avr_sei funktioniert.
Jetzt müsste man noch gucken, was sleep genau macht. Ob dies dem Arduino "delayMicroseconds(...); " entspricht.

Wahrscheinlich noch nirgends, ist noch zu neu, ist sicher noch nicht im wiki. Ansonsten eben in der Unit intrinsics.

Ich werde dies im Wiki vermerken. So was muss man fast weiter geben. :wink:

Jetzt habe ich gerade noch etwas entdeckt. wen ich am Programm-Ende folgendes mache,

Code: Alles auswählen

  repeat
  until 1 = 2;
  avr_sei;
end.
wird avr_sein nicht mit kompiliert, anscheinend merkt der Compiler, das er aus dem repeat-until nicht raus kommen kann.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: AVR ohne Loop

Beitrag von Mathias »

Ich habe gerade mit avr_sleep; rumprobiert.
Dies macht etwa das gleiche wie avr_nop; .

Hier ist die Verzögerung die selbe, egal ob ich nop oder sleep nehme.

Code: Alles auswählen

  procedure mysleep(t: int32); // Ein einfaches Delay.
  var
    i: Int32;
  begin
    for i := 0 to t do begin
      avr_nop;
    end;
  end;


Noch was habe ich festgestellt, ich kann die for-Schleife leer lassen, die Verzögerung ist etwa gleich, anscheinend hat die Schleife so viel Overhead, das es schon eine Verzögerung gibt.

Erst wen ich etwa 50x hintereinander nop oder sleep schreibe, dann sieht man eine Änderung.

Aber etwas muss doch anders sein zwischen nop und sleep, wen man die Source von cpuinnr.inc anguckt.

Code: Alles auswählen

  in_avr_cli = fpc_in_cpu_first;
  in_avr_sei = fpc_in_cpu_first+1;
  in_avr_wdr = fpc_in_cpu_first+2;
  in_avr_sleep = fpc_in_cpu_first+3;
  in_avr_nop = fpc_in_cpu_first+4;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: AVR ohne Loop

Beitrag von Timm Thaler »

FPK hat geschrieben:Ich verwende in solchen Fällen einfach die "Suchen in Dateien"-Funktion von Lazarus mit $(ProjPath)\..\ als Suchpfad. In dem Fall mit dem embedded-Projekt für die rtl (fpc/rtl/embedded/buildrtl.lpi, lässt sich nicht übersetzen, ist aber zum RTL bearbeiten etc. geeignet)


Ich hab über den kompletten Baum des Laz / FPV Verzeichnisses gesucht, da habe ich ettliche .o gefunden, in denen das anscheinend verwendet wird. Und in generic.inc eine Routine um das abzuhandeln, aber keinen Assemblercode. Ist wirklich nicht so einfach da was zu finden.

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: AVR ohne Loop

Beitrag von Timm Thaler »

Mathias hat geschrieben:Ich habe gerade mit avr_sleep; rumprobiert.
Dies macht etwa das gleiche wie avr_nop;


Ähm, um den AVR schlafenzulegen, muss man vorher einige Register einstellen. Und auch sicherstellen, dass er wieder aufwacht. Das heisst, einen Timer- oder externen Interrupt scharfschalten.

Mit dem Sleep-Befehl kann man den Controller dann an dieser Programmstelle anhalten. Das heisst, das Programm bleibt hier stehen und der Stromverbrauch sinkt auf ein Minimum. Timer-Zähler, ADC-Wandlung usw. laufen aber weiter. Wird dann ein Timer ausgelöst, wird dessen Interrupt-Routine ausgeführt und danach macht das Programm an der Stelle nach dem Sleep-Befehl weiter.

Ein Sleep ohne Registereinstellung bringt genau das Gleiche wie ein Nop: Nichts, ausser einen Taktzyklus zu verbraten.

Bei Wdt = Watchdog-Reset das Gleiche. Der Watchdog muss vorher eingerichtet werden, und dann muss in regelmäßigen Abständen Wdt aufgerufen werden, um ein Reset zu verhindern.

Die Befehle in der intrinsics sind Kurzschreibweisen für asm cli end;...

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: AVR ohne Loop

Beitrag von Mathias »

Wahrscheinlich noch nirgends, ist noch zu neu, ist sicher noch nicht im wiki. Ansonsten eben in der Unit intrinsics.

So neu ist die Unit auch wieder nicht, im Kopf steht 2016.

Ich habe mal begonnen ein Wiki für AVR-Units zu schreiben: http://wiki.freepascal.org/AVR_Embedded_Tutorial_-_Library/de

Vielleicht gibt es in Zukunft noch mehr Units, welche man dokumentieren kann.

Ich hab über den kompletten Baum des Laz / FPV Verzeichnisses gesucht, da habe ich ettliche .o gefunden, in denen das anscheinend verwendet wird. Und in generic.inc eine Routine um das abzuhandeln, aber keinen Assemblercode. Ist wirklich nicht so einfach da was zu finden.

Wen man hinter uses Ctrl+Space drückt, werden alle verfügbaren Units aufgelistet.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

FPK
Beiträge: 65
Registriert: Mi 21. Mai 2008, 19:38
Wohnort: Erlangen

Re: AVR ohne Loop

Beitrag von FPK »

Mathias hat geschrieben:
Wahrscheinlich noch nirgends, ist noch zu neu, ist sicher noch nicht im wiki. Ansonsten eben in der Unit intrinsics.

So neu ist die Unit auch wieder nicht, im Kopf steht 2016.


Im Kopf kann viel stehen :) Relevant ist das svn log:

------------------------------------------------------------------------
r37544 | florian | 2017-11-01 17:33:34 +0100 (Mi, 01 Nov 2017) | 1 line

+ implemented some AVR specific intrinsics
------------------------------------------------------------------------

Timm Thaler hat geschrieben:
FPK hat geschrieben:Ich verwende in solchen Fällen einfach die "Suchen in Dateien"-Funktion von Lazarus mit $(ProjPath)\..\ als Suchpfad. In dem Fall mit dem embedded-Projekt für die rtl (fpc/rtl/embedded/buildrtl.lpi, lässt sich nicht übersetzen, ist aber zum RTL bearbeiten etc. geeignet)


Ich hab über den kompletten Baum des Laz / FPV Verzeichnisses gesucht, da habe ich ettliche .o gefunden, in denen das anscheinend verwendet wird. Und in generic.inc eine Routine um das abzuhandeln, aber keinen Assemblercode. Ist wirklich nicht so einfach da was zu finden.


Nur in *.pp;*.pas;*.inc suchen. Und ja, avr verwendet einfach die generische Version und keine Assembler-Implementierung.

Antworten