I2C (5 points)
L'I2C est un bus de communication très utilisé dans l'embarqué. Il permet généralement de connecter des micro-contrôleurs à des périphériques simples (flash, capteurs...).
Physiquement le bus I2C est composé de deux fils : un fil de données (SDA
) et un fil d'horloge (SCL
). Il s'agit d'un protocole série synchrone, les données étant transmises en série (chaque bit l'un après l'autre) sur le fil de données, au rythme de l'horloge SCL
.
Les entités connectés sur le bus I2C peuvent se comporter en maître ou en esclave. Les transferts sont initiés uniquement par un maître, vers une autre entité qui se comportera en esclave. L'horloge est généré par le périphérique maître.
Chaque périphérique esclave a une adresse sur 7 bits (dans la version d'I2C qui nous intéresse).
Au niveau le plus bas, I2C permet à un maître d'envoyer un ou plusieurs octets vers un esclave (écriture) ou de lire un ou plusieurs octets depuis un esclave (lecture).
Écriture
Maître : START | ADRESSE (7 bits) / 0 (Write) | | DATA (8 bits) | | DATA (8 bits) | | STOP
Esclave : | | ACK | | ACK | | ACK |
Lecture
Maître : START | ADRESSE (7 bits) / 1 (Read) | | ACK | | NACK | STOP
Esclave : | | DATA (8 b) | | DATA (8 b) | |
START
(début d'échange) et STOP
(fin d'échange) sont des conditions particulières du signal SDA
par rapport à l'horloge. Tout le reste (y compris ACK
, acquittement positif et NACK
, acquittement négatif) sont des bits échangés au rythme de l'horloge.
Restart
Il est possible, et cela sera nécessaire pour parler à l'accéléromètre, d'enchaîner deux échanges, en particulier une écriture et une lecture en supprimant le STOP
à la fin du premier échange, le deuxième START
étant appelé dans ce cas dans les documents un RESTART
.
Travail à faire
Dans un fichier approprié, vous allez écrire les fonctions de base pour manipuler le bus I2C et faire des échanges simples qui nous permettrons par la suite de communiquer avec l'accéléromètre.
Dans notre cas, le micro-contrôleur sera maître sur le bus I2C et nous utiliserons des adresses I2C de 7 bits.
Identification de l'I2C et des IO nécessaires
❎ Identifiez, à partir des documents fournis, le bus I2C (il y en a plusieurs) et les pins auxquels l'accéléromètre LSM6DSL est relié. Indiquez vos réponses en commentaires en début du fichier dans lequel vous allez mettre les fonctions ci-dessous.
Indice : partez de la documentation de la carte, puis des schémas électroniques.
Initialisation de l'I2C
❎ Écrivez une fonction i2c_init
qui initialise le bus I2C auquel est relié l'accéléromètre. Cette fonction doit notamment :
- Configurer correctement les pins nécessaires (
SDA
etSCL
) pour que le micro-contrôleur et l'accéléromètre puissent dialoguer en I2C - Configurer l'horloge du contrôleur I2C (plusieurs sources d'horloge sont possibles, cf. registre
RCC_CCIPR
, on choisira l'horlogePCLK
) - Initialiser le contrôleur I2C en suivant la procédure décrite figure 393 (p. 1272 du manuel de référence)
- Les champs
NOSTRETCH
,ANFOFF
etDNF
peuvent rester dans leurs valeurs par défaut après reset - Concernant les timings I2C, on calculera les différentes valeurs demandées du registre
I2C_TIMINGR
à partir des données suivantes :- L'horloge du contrôleur I2C
I2CCLK
estPCLK
qui est à 80 MHz (soit une période de 12,5 ns) - Choisissez une valeur de
PRESC
intelligente pour avoir une périodet_PRESC
facile pour les générer les timings suivants t_SCLL
= 5 µst_SCLH
= 5 µst_SCLDEL
= 1 µst_SDADEL
= 500 ns- Ces valeurs sont conformes à ce qu'attend l'accéléromètre et donnent une fréquence d'horloge I2C (
SCL
) de l'ordre de 100 kHz.
- L'horloge du contrôleur I2C
- Les champs
Transferts de données
❎ Écrivez une fonction void i2c_write(uint8_t saddr, const uint8_t *data, uint8_t num, uint8_t stop)
Cette fonction prend les arguments suivants :
saddr
: adresse du périphérique esclave I2C concerné par le transfert (7 bits)data
: pointeur vers les données à transmettre au périphériquenum
: nombre d'octets à transmettre (num
<= 255)stop
: si 0, ne pas envoyer la conditionSTOP
à la fin du transfert des données
Cette fonction envoie (écriture) num
octets (maximum 255) situés à l'adresse data
vers le périphérique I2C dont l'adresse est saddr
. Si stop
vaut 0, la condition STOP
n'est pas transmise permettant de générer un RESTART
lors d'un transfert suivant immédiatement.
Indice : on pourra s'inspirer du texte page 1288 et de la figure 407 page suivante. La branche de gauche du schéma (NACKF
) ne vous intéresse pas.
Note : on regardera attentivement la description du champ SADD
.
❎ Écrivez une fonction void i2c_read(uint8_t saddr, uint8_t *data, uint8_t num, uint8_t stop)
Cette fonction prend les arguments suivants :
saddr
: adresse du périphérique esclave I2C concerné par le transfert (7 bits)data
: pointeur vers l'adresse où stocker les données reçuesnum
: nombre d'octets à recevoir (num
<= 255)stop
: si 0, ne pas envoyer la conditionSTOP
à la fin du transfert des données
Cette fonction reçoit (lecture) num
octets (maximum 255) et les place à l'adresse data
depuis le périphérique I2C dont l'adresse est saddr
. Si stop
vaut 0, la condition STOP
n'est pas transmise permettant de générer un RESTART
lors d'un transfert suivant immédiatement.
Indice : on pourra s'inspirer du texte de la page 1292 et de la figure 410 page suivante.