Ich habe nach langer Zeit endlich mal wieder WinAVR angefasst, da mein Grundlayout erstmal fertig ist und ich ein Menü über ein VFD-Display steuern will. Folgendes Problem: Irgendwann, wenn mein Menü groß genug ist stürzt der ATmega16 einfach nach Start ab, weil der Speicher gefüllt ist. Mein Menü liegt dabei in einem Stringarray. Folgende Lösungsansätze gab es: 1. ATmega32 verwenden (Pinkompatibel) - nur wegen des SRAMs ?! 2. Array im Flash ablegen und zugreifen Punkt 2 wäre natürliche die optimalste Lösung. Aber wie soll das funktionieren, dass ich da auch noch zugreifen kann? Wenn es einmal im Flash ist, müsste ich ja mit den verbiegen von Adressen direkt darauf zugreifen - sofern der ATmega mich lässt. Nur wie bekomme ich das Array da rein und wie greife ich bestmöglich darauf zurück? Ich hatte das damals mal mit einer Funktion gemacht, die ich einfach in den Hauptspeicher kopiert habe, um den Flash wärend des betriebes neu zu beschreiben. Das war aber auch kein Atmel und der Flash war ein externer Speicher. Nur hier ist ja erst einmal die Schwierigkeit das in den Flash zu bekommen. Die 16K sind ja locker ausreichend.
Moin, Schau mal in die AVR-GCC FAQ[1], unter "Program Space String" dort ist es beschrieben. [1] http://jubal.westnet.com/AVR/doc/avr-libc-user-manual/group__avr__pgmspace.html Schöne Ostern Wolf
Vielen Dank! Ich glaube das war der nötige Anstoß, den ich brauchte. Ich kann zwar mitd en Funktionen selbst nichts anfangen, da ich ja keine flexiblen Daten irgendwo speichere aber mein erster Test mit einer CRC-Tabelle hat schonmal massig Speicher gespart: const unsigned char crc8_data[] = { x, y, .. }; umgewandelt in const unsigned char crc8_data[] PROGMEM = { x, y, .. }; Ich hoffe das klappt dann auch so und ich kann dann mein Menü in den Flash schieben. Muss ich demnächst mal probieren. Gesegnete Osterfeiertage wünsche ich noch.
> http://jubal.westnet.com/AVR/doc/avr-libc-user-manual/group__avr__pgms... Bitte wieder den offiziellen Standort benutzen: http://www.nongnu.org/avr-libc/user-manual/index.html http://www.nongnu.org/avr-libc/user-manual/FAQ.html jubal.westnet.com war nur ein Ausweich-Standort, bis wir ein Verfahren gefunden hatten, mit dem wir es auf www.nongnu.org ablegen können.
Ich habe mir das mal angeschaut. Die optimalste Lösung ist das ja leider nicht. Ich verstehe garnicht, wieso "const" nicht sowieso in den Festspeicher gelegt werden. Aber für die notwendigsten Sachen werde ich es doch machen. Für einzelne Bytetabellen lohnt das ja kaum, da man die Werte ja immer mit pgm_read_byte aulesen muss. Aber warum kriegt der das hier nicht auf die Reihe? Bin ich blind? So ein paar Ausschnitte: const char menu_tab_temp_a[] PROGMEM = "Temperatur Sensor %d\r\n%d \370C"; const char menu_tab_temp_b[] PROGMEM = "Sensor an/aus\r\n%s"; const char menu_tab_type[] = { MENU_TYPE_HEAD, MENU_TYPE_SUB, MENU_TYPE_SUB, MENU_TYPE_SUB, MENU_TYPE_SUB, MENU_TYPE_SUB, MENU_TYPE_SUB, MENU_TYPE_ENDSUB, MENU_TYPE_HEAD, MENU_TYPE_SUB, MENU_TYPE_SUB, MENU_TYPE_SUB, MENU_TYPE_SUB, MENU_TYPE_SUB, MENU_TYPE_SUB, MENU_TYPE_ENDSUB, PGM_P menu_tab_text[] PROGMEM = { menu_tab_temp_a, menu_tab_temp_b, menu_tab_temp_c, menu_tab_temp_d, menu_tab_temp_e, menu_tab_temp_f, menu_tab_temp_g, 0, menu_tab_temp_a, menu_tab_temp_b, menu_tab_temp_c, menu_tab_temp_d, menu_tab_temp_e, menu_tab_temp_f, menu_tab_temp_g, 0, char menu_text[50]; char menubuf[50]; unsigned char menupos = 0; menupos = 0; strcpy_P(menu_text, menu_tab_text[menupos]); switch (menu_tab_type[menupos]) { case MENU_TYPE_HEAD: sprintf(menubuf, menu_text, 1, 25); break; case MENU_TYPE_SUB: sprintf(menubuf, menu_text, 41); break; default: menubuf[0] = 'A'; menubuf[1] = 0; } vfd_print(menubuf); Der gibt da immeer Müll als Text aus. Oder kurz: Sieht aus, als ob menupos nicht 0 ist.
> Ich verstehe garnicht, wieso "const" nicht sowieso in den > Festspeicher gelegt werden. Weil das absolut nicht der Sinn des `const' qualifiers ist (zumindest nicht in C -- in C++ ist das was anderes). Insbesondere aber, weil C ganz offenbar nicht so recht für Harvard-Architekturen konzipiert worden ist. Hatten wir hier schon ein paarmal. Ein string literal (das ja implizit sowas wie `const' ist) ist ein gültiger Parameter für die str*() Standard-Funktionen. Mit separatem ROM-Segment funktioniert das aber nicht mehr (*), wenn die string literals automatisch im ROM landen. (*) Ausnahme: nur über objektorientierte Ansätze wie die `generic pointers' beim Keil C51 Compiler. Das wiederum geht zu Lasten von Speicherplatz (jede Funktion ist zwangsweise dreimal da, da erst zur Laufzeit entschieden wird, was wirklich benötigt wird) und Laufzeit. > Für einzelne Bytetabellen lohnt das ja kaum, da man die Werte ja > immer mit pgm_read_byte aulesen muss. Der Prozessor muß das ohnehin, egal, ob Dir der Compiler das abnimmt (wie beim IAR) oder ob Du das explizit hinschreiben mußt (wie beim GCC). > PGM_P menu_tab_text[] PROGMEM Das sieht mir sehr nach doppelt gemoppelt aus. const char *menu_tab_text[] PROGMEM = ... müßte meiner Meinung nach OK sein. menu_tab_text[] wandert durch `PROGMEM' in den ROM. Du mußt dann jeden der Pointer mit pgm_read_word() erstmal auslesen, bevor Du den Inhalt nach strcpy_P() schicken darfst.
> Der Prozessor muß das ohnehin, egal, ob Dir der Compiler das abnimmt > (wie beim IAR) oder ob Du das explizit hinschreiben mußt (wie beim > GCC). Nagut, wenn das nacher funktioniert und ich immernoch zu enig Speicher habe, kann ich es ja auch umbauen. >> PGM_P menu_tab_text[] PROGMEM > Das sieht mir sehr nach doppelt gemoppelt aus. > const char *menu_tab_text[] PROGMEM = ... > müßte meiner Meinung nach OK sein. Dachte ich auch erst. Aber laut FAQ (http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_rom_array) soll das so gemacht werden. Letztendlich steht da sicher auch nur für PGM_P const char * irgendwas nehme ich mal an. > menu_tab_text[] wandert durch `PROGMEM' in den ROM. Du mußt dann > jeden der Pointer mit pgm_read_word() erstmal auslesen, bevor Du > den Inhalt nach strcpy_P() schicken darfst. Auch hier wird das nach FAQ so gemnacht. Dafür denke ich ist ja die Funktion strcpy_P da, die in pgmspace.h definiert wurde. Nachtrag: Wenn ich anstatt "menupos" eine 0 eintrage geht das. Aber warum?
> Auch hier wird das nach FAQ so gemnacht. Dafür denke ich ist ja die > Funktion strcpy_P da, die in pgmspace.h definiert wurde. Jein. Du hast beides im ROM stehen: menu_tab_text[] selbst, sowie die Zeiger auf die Strings, die in dieser Tabelle enthalten sind. strcpy_P() extrahiert die Strings sauber aus dem ROM, aber Du extrahierst den Inhalt von menu_tab_text[] selbst nicht aus dem ROM (sondern aus dem RAM). Da fehlt ein pgm_read_word(). > Nachtrag: Wenn ich anstatt "menupos" eine 0 eintrage geht das. Aber > warum? Weil der Compiler dann bereits die dereferenzierte ROM-Adresse an strcpy_P() übergibt, d. h. menu_tab_text[0] wird gar nicht zur Laufzeit ermittelt, sondern bereits zur Compilezeit. Genau dieses Symptom ist ein typischer Fall für pgm_read_word() vergessen. ;-)
Vielen Dank. Ich habe das jetzt verstanden und habe das natürlich gleich eingebunden. Strings gehen schon ganz gut.
hi! was verwendet man beim IAR compiler für pgm_read_word (gcc)?? bye
Man erstellt einen neuen Beitrag und stellt ihn ins Forum "µC&Elektronik". Mensch, waren wir einmal jung ;-)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.