Un bus I2C (Inter-IC Bus) est un bus série synchrone souvent utilisé pour échanger des données entre un microcontrôleur et un ou plusieurs périphériques. Dans le cadre de ce projet, il permettra à notre application de dialoguer avec un module capteur de température,
Historiquement, les électroniciens utilisent les termes « maître » et « esclave » (ou « master » et « slave ») pour désigner les rôles joués par les composants d’un système lorsqu’ils communiquent ensemble. Il s’agit d’une analogie qui vise à faciliter la compréhension : dans un ordinateur, on dira que le processeur se comporte comme un maître, et ses périphériques comme des esclaves.
Il ne s’agit pas de faire la promotion de l’esclavage, ni d’en minimiser la gravité.
Cependant, depuis plusieurs années, cette terminologie est remise en question. La communauté des informaticiens et électroniciens remplace progressivement les mots « maître » et « esclave » par des termes plus neutres. À notre connaissance, il n’existe pas encore de consensus sur le choix de ces nouveaux termes. Pour cette raison, cette page continue à utiliser les mots « maître » et « esclave » qui restent très présents dans les documentations techniques des constructeurs et dans les spécifications de protocoles.
Dans une communication I2C, le maître est le composant qui a l’initiative des communications. L’esclave répond aux demandes du maître.
Physiquement, un bus I2C est composé de deux signaux :
C’est toujours le maître qui produit le signal d’horloge. Comme il n’y a qu’une ligne de données, le maître et l’esclave prennent alternativement le contrôle de SDA pour envoyer des données ou acquitter la réception d’un octet.
Contrairement au bus SPI, un bus I2C peut interconnecter plusieurs maîtres et plusieurs esclaves. Chaque esclave possède une adresse sur 7 bits qui permet de l’identifier.
Au démarrage d’une trame I2C, le maître prend le contrôle des lignes SCL et SDA :
Ensuite, il peut utiliser SDA pour transmettre une séquence d’octets, ou libérer SDA pour laisser l’esclave lui transmettre des données. À la fin de chaque octet, le destinataire envoie un bit d’acquittement sur SDA.
Le protocole de communication est assez complexe à mettre en œuvre, d’abord à cause de la présence d’une seule ligne de données SDA qui a plusieurs rôles (signaler le démarrage ou l’arrêt d’une communication, envoyer ou recevoir des bits d’adresse ou de données, acquitter la réception d’un octet), mais aussi à cause de la présence éventuelle de plusieurs maîtres qui peuvent tenter de démarrer une communication simultanément.
Nous ne détaillerons pas le protocole dans cette page. Si vous le souhaitez, vous pouvez consulter la spécification officielle du bus I2C.
Si ce n’est pas déjà fait, ouvrez votre projet Computer
dans Vivado :
cd $HOME/CoCiNum
./scripts/vivado vivado/Computer/Computer.xpr
Dans le panneau, Flow Navigator, exécutez l’action Add Sources, choisissez Add or create design sources et pressez le bouton Next.
Ajoutez les fichiers source VHDL suivants à votre projet.
Tous ces fichiers sont situés dans des sous-dossiers de CoCiNum/src/vhdl
.
Sous-dossier | Fichier | Rôle |
---|---|---|
I2C |
I2CMaster-precompiled.vhd |
Un périphérique contrôleur de bus I2C. |
Nous ne fournissons pas le code source du contrôleur I2C.
Le fichier I2CMaster-precompiled.vhd
contient du code VHDL qui a fait l’objet
d’une première étape de synthèse logique.
Il n’est pas destiné à être lu par un être humain.
Choisissez sur quel connecteur d’extension Pmod de la carte Basys3 vous allez
brancher votre périphérique I2C.
Sur la sérigraphie de la carte, ils portent les noms JA
(en haut à gauche),
JB
(en haut à droite), JC
(en bas à droite), et JXADC
(en bas à gauche).
Dans le panneau, Flow Navigator, exécutez à nouveau l’action Add Sources, choisissez Add or create constraints et pressez le bouton Next.
Ajoutez au projet Vivado le fichier de contraintes correspondant à votre choix :
Sous-dossier | Fichier | Rôle |
---|---|---|
Basys3 |
Basys3_PmodA.xdc |
Fichier de contraintes pour Vivado, brochage du connecteur JA. |
Basys3 |
Basys3_PmodB.xdc |
Fichier de contraintes pour Vivado, brochage du connecteur JB. |
Basys3 |
Basys3_PmodC.xdc |
Fichier de contraintes pour Vivado, brochage du connecteur JC. |
Basys3 |
Basys3_PmodXADC.xdc |
Fichier de contraintes pour Vivado, brochage du connecteur JD. |
L’entité I2CMaster
est conçue comme un périphérique pour le processeur Virgule
.
Elle possède deux paramètres génériques :
Port | Type | Rôle |
---|---|---|
CLK_FREQUENCY_HZ |
Entier | La fréquence du signal d’horloge clk_i , en Hz |
I2C_FREQUENCY_HZ |
Entier | La fréquence du signal d’horloge série scl_io , en Hz. Par défaut 100 kHz. |
Et voici la liste de ses ports :
Port | Direction | Type | Rôle |
---|---|---|---|
clk_i |
Entrée | Logique | Le signal d’horloge global |
reset_i |
Entrée | Logique | La commande de réinitialisation |
valid_i |
Entrée | Logique | Demande de transfert de donnée |
ready_o |
Sortie | Logique | Indicateur de fin d’une lecture ou d’une écriture |
write_i |
Entrée | Vecteur de 4 bits | Sélection des octets à écrire |
address_i |
Entrée | Logique | Le bus d’adresses |
wdata_i |
Entrée | Vecteur de 32 bits | Le bus de données en écriture |
rdata_o |
Sortie | Vecteur de 32 bits | Le bus de données en lecture |
evt_o |
Sortie | Logique | Indique la fin d’un échange de données |
error_o |
Sortie | Logique | Indique une erreur au cours d’un échange de données |
scl_io |
Entrée-sortie | Logique | La ligne d’horloge I2C |
sda_io |
Entrée-sortie | Logique | La ligne de données I2C |
Dans une situation simple avec un seul maître et un seul esclave, la sortie
error_o
ne sera pas utilisée.
En VHDL, les ports scl_io
et sda_io
sont déclarés avec le mode inout
car ils jouent alternativement les rôles d’entrées ou de sorties.
L’entrée address_i
permet d’accéder à deux registres de 32 bits.
À l’adresse '1'
, le registre de contrôle se décompose en plusieurs champs :
address_i |
Bits | Registre | Rôle |
---|---|---|---|
'0' |
31 à 0 | data_reg |
Les données envoyées ou reçues. |
'1' |
14 à 12 | send_len_reg |
Le nombre d’octets à envoyer (entre 0 et 4) |
'1' |
10 à 8 | receive_len_reg |
Le nombre d’octets à recevoir (entre 0 et 4) |
'1' |
6 à 0 | slave_address_reg |
L’adresse de l’esclave |
L’entité I2CMaster
implémente un scénario d’utilisation du bus I2C dans
lequel une trame se décompose en :
Pour réaliser un tel échange, il faut :
send_len_reg
, receive_len_reg
et slave_address_reg
.data_reg
pour démarrer la communication. S’il n’y a rien à envoyer (send_len_reg
= 0), on peut écrire n’importe quoi dans data_reg
.evt_o
passe à '1'
.data_reg
.La sortie evt_o
sera typiquement reliée au contrôleur d’interruptions.
Computer_pkg
Dans le fichier Computer_pkg.vhd
, ajoutez des constantes pour définir les
caractéristiques des nouveaux périphériques du système :
Constante | Type | Valeur | Rôle |
---|---|---|---|
I2C_ADDRESS |
Octet | 84hex | Les bits 31 à 24 de l’adresse pour accéder au contrôleur SPI. |
INTC_EVENTS_I2C |
Entier | 3 | Pour le contrôleur d’interruptions, le numéro de l’événement indiquant la fin d’une communication SPI. |
Les informations contenues dans la colonne Valeur sont des exemples. Vous pouvez les modifier à condition que chaque périphérique de votre architecture ait une adresse et un numéro d’événement différents des autres périphériques.
Computer
Dans le fichier Computer.vhd
, complétez l’entité Computer
en déclarant
les ports du connecteur d’extension que vous avez choisi.
Le tableau ci-dessous donne la liste des ports disponibles et leur rôle.
Ils sont tous de type std_logic
.
Rôle | JA |
JB |
JC |
JXADC |
Mode |
---|---|---|---|---|---|
Serial Clock | pmod_a3 |
pmod_b3 |
pmod_c3 |
pmod_xadc3 |
inout |
Serial Data | pmod_a4 |
pmod_b4 |
pmod_c4 |
pmod_xadc4 |
inout |
Structural
Dans le fichier Computer.vhd
, complétez l’architecture pour intégrer un
contrôleur I2C en utilisant les constantes que vous avez ajoutées
au paquetage Computer_pkg
.
Inspirez-vous des instances déjà présentes dans l’architecture.
Représentez sous la forme d’un schéma la nouvelle structure du système.
Le bus I2C nécessite la présence de résistances de tirage pull-up sur les lignes SCL et SDA. Nous allons profiter du fait que les entrées-sorties du FPGA Artix-7 possèdent des résistances internes dont l’utilisation est configurable.
Si vous avez choisi le connecteur JA, par exemple, ouvrez le fichier
CoCiNum/src/vhdl/Basys3/Basys3_PmodA.xdc
et ajoutez les lignes suivantes :
set_property PULLUP true [get_ports pmod_a3]
set_property PULLUP true [get_ports pmod_a4]
Vous pouvez procéder de la même manière si vous avez choisi un autre connecteur.
Dans Vivado, générez le fichier binaire à charger dans le FPGA : Flow Navigator → Program and Debug → Generate Bitstream.
Si ce n’est pas déjà fait, reliez le connecteur micro-USB de la carte à un port USB de votre PC et mettez la carte sous tension.
Connectez Vivado à votre carte Basys3 : Flow Navigator → Program and Debug → Open Hardware Manager → Open Target → Auto-connect.
Configurez le FPGA : Flow Navigator → Program and Debug → Open Hardware Manager → Program Device.
Si vous n’avez pas d’autre périphérique à ajouter, vous pouvez passer à la section Développement logiciel embarqué.