Publié le 18 juillet 2020 - par

Exploration de l’EEPROM HAT du Raspberry Pi (Partie 2/2)

Dans la première partie de cet article, nous avons vu comment accéder aux données de l’EEPROM de la carte HAT pour le Raspberry Pi. Voyons maintenant ce qu’elles contiennent et comment insérer nos données spécifiques.

Le contenu de l’EEPROM

Ce que vous allez lire dans la mémoire de l’EEPROM est structuré en un entête (le header) et des blocs de données (les atoms).

Le header

Le header qui se trouve en début de la mémoire est constitué des éléments suivants :

  • – les 4 premiers octets sont les codes ASCII de ‘R-Pi’
  • – un octet pour le numéro de version (actuellement seule la version 1 est définie)
  • – un octet réservé pour le futur
  • – le nombre d’atomes
  • – la longueur totale en octets des données

Les atoms

Chaque bloc de données comprend :

  • – un identifiant de type
  • – le numéro
  • – la taille des données + CRC
  • – les données proprement dites
  • – le CRC selon la norme CCITT16.

Il y a 3 type d’atoms spécifiques, en principe obligatoires, auxquels l’utilisateur peut ajouter ses propres atoms.

L’atom Vendor

Cet atom est identifié par le type 1 (le type 0 est invalide). Les données spécifiques sont dans l’ordre :

  • Un identifiant unique de type UUID
  • Un numéro de produit
  • Un numéro de version
  • La longueur de la chaine de caractères vendeur
  • La longueur de la chaine de caractère produit
  • La chaine de caractères qui décrit le vendeur
  • La chaine de caractères qui décrit le produit
     

L’atom GPIO

Cet atom est identifié par le type 2. Les données spécifiques sont dans l’ordre :

  • Un caractère qui décrit la consommation de la carte
  • Un caractère pour décrire si la carte fourni l’alimentation
  • 28 caractères, un par GPIO pour spécifier le type des entrées/sorties (utilisé par la carte, pull up ou down…

Les données sont codées sur des bits spécifiques des caractères : voir le lien en référence. Le programme affiche les données brutes en hexadécimal de cet atom. N’ayant pas l’usage je ne suis pas allé plus loin.

L’atom Device Tree

Cet atom est identifié par le type 3.

Il est, d’après les spécifications HAT, obligatoire mais n’est pas présent sur les eeprom que j’ai eu sous la main. Les données de cet atom ont pour but de permettre un support éventuel du matériel par Linux. N’ayant pas l’usage le programme ne traite pas ce type.

L’atom Custom

Cet atom est identifié par le type 4. L’utilisateur stocke ses données dans la zone data d’un atom générique. On peut avoir autant d’atoms que souhaité, le programme n’affichant que le premier

Décodage

Le décodage (procedure ParseBuffer) consiste simplement à découper les zones de la mémoire dans des enregistrements structurés pour pouvoir les manipuler aisément. Ci-dessous un extrait des structures et du décodage :

  TheaGPIO = record
    aType: UInt16;        // 0x0002 = GPIO map
    count: UInt16;        // incrementing atom count
    dLen: UInt32;         // length in bytes of data+CRC
    bank_drive: byte;     // bank drive strength/slew/hysteresis, BCM2835 can only set per bank, not per IO
                             // Bits in byte:
                             // [3:0] drive       0=leave at default, 1-8=drive*2mA, 9-15=reserved
                             // [5:4] slew        0=leave at default, 1=slew rate limiting, 2=no slew limiting, 3=reserved
                             // [7:6] hysteresis  0=leave at default, 1=hysteresis disabled, 2=hysteresis enabled, 3=reserved
    power: byte;          // [1:0] back_power  0=board does not back power Pi
                             // 1=board back powers and can supply up to 1.3A to the Pi
                             // 2=board back powers and can supply up to 2A to the Pi
                             // 3=reserved
                             // If back_power=2 high current USB mode is automatically enabled.
                          // [7:2] reserved    set to 0
    IO: array[0..27] of byte;
                          //  1 byte per IO pin, bits in each byte:
                             //  [2:0] func_sel    GPIO function as per FSEL GPIO register field in BCM2835 datasheet
                             //  [4:3] reserved    set to 0
                             //  [6:5] pulltype    0=leave at default setting,  1=pullup, 2=pulldown, 3=no pull
                             //  [  7] is_used     1=board uses this pin, 0=not connected and therefore not used
    crc16: UInt16;
  end;

Et pour représenter la collection d’atoms :

  TAtoms = record
    Header: TheHeader;
    Vendor: TheaVendor;
    GPIO: TheaGPIO;
    DeviceTreeBlob: TheaCustom;
    Customs: array of TheaCustom;
  end;

procedure THat_eeprom_ctlr.ParseBuffer;
// set the atoms from content
var Offset, pLen, dLen: UInt32;
    i, aType, Count: UInt16;
begin
  ResetAtoms;
  try
    FLastError:= '';
    // check signature
    offset:= 0;
    pLen:= 4;
    Move(FeBuf[0], FAtoms.Header.signature, pLen);
    if FAtoms.Header.signature <> 'R-Pi'
    then begin
      FAtoms.Header.numAtoms:= 0;
      FAtoms.Header.eepLen:= 0;
      Exit;
    end;
    // set Header
    Offset:= pLen;
    FAtoms.Header.version:= byte((@FeBuf[Offset])^);
    Offset:= Offset + SizeOf(FAtoms.Header.version);
    FAtoms.Header.reserved:= byte((@FeBuf[Offset])^);
    Offset:= Offset + SizeOf(FAtoms.Header.reserved);
    FAtoms.Header.numAtoms:= UInt16((@FeBuf[Offset])^);
    Offset:= Offset + SizeOf(FAtoms.Header.numAtoms);
    FAtoms.Header.eepLen:= UInt32((@FeBuf[Offset])^);
    Offset:= Offset + SizeOf(FAtoms.Header.eepLen);
  … 

A partir de là on peut afficher de façon claire les données de notre eeprom :

procedure TfHatEeprom.ShowAtoms;
begin
  tsHeader.TabVisible:= True;
  eRPi.Text := Eeprom.Atoms.Header.signature;
  eVersion.Text := IntToStr(Eeprom.Atoms.Header.version);
  eNumAtoms.Text := IntToStr(Eeprom.Atoms.Header.numAtoms);
  eELen.Text := IntToStr(Eeprom.Atoms.Header.eepLen);
…

Ce qui donne :

Inversement l’objet implémente la fonction qui permet de passer des atoms au buffer (procedure AtomsToBuffer) pour pouvoir flasher nos données personnalisées.

Duplication

Si vous dupliquez des eeprom identiques utilisez la fonction NewUUID (bouton New UUID) pour attribuer un identifiant unique à chacune de vos cartes HAT.

Création d’un jeu de données

Le programme permet d’initialiser un jeu de données personnalisé avec une structure minimale : Header, Vendor avec vos identifiants, GPIO vierge. Lancez la commande Atoms > > Init atoms, entrez alors votre description de fabricant et du produit et les identifiants produit et version (nombres entiers) :

Il ne reste plus qu’à lancer la commande Atom > > Validate pour que le programme vous génère toutes les données (longueurs, CRC..) et le buffer prêt à être flashé si vous le désirez.

Utilisation opérationnelle

L’objectif d’avoir un outil pour enregistrer des données propres au matériel en respectant le standard HAT est atteint. Le programme eXplorer s’arrête là, pour implémenter vos atoms custom il vous faudra programmer. L’objet permet avec quelques lignes d’utiliser l’EEPROM pour mes besoins. L’exemple ci-dessous montre un usage typique pour enregistrer un couple de données gain + offset de calibration.

Pour initialiser l’EEPROM avec mes données, équivalent de la fonction Init Atom avec en plus mon atom personnalisé :

type TCal = record
  Gain: double;
  Offset: double;
end;
var rCal: TCal;

   Eeprom:= THat_eeprom_ctlr.Create(Self, ec32);
  Eeprom.InitAtoms('OpenAvionics', 'Primary Flight Display', 1, 1);
  rCal.Gain:= 1.;
  rCal.Offset:= 0.;
  Eeprom.AddCustom(rCal, SizeOf(TCal));
  Eeprom.AtomsToBuffer;
  Eeprom.BufferToEprom;

Pour récupérer mes données :

  If not Assigned(Eeprom) then Eeprom.THat_eeprom_ctlr.Create(Self, ec32);
  Eeprom.GetFromCustom(0, rCal, SizeOf(TCal));

Et pour modifier les valeurs :
  If not Assigned(Eeprom) then Eeprom.THat_eeprom_ctlr.Create(Self, ec32);
  rCal.Gain:= 1.5;
  rCal.Offset:= 3.6;
  Eeprom.SaveToCustom(0, rCal, SizeOf(TCal)); }

 

La suite est à vous

Le programme Hat Eeprom eXplorer reste limité dans ses possibilités, l’objectif étant la mise au point de l’outil. Le source est disponible et les bonnes volontés sont bien venues pour :

  • – gérer l’atom GPIO de façon plus conviviale
  • – gérer l’atom Tree
  • – vérifier la programmation et les CRC
  • – gérer l’initialisation d’atom custom personnalisés
  • – gérer les atoms customs multiples
  • – corriger mes bugs
  • – etc.

Vous pouvez télécharger le programme ainsi que ses sources en cliquant sur ce lien.

Cf :

CRC : Cyclic Redundancy Check

UUID : Universal Unique IDentifier

Programme et sources

https://github.com/raspberrypi/hats/blob/master/eeprom-format.md

Exploration de l’EEPROM HAT du Raspberry Pi (Partie 1/2)

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.