AVR Stringoperationen

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
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 Stringoperationen

Beitrag von Mathias »

Wieso geht so eine einfache String-Operation nicht ?

Code: Alles auswählen

var
  s: shortstring;
begin
  s := '123';
  s := s + '456'// Project1.pas(162,8) Fatal: Unknown compilerproc "fpc_shortstr_to_ansistr". Check if you use the correct run time library.

Irgendwie will er etwas ansistring machen, obwohl es die in AVR nicht gibt. :roll:
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 Stringoperationen

Beitrag von Timm Thaler »

Weil das eine ein shortstring ist und das andere ein Ansistring (string).

Mach doch beide normale string. shortstring brauchst Du meiner bisherigen Beobachtung nach nicht.

Aber Vorsicht: Stringoperationen können ganz schnell den Speicherbedarf ganz sehr aufblähen. Funktionieren aber unter Beachtung einiger Sonderlichkeiten erstaunlich gut.

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 Stringoperationen

Beitrag von Mathias »

Weil das eine ein shortstring ist und das andere ein Ansistring (string).

Unter PC-Lazarus geht dies.

Mach doch beide normale string. shortstring brauchst Du meiner bisherigen Beobachtung nach nicht.

Dies get auch nicht.

Code: Alles auswählen

var
  s: string;
begin
  s := '123'// Project1.pas(161,3) Fatal: Unknown compilerproc "fpc_ansistr_assign". Check if you use the correct run time library.
  s := s + '456';
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 Stringoperationen

Beitrag von Timm Thaler »

Das geht:

Code: Alles auswählen

  text1, text2 : string[30];
begin
  text1 := '123';
  text1 := text1 + '4' + '5' + '6';
  text2 := '456';
  text1 := text1 + text2;
  text1 := concat(text1, text2);
 

Strings mit Länge definieren ist eine gute Idee, weil der Compiler ja genug Sram dafür reservieren muss.

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

Re: AVR Stringoperationen

Beitrag von kupferstecher »

Mathias, vermutlich hast du den {H+}-Kompilerswitch in der Datei?

Hab mir vor ein paar Tagen die ShortString-Thematik nochmal angeschaut.

In Kürze:
- Auf dem AVR sind nur Shortstrings möglich.
- Die Deklaration "String[30]" bedeuted immer Shortstring mit Länge 30. Ansistrings haben eine dynamische Größe, dort gibt es keine Deklarationen mit Längenangabe.
- "ShortString" ist ein Shortstring mit Länge 255.
- Der Kompilerswitch {H+} verwendet für alle Stringdeklaration Ansistring statt Shortstring, vermutlich auch bei den Konstanten.

Wie Tim Thaler schon gesagt hat, die String-Operationen sind sehr teuer was Speicherbedarf angeht. Am besten immer Shortstrings mit Längenangabe verwenden. Vom ersten Blick auf des Assemblerlisting zu urteilen verwenden die Freepascal-Routinen aber intern die Längen 255 für Zwischenergebnisse. Es kann sich also lohnen maximal 2 Strings pro Zeile zu verknüpfen, also bspw.

Result:= Str1+Str2;
Result:= Result + Str3;

statt

Result:= Str1+Str2 + Str3;

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 Stringoperationen

Beitrag von Timm Thaler »

Facepalm! Natürlich, mit {$H-} geht auch das:

Code: Alles auswählen

  text1 := text1 + '789';


Das Compilat sieht dann zu meinem obigen Beispiel so aus:

Code: Alles auswählen

PASCALMAIN:
# [9] begin
   push   r29
   push   r28
   in   r28,61  ;bißchen Stackpointer einrichten und sichern
   in   r29,62
   subi   r28,10
   sbci   r29,2
   in   r0,63
   cli
   out   62,r29
   out   63,r0
   out   61,r28
   call   FPC_INIT_FUNC_TABLE  ;globale Variablen initialisiseren UND STRINGS AUS FLASH IN SRAM ABLEGEN
# [10] text1 := '123';
   ldi   r18,lo8(U_sPsTEST_ss_TEXT1)  ;Adresse text1 im Sram
   ldi   r25,hi8(U_sPsTEST_ss_TEXT1)
   ldi   r20,lo8(_sTESTs_Ld1)  ;Adresse String '123' im Sram
   ldi   r21,hi8(_sTESTs_Ld1)
   ldi   r22,30  ;Länge text1
   mov   r23,r1
   mov   r24,r18
   call   fpc_shortstr_to_shortstr  ;String kopieren
# [11] text1 := text1 + '4' + '5' + '6';
   ldi   r20,lo8(U_sPsTEST_ss_TEXT1)  ;Adresse text1
   ldi   r21,hi8(U_sPsTEST_ss_TEXT1)
   ldi   r22,-1
   mov   r23,r1
   ldi   r24,lo8(266)
   ldi   r25,hi8(266)
   add   r24,r28
   adc   r25,r29
   call   fpc_shortstr_to_shortstr   ;Kopie von text1
   ldi   r19,lo8(266)
   ldi   r18,hi8(266)
   add   r19,r28
   adc   r18,r29
   ldi   r30,lo8(258)
   ldi   r31,hi8(258)
   add   r30,r28
   adc   r31,r29
   st   Z+,r19
   st   Z,r18
   ldi   r18,lo8(_sTESTs_Ld2)  ;'4' anhängen
   ldi   r19,hi8(_sTESTs_Ld2)
   ldi   r30,lo8(260)
   ldi   r31,hi8(260)
   add   r30,r28
   adc   r31,r29
   st   Z+,r18
   st   Z,r19
   ldi   r18,lo8(_sTESTs_Ld3)  ;'5' anhängen
   ldi   r19,hi8(_sTESTs_Ld3)
   ldi   r30,lo8(262)
   ldi   r31,hi8(262)
   add   r30,r28
   adc   r31,r29
   st   Z+,r18
   st   Z,r19
   ldi   r18,lo8(_sTESTs_Ld4)  ;'6' anhängen
   ldi   r19,hi8(_sTESTs_Ld4)
   ldi   r30,lo8(264)
   ldi   r31,hi8(264)
   add   r30,r28
   adc   r31,r29
   st   Z+,r18
   st   Z,r19
   ldi   r20,lo8(258)
   ldi   r21,hi8(258)
   add   r20,r28
   adc   r21,r29
   ldi   r18,3
   mov   r19,r1
   ldi   r22,-1
   mov   r23,r1
   ldi   r24,lo8(2)
   ldi   r25,hi8(2)
   add   r24,r28
   adc   r25,r29
   call   fpc_shortstr_concat_multi  ;Strings verbinden = Gesamtzahl Zeichen ermitteln
   ldi   r20,lo8(2)
   ldi   r21,hi8(2)
   add   r20,r28
   adc   r21,r29
   ldi   r24,lo8(U_sPsTEST_ss_TEXT1)  ;Adresse text1
   ldi   r25,hi8(U_sPsTEST_ss_TEXT1)
   ldi   r22,30
   mov   r23,r1
   call   fpc_shortstr_to_shortstr  ;text1 wieder zurückschreiben
# [12] text2 := '456';
   ldi   r24,lo8(U_sPsTEST_ss_TEXT2)  ;Adresse text2 im Sram
   ldi   r25,hi8(U_sPsTEST_ss_TEXT2)
   ldi   r20,lo8(_sTESTs_Ld5)  ;Adresse '456' im Sram
   ldi   r21,hi8(_sTESTs_Ld5)
   ldi   r22,30
   mov   r23,r1
   call   fpc_shortstr_to_shortstr  ;'456' in text2
# [13] text1 := text1 + text2;
   ldi   r18,lo8(U_sPsTEST_ss_TEXT2)  ;Adresse text2
   ldi   r19,hi8(U_sPsTEST_ss_TEXT2)
   ldi   r20,lo8(U_sPsTEST_ss_TEXT1)  ;Adresse text1
   ldi   r21,hi8(U_sPsTEST_ss_TEXT1)
   ldi   r22,-1
   mov   r23,r1
   ldi   r24,lo8(2)
   ldi   r25,hi8(2)
   add   r24,r28
   adc   r25,r29
   call   fpc_shortstr_concat  ;Strings verbinden
   ldi   r20,lo8(2)
   ldi   r21,hi8(2)
   add   r20,r28
   adc   r21,r29
   ldi   r24,lo8(U_sPsTEST_ss_TEXT1)  ;Adresse text1
   ldi   r25,hi8(U_sPsTEST_ss_TEXT1)
   ldi   r22,30
   mov   r23,r1
   call   fpc_shortstr_to_shortstr  ;zurückschreiben in text1
# [14] text1 := text1 + '789';
   ldi   r20,lo8(U_sPsTEST_ss_TEXT1)
   ldi   r21,hi8(U_sPsTEST_ss_TEXT1)
   ldi   r18,lo8(_sTESTs_Ld6)
   ldi   r19,hi8(_sTESTs_Ld6)
   ldi   r22,-1
   mov   r23,r1
   ldi   r24,lo8(2)
   ldi   r25,hi8(2)
   add   r24,r28
   adc   r25,r29
   call   fpc_shortstr_concat
   ldi   r20,lo8(2)
   ldi   r21,hi8(2)
   add   r20,r28
   adc   r21,r29
   ldi   r24,lo8(U_sPsTEST_ss_TEXT1)
   ldi   r25,hi8(U_sPsTEST_ss_TEXT1)
   ldi   r22,30
   mov   r23,r1
   call   fpc_shortstr_to_shortstr
# [15] text1 := concat(text1, text2);
   ldi   r18,lo8(U_sPsTEST_ss_TEXT2)
   ldi   r19,hi8(U_sPsTEST_ss_TEXT2)
   ldi   r20,lo8(U_sPsTEST_ss_TEXT1)
   ldi   r21,hi8(U_sPsTEST_ss_TEXT1)
   ldi   r22,-1
   mov   r23,r1
   ldi   r24,lo8(2)
   ldi   r25,hi8(2)
   add   r24,r28
   adc   r25,r29
   call   fpc_shortstr_concat
   ldi   r20,lo8(2)
   ldi   r21,hi8(2)
   add   r20,r28
   adc   r21,r29
   ldi   r24,lo8(U_sPsTEST_ss_TEXT1)
   ldi   r25,hi8(U_sPsTEST_ss_TEXT1)
   ldi   r22,30
   mov   r23,r1
   call   fpc_shortstr_to_shortstr
# [16] end.
...
# Begin asmlist al_typedconsts
_sTESTs_Ld1:
   .ascii   "\003123\000"  ;3 Zeichen 123
_sTESTs_Ld2:
   .ascii   "\0014\000"  ;1 Zeichen 4
_sTESTs_Ld3:
   .ascii   "\0015\000"  ;1 Zeichen 5 usw.
_sTESTs_Ld4:
   .ascii   "\0016\000"
_sTESTs_Ld5:
   .ascii   "\003456\000"
_sTESTs_Ld6:
   .ascii   "\003789\000"


Man sieht: concat macht nix anderes als text1 + text2. Zeichen einzeln zuweisen macht genausoviel Aufwand wie längere Strings zuweisen. Und der Sram-Verbrauch ist erheblich, weil auch die Stringkonstanten erstmal alle im Sram gespeichert werden und nicht direkt aus dem Flash geholt werden.

Und das Hin- und Herkopiere mit fpc_shortstr_to_shortstr trägt nicht gerade zur Effizienz bei. Obwohl die maximale Länge des String mit 30 vorgegeben ist und zusätzliche String gleich an diese Stelle kopiert werden könnte, wird offenbar erstmal eine Kopie angelegt und diese dann zurückkopiert.

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 Stringoperationen

Beitrag von Mathias »

Mathias, vermutlich hast du den {H+}-Kompilerswitch in der Datei?

Genau, das war der Fehler.
Jetzt geht so was:

Code: Alles auswählen

var
  s: String; // oder String[20];
begin
    UARTSendString(s + #13#10);
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten