Programmieren Sie das AVR-EEPROM direkt von der C-Quelle

11

Wenn Sie den folgenden Code in eine AVR C-Quelle aufnehmen, können Sie die Sicherungen anscheinend direkt programmieren, ohne dass ein zusätzlicher Befehl oder eine zusätzliche .hex-Datei erforderlich ist:

#include <avr/io.h>

FUSES = {
        .low =          LFUSE_DEFAULT ,
        .high =         HFUSE_DEFAULT ,
        .extended =     EFUSE_DEFAULT ,
};

Gibt es einen ähnlichen Trick wie bei Programmwerten im EEPROM?

Ich habe überprüft, /usr/lib/avr/include/avr/fuse.hwo ich einige Kommentare zu einem Makro finden kann, aber ich kann keinen ähnlichen Kommentar in finden, /usr/lib/avr/include/avr/eeprom.hund die Interpretation des Präprozessor-Materials ist etwas außerhalb meiner Liga.

Es wäre sehr praktisch, wenn ich Standard-EEPROM-Werte in den C-Quellcode aufnehmen könnte. Weiß jemand, wie man das erreicht?

edit1:

Dieser FUSES-Trick wird nur zur ISP-Zeit ausgeführt, nicht zur RUN-Zeit. Es werden also keine Sicherungen im resultierenden Baugruppencode in der Steuerung programmiert. Stattdessen durchläuft der Programmierer automatisch einen zusätzlichen FUSES-Programmierzyklus.

edit2:

Ich benutze die Toolkette avr-gcc und avrdude unter Linux.

Jippie
quelle
Ist dies nur beim Programmieren von ISP? Bei den meisten Bootloadern können Sie keine Sicherungen programmieren, oder?
Angelatlarge
2
Ich habe momentan keine Zeit, eine vollständige Antwort zu schreiben, aber als Hinweis versuchen Sie es mit einer Suche in der EEMEM-Direktive. Außerdem müssen Sie möglicherweise die Linker-Einstellungen ändern, um eine separate .EPP-Datei zu erstellen, die der Programmierer verwendet.
PeterJ
@angelatlarge Nur ISP-Programmierung. In diesem Setup befindet sich kein Bootloader.
Jippie
2
Beachten Sie, dass die Antworten darauf vollständig davon abhängen, was die Toolchain in ihrer Ausgabe aufzuzeichnen bereit ist und was der Programmierer bereit ist, zu analysieren. Die meisten Toolchains könnten so konfiguriert werden, dass sie einen speziellen Abschnitt erstellen (oder Daten an einer fiktiven Adresse ablegen), sodass es letztendlich darauf ankommt, dass der Programmierer sie entweder extrahieren kann oder von einem benutzerdefinierten Skript gesteuert werden kann, das dies tun würde.
Chris Stratton

Antworten:

7

Mit avr-gcc kann das EEMEMMakro für die Definition einer Variablen verwendet werden. Weitere Informationen finden Sie in den libcDokumenten und in einem Beispiel hier :

#include <avr/eeprom.h>
char myEepromString[] EEMEM = "Hello World!";

deklariert das Zeichenarray in einem Abschnitt mit dem Namen ".eeprom", der dem Programmierer nach der Kompilierung mitteilt, dass diese Daten in das EEPROM programmiert werden sollen. Abhängig von Ihrer Programmiersoftware müssen Sie dem Programmierer möglicherweise explizit den Namen der ".eep" -Datei geben, die während des Erstellungsprozesses erstellt wurde, oder er findet sie implizit selbst.

JimmyB
quelle
Ich habe einen etwas anderen Dateinamen verwendet, als ich eigentlich sollte, aber dies sind die Befehle, die ich zum Programmieren des EEPROM über die Befehlszeile (und das Makefile)
eingefügt habe
1
Erstellen Sie eine Datei mit Intel Hex-Daten, die vom Programmierer verwendet werden:avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 ihex $(src).elf $(src).eeprom.hex
Jippie
1
Die eigentliche Programmierung erfolgt durch:avrdude -p$(avrType) -c$(programmerType) -P$(programmerDev) -b$(baud) -v -U eeprom:w:$(src).eeprom.hex
Jippie
7

Ja, Sie können Standarddaten im Quellcode manuell in das EEPROM schreiben. Schauen Sie sich zuerst diese fantastische Anleitung zum EEPROM mit AVR an: Dean's AVR EEPROM Tutorial. Außerdem sollte ich hinzufügen, dass es eine bessere Idee ist, eine .eep-Datei mit den EEPROM-Daten unter Verwendung des Makefiles zu erstellen, das zusammen mit dem Quellcode auf dem Gerät programmiert wird. Wenn Sie jedoch mit verschiedenen Makefile- und Linker-Vorgängen nicht vertraut sind, können Sie diese weiterhin in Ihrer Quellcodedatei ausführen. Dies geschieht nur, sobald die Schaltung mit Strom versorgt wird und die anfängliche Programmoperation blockiert.

Zu Beginn des Programms (vor jeder Art von Hauptschleife) können Sie Folgendes tun:

#include <avr/eeprom.h>

#define ADDRESS_1 46  // This could be anything from 0 to the highest EEPROM address
#define ADDRESS_2 52  // This could be anything from 0 to the highest EEPROM address
#define ADDRESS_3 68  // This could be anything from 0 to the highest EEPROM address

uint8_t dataByte1 = 0x7F;  // Data for address 1
uint8_t dataByte2 = 0x33;  // Data for address 2
uint8_t dataByte3 = 0xCE;  // Data for address 3

eeprom_update_byte((uint8_t*)ADDRESS_1, dataByte1);
eeprom_update_byte((uint8_t*)ADDRESS_2, dataByte2);
eeprom_update_byte((uint8_t*)ADDRESS_3, dataByte3);

Die Funktion "Aktualisieren" prüft zuerst, ob dieser Wert bereits vorhanden ist, um unnötige Schreibvorgänge zu sparen und die Lebensdauer des EEPROM zu erhalten. Dies für sehr viele Standorte zu tun, kann jedoch einige Zeit in Anspruch nehmen. Es ist möglicherweise besser, einen einzelnen Standort zu überprüfen. Wenn dies der gewünschte Wert ist, können die restlichen Aktualisierungen vollständig übersprungen werden. Beispielsweise:

if(eeprom_read_byte((uint8_t*)SOME_LOCATION) != DESIRED_VALUE){
  eeprom_write_byte((uint8_t*)SOME_LOCATION, DESIRED_VALUE);
  eeprom_update_byte((uint8_t*)ADDRESS_1, dataByte1);
  eeprom_update_byte((uint8_t*)ADDRESS_2, dataByte2);
  eeprom_update_byte((uint8_t*)ADDRESS_3, dataByte3);
}

Wenn Sie große Datenmengen aktualisieren möchten, verwenden Sie die anderen Funktionen wie z eeprom_update_block(...). Und lesen Sie auf jeden Fall dieses Tutorial; es ist gut geschrieben.

Sie können alle EEPROM-Aktualisierungsanweisungen in eine einzige bedingte Präprozessoranweisung einfügen. Dies ist sehr einfach zu tun:

#if defined _UPDATE_EEPROM_
  #define ADDRESS_1 46  // This could be anything from 0 to the highest EEPROM address
  uint8_t dataByte = 0x7F;  // Data for address 1
  eeprom_update_byte((uint8_t*)ADDRESS_1, dataByte1);
#endif // _UPDATE_EEPROM_

Dieses Codebit wird erst kompiliert, wenn Sie Folgendes tun:

#define _UPDATE_EEPROM_

Sie können dies als Kommentar hinterlassen und dann auskommentieren, wenn Sie die Standard-EEPROM-Werte ändern müssen. Weitere Informationen zum C-Präprozessor finden Sie in diesem Online-Handbuch . Ich denke, Sie interessieren sich vielleicht am meisten für die Abschnitte über Makros und bedingte Anweisungen.

Kurt E. Clothier
quelle
Es sieht so aus, als ob die richtige Antwort im letzten Absatz des verknüpften PDFs steht. Ch. 7 Setting Initial Values.
Jippie
Ja du hast Recht. Ich erwähnte das in meinem ersten Absatz, fuhr aber fort, falls Sie nicht mit .eep-Dateien und dem Linker im Makefile vertraut waren!
Kurt E. Clothier
1
Die Verwendung statischer EEPROM-Adressen ist eine schlechte Praxis. Es ist besser, stattdessen das EEMEM-Attribut zu verwenden und den Compiler die Adressverteilung verwalten zu lassen. Außerdem würde ich empfehlen, eine CRC-Prüfung für jeden Abschnitt durchzuführen. Wenn die CRC fehlschlägt, enthält der entsprechende Abschnitt nicht initialisierte oder beschädigte Daten. Auf diese Weise können Sie im Falle einer Datenbeschädigung sogar einen Fallback-Mechanismus für die vorherige Konfiguration implementieren.
Rev1.0
"Die Verwendung statischer EEPROM-Adressen ist eine schlechte Praxis." Warum?
Angelatlarge
1
Bei der Verwendung von EEMEMVariablen kümmert sich der Compiler darum, zu verwalten, welche Variable sich wo im EEPROM befindet. Auf diese Weise bearbeiten Sie beim Zugriff auf die Daten nur (konstante, vom Compiler generierte) Zeiger auf Variablen. Wenn Sie andererseits explizit die Adresse definieren, an der sich jede Variable befindet, müssen Sie sich selbst um diese Adressen kümmern, einschließlich der Sicherstellung, dass keine Variablen versehentlich dieselbe Adresse belegen und sich gegenseitig überschreiben. oder alle Adressen neu berechnen, falls sich die Speichergröße einer Variablen in Zukunft ändert usw.
JimmyB