Outils pour utilisateurs

Outils du site


lang:c:microcontroleur

Manipulation de registres matériels par champ de bits

Modifier une variable logiciel par champ de bits s'effectue sans problème par le biais suivant :

struct {
  bool flag1 :1;
  unsigned char flag2 :2;
  bool flag3 :1;
  bool flag4 :1;
  unsigned char flag5 :3;
  unsigned char flag6 :6;
} Flags0;

Maintenant, on souhaite que ces données soient stockées dans un registre dont les données survivent à un reset du microtrôleur.

En prenant le cas d'un microcontrôleur ARM, il est possible de stocker ces données dans le registre GPREG0 (à l'adresse 0x40024044) accessible par la macro LPC_RTC->GPREG0.

Mais la modification du flag flag6 va modifier uniquement l'adresse 0x40024045 :

ldr	r3, [pc, #92] ; Chargement de 0x40024044
movs	r2, #40	      ; Chargement de la donnée 40 sur un octet
strb	r2, [r3, #1]  ; Ecriture de 40 dans 0x40024044 + 1

Et là, c'est le drame. Le microcontrôleur va se mettre à écrire n'importe quoi dans le registre GPREG0 puisque la seule instruction qu'il sait traiter correctement pour ce registre est un accès par le début du registre (0x40024044).

La seule solution est de passer par une écriture complète du registre. Par exemple :

union UGPreg0 {
  struct {
    bool flag1 :1;
    unsigned char flag2 :2;
    bool flag3 :1;
    bool flag4 :1;
    unsigned char flag5 :3;
    unsigned char flag6 :6;
  } Flags0;
  uint32_t bits;
};
 
static unsigned char getFlag6() {
  UGPreg0 uGPreg0;
  uGPreg0.bits = LPC_RTC->GPREG0;
  return uGPreg0.Flags0.flag6;
}
 
static void setFlag6(unsigned char val) {
  UGPreg0 uGPreg0;
  uGPreg0.bits = LPC_RTC->GPREG0;
  uGPreg0.Flags0.flag6 = val;
  LPC_RTC->GPREG0 = uGPreg0.bits;
}
lang/c/microcontroleur.txt · Dernière modification : 2020/01/16 13:54 de root