PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : kriege Pointer auf String im Flash nicht übergeben...



derbasti
22.03.2006, 15:52
Hi!

Ich bin grad dabei meine LCD-lib etwas aufzumöbeln und kriege einen Pointer auf einen String im Flash im zusammenspiel mit einer variablen Argumentenliste nicht übergeben.

Das Funktioniert einwandfrei:

void lcd_test_p(uint8_t x, uint8_t y, PGM_P test) {
char temp[LCD_WIDTH];
sprintf_P(temp,test);
lcd_gotoxy(x,y);
lcd_write(temp);
}

das allerdings garnicht (crashed mein Programm):

void lcd_printf_xy_p(uint8_t x, uint8_t y, PGM_P fmt, ...) {
char temp[LCD_WIDTH];
va_list argp;
va_start(argp, fmt);
vsprintf_P(temp, fmt, argp);
va_end(argp);
lcd_gotoxy(x, y);
lcd_write(temp);
}

hab probiert die argumente zu vertauschen (erst das PGM_P fmt, dann x und y, dann die variable Argumentenliste) aber das hat garnix gebracht.

aufgerufen hab ich die funktionen so:

lcd_test_p(0,0,PSTR("Test")); /* funktioniert */
lcd_printf_xy_p(0,0,PSTR("Test")); /* funktioniert nicht */
lcd_printf_xy_p(0,0,PSTR("test %i"),1); /* funktioniert nicht */

wie kriegt man das gelöst? :-k

grüße,
Basti

SprinterSB
22.03.2006, 16:26
Kann man so schlecht sagen. Schau mal in den erzeugten Assembler, dann gibt's vielleicht ein Aha-Erlebnis. Wahrscheinlich fehlt eine Indirektonirgendwo oder ein Cast stimmt nicht

ogni42
23.03.2006, 09:02
Schau Dir mal die Makros für PGM_P va_start() und va_arg an. Ich vermute mal, da geht irgend etwas bei der Makrop-Expansion schief.

SprinterSB
23.03.2006, 10:53
Soweit ich sehen kann ist ok, was da raus kommt. Die Offsets stimmen (LCD_WIDTH=16).

Kann es sein, daß das Problem ganz woanders ist, daß dir RAM oder Flash ausgeht? Oder Arrays nicht groß genug sind?

*.i:

void lcd_printf_xy_p(uint8_t x, uint8_t y, const prog_char * fmt, ...) {
char temp[16];
va_list argp;
__builtin_va_start(argp,fmt);
vsprintf_P(temp, fmt, argp);
__builtin_va_end(argp);
lcd_gotoxy(x, y);
lcd_write(temp);
}

void foo(int val)
{
lcd_printf_xy_p(1, 2, ({static char __c[] __attribute__((__progmem__)) = ("Hallo %d"); __c;}), val);
}


*.s:

.global lcd_printf_xy_p
.type lcd_printf_xy_p, @function
lcd_printf_xy_p:
/* prologue: frame size=16 */
push r16
push r17
push r28
push r29
in r28,__SP_L__
in r29,__SP_H__
sbiw r28,16
in __tmp_reg__,__SREG__
cli
out __SP_H__,r29
out __SREG__,__tmp_reg__
out __SP_L__,r28
/* prologue end (size=12) */
ldd r16,Y+23 ; x, x ; 3 *movqi/4 [length = 1]
ldd r17,Y+24 ; y, y ; 4 *movqi/4 [length = 1]
ldd r24,Y+25 ; fmt, fmt ; 5 *movhi/2 [length = 2]
ldd r25,Y+26 ; fmt, fmt
movw r20,r28 ; argp, ; 37 *movhi/1 [length = 1]
subi r20,lo8(-(27)) ; argp, ; 16 *addhi3/4 [length = 2]
sbci r21,hi8(-(27)) ; argp,
movw r22,r24 ; fmt, fmt ; 17 *movhi/1 [length = 1]
movw r24,r28 ; , ; 38 *movhi/1 [length = 1]
adiw r24,1 ; , ; 18 *addhi3/2 [length = 1]
rcall vsprintf_P ; ; 19 call_value_insn/3 [length = 1]
mov r24,r17 ; y, y ; 22 zero_extendqihi2/2 [length = 2]
clr r25 ; y
movw r22,r24 ; y, y ; 24 *movhi/1 [length = 1]
mov r24,r16 ; x, x ; 25 zero_extendqihi2/2 [length = 2]
clr r25 ; x
rcall lcd_gotoxy ; ; 26 call_value_insn/3 [length = 1]
movw r24,r28 ; , ; 39 *movhi/1 [length = 1]
adiw r24,1 ; , ; 28 *addhi3/2 [length = 1]
rcall lcd_write ; ; 29 call_value_insn/3 [length = 1]
/* epilogue: frame size=16 */
adiw r28,16
in __tmp_reg__,__SREG__
cli
out __SP_H__,r29
out __SREG__,__tmp_reg__
out __SP_L__,r28
pop r29
pop r28
pop r17
pop r16
ret
/* epilogue end (size=11) */
/* function lcd_printf_xy_p size 43 (20) */
.size lcd_printf_xy_p, .-lcd_printf_xy_p
.section .progmem.data
.type __c.0, @object
.size __c.0, 9
__c.0:
.string "Hallo %d"
.text
.global foo
.type foo, @function
foo:
/* prologue: frame size=0 */
/* prologue end (size=0) */
push r25 ; val ; 12 *pushhi/1 [length = 2]
push r24 ; val
ldi r24,lo8(__c.0) ; tmp42, ; 13 *movhi/4 [length = 2]
ldi r25,hi8(__c.0) ; tmp42,
push r25 ; tmp42 ; 14 *pushhi/1 [length = 2]
push r24 ; tmp42
ldi r24,lo8(2) ; tmp43, ; 15 *movqi/2 [length = 1]
push r24 ; tmp43 ; 16 *pushqi/1 [length = 1]
ldi r24,lo8(1) ; tmp44, ; 17 *movqi/2 [length = 1]
push r24 ; tmp44 ; 18 *pushqi/1 [length = 1]
rcall lcd_printf_xy_p ; ; 19 call_insn/3 [length = 1]
in r24,__SP_L__ ; ; 28 *movhi/7 [length = 2]
in r25,__SP_H__ ;
adiw r24,6 ; , ; 21 *addhi3/2 [length = 1]
in __tmp_reg__,__SREG__ ; 29 *movhi/6 [length = 5]
cli
out __SP_H__,r25 ;
out __SREG__,__tmp_reg__
out __SP_L__,r24 ;
/* epilogue: frame size=0 */
ret

derbasti
23.03.2006, 11:31
Danke für die Antworten erstmal!
...leider übersteigen sie mein derzeitigen Horizont etwas... 8-[

Hab noch nie was mit AVR-Assembler gemacht und kannte C bis vor kurzem auch nur von anderen Plattformen...


Kann es sein, daß das Problem ganz woanders ist, daß dir RAM oder Flash ausgeht? Oder Arrays nicht groß genug sind?

Ich glaube nicht, hab das Programm eben darauf reduziert das LCD zu initialisieren und einmal die lcd_prinft_xy_p() aufzurufen, der Compiler meldet dabei 59% Flash belegt und 55% Ram belegt.

Dann eine Frage, Du hast hier ein *.i gepastet, scheint wohl das C-File zu sein nachdem der Preprozessor die Makros expandiert hat. Beim compilieren entsteht bei mir aber kein *.i File, wie kommt man da ran?

Hab grad mal das Quellcode-Stück mit den expandierten Makros von Dir verwendet, macht kein unterschied. D.h. dann dass es nicht an der Expansion der Makros liegt, oder?

Das *.s scheint wohl der erzeugte Assembler zu sein, etwas ähnliches befindet sich bei mir in main.lss. Sieht ziemlich gleich aus wie das was Du gepastet hast, nur ohne Kommentare. Leider versteh ich fast nur Bahnhof wenn ich da reinschau...

Heisst das nun: wenn ich diesen Fehler finden und beheben will komm ich nicht drum rum mich in AVR-Assembler einzuarbeiten?

Gruß,
Basti

SprinterSB
23.03.2006, 11:47
avr-gcc (https://www.roboternetz.de/wissen/index.php/Avr-gcc) erzeugt das precompile (*.i) und den Assembler (*.s) nur temporär und löscht diese Dateien wieder. Mit der Option -save-temps bleiben die Dateien erhalten.

An den Makros schein's nicht zu liegen.
Und der Assembler schaut auch ganz ok aus. Einfacher durchzusteigen ist vielleicht mit einem Debugger (auf asm-Ebene) durchzusteppen und zu schauen, ob die Adressen stimmen.

Die Speicher-Verbrauche kommen mir recht hoch vor, nur für LCD Ausgabe. Andererseits sind die *printf* als Speicherfresser bekannt...

Zur Compile-Zeit (bzw Link-Zeit) kann nur der statische Speicherplatzbedarf bestimmt werden. Da kommt noch hinzu, was der Compiler nicht sehen kann, also Platz für die Frames von Funktionen, Funktionsaufrufe und dynamischer Speicher via malloc, etc

Assembler zu können ist nicht notwendig, aber manche Fehler lassen sich fix finden, wenn man nen Blick ins asm wirft und es einem wie Schuppen von den Augen fällt...

derbasti
23.03.2006, 12:11
irgendwie krieg ich das mit den save-temps nicht hin. Hab folgende Zeile in mein Makefile geschrieben:
CFLAGS += -save-temps
hab die Zeile nach CFLAGS += -O$(OPT) eingefügt...
aber ich kann keine .i und .s dateien finden... was mach ich falsch? :)

SprinterSB
23.03.2006, 15:51
Die Dateien müssten im gleichen Verzeichnis auftauchen wie deine Objekte (*.o). Mit -save-temps bleiebn die Dateien erhalten wie von GCC erzeugt. Man kann auch Optionen mit -Wa,-adhlns=<Dateiname> an den Assembler (avr-as) weiterleiten, so daß er ein Listing schreibt. Zusammen mit -g hat man dann ein Mix aus asm und C-Quelle, wenn man das mag. Bei -save-temps kann man aber noch optionen angeben und sieht besser, aus welchen internen Operationen (INSNS) GCC den Assembler baut.

Ich vermute mal, du hast das Makefile nicht selber geschrieben und es sieht nicht gerade gut durchdringbar aus...;-) Eigentlich sollte es gehen. Ich verwende allerdings 2 Compileläufe, einen mit -c bis zum Object und einen mit -dp -S -save-temps -fverbose-asm für *.s und *.i.

Das *.lss oder *.lst ist kein Assembler-Listing, sondern ein Disassemble aus dem Object (*.o oder *.elf) und ebthält kaum noch Symbolinfos. Zusammen mit -g kann man aber auch mit C-Quelle mischen.

Kannst du irgendwie eingrenzen, was bei deinem Beispiel nicht funktioniert?

SprinterSB
24.03.2006, 11:11
Das Beispiel von oben hab ich mal durchdebuggt. Es geht so, wie man sich das vorstellt. Die Funktionen werden richtig aufgerufen, Stack richtig aufgebaut/abgebaut und Argumente korrekt übergeben.
Der String steht danach dort, wo er soll, und das Programm kehrt friedlich zurück nach main.

Das lcd_gotoxy und lcd_write hab ich rausgeworfen (hab ich net).

Also ist der Fehler dort, oder der Wurm ist wirklich beim Speicherverbrauch oder im Rest deines Programms.

Das kleine Progrämmchen (nur main, foo, lcd_printf_xy_p und die Lib-Funcs) brauchen mit -O2 schon über 0x700 (Dez ca. 1800) Bytes an Flash!!!
vsprintf scheint ca 60 Bytes an SRAM zu brauchen.

Check mal durch, ob das wirklich alles reinpasst bei dir.

derbasti
26.03.2006, 17:48
Vielen Dank für deine Mühe SprinterSB,
der Fehler war wie Du sagtest woanders im Programm, es lag einfach an meiner Dummheit... Der Compiler hatts mir immer gesagt, aber ich hab unter lauter "enumartion not handled in switch" warnings übersehen dass ich die lcd_printf_xy_p selbst nicht richtig deklariert hab. Habs erst dann bemerkt als ich nochmal nen leeres Projekt benutzt hab um die lcd lib zu testen...
"thy shall not ignore compiler warnings..." nochmal passiert mir das nicht... *schäm* ;)

Das mit dem Speicherbedarf is echt bissle heftig, is mir auch erst so richtig aufgefallen als Du mich mal drauf hingewiesen hast... Hab mal diese compiler-switches probiert um mit der abgespeckten Printf Version bissle Flash zu sparen, aber das lohnt ja kaum und ich brauch die Formatierung mit vorangestellter Null... Ich überleg mal ob ich um diese printf geschichte rumkomm, aber das ist halt so schön komfortabel...

Danke nochma,
Basti

SprinterSB
26.03.2006, 21:02
Warnungen zur Compilezeit werden nicht selten zu Laufzeit-Fehlern. Leztere sind deultich schwerer zu finden, als angewarnten Code in Odnung zu bringen...

In printf werden ja viele Formate abgehandelt, auch solche, die du net brauchst. Ne führende 0 vorzuhängen ist ja keine Wissenschaft.

Komfortabel isses, aber Bequemlichkeit kostet eben auch was... ;-)