AVR Stringoperationen

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
Mathias
Beiträge: 6918
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: 6918
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: 431
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: 6918
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