ATtiny, div und mod

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.

ATtiny, div und mod

Beitragvon Mathias » 25. Okt 2017, 21:01 ATtiny, div und mod

Bei folgenden Zeilen motzt er, das zu wenig Speicher vorhanden ist.
Code: Alles auswählen
var
  zahl: array[0..3] of byte;
 
procedure Timer0_Interrupt; public Name 'TIMER0_COMPA_ISR'; interrupt;
  d: integer;
begin
...
  zahl[1] := d div 100;
  zahl[2] := d mod 100 div 10;
  zahl[3] := d mod 10;

Code: Alles auswählen
Projekt kompilieren, OS: embedded, CPU: avr, Ziel: Project1: Exit code 256, Fehler: 1, Warnungen: 1, Hinweise: 1
Project1.pas(69,22) Hint: Mixing signed expressions and longwords gives a 64bit result
Project1.pas(123,63) Warning: Calling convention directive ignored: "OldFPCCall"
Assembling project1
Linking Project1
/usr/bin/avr-ld: Project1.elf section `.text' will not fit in region `text'
/usr/bin/avr-ld: Project1.elf section `.data' will not fit in region `data'
/usr/bin/avr-ld: region `text' overflowed by 1000 bytes
/usr/bin/avr-ld: region `data' overflowed by 206 bytes
....
Project1.pas(128,3) Error: Error while linking


Ich habe den selben Code schon mal mit Arduino programmiert.
Code: Alles auswählen
 
   zahl[1] = d / 100;
   zahl[2] = d % 100 / 10;
   zahl[3] = d % 10;

Und hier gibt es keine Probleme.

Die Idee dahinter, ich wollte ein Arduino-Sketch nach Pascal portieren.

Im Anhang noch der komplette Code von beiden Plattformen.
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3195
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 25. Okt 2017, 23:48 Re: ATtiny, div und mod

Kannst Du mal schauen, ob der Compiler eine *.s Datei baut und diese hier posten.

Prinzipiell:
- Es ist keine gute Idee, derart lange in der Interrupt-Routine zu verbringen.
- Es ist keine gute Idee, Zahlen so zu zerlegen. Divisionen durch alles, was nicht 2^n ist kostet Zeit und Speicher.

Das Problem könnte sein, dass FPC hier eine 16-bit Division einbaut. Die allein ist noch nicht so groß. Aber vielleicht bringt die noch andere Routinen in der Lib mit, die ebenfalls eingebaut werden - und dann platzt der Speicher.

Eine Routine zum Zerlegen einer Zahl in Ziffern hab ich hier:

Code: Alles auswählen
// Anzeige Wert als #####
 
procedure disp_valnnnnn(vval : uint16; pos : uint8);
var
  achr : uint8;
  leer : boolean = true;
begin
  achr := uint8('0');
  while (vval >= 10000) do begin
    vval := vval - 10000;
    achr := achr + 1;
    leer := false;
  end;
  if leer then begin
    achr := uint8(' ');
  end;
  dispbuf[pos] := char(achr);
 
  achr := uint8('0');
  while (vval >= 1000) do begin
    vval := vval - 1000;
    achr := achr + 1;
    leer := false;
  end;
  if leer then begin
    achr := uint8(' ');
  end;
  dispbuf[pos + 1] := char(achr);
 
  achr := uint8('0');
  while (vval >= 100) do begin
    vval := vval - 100;
    achr := achr + 1;
    leer := false;
  end;
  if leer then begin
    achr := uint8(' ');
  end;
  dispbuf[pos + 2] := char(achr);
 
  achr := uint8('0');
  while (vval >= 10) do begin
    vval := vval - 10;
    achr := achr + 1;
    leer := false;
  end;
  if leer then begin
    achr := uint8(' ');
  end;
  dispbuf[pos + 3] := char(achr);
 
  achr := uint8('0');
  while (vval >= 1) do begin
    vval := vval - 1;
    achr := achr + 1;
  end;
  dispbuf[pos + 4] := char(achr);
end


Die Idee ist, dass man nicht dividiert, sondern immer eine Stelle runterzählt und gleichzeitig die Ziffer hochzählt. Klingt erstmal umständlich, ist aber deutlich schneller als wenn man das mit Division macht.
Timm Thaler
 
Beiträge: 431
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 26. Okt 2017, 16:24 Re: ATtiny, div und mod

Danke, dein Listing klappt, ich musste die Char entfernen.
Code: Alles auswählen
...
  achr := 0;
  while (vval >= 100) do begin
    Dec(vval, 100);
    Inc(achr);
    leer := false;
  end;
  if leer then begin
    achr := 16;
  end
...


Dabei habe ich noch etwas interessantes entdeckt. Ein x := x - 10, ist nicht das Gleiche wie Dec(x, 10).

Die Byte geben den Speicherverbrauch an.

Code: Alles auswählen
vval := vval - 10; // 1254Byte
vval := vval + 10; // 1256Byte
Dec(vval, 10);     // 1246Byte
Inc(vval, 10);     // 1248Byte
Dec(vval);         // 1246Byte
Inc(vval);         // 1248Byte

Dies ist nur der Fall bei Byte, bei Integer gibt es kein Unterschied.

Dies ist auch unterschiedlich goss:
Code: Alles auswählen
        vval := vval - byte(10);
        vval := vval - 10;


- Es ist keine gute Idee, Zahlen so zu zerlegen. Divisionen durch alles, was nicht 2^n ist kostet Zeit und Speicher.
Da stimme ich dir zu, der ATtiny kann keine Hardware-Division und -Addition. Nur habe ich in meiner Schaltung genügend Reserven.

- Es ist keine gute Idee, derart lange in der Interrupt-Routine zu verbringen.

Ich könnte die Vorzeichen abfrage und das disp_val in den Haupt-Loop nehmen und im Timer nur den Multiplex.
ShiftIn74HC165 muss ich im Mutiplex machen, da alle Shiftregister hintereinander verschalten sind.

So wie es scheint hat der AVR-Compiler einen Bug, sont würde das Ganze in C++ auch nicht funktionieren.

PS:Noch eine Speicherdifferenz.
Code: Alles auswählen
var
  leer: boolean = true;
braucht 4 Bytes mehr als
Code: Alles auswählen
var
  leer: boolean;
begin
  leer := true


Was wird da anders gemacht ?
Zuletzt geändert von Mathias am 26. Okt 2017, 20:58, insgesamt 1-mal geändert.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3195
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 26. Okt 2017, 20:46 Re: ATtiny, div und mod

Was da gemacht wird? Guckst Du in die *.s- Datei.

Das Laden aus einem "unverhersagbaren" Register UDR0 ist nötig, weil der Compiler ja nicht ganz blöd ist. Bei einer Zuweisung "vval := 127" setzt er einfach vorberechnete Werte ein.
Code: Alles auswählen
var
  vval : uint8; 
begin
    vval := UDR0;
    vval := vval - 10; // 1254Byte
    vval := UDR0;
    vval := vval + 10; // 1256Byte
    vval := UDR0;
    Dec(vval, 10);     // 1246Byte
    vval := UDR0;
    Inc(vval, 10);     // 1248Byte
    vval := UDR0;
    Dec(vval);         // 1246Byte
    vval := UDR0;
    Inc(vval);         // 1248Byte
end


Daraus wird der Assembler-Code, der dann direkt in die Maschinensprache (das Hexfile) umgesetzt wird.

Code: Alles auswählen
   lds   r18,(198)  ;das Laden aus dem UDR0
   subi   r18,10  ;"-" Subtrahieren mit einer Konstanten, easy
   lds   r19,(198)
   ldi   r18,10
   add   r19,r18  ;"+" Addieren mit einem Register, es gibt kein addi, es wäre aber ein subi r18, 246 möglich
   lds   r18,(198)
   subi   r18,10  ;"dec" wie "-"
   lds   r19,(198)
   ldi   r18,10
   add   r19,r18  ;"inc" wie "-"
   lds   r18,(198)
   dec   r18  ;"dec" nutzt das eingebaute dec
   lds   r18,(198)
   inc   r18  ;"dec" nutzt das eingebaute inc
 


Fazit: Fast optimal, bis auf das Addieren. Das Ganze wird zwar doppelt so groß, wenn man vval als integer nimmt, klar. Aber nichts erzeugt hier den Zuwachs um 10 Byte pro Anweisung, wie bei Dir. Da musst Du wohl selbst mal nachschauen.
Timm Thaler
 
Beiträge: 431
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Timm Thaler » 26. Okt 2017, 20:56 Re: ATtiny, div und mod

Mathias hat geschrieben:
Code: Alles auswählen
var
  leer: boolean = true;
braucht 4 Bytes mehr als
Code: Alles auswählen
var
  leer: boolean;
begin
  leer := true

Was wird da anders gemacht ?


Bei der ersten Zuweisung wird die Variable im Speicher angelegt und beim Start aus dem Flash mit dem Wert "1" initialisiert, im Programm wird der Wert mit lds (load direct from sram) aus dem Speicher übernommen. Bei der zweiten Zuweisung wird die Variable - wenn sie nicht anderweitig benutzt wird, als Register angelegt und direkt mit ldi (load immediate) mit einer Konstante initialisiert.

Zweiteres ist, obwohl im Programm eine Zeile mehr, auf dem AVR weniger Code.
Timm Thaler
 
Beiträge: 431
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 26. Okt 2017, 21:00 Re: ATtiny, div und mod

Kannst Du mal schauen, ob der Compiler eine *.s Datei baut und diese hier posten.

Da hat sich bei mir ein falsvhe Zitat eingeschlichen. :oops:
Eigentlich wollt ich sagen, ich habe keine *.s Datei.

Ist UDRO nicht für die Zeichen des UART ?
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3195
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 26. Okt 2017, 21:49 Re: ATtiny, div und mod

Mathias hat geschrieben:Eigentlich wollt ich sagen, ich habe keine *.s Datei.


Schau mal in Deinem Projektverzeichnis, da sollte ein Unterverzeichnis lib/avr-embedded sein, in dem sind die compilierten *.o und *.ppu Dateien und auch die *.s Dateien. Die müssen irgendwo sein, denn das ist das was der FPC-Compiler an den Linker schickt, aus dem der dann mit Hilfe des ASM-Compilers Dein Hexfile baut.

Mathias hat geschrieben:Ist UDRO nicht für die Zeichen des UART ?


Ja. Du brauchst halt eine Quelle für die Werte, die der Compiler nicht vorhersagen kann. Wenn Du einfach vval := 127 machst, dann guckt der Compiler, oh, vval := vval - 10, vval = 127, dann kann ich ja gleich vval 117 zuweisen:
Code: Alles auswählen
    vval := 127;
    vval := vval - 10; // 1254Byte

wird zu
Code: Alles auswählen
   ldi   r18,127
   ldi   r18,117

Klever. Bringt Dich aber nicht weiter in der Evaluierung, was der Compiler macht. Der hat Dich ausgetrickst.

Das gilt für Compilereinstellung -o3, bei -o1 sieht das anders aus:
Code: Alles auswählen
   ldi   r18,127
   sts   (U_sPsTEST_ss_VVAL),r18
   lds   r18,(U_sPsTEST_ss_VVAL)
   subi   r18,10
   sts   (U_sPsTEST_ss_VVAL),r18

Hier wird das Programm eher "wörtlich" übersetzt, erzeugt aber auch viel unnötigen Code.
Timm Thaler
 
Beiträge: 431
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 28. Okt 2017, 16:37 Re: ATtiny, div und mod

Klever. Bringt Dich aber nicht weiter in der Evaluierung, was der Compiler macht. Der hat Dich ausgetrickst.

Wen das Klever wäre, dann würde es keine Sinn machen
Code: Alles auswählen
ldi   r18,127
aufzurufen, er könnte doch direkt
Code: Alles auswählen
ldi   r18,117
machen. :roll:
Oder habe ich etwas übersehen ?
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3195
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 28. Okt 2017, 18:50 Re: ATtiny, div und mod

Ja, da steht vorher vval := 127;, und genau das macht der Compiler, obwohl vval gleich danach überschrieben wird.

Ein "besserer" Compiler würde das vielleicht noch wegoptimieren. Aber das kann auch schiefgehen.

Code: Alles auswählen
procedure rtc_interrupt; alias: 'TIMER2_COMPA_ISR'; interrupt; public;
begin
  TCCR2B := TCCR2B;


Sieh auch erstmal aus, als könne das weg. Das Neuschreiben des Registers mit dem gleichen Wert ist aber essentiell wichtig, um das Aktualisieren diverser Flags anzustoßen.

Würde mir der Compiler das wegoptimieren wäre ich sauer. ;-)
Timm Thaler
 
Beiträge: 431
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 28. Okt 2017, 18:56 Re: ATtiny, div und mod

Sind dies nicht zweierlei Schuhe ?

TCCR2B ist ein Register/Port, welches im PC vergleichbar ist mit Port[$F8] oder Mem[$B800:0000] welches auf Hardware/Speicherbereich zugreift.
r18 ist ein Processoerregister, verglich bar mit ax, bc, ebx etc.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3195
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon siro » 28. Okt 2017, 19:14 Re: ATtiny, div und mod

Timm Thaler hat geschrieben:Ja, da steht vorher vval := 127;, und genau das macht der Compiler, obwohl vval gleich danach überschrieben wird.

Ein "besserer" Compiler würde das vielleicht noch wegoptimieren. Aber das kann auch schiefgehen.

Code: Alles auswählen
procedure rtc_interrupt; alias: 'TIMER2_COMPA_ISR'; interrupt; public;
begin
  TCCR2B := TCCR2B;


Sieh auch erstmal aus, als könne das weg. Das Neuschreiben des Registers mit dem gleichen Wert ist aber essentiell wichtig, um das Aktualisieren diverser Flags anzustoßen.

Würde mir der Compiler das wegoptimieren wäre ich sauer. ;-)


Würde mir der Compiler das wegoptimieren wäre ich sauer.

gibt es für den Pascalcompiler so etwas wie "volatile" in "C"
damit man dem Compiler mitteilen kann, dass er NICHT optimieren darf ?
Das ist ja SEHR wichtig für spezielle Prozessorregister.
Grüße von Siro
"C" verCehnfacht die Entwicklungszeit...
siro
 
Beiträge: 222
Registriert: 23. Aug 2016, 13:25
Wohnort: Berlin
OS, Lazarus, FPC: Windows 7 Windows 8.1 Windows 10 | 
CPU-Target: 64Bit
Nach oben

Beitragvon Mathias » 28. Okt 2017, 19:25 Re: ATtiny, div und mod

damit man dem Compiler mitteilen kann, dass er NICHT optimieren darf ?

Code: Alles auswählen
  {$o-} // aus
  {$o+} // ein
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3195
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon siro » 28. Okt 2017, 19:28 Re: ATtiny, div und mod

Okay, Danke
Grüße von Siro
"C" verCehnfacht die Entwicklungszeit...
siro
 
Beiträge: 222
Registriert: 23. Aug 2016, 13:25
Wohnort: Berlin
OS, Lazarus, FPC: Windows 7 Windows 8.1 Windows 10 | 
CPU-Target: 64Bit
Nach oben

Beitragvon Mathias » 28. Okt 2017, 19:30 Re: ATtiny, div und mod

Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3195
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

• Themenende •

Zurück zu Sonstiges



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast

porpoises-institution
accuracy-worried