Hallo zusammen, ich suche nach einer Möglichkeit eine Konstante bzw. Variable direkt im C-Code (Notfalls auch im Linkerscript) an eine bestimmte Flashadresse zu speichern. Zum einen soll in alle Codes immer an der selben Flashadresse eine Seriennummer stehen und zum Anderen eine 32Bit Zahl ganz am Ende des Flashspeichers. Die "Prüfzahl" soll später vom Bootloader ausgelesen werden um sicherzustellen, dass bei einer Stromunterbrechung wären einem Update die Firmware komplett bis zum Ende geschrieben wurde. Wer hat eine Idee, wie sich dies einfach und schnell im C-Code umsetzen läßt? Ich denke mit (void *) checksum = FLASHEND-32; Lässt sich Adresse der Variable setzen und später auslesen. Aber wie schreibe ich den Inhalt beim Compiling (oder Linking) direkt an diese Adresse? Kann ich dem Compiler irgendwie mitteilen, an welcher Stelle im Flash diese Prüfzahl mit einem bestimmten Wert geschrieben werden soll? Noch eine Frage am Rande: Wo kann ich die max. Flashgröße in AVR Studio begrenzen? Sprich, dass er eine Fehlermeldung abgibt, wenn die Flashgröße - meinem Limit überschritten wird? Was passiert eigentlich mit den unbeschrieben Pages im mC? Bleiben diese beim AVR ATmega dann einfach auf dem alten Stand?
:
Bearbeitet durch User
Kai schrieb: > Notfalls auch im Linkerscript
1 | const uint32_t my_serial __attribute__ ((section (".myserialsection"))=0xDEADBEEF; |
Linker-Aufruf mit -Wl,--section-start=.myserialsection=0x12345 Vorsicht mit "-Wl,--gc-sections". Vorsicht beim objcopy, wenn aus dem .elf ein .hex werden soll, das muss die section auch kennen, wenn der Wert in's .hex soll. Auslesen von Werten aus der Section per pgm_read_xxx aus der avr/pgmspace.h. die Magie mit "__flash"-Variablen, die Zugriffe automatisch auf LPM mappt, geht mit deiner extra-Section nicht. (Lässt sich evtl. aber nachrüsten? k.A.)
:
Bearbeitet durch User
im Linker-Skript z. B. /* CRC32 checksum goes into FLASH at the very end */ .chcksm ORIGIN(FLASH) + LENGTH(FLASH) - 4 : { . = ALIGN(4); KEEP(*(.chcksm)) . = ALIGN(4); } >FLASH und in einem der Source-Files: __attribute__((section(".chcksm"), used)) const uint32_t chcksm; Allerdings lässt sich der Inhalt (also die tatsächliche Prüfsumme) nur zu Fuß in die Hex-Datei hineinmogeln, z. B. im Makefile: $(BUILD_DIR)/$(TARGET).hex: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).lst | $(BUILD_DIR) $(HEX) --gap-fill 0xFF $< $@ @BEG=$$(nm $< | sed -n -E 's/^(\w+).*_sidata$$/\1/p' | tr [:lower:] [:upper:]); \ END=$$(nm $< | sed -n -E 's/^(\w+).*chcksm$$/\1/p' | tr [:lower:] [:upper:]); \ CHCKSM=$$(./$(BUILD_DIR)/calc_crc32 $@ 0x$${BEG} 0x$${END}); \ sed -i -E "s/^S3..$${END}.*$$/$${CHCKSM}/" $@; \ echo "0x$${BEG}-0x$${END}: $${CHCKSM}" Da wird die Hex-Datei erstellt, von "calc_crc32" die Prüfsumme von _sidata bis chsksm (exkl.) berechnet, (in Motorola-Format) ausgegeben und in der Hex-Datei eingefügt. Bei einer Seriennummer etc. ist das deutlich einfacher, weil man den Inhalt ja gleich in den Sourcen angeben kann. Allerdings muss man da wiederum die Sektion im Linker-Skript "dazwischen" schieben, also unmittelbar nach der Vektortabelle oder so. Man bekommt den Linker leider nicht dazu, den Code automatisch "um eine Lücke herum" zu platzieren ... Oder man legt sie einfach "eingerahmt" irgendwo hin und sucht sie zur Laufzeit.
Andreas B. schrieb: > Bei einer Seriennummer etc. ist das deutlich einfacher, weil man den > Inhalt ja gleich in den Sourcen angeben kann. Zum Ausgleich muss man für jedes Gerät neu übersetzen... Aber ich hab's trotzdem so gemacht :) > Allerdings muss man da wiederum die Sektion im Linker-Skript > "dazwischen" schieben, also unmittelbar nach der Vektortabelle oder so. Das finde ich viel praktischer als am Flash-Ende: - die Adresse ist genauso konstant und absolut - für den Linker ist es eine normale Adresse, wie die Vektortabelle - es kostet kein Byte extra - das Image bekommt kein "Loch" (was evt. unnötig geflasht würde) - mehr oder weniger großes Flash ändert garnichts - ein Check, ob das Flash ausreicht, muss das "Loch" nicht beachten
Andreas B. schrieb: > Man bekommt den Linker > leider nicht dazu, den Code automatisch "um eine Lücke herum" zu > platzieren Ja, dafür habe ich auch keine Lösung gefunden. Ich habe gemerkt, daß der Linker die Objekte alphabetisch sortiert. Ich habe einen String in die Datei "_version.c" geschrieben und dann landet sie direkt hinter der Vektortabelle.
1 | #include "_version.h" |
2 | #include <avr/pgmspace.h> |
3 | |
4 | const char Version[] __attribute__((used)); |
5 | const char Version[] PROGMEM = PROJECT_STRING ", " |
6 | "V:" REVISION_STRING ", " |
7 | __DATE__ "\n"; |
Kai schrieb: > Die "Prüfzahl" soll später vom Bootloader ausgelesen > werden um sicherzustellen, dass bei einer Stromunterbrechung wären einem > Update die Firmware komplett bis zum Ende geschrieben wurde. Dafür habe ich eine Variable im EEPROM reserviert, die der Bootloader zuerst löscht und nach dem Flashen ein Magic reinschreibt.
Ist es nicht so, dass der Flash-Speicher aufgeteilt wird, um Daten zu speichern?
Was Du da zeigst, trifft nur auf die neuesten AVRs zu. Die standard AVRs, mit denen der AVR-GCC entwickelt wurde, fangen mit der Applikation immer an 0x0000 an. Da plaziert also der AVR-GCC die Vectortabelle. Danach kommen die konstanten Daten, da mit int (16 Bit) nur die ersten 64kB direkt zugreifbar sind. Darüber braucht man spezielle Hilfsregister und Befehle. Bzw. für Funktionspointer > 16 Bit gibt es eine .trampolines section. Für den Bootloader ist ein Bereich am Flashende reserviert. Das hat den Charme, daß die Applikation keine speziellen Linkerscripte benötigt. Sie muß nichtmal wissen, daß ein Bootloader existiert und wo der sitzt. Bei den neuen AVRs ist das Bootloadergedöns deutlich komplizierter. Wenn Bootloader und Applikation nicht zueinander passen, kracht es.
Kai schrieb: > Wo kann ich die max. Flashgröße [...] begrenzen? Je nach verwendetem Linker Script, Symbol__TEXT_REGION_LENGTH__ definieren:
1 | -Wl,--defsym,__TEXT_REGION_LENGTH__=32k |
Georg M. schrieb: > Ist es nicht so, dass der Flash-Speicher aufgeteilt wird, um Daten zu > speichern? Kann man auf AVR-Dx und AVR-Ex je nach Konfiguration von FLMAP dazu verwenden, um mit LD / LDS Daten aus dem Flash zu lesen. Daran, wie die o.g. Variable im Flash angelegt wird, ändert das aber nix.
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.