SRAM voll, RAM fast leer, printf und Array

OP (Firma: none) #961249
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...
#961254
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++.
OP (Firma: none) #961627
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
#961628
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.
#961629
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.
OP (Firma: none) #961677
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
#961688
#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.
OP (Firma: none) #961758
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
Persönliche Seite #961761
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?
OP (Firma: none) #961779
> "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'
#962739
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.
Persönliche Seite #962770
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?
Persönliche Seite #962808
>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.
Gast #962833
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
#962867
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.
#963182
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.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 18 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.