Forum: Compiler & IDEs Menü mit WinAVR - Speicherproblem


von Ronny Schulz (Gast)


Lesenswert?

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.

von Wolf-Ruediger Juergens (Gast)


Lesenswert?

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

von Ronny Schulz (Gast)


Lesenswert?

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.

von Jörg Wunsch (Gast)


Lesenswert?

>
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.

von Ronny Schulz (Gast)


Lesenswert?

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.

von Jörg Wunsch (Gast)


Lesenswert?

> 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.

von Ronny Schulz (Gast)


Lesenswert?

> 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?

von Jörg Wunsch (Gast)


Lesenswert?

> 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. ;-)

von Ronny Schulz (Gast)


Lesenswert?

Vielen Dank. Ich habe das jetzt verstanden und habe das natürlich gleich
eingebunden. Strings gehen schon ganz gut.

von Gerald (Gast)


Lesenswert?

hi!

was verwendet man beim IAR compiler für pgm_read_word (gcc)??

bye

von Gast (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.