Programmez l'AVR EEPROM directement à partir de la source C

11

Lorsque vous incluez le code suivant dans une source AVR C, vous pouvez apparemment directement programmer les fusibles, sans avoir besoin d'une commande supplémentaire ou d'un fichier .hex:

#include <avr/io.h>

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

Existe-t-il une astuce similaire pour programmer les valeurs en EEPROM?

J'ai vérifié /usr/lib/avr/include/avr/fuse.hoù je peux trouver des commentaires sur une macro, mais je ne trouve pas de commentaire similaire dans /usr/lib/avr/include/avr/eeprom.het interpréter les trucs du préprocesseur est un peu hors de ma ligue.

Ce serait vraiment pratique si je pouvais inclure des valeurs EEPROM par défaut dans le code source C. Quelqu'un sait comment accomplir cela?

edit1:

Cette astuce FUSES n'est exécutée qu'au moment du FAI, pas au moment de l'exécution. Il n'y a donc pas de fusibles programmés dans le code d'assemblage résultant dans le contrôleur. Au lieu de cela, le programmeur parcourt automatiquement un cycle de programmation FUSES supplémentaire.

edit2:

J'utilise la chaîne d'outils avr-gcc et avrdude sous Linux.

jippie
la source
Est-ce uniquement lors de la programmation du FAI? La plupart des chargeurs de démarrage ne vous permettent pas de programmer des fusibles, non?
angelatlarge
2
Je n'ai pas le temps d'écrire une réponse complète pour le moment, mais comme indice, essayez une recherche sur la directive EEMEM. De plus, vous devrez peut-être modifier les paramètres de l'éditeur de liens pour créer un fichier .EPP séparé que le programmeur utilisera.
PeterJ
@angelatlarge Seulement programmation ISP. Il n'y a pas de chargeur de démarrage dans cette configuration.
jippie
2
Notez que les réponses à cela dépendent entièrement de ce que la chaîne d'outils est prête à enregistrer dans sa sortie et de ce que le programmeur est prêt à analyser. La plupart des chaînes d'outils peuvent être configurées pour créer une section spéciale (ou placer les données à une adresse fictive), ce qui revient finalement au programmeur soit à pouvoir l'extraire, soit à être piloté par un script personnalisé qui le ferait.
Chris Stratton

Réponses:

7

Avec avr-gcc, la EEMEMmacro peut être utilisée sur la définition d'une variable, voir la libcdocumentation et un exemple ici :

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

déclare que le tableau de caractères doit résider dans une section nommée ".eeprom" qui, après compilation, indique au programmeur que ces données doivent être programmées dans l'EEPROM. En fonction de votre logiciel de programmation, vous devrez peut-être donner explicitement le nom du fichier ".eep" créé au cours du processus de génération au programmeur, ou il pourra le trouver implicitement par lui-même.

JimmyB
la source
J'ai utilisé un nom de fichier légèrement différent de celui que je suis censé utiliser, mais ce sont les commandes que j'ai incluses pour programmer l'EEPROM à partir de la ligne de commande (et du makefile):
jippie
1
Créez un fichier contenant des données Intel Hex utilisées par le programmeur:avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 ihex $(src).elf $(src).eeprom.hex
jippie
1
La programmation proprement avrdude -p$(avrType) -c$(programmerType) -P$(programmerDev) -b$(baud) -v -U eeprom:w:$(src).eeprom.hex
dite
7

Oui, vous pouvez écrire manuellement les données par défaut dans l'EEPROM dans le code source. Tout d'abord, consultez ce guide génial sur l'EEPROM avec AVR: le didacticiel AVR EEPROM de Dean. En outre, je dois ajouter qu'il est préférable de créer un fichier .eep contenant les données EEPROM à l'aide du makefile qui sera programmé pour l'appareil avec le code source. Cependant, si vous n'êtes pas familier avec les diverses opérations de makefile et de l'éditeur de liens, cela peut toujours être fait à partir de votre fichier de code source - cela se produira juste dès que le circuit sera alimenté, bloquant l'opération initiale du programme.

Au début du programme (avant toute sorte de boucle principale), vous pouvez faire quelque chose comme ceci:

#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);

La fonction "mise à jour" vérifie d'abord si cette valeur est déjà là, pour économiser sur les écritures inutiles, en préservant la durée de vie de l'EEPROM. Cependant, cela peut prendre beaucoup de temps pour de très nombreux sites. Il pourrait être préférable de vérifier un seul emplacement. S'il s'agit de la valeur souhaitée, les autres mises à jour peuvent être ignorées complètement. Par exemple:

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);
}

Si vous cherchez à mettre à jour de grandes quantités de données, essayez d'utiliser les autres fonctions telles que eeprom_update_block(...). Et lisez certainement ce tutoriel; c'est bien écrit.

Vous pouvez placer toutes les instructions de mise à jour EEPROM dans une seule instruction conditionnelle de préprocesseur. C'est très simple à faire:

#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_

Ce morceau de code ne sera même pas compilé sauf si vous effectuez les opérations suivantes:

#define _UPDATE_EEPROM_

Vous pouvez y laisser un commentaire, puis décommenter si vous devez modifier les valeurs EEPROM par défaut. Pour plus d'informations sur le préprocesseur C, consultez ce manuel en ligne . Je pense que vous pouvez être plus intéressé par les sections sur les macros et les instructions conditionnelles.

Kurt E. Clothier
la source
Il semble que la bonne réponse se trouve dans le dernier paragraphe du PDF lié. Ch. 7 Setting Initial Values.
jippie
Oui vous avez raison. Je l'ai mentionné dans mon premier paragraphe, mais j'ai continué au cas où vous ne connaissiez pas les fichiers .eep et l'éditeur de liens dans le makefile!
Kurt E. Clothier
1
L'utilisation d'adresses EEPROM statiques est une mauvaise pratique. Il vaut mieux utiliser l'attribut EEMEM à la place et laisser le compilateur gérer la distribution des adresses. Aussi, je recommanderais de mettre en œuvre / effectuer une vérification CRC sur chaque section. Si le CRC échoue, la section correspondante contient des données non initialisées ou corrompues. De cette façon, vous pouvez même implémenter un mécanisme de secours à la configuration précédente en cas de corruption de données.
Rev1.0
"L'utilisation d'adresses EEPROM statiques est une mauvaise pratique." Pourquoi?
angelatlarge
1
Lors de l'utilisation de EEMEMvariables, le compilateur se charge de gérer quelle variable réside où dans l'EEPROM. De cette façon, vous n'opérez sur des pointeurs (constants, générés par le compilateur) vers des variables que lorsque vous accédez aux données. Si, d'autre part, vous définissez explicitement l'adresse où réside chaque variable, vous devrez vous occuper de ces adresses vous-même, notamment en vous assurant qu'aucune variable n'occupe accidentellement la même adresse, en vous écrasant; ou recalculer toutes les adresses au cas où la taille de stockage d'une variable changerait à l'avenir, etc.
JimmyB