Forum: Compiler & IDEs SRAM voll, RAM fast leer, printf und Array


von Hans J. (Firma: none) (hans-jakob)


Lesenswert?

Hallo zusammen!

Nachdem ich nun den ganzen Tag herum gesucht habe auf sämtlichen AVR 
Seiten und Foren und leider keine explizite Antwort bekommen habe, 
versuche ich nun doch mit meine Fragen an die Öffentlichkeit zu gehen.

Ich habe ein Programm mit vielen printf- Funktionen geschrieben.
Mein „Debugging“ mache ich über das HTerminal. Um den Programmablauf 
nachvollziehen zu können benötige ich die printf Funktionen. Jedes 
Zeichen im printf „klaut mir“ ein Byte im SRAM, soweit ist das klar.

Ich benutze einen ATMega 2561. Durch die bereits implementierten printfs 
usw. ist mein Data: (.data + .bss + .noinit) schon bei 3206 bytes (39.1% 
Full)

Mein Problem ist nun, dass ich einen Global Array von [6144] Werten 
erzeugen muss, um eine Tabelle einlesen zu können. Die Tabelle wird im 
SRAM abgespeichert. D.h. mein SRAM steigt auf ganze auf Data:9350 bytes 
(114.1% Full) (.data + .bss + .noinit) an.

D.h. das Programm ist unbrauchbar und ich kann es nicht mehr verwenden.
Hardwaretechnisch ist schon alles gefixt, so dass ich auch keinen 
externen SRAM mehr anbauen kann.

Wie kann ich denn nun schnell und effizient den SRAM nicht so auslasten 
und den Speicher für die Tabelle garantieren??

Gibt es die Möglichkeit die uint8_t Tabelle[6144] über PROGMEM in den 
RAM zu schreiben,
diese dann während der Programmlaufzeit mit Werten zu füllen und später 
wieder auszulesen??

Wäre echt super wenn mir jemand einen Rat hätte!
Vielen Dank

------------------------------------------------------------------------ 
-------------------------------------------

Build started 20.8.2008 at 19:52:40
avr-gcc.exe -mmcu=atmega2561 -Wl,-Map=weiterleitung.map 2561.o Delay.o 
RS232.o TWI216.o Main.o TWI_Master.o TMCadvanced.o TMCbasic.o USART.o 
Interrupt.o     -o weiterleitung.elf
avr-objcopy -O ihex -R .eeprom  weiterleitung.elf weiterleitung.hex
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" 
--change-section-lma .eeprom=0 --no-change-warnings -O ihex 
weiterleitung.elf weiterleitung.eep || exit 0
avr-objdump -h -S weiterleitung.elf > weiterleitung.lss

AVR Memory Usage
----------------
Device: atmega2561

Program:   17984 bytes (6.9% Full)
(.text + .data + .bootloader)

Data:       9350 bytes (114.1% Full)
(.data + .bss + .noinit)


Build succeeded with 0 Warnings...

Build succeeded with 1 Warnings...

von Andreas K. (a-k)


Lesenswert?

Debug-Strings müssen nicht ins RAM. Mit
   printf_P(PSTR("Hallo"));
landen sie nur im ROM.

Und mit
1
#if DEBUG
2
  #include <stdio.h>
3
  #define PRINTF(s, ...) do{ static char __s[] PROGMEM = (s); \
4
         printf_P(__s, ## __VA_ARGS__); }while(0)
5
#else
6
  #define PRINTF(s, ...)
7
#endif
kann man das auch als
  PRINTF("Hallo");
schreiben. Es gibt davon auch kürzere Varianten, aber diese funktioniert 
auch in C++.

von Hans J. (Firma: none) (hans-jakob)


Lesenswert?

vielen Dank für die schnelle Antwort!

ich habe

#if DEBUG
  #include <stdio.h>
  #define PRINTF(s, ...) do{ static char __s[] PROGMEM = (s); \
         printf_P(__s, ## _VA_ARGS_); }while(0)
#else
  #define PRINTF(s, ...)
#endif

eingefügt und alle printf mit PRINTF ersetzt.

Das Resultat war deutlich spürbar:
Von Data: 9350 bytes (114.1% Full) bin ich wirklich auf Data: 6476 bytes 
(79.1% Full) gekommen bei meinem 8K SRAM.

eine Frage habe ich noch:

Werte von Variablen werde ich wahrscheinlich mit der printf funktion 
printf(" %d \n", UDR); auf den Bildschirm hohlen müssen ??

Wenn ich mehrere C-Files habe, muss ich dann #if DEBUG ... #endif in 
jedes File einfügen? oder nur in mein Global.h oder in die Main.C ??

vielen Dank
Hans-Jakob

von Andreas K. (a-k)


Lesenswert?

Häng diese Definition in ein zentrales Includefile. Also dein Global.h.

Das geht natürlich genauso:
 PRINTF(" %d \n", UDR);
oder
 PRINTF("-%S-", PSTR("irgendeintextimROM"));
Das Makro sorgt nur dafür, dass der erste Parameter automatisch im ROM 
landet und die dazu passende printf-Version aufgerufen wird, ansonsten 
ist das mit dem normalen printf identisch.

von Andreas K. (a-k)


Lesenswert?

Ach ja: DEBUG muss natürlich irgendwie !=0 definiert sein. Ich habe 
üblicherweise ein zentrales Config-Include, in dem dann
  #define DEBUG 1
steht. Und wenn das Debugging nicht mehr gebraucht wurd, dann wird das 
0.

von Hans J. (Firma: none) (hans-jakob)


Lesenswert?

Okay! Super! vielen Dank!

deinen letzten Beitrag kapiere ich leider nicht.

Wie ist das mit dem #define DEBUG 1

und dem "Und wenn das Debugging nicht mehr gebraucht wurd, dann wird das
0."

kannst du mir da evtl ein bsp Quellcode zeigen?


Danke

von Andreas K. (a-k)


Lesenswert?

#define DEBUG 1
 => die PRINTF Statements werden übersetzt und ggf. ausgeführt.

#define DEBUG 0
 => die PRINTF Statements werden vom Compiler komplett ignoriert.

Wenn DEBUG nicht definiert ist, wirkt das als wäre es 0, so dass der 
Code vom Compiler ignoriert wird. Das spart natürlich doppelt Platz. Nur 
kriegst du so auch keine Ausgabe zu sehen.

von Hans J. (Firma: none) (hans-jakob)


Lesenswert?

Also folgende Funktionen funktionieren nicht:

PRINTF(" %d \n", UDR);

PRINTF("bitte mal UDR ausgeben %d \n", UDR);

PRINTF("-%S-", PSTR("irgendeintextimROM"));


Desweiteren bin ich echt zu doof dieses #define DEBUG 1 oder #define 
DEBUG 0 einzubauen.
Da kommt immer eine Fehler Meldung, das DEBUG redefined wird.
ob ich es in Golobal.h oder Main.c einbaue.

Zusätzlich habe ich festgestellt, wenn ich eine der nicht 
funktionierenden Funktionen einbaue, überhaupt keine Ausgabe auf dem 
Terminal stattfindet und sobald ich versuche diese nicht 
funktionierenden Funktionen wieder ausklammere mit // und es dann wieder 
compile und builde das ganze trotzdem nicht funktioniert.

Erst wenn ich eine Kopie des ganzen Programmes mache und dies wieder 
zusammen builde läuft die Kopie des Programmes, bis ich wieder eine 
nicht funktionierende Funktion einbaue.

------------------------------------------------------------------------ 
---
AVR Studio    4.14.589
GUI Version    4, 14, 0, 589
AVR Simulator    1, 0, 2, 1
ATmega2561    167

Operating System
Major      5
Minor      1
PlatformID    2
Build      2600
Service Pack 3

Plugins:

AvrPluginAvrAsmObject  1, 0, 0, 46
AvrPluginavrgccplugin  1, 0, 0, 9
Stk500Dll    1, 0, 1, 10

Zudem verwende ich die RS232.c und RS232.h Versionen aus 
Beitrag "AVR TWI Master und Slave Funtionen in C"

und WinAVR-20080512

von Simon K. (simon) Benutzerseite


Lesenswert?

Hans Jakob wrote:
> Also folgende Funktionen funktionieren nicht:
>
> PRINTF(" %d \n", UDR);
>
> PRINTF("bitte mal UDR ausgeben %d \n", UDR);
>
> PRINTF("-%S-", PSTR("irgendeintextimROM"));

"funktionieren nicht"? Was heißt das im Klartext?

Und wenn du DEBUG nochmal definierst, obwohl es schon definiert war, 
dann kommt der von dir genannte Fehler. Hast du schon irgendwo DEBUG im 
Code definiert? u.U. in deinen RS232 Quellen?

von Hans J. (Firma: none) (hans-jakob)


Lesenswert?

> "funktionieren nicht"? Was heißt das im Klartext?

Der Compiler baut alles schön zusammen und alles ist bereit zum Flashen. 
Nach korrektem Anschließen und Verbindungsaufbau an das Terminal müsste 
die Bildschirmausgabe kommen. Diese kommt nicht.

>Hast du schon irgendwo DEBUG im Code definiert? u.U. in deinen RS232 >Quellen?

Das einzige was ich gemacht habe ist das Macro von oben miteingebaut 
(#if DEBUG...#endif) und dann den Rat befolgt:
>>#define DEBUG 1
>> => die PRINTF Statements werden übersetzt und ggf. ausgeführt.
>>#define DEBUG 0
>> => die PRINTF Statements werden vom Compiler komplett ignoriert.

schreibe ich nun #define DEBUG 1 hinzu kommt folgende Fehlermeldung:
GlobalTest.c:24: undefined reference to `PRINTF_P'

von Martin Schneider (Gast)


Lesenswert?

sollte die Funktion nicht   printf_P   heißen?
Schau mal in deine Definition von PRINTF!

Ahoi, Martin

von A. F. (artur-f) Benutzerseite


Lesenswert?

@ Andreas Kaiser: das war der interessanteste Beitrag seit 2 Monaten, 
den ich hier gelesen habe :) Hatte auch Tabellen mit Pointern auf 
Funktionen, die nun  im ROM gelandet sind. Danke!

von Andreas K. (a-k)


Lesenswert?

Hans Jakob wrote:

> schreibe ich nun #define DEBUG 1 hinzu kommt folgende Fehlermeldung:
> GlobalTest.c:24: undefined reference to `PRINTF_P'

Dann hast du irgendwo im Makro PRINTF_P statt printf_P stehen.

von Andreas K. (a-k)


Lesenswert?

Artur F***** wrote:

> den ich hier gelesen habe :) Hatte auch Tabellen mit Pointern auf
> Funktionen, die nun  im ROM gelandet sind. Danke!

Das ist schon ein bischen um die Ecke gedacht, denn während das mit 
printf ziemlich transparent abläuft musst du dir die Pointer mit 
pgm_read_word zu Fuss aus dem ROM fischen.

von A. F. (artur-f) Benutzerseite


Lesenswert?

Ja stimmt, habe es nur mit meinen debug Messages getestet und zu früh 
gefreut :(
Das geht tatsächlich nicht. Habe folgendes Array:
1
typedef u8 (*fp)(void);
2
3
fp CMD_f[] PROGMEM = {  
4
NULL_CMD,CMD_0x01,CMD_0x02,CMD_0x03,CMD_0x04,NULL_CMD,NULL_CMD,NULL_CMD,  
5
NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,    
6
NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,  
7
NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,    
8
NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,NULL_CMD,  
9
...usw
10
};

Und die dazugehörige Funktion, die auf das Dasein des Pointers prüft:
...
1
  
2
fp FCTN  = CMD_f [CMD_BYTE];  
3
if (NULL_CMD != FCTN)  { 
4
      (*FCTN)();
5
send_data(rx_buff);
6
}
...
Habe diese folgendermaßen modufiziert:
...
1
  
2
fp FCTN  = pgm_read_word(CMD_f) [CMD_BYTE];  
3
if (NULL_CMD != FCTN)  { 
4
      (*FCTN)();
5
send_data(rx_buff);
6
}
...
Läuft leider nicht ohne weiteres. Oder verstehe ich da was falsch?

von Stefan E. (sternst)


Lesenswert?

> fp FCTN  = pgm_read_word(CMD_f) [CMD_BYTE];

Ich glaube kaum, dass diese Zeile vom Compiler überhaupt geschluckt 
wird.

fp FCTN = (fp)pgm_read_word(&CMD_f[CMD_BYTE]);

von A. F. (artur-f) Benutzerseite


Lesenswert?

>Ich glaube kaum, dass diese Zeile vom Compiler überhaupt geschluckt
>wird.
Hast recht, war eigentlich: fp FCTN  = pgm_read_word(CMD_f [CMD_BYTE]); 
gemeint.

>fp FCTN = (fp)pgm_read_word(&CMD_f[CMD_BYTE]);
&CDM_f leuchtet mir ein, aber warum muss vor pgm_read.. noch  (fp) vor?

Dein Vorschlag geht übrigens! Danke für die Hilfe.

von mars (Gast)


Lesenswert?

Hi!

Für Debug Ausgaben verwende ich immer folgendes Macro:
1
#ifdef DEBUG
2
 #define DbgPrintf(format, ...) printf_P(PSTR(format), ##__VA_ARGS__)
3
#else
4
 #define DbgPrintf(format, ...)
5
#endif

von Andreas K. (a-k)


Lesenswert?

Yep, das geht normalerweise auch. Nur hatte sich der Compiler bei C++ 
verweigert, daher verwende ich seither routinemässig die andere 
Variante.

von Stefan E. (sternst)


Lesenswert?

Artur F***** wrote:

>>fp FCTN = (fp)pgm_read_word(&CMD_f[CMD_BYTE]);
> &CDM_f leuchtet mir ein, aber warum muss vor pgm_read.. noch  (fp) vor?

pgm_read_word liefert ein uint16_t zurück. Der Cast macht daraus wieder 
den gewünschten Typ.

von A. F. (artur-f) Benutzerseite


Lesenswert?

Ach so, das kam mir leider nicht in den Sinn. Danke, wieder was dazu 
gelernt :)

von Εrnst B. (ernst)


Lesenswert?

Was du auch noch beachten solltest:

Keine Seiteneffekte in den PRINTF - Parametern auslösen, sonst läuft das 
Programm später mit ausgeschaltetem Debugging nicht mehr.

Beispiel:

  PRINTF("UDR=%d\n",UDR);

liest das UDR-Register, und setzt damit ggfs das RXC-Bit zurück oder 
holt das nächste Byte aus dem FIFO.

mit
#define DEBUG 0

wird das UDR-Register nicht mehr gelesen, und das Programm verhängt sich 
evtl. in endlosen Interrupt-Aufrufen usw.

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.