Les GPIO de la Stellaris Launchpad

J’ai enfin réussi à faire tourner et à débugger mon premier programme pour la Stellaris Launchpad. Oh, ce n’est pas grand chose, j’ai fait clignoter une LED. Mais qu’est ce que j’ai appris de choses!

En particulier, j’ai découvert pas mal de choses sur les fonctions GPIO (general purpose input/output) de ce microcontrôleur.

Accès GPIO par les bus APB et AHB

Le CPU ARM Cortex contient plusieurs bus de donnée à l’extérieur du coeur du processeur.

  • le bus APB, Advanced Peripheral Bus
  • le bus AHB, Advanced High-Performance Bus

Les périphériques internes du Stellaris sont connectés à l’un ou à l’autre de ces bus:

Archi interne Stellaris
Archi interne Stellaris

Pour les périphériques GPIO (= lignes de sorties qu’on peut piloter et lire), on a le choix du bus utilisé. Prenons l’exemple du port F, utilisé pour piloter les LEDs de la carte Stellaris Launchpad. Ce port est accessible depuis deux adresses:

  • Pour sa connexion à l’APB, les registres sont disponibles à partir de l’adresse 0x40025000
  • Pour sa connexion à l’AHB, les registres sont disponibles à partir de l’adresse 0x4005D000

Les registres accessibles sont les mêmes, mais le bus AHB possède une plus faible latence, et ses adresses sont plus pratiques à utiliser dans des calculs.

Mais attention : Au reset, seul l’accès par le bus APB est possible. Toute tentative d’accès aux ports AHB provoquera une exception de type “Bus Fault”, et comme dans un code basique, cette exception n’est pas activée, on obtiendra une “Hard Fault”.

Après quelques heures passées sur le sujet, j’ai bien relu la datasheet, et j’ai compris que les bons bits devaient être définis dans le registre GPIOHBCTL, documenté au paragraphe 5.5, page 247.

Recette 1: Accès GPIO qui produit une hardfault (ou une busfault) -> Vérifier GPIOHBCTL

 

Ecriture de données sur les ports GPIO

Après cette découverte, je n’ai plus eu de Hard Fault. En revanche, toute écriture dans le registre GPIODATA n’avait aucun effet.

De la même manière, seule une lecture attentive de la datasheet m’a donné l’explication. GPIODATA n’est pas un registre, mais une PLAGE de 256 registres.

En effet, tout accès à la zone [GPIODATA..GPIODATA+256*4] s’accompagne d’une écriture sur le port, mais les bits de poids faible de l’adresse sont utilisés comme un masque définissant quels bits seront écrits. Le but de cette fonctionnalité, documentée page 608, est de permettre les modifications de bits individuels du port sans utiliser la technique du read-modify-write:

WRITE(address, READ(address) OP mask)

En effet, les seuls bits modifiés du port sont ceux dont les bits d’adresse 9..2 sont à 1.

Supposons que j’écrive 0xEB à l’adresse GPIODATA+0x98, voici ce qui se passe:

gpiodata access

u signifie que le bit n’est pas modifié, 0 ou 1 montre la valeur réellement écrite.

Donc en général, pour la modification du bit N, vous devez écrire 1<<bit à l’adresse GPIODATA+(1<<bit)

Eh non! Vous avez encore mal lu! Les bits significatifs sont 9..2 et non 7..0 !

Pour la modification du bit N, vous devez écrire 1<<(bit+2) à l’adresse GPIODATA+(1<<(bit+2))

Recette 2: Si les GPIO ne changent pas, vérifiez votre adresse GPIODATA

 

Tout ceci m’inspire une 3e recette, car ce circuit est manifestement plus complexe et moins évident qu’un PIC:

Recette 3: Pour le Stellaris LM4F, le RTFM est vraiment important!