Die Daten im Flash sind 16 Bit, ein Character aber nur 8 Bit. Du mußt die Pointer adresse * 2 nehmen.
Hallo,
irgendwie verstehe ich das jetzt mit den Pointern auf Flashspeicher nicht![]()
Als Beispiel hier ein Miniprogramm in C:
Es hat nicht viel Sinn, soll einfach nur deutlich machen, wo mein Problem liegt.Code:#include<stdio.h> void zeige(void) { printf("Hallo, hier bin ich\n"); } void zeige2(void) { printf("und hier noch einmal\n"); } int main(void) { typedef void (*funktion) (void); funktion feld[] = {&zeige,&zeige2}; feld[0](); feld[1](); return 0; }
Auf dem PC klappt es ja Prima, auf dem AVR hol ich mir ja irgendwelche RAM Adressen.
Ich weiß daß es an der Harvard Architektur und an den getrennten RAM/FLASH/EEPROM Adressräumen liegt, es ist auch kein Problem Daten zu lesen, nur halt mit Zeigern krieg ich das nicht hin
Aus der Doku zu avr-gcc werde ich auch nicht schlauer...
Könnte mir mal jemand unter die Arme greifen und mir mal sagen wie ich das Miniprogramm in AVR implementiere ?
Gruß Sebastian
Linus TorvaldSoftware is like s e x: its better when its free.
Die Daten im Flash sind 16 Bit, ein Character aber nur 8 Bit. Du mußt die Pointer adresse * 2 nehmen.
Hallo JonnyP,
würden wir hier von AVR Pointern sprechen, würde ich Dir recht geben, es geht sich aber um die C Zeiger und die haben damit nichts zu tun.
Trotzdem danke für die Antwort, ich komme schon langsam selber auf die Lösung![]()
Linus TorvaldSoftware is like s e x: its better when its free.
Ich hab da ein beispiel, da läuft das so:
Sieht wüst aus, aber du siehst, eigentlich brauch ich da nix tricksenCode:void HeartbtAct(UNIT* pUnit, unsigned char Cmd, unsigned short Param) { } // --------------------------------------------------- UNIT* HeartbtBuild(UNIT* pUnit, unsigned char UnitClass, unsigned char UnitIdent) { pUnit->iVect = (int)HeartbtAct; //SETZEN VECTOR } ..... später dann: union {void (*vVec)(UNIT* pUnit, unsigned char Cmd, unsigned short Param); int iVec; } Vec; UNIT* pUnit = (UNIT*)pMsg->iUnit; Vec.iVec = pUnit->iVect; // HOLEN VECTOR (*Vec.vVec)(pUnit, pMsg->bCommand, pMsg->wParam); // und aufrufen
Ich hoff', Du kannst Dir das ausdeutschen ?
mfg robert
Wer glaubt zu wissen, muß wissen, er glaubt.
Code:typedef void (*function_t) (void); extern void zeige (void); extern void zeige2 (void); function_t feld[] = {zeige, zeige2}; void caller (int addr, function_t zeige3) { feld[0](); feld[1](); zeige3(); ((void(*)(void)) addr) (); }Geht genauso.Zitat von izaseba
Obiger Code assemblier avr-gcc so:
Code:.file "foo.c" .arch atmega8 __SREG__ = 0x3f __SP_H__ = 0x3e __SP_L__ = 0x3d __tmp_reg__ = 0 __zero_reg__ = 1 .global __do_copy_data .global __do_clear_bss .global feld .data .type feld, @object .size feld, 4 feld: .word pm(zeige) .word pm(zeige2) .text .global caller .type caller, @function caller: /* prologue: frame size=0 */ push r14 push r15 push r16 push r17 /* prologue end (size=4) */ movw r14,r24 movw r16,r22 lds r30,feld lds r31,(feld)+1 icall lds r30,feld+2 lds r31,(feld+2)+1 icall movw r30,r16 icall movw r30,r14 icall /* epilogue: frame size=0 */ pop r17 pop r16 pop r15 pop r14 ret /* epilogue end (size=5) */ /* function caller size 25 (16) */ .size caller, .-caller /* File "adc.c": code 25 = 0x0019 ( 16), prologues 4, epilogues 5 */
Disclaimer: none. Sue me.
Hallo,
Danke erstmal.
Ich glaube, ich hab mich falsch ausgedrückt.
Sprinter, bei Deinem Beispiel klappt das, weil der Compiler die Adressen direkt einsetzen kann ? Kann das sein ?
Ich meine Hier:
Die Adressen stehen zu Kompilierzeit fest und müßen nicht im laufendem Betrieb geholt werden.Code:feld[0](); feld[1]();
Ich glaube, wenn man eine Variable bei dem Arrays verwenden würde würde es nicht klappen ?
Aber nochmal ein Beispiel:
Ich habe ein paar Strings in Flash gelegt:
dann eine Struktur :Code:const char menuhauptstr[] PROGMEM = "Hauptmenu"; const char menukontstr[] PROGMEM = "Kontrast"; const char menuhellstr[] PROGMEM = "Helligkeit"; const char menufrage[] PROGMEM = "Speichern ? ";
Zum Schluß ein Array mit diesen Strukturen im Flash:Code:struct MENU { const char *Menu_Name; uint8_t Entrie_up; uint8_t Entrie_down; uint8_t Entrie_right; uint8_t Entrie_left; void(*Menu_Funkt)(void); };
Will ich jetzt z.B. mit:Code:const struct MENU menu[] PROGMEM = { {menuhauptstr,3,1,10,15,Draw_Main}, {menuhellstr,0,2,10,15,Draw_Hell}, {menukontstr,1,3,10,15,NULL}, {menufrage,2,0,1,0,NULL} };
Meine Funktion aufrufen, klappt das nicht.Code:menu[i].Menu_Funkt();
Ich habe gelesen, daß man sich die Adresse zuerst mit (const char *)pgm_read_word(menu) holen muß, nur irgendwie krieg ich das nicht hin![]()
Ich hab es jetzt so gelöst, daß ich mein Array in RAM gelegt habe, dann geht alles wunderbar.
Ich glaub, entweder hab ich den Kapitel über Pointer bei Kernighan u. Ritchie oder die Harvald Architektur nicht verstanden.
Gruß Sebastian
Linus TorvaldSoftware is like s e x: its better when its free.
Dei Adresse muss nicht bekannt sein. Zwei Adressen in meinem Beispiel ergeben sich werst zur Laufzeit, andere zur Linkzeit (extern...). Woher die Adressen sind ist ja egal.
oderCode:function_t func = (function_t) pgm_read_word (& menu[i].Menu_Funkt); func();
Das Problem mit der Harvard-Architektur und GCC ist, daß man Flash-Adressen (dito EEPROM) als Attribut angibt, und nicht wie es sein müsste als Qualifier (so wie const, volatile, unsigned, ...). Das macht vielerorts Probleme. U.a weiß GCC beim zugriff nicht, wie er darauf zugreifen soll. Etwa wenn ein Zeiger in eine Funktion run kommt: ist es RAM-Adresse? EEPROM? oder Flash? Deshalb muss man umständlich mit den pgm_read/write Zeug arbeiten.Code:((function_t) pgm_read_word (& menu[i].Menu_Funkt))();
Für andere Architekturen (linearere Adressraum) hätte man einfach sagen können
#define pgm_read_byte(addr) (*((uint8_t*) addr))
bzw
#define pgm_read_byte(addr) (* addr)
wenn addr ein Zeiger aud uint8_t ist.
Wenn du eine Struktur im Flash hast musst du eben die Komponenten per pgm_xxx holen/schreiben:
x = a.b; --> pgm_read_block (&x, &a.b, sizeof (a.b));
x = a->b; --> pgm_read_block (&x, &a->b, sizeof (a->b));
Disclaimer: none. Sue me.
Beachte auch, daß du für die Strings zwei Induirektionen via pgm_xxx drinne hast (die zeite wohl in deiner out-Routine, die nen Zeiger ins Flash bekommt.
ergibt übrigensCode:void foo (uint8_t i) { ((void(*)(void)) pgm_read_word (& menu[i].Menu_Funkt)) (); }
Code:foo: mov r30,r24 clr r31 ldi r24,3 1: lsl r30 rol r31 dec r24 brne 1b subi r30,lo8(-(menu+6)) sbci r31,hi8(-(menu+6)) /* #APP */ lpm r24, Z+ lpm r25, Z /* #NOAPP */ movw r30,r24 icall ret
Disclaimer: none. Sue me.
Danke,
ich glaub es hat klick gemacht
Ich habe hier immer auf (const char) gecastet warum auf immerfunction_t func = (function_t) pgm_read_word (& menu[i].Menu_Funkt);
func();, jetzt hab ich wieder was zum probieren
Gruß Sebastian
Linus TorvaldSoftware is like s e x: its better when its free.
Ich hab den entsprechenden Abschnitt im C-Tutorial mal ausgefüllt. Hätte nicht gedacht, daß jemand Funktionszeiger benutzt
https://www.roboternetz.de/wissen/in...auf_Funktionen
Ein Beispiel haz's auch in
https://www.roboternetz.de/wissen/in...#Sprungtabelle
Disclaimer: none. Sue me.
Lesezeichen