AVR - Strings direkt aus Flash lesen

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 - Strings direkt aus Flash lesen

Beitrag von Mathias »

Code: Alles auswählen

procedure TextStr;
begin
  asm  db $5,'Hallo'   { Längenbyte und der Text selbst }
end;

Sowas kommt mir sehr bekannt vor, bei Turbo-Pascal, hat man nur 64KB für Konstanten zu Verfügung.
Das Programm selbst, konnte den ganzen Heap nutzen.

Ich hatte mal einen ganze Font so abgespeichert:

Code: Alles auswählen

procedure CharTab; assembler;
asm                         
 db    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 db    0,   0, 126, 129, 165, 129, 129, 189, 153, 129, 126,   0,   0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
............


Der Zugriff habe ich dann par ASM gelöst:

Code: Alles auswählen

procedure LoadoldChar; assembler;  { Lädt Zeichensatz aus ROM }
asm
        push    bp
        push    ds
        mov     ax, 1130h
        mov     bh, 02h
        int     10h
        mov     si, bp
        mov     di, offset CharTab
        mov     cx, 1792
        mov     ax, es
        mov     bx, ds
        mov     ds, ax
        mov     es, bx
        rep     movsw
        pop     ds
        pop     bp
end;

Dazumal musste man noch recht basteln. :wink:
Die Lösung mit dem Pointer ist auch sehr gut.
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 - Strings direkt aus Flash lesen

Beitrag von Timm Thaler »

Ich habe mit den Angaben aus dem bugtracker forum nochmal rumprobiert:

Code: Alles auswählen

var
  dispbuf : string[32];
const
  text00 : string[32] = 'MyDisplayText...' +
                        '.......... start'; section '.progmem';
var
  sptr, tptr : pchar;
 
  sptr := @text00; 
  tptr := @dispbuf;
  copy_pgm_string(sptr, tptr, 32)// String von Flash in Buffer
 
procedure copy_pgm_string(psrc, pto : pchar; len : uint8);
label
  loop;
var
  lo_psrc, hi_psrc, lo_pto, hi_pto : uint8;
begin
  lo_psrc := uint16(psrc) and $FF;
  hi_psrc := uint16(psrc) shr 8;
  lo_pto := uint16(pto) and $FF;
  hi_pto := uint16(pto) shr 8;
  asm
    ldd r30, lo_psrc
    ldd r31, hi_psrc
    ldd r26, lo_pto
    ldd r27, hi_pto
    ldd r16, len
    inc r16
    loop:
    lpm r0, Z+
    st X+, r0
    dec r16
    brne loop
  end['r0','r16','r26','r27','r30','r31'];
end;


Funktioniert!

Allerdings erzeugt die Übergabe der Adressen noch reichlich Overhead.

Code: Alles auswählen

 402:   8a 83          std   Y+2, r24   ; 0x02 <= hier werden die Adressen in die Prozedur übergeben
 404:   9b 83          std   Y+3, r25   ; 0x03
 406:   6c 83          std   Y+4, r22   ; 0x04
 408:   7d 83          std   Y+5, r23   ; 0x05
 40a:   4e 83          std   Y+6, r20   ; 0x06
 40c:   2a 81          ldd   r18, Y+2   ; 0x02
 40e:   2f 83          std   Y+7, r18   ; 0x07
 410:   3a 81          ldd   r19, Y+2   ; 0x02
 412:   4b 81          ldd   r20, Y+3   ; 0x03
 414:   58 e0          ldi   r21, 0x08   ; 8
 416:   21 2d          mov   r18, r1
 418:   55 23          and   r21, r21
 41a:   21 f0          breq   .+8         ;  0x424
 41c:   46 95          lsr   r20
 41e:   37 95          ror   r19
 420:   5a 95          dec   r21
 422:   e1 f7          brne   .-8         ;  0x41c
 424:   38 87          std   Y+8, r19   ; 0x08
 426:   2c 81          ldd   r18, Y+4   ; 0x04
 428:   29 87          std   Y+9, r18   ; 0x09
 42a:   3c 81          ldd   r19, Y+4   ; 0x04
 42c:   4d 81          ldd   r20, Y+5   ; 0x05
 42e:   58 e0          ldi   r21, 0x08   ; 8
 430:   21 2d          mov   r18, r1
 432:   55 23          and   r21, r21
 434:   21 f0          breq   .+8         ;  0x43e
 436:   46 95          lsr   r20
 438:   37 95          ror   r19
 43a:   5a 95          dec   r21
 43c:   e1 f7          brne   .-8         ;  0x436
 43e:   3a 87          std   Y+10, r19   ; 0x0a
 440:   ef 81          ldd   r30, Y+7   ; 0x07 <= hier stehen sie endlich in den richtigen Registern
 442:   f8 85          ldd   r31, Y+8   ; 0x08
 444:   a9 85          ldd   r26, Y+9   ; 0x09
 446:   ba 85          ldd   r27, Y+10   ; 0x0a
 448:   0e 81          ldd   r16, Y+6   ; 0x06


Das geht doch bestimmt eleganter...?

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 - Strings direkt aus Flash lesen

Beitrag von Mathias »

Code: Alles auswählen

end['r0','r16','r26','r27','r30','r31'];

Was macht diese Zeile ?
Oder sollte die Kommentar sein ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: AVR - Strings direkt aus Flash lesen

Beitrag von Socke »

Ist das hier effizienter?

Code: Alles auswählen

var
  lo_psrc, hi_psrc, lo_pto, hi_pto : uint8;
begin
  lo_psrc := lo(uint16(psrc));
  hi_psrc := hi(uint16(psrc));
  lo_pto := lo(uint16(pto));
  hi_pto := hi(uint16(pto));
  // ...
end;


Edit:
Man kann das Hin- und Hergeschiebe auch komplett eleminieren:

Code: Alles auswählen

procedure copy_pgm_string(psrc, pto : pchar; len : uint8);
type
  // Struktur zum Zugriff auf die einzelnene Bytes
  TUInt16Struct = packed record
    l: uint8;
    h: uint8;
  end;
var
  // es kann kein direkter Zugriff auf die Record-Elemente erfolgen
  // daher muss jedes Byte einen separaten Namen erhalten
  s: TUInt16Struct absolute psrc;
  lsrc: Uint8 absolute s.l;
  hsrc: Uint8 absolute s.h;
  t: TUInt16Struct absolute pto;
  lto: Uint8 absolute t.l;
  hto: Uint8 absolute t.h;
label
  loop;
begin
  asm
    ldd r30, lsrc
    ldd r31, hsrc
    ldd r26, lto
    ldd r27, hto
    ldd r16, len
    inc r16
    loop:
    lpm r0, Z+
    st X+, r0
    dec r16
    brne loop
  end['r0','r16','r26','r27','r30','r31'];
end;
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

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

Re: AVR - Strings direkt aus Flash lesen

Beitrag von FPK »

Timm Thaler hat geschrieben:Das geht doch bestimmt eleganter...?


Assembler und Pascal in einem Unterprogramm nicht mischen, da gibt der Optimierer schnell auf. Einfach direkt auf r20 bis r25 zurgreifen.

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 - Strings direkt aus Flash lesen

Beitrag von Timm Thaler »

FPK hat geschrieben:Assembler und Pascal in einem Unterprogramm nicht mischen, da gibt der Optimierer schnell auf. Einfach direkt auf r20 bis r25 zurgreifen.


Das hätte ich auch gern gemacht, aber woher weiss ich wie r20 bis r25 zugeordnet werden, und ob das immer gleich bleibt?

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 - Strings direkt aus Flash lesen

Beitrag von Timm Thaler »

Mathias hat geschrieben:Was macht diese Zeile ?


In the assembler block modified registers have to be published to the compiler in the end statement, so that the compiler can take care of pushing or avoiding registers. The resulting code is more effective than pushing registers manually inside the asm section. Modified but unpublished registers may leed to malfunction.

Code: Alles auswählen

asm
  ldi r20,35        //r20 modified
  ldi r21,12        //r21 modified
end['r20','r21'];   //publish modified registers to compiler
 

http://wiki.freepascal.org/AVR_Programming#Inline_assembler

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: AVR - Strings direkt aus Flash lesen

Beitrag von Socke »

Timm Thaler hat geschrieben:
FPK hat geschrieben:Assembler und Pascal in einem Unterprogramm nicht mischen, da gibt der Optimierer schnell auf. Einfach direkt auf r20 bis r25 zurgreifen.

Das hätte ich auch gern gemacht, aber woher weiss ich wie r20 bis r25 zugeordnet werden, und ob das immer gleich bleibt?

Soweit ich das gesehen habe, müsste mein Code von Oben das umsetzen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

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 - Strings direkt aus Flash lesen

Beitrag von Timm Thaler »

Socke hat geschrieben:Soweit ich das gesehen habe, müsste mein Code von Oben das umsetzen.


Besser, aber nicht optimal. Naja, wenn man optimal will muss man wahrscheinlich alles in ASM machen.

Code: Alles auswählen

procedure copy_pgm_string(psrc, pto : pchar);
label
  loop;
begin
  asm
    mov r26, r22
    mov r27, r23
    mov r30, r24
    mov r31, r25
    lpm r0, Z+
    st X+, r0
    mov r16, r0
    loop:
    lpm r0, Z+
    st X+, r0
    dec r16
    brne loop
  end['r0','r16','r26','r27','r30','r31'];
end;


kompiliert zu:

Code: Alles auswählen

GH_INIT_ss_COPY_PGM_STRINGsPCHARsPCHAR:
   push   r29
   push   r28
   push   r16
   in   r28,61
   in   r29,62
   subi   r28,6
   sbci   r29,0
   in   r0,63
   cli
   out   62,r29
   out   63,r0
   out   61,r28
   std   Y+2,r24
   std   Y+3,r25
   std   Y+4,r22
   std   Y+5,r23
CPU AVR5
   mov   r26,r22
   mov   r27,r23
   mov   r30,r24
   mov   r31,r25
   lpm   r0,z+
   st   x+,r0
   mov   r16,r0
.Lj9:
   lpm   r0,z+
   st   x+,r0
   dec   r16
   brne   .Lj9
CPU AVR5
   subi   r28,-6
   sbci   r29,-1
   in   r0,63
   cli
   out   62,r29
   out   63,r0
   out   61,r28
   pop   r16
   pop   r28
   pop   r29
   ret
 


Und Dein Code:

Code: Alles auswählen

procedure copy2_pgm_string(psrc, pto : pchar);
label
  loop;
type
  // Struktur zum Zugriff auf die einzelnene Bytes
  TUInt16Struct = packed record
    l: uint8;
    h: uint8;
  end;
var
  // es kann kein direkter Zugriff auf die Record-Elemente erfolgen
  // daher muss jedes Byte einen separaten Namen erhalten
  s: TUInt16Struct absolute psrc;
  lsrc: Uint8 absolute s.l;
  hsrc: Uint8 absolute s.h;
  t: TUInt16Struct absolute pto;
  lto: Uint8 absolute t.l;
  hto: Uint8 absolute t.h;
begin
  asm
    ldd r30, lsrc
    ldd r31, hsrc
    ldd r26, lto
    ldd r27, hto
    lpm r0, Z+
    st X+, r0
    mov r16, r0
    loop:
    lpm r0, Z+
    st X+, r0
    dec r16
    brne loop
  end['r0','r16','r26','r27','r30','r31'];
end;


kompiliert zu:

Code: Alles auswählen

GH_INIT_ss_COPY2_PGM_STRINGsPCHARsPCHAR:
   push   r29
   push   r28
   push   r16
   in   r28,61
   in   r29,62
   subi   r28,6
   sbci   r29,0
   in   r0,63
   cli
   out   62,r29
   out   63,r0
   out   61,r28
   std   Y+2,r24
   std   Y+3,r25
   std   Y+4,r22
   std   Y+5,r23
CPU AVR5
   ldd   r30,Y+2
   ldd   r31,Y+2
   ldd   r26,Y+4
   ldd   r27,Y+4
   lpm   r0,z+
   st   x+,r0
   mov   r16,r0
.Lj12:
   lpm   r0,z+
   st   x+,r0
   dec   r16
   brne   .Lj12
CPU AVR5
   subi   r28,-6
   sbci   r29,-1
   in   r0,63
   cli
   out   62,r29
   out   63,r0
   out   61,r28
   pop   r16
   pop   r28
   pop   r29
   ret
 


Mit den paar unnötigen st, ld muss man wohl leben.

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: AVR - Strings direkt aus Flash lesen

Beitrag von Socke »

Timm Thaler hat geschrieben:
Socke hat geschrieben:Soweit ich das gesehen habe, müsste mein Code von Oben das umsetzen.


Besser, aber nicht optimal. Naja, wenn man optimal will muss man wahrscheinlich alles in ASM machen.

Okay, du hast mich überzeugt :oops:

Timm Thaler hat geschrieben:Mit den paar unnötigen st, ld muss man wohl leben.

Bringt der Prozedur-Modifier nostackframe bzw. assembler etwas? Dann muss ggf. zwar noch mehr in Assembler geschrieben werden, aber damit solltest du volle Kontrolle über den dann nicht mehr veränderten Assembler-Code haben.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

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 - Strings direkt aus Flash lesen

Beitrag von Mathias »

Ich habe mal folgendes probiert, anstelle von Hello Word, kommen nur Hieroglyphen.

Code: Alles auswählen

const
  s: ShortString = 'Hello World !'; section '.eeprom';
begin
  UARTInit;
  repeat
    if UARTReadChar = #32 then begin
      UARTSendString(s + #13#10);
    end;
  until 1 = 2;
end.

Habe ich da etwas falsch verstanden ?

Das ich die probieren wollte, unter Arduino habe ich dafür die Funktion F(entdeckt.

Code: Alles auswählen

  Serial.println(F("Hello World"));

Code: Alles auswählen

#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: AVR - Strings direkt aus Flash lesen

Beitrag von kupferstecher »

Mathias hat geschrieben:Ich habe mal folgendes probiert, anstelle von Hello Word, kommen nur Hieroglyphen.

Code: Alles auswählen

const
  s: ShortString = 'Hello World !'; section '.eeprom';
 

Der Teil ist richtig.

Code: Alles auswählen

 
      UARTSendString(s + #13#10);
 

Das funktioniert nicht. Der FPC kann bisher nicht vom Eeprom laden. Du musst den String mittels Inline-Assembler laden und uebergeben. Vermutlich laedt das Programm in deinem Fall vom SRAM an gleicher Adresse, daher die Hieroglyphen.

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 - Strings direkt aus Flash lesen

Beitrag von Mathias »

Das funktioniert nicht. Der FPC kann bisher nicht vom Eeprom laden. Du musst den String mittels Inline-Assembler laden und uebergeben.

Ist dies der gleiche EEPROM wie hier ?

http://wiki.freepascal.org/AVR_Embedded ... _EEPROM/de
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: AVR - Strings direkt aus Flash lesen

Beitrag von kupferstecher »

Ja, ist der Gleiche.
D.h. du hast recht, Inline-Assembler ist natuerlich nicht noetig. Beim Flash-Speicher (section '.progmem') aber schon, da gibt es einen speziellen Asm-Befehl (LPM) zum Laden der Werte (statt ueber Register).
Ob das Speichern in den Eeprom ueber den Programmer so funktioniert muesste man testen. Zumindest die Syntax stimmt.

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 - Strings direkt aus Flash lesen

Beitrag von Mathias »

Ob das Speichern in den Eeprom ueber den Programmer so funktioniert muesste man testen. Zumindest die Syntax stimmt.

So wie es aussieht, geht dies NICHT.

Zuerst habe ich folgenden Code ausgeführt, wie oben beschrieben kommt nur Mist.

Code: Alles auswählen

const
  s: ShortString = 'Ich liebe Lazarus !'; section '.eeprom';
begin
  UARTInit;
  repeat
    if UARTReadChar = #32 then begin
      UARTSendString(s + #13#10);
    end;
  until 1 = 2;
end.


Anschliessend habe ich folgendes ausgeführt, da kommt immer noch der EEPROM-Inhalt, welcher ich vor längerer Zeit hoch geladen habe.

Code: Alles auswählen

begin
  UARTInit;
  // String lesen, inklusive Längenbyte.
  SetLength(s, EEPROM_read(0)); // Länge auslesen.
  for i := 1 to Length(s) do begin
    s[i] := char(EEPROM_read(i));
  end;
 
  repeat
    UARTSendString(s);
    UARTSendString(#13#10);
  until 1 = 2;
end.



Jetzt habe ich gerade noch etwas anderes festgestellt.
Folgender Code gibt Hieroglyphen aus:

Code: Alles auswählen

      UARTSendString(s + #13#10);


Ändere ich ihn zu diesem:

Code: Alles auswählen

      UARTSendString(s);
      UARTSendString('-'#13#10);

Dann kommt nur noch ein '-' und der Zeilenumbruch.


Noch etwas, schreibe ich Müll bei section, dann motz nicht mal der Compiler/Linker.

Code: Alles auswählen

const
  s: ShortString = 'Ich liebe Lazarus !'; section '.abc';
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten