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...
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++.
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
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.
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.
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
#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.
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
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?
> "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'
sollte die Funktion nicht printf_P heißen? Schau mal in deine Definition von PRINTF! Ahoi, Martin
@ 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!
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.
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.
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?
> 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]);
>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.
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
|
Yep, das geht normalerweise auch. Nur hatte sich der Compiler bei C++ verweigert, daher verwende ich seither routinemässig die andere Variante.
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.
Ach so, das kam mir leider nicht in den Sinn. Danke, wieder was dazu gelernt :)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.