Interface logicielle (API) - Driver I²C

De Wiki Techno-Innov
< Technique‎ | Logiciel‎ | API‎ | Use‎ | Drivers
Révision datée du 2 septembre 2020 à 05:49 par Nathael (discussion | contributions) (Page créée avec « {{DISPLAYTITLE:Interface logicielle (API) - Driver I²C}} == Présentation == #include "drivers/i2c.h" Le driver "i2c" donne accès aux périphériques présents sur les... »)
(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)
Aller à la navigation Aller à la recherche


Présentation

#include "drivers/i2c.h"

Le driver "i2c" donne accès aux périphériques présents sur les Bus I²C (Inter-Integrated Circuit) ou SMBus (Slave-Master Bus), dont le fonctionnement est très proche.

Lorsque le micro-contrôleur inclue plusieurs liaisons I²C le fichier d'entête fournit plusieurs définitions permettant d'indiquer le Bus I²C à utiliser lors des appels aux différentes fonctions :

  • I2C0
  • I2C1
  • I2C2
  • I2C3
  • ....


Configuration

int i2c_on(uint8_t bus_num, uint32_t i2c_clk_freq, uint8_t mode);
int i2c_off(uint8_t bus_num);

La fonction i2c_on() permet de configurer un des Bus I²C dans le mode de fonctionnement passé en paramètre

Le paramètre 'i2c_clk_freq' sert à spécifier la vitesse du Bus I2C. Le fichier d'entête fournit plusieurs définitions permettant d'indiquer la fréquence de l'horloge (SCL) pour le Bus sélectionné par la paramètre 'bus_num' :

#define I2C_CLK_100KHz  (100*1000)
#define I2C_CLK_400KHz  (400*1000)

Le paramètre 'mode' sert à définir le mode de fonctionnement du Bus I²C sélectionné. Le fichier d'entête fournit une énumération 'i2c_type' avec les valeurs suivantes pour définir le mode de fonctionnement :

  • 'I2C_MASTER' : Le micro-contrôleur est maître sur ce Bus.
  • 'I2C_SLAVE' : Le micro-contrôleur est esclave sur ce Bus.
  • 'I2C_MONITOR' : Le micro-contrôleur fonctionne en espion, il ne participe pas aux échanges, mais permet de vérifier le fonctionnement du Bus en donnant accès à toutes les adresses et données, mais aussi aux acquittements et autres états du Bus I²C.

Utilisation : Principe général

Pour permettre à l'utilisateur du driver i2c d'accéder à tous les modes de fonctionnement possible du Bus I²C et ainsi de de s'interfacer avec tous les périphériques, les fonctions de lecture et d'écriture utilisent un buffer de "contrôle" et un ou deux buffers de données.

Buffer de commandes

Les fonctions i2c_read() et i2c_write() utilisent un buffer de commandes qui contient les données spécifiques à la communication comme l'adresse de l'esclave et l'éventuel offset de lecture ou d'écriture.
Pour la fonction i2c_read(), il s'agit du paramètre 'cmd_buf' dont la taille est 'cmd_size'.
Pour la fonction i2c_write() ce buffer est inclus au début du buffer de données 'buf'.

Le premier octet de ce buffer doit toujours être l'adresse de l'esclave, avec le bit R/W positionné selon le besoin. Les octets suivants dépendent du protocole de communication de l'esclave et du contenu du buffer de contrôle. Il s'agit le plus souvent d'un offset déterminant l'adresse de lecture ou d'écriture pour les données à suivre.
Après chaque action 'I2C_DO_REPEATED_START' ou 'I2C_DO_STOP_START' du buffer de contrôle, le buffer de commande doit contenir l'adresse de l'esclave avec le bit R/W positionné selon le besoin. L'utilité principale de ce mécanisme est de permettre l'exécution du cycle de contrôle (envoi des données de contrôle à l'esclave, bit R/W de l'adresse positionné à 0 (écriture)) puis d'enchaîner immédiatement avec le cycle de lecture (envoi de l'adresse avec le bit R/W positionné à 1 (lecture) et réception des données transmises par l'esclave).

Buffer de contrôle

L'utilisation d'un buffer de contrôle permet l'implémentation des différentes séquences nécessaires à la communication avec les périphériques divers pouvant être interfacés à travers le Bus I²C.

Ce buffer de contrôle contient les actions à effectuer après chaque donnée envoyée, et a donc la même taille que le buffer de commandes pour i2c_read() ou que le buffer de sortie pour i2c_write().
Ces actions contrôlent la machine d'état qui gère la communication sur le Bus I²C.
Les actions possibles sont au nombre de 4 :

  • I2C_CONT : Aucune action particulière, la machine d'état passe à l'envoi de la donnée suivante.
  • I2C_DO_REPEATED_START : Envoie un "Reapeated start" sur le Bus I²C. Utilisé principalement pour la transition entre le cycle de contrôle (adresse et données de contrôle, envoyées à l'esclave) et le cycle de lecture (adresse et données lues, en provenance de l'esclave) pour i2c_read().
  • I2C_DO_STOP_START : Envoie un "Stop" sur le Bus I²C, mais continue la communication (un "Start" sera donc envoyé ensuite). Cette action n'est pas autorisée pour la fonction d'écriture i2c_write().
  • I2C_STOP: Indique la fin de la transmission à l'esclave par l'envoie d'un "Stop" sur le Bus I²C.

Lorsque le buffer de contrôle n'est pas utilisé (NULL), la machine d'état considère que l'action est toujours 'I2C_CONT', jusqu'à ce qu'il n'y ait plus de données à envoyer, auquel cas elle envoie un "Stop" et termine la communication sur le Bus I²C.

Buffer de données

Ce buffer correspond au paramètre 'inbuff' pour la fonction i2c_read() et "au reste" du buffer de données 'buf' pour la fonction i2c_write().
Ce buffer contient les données à écrire pour la fonction i2c_write() et sert à stocker les données lues pour la fonction i2c_read().

Adresses I²C

Les adresses des esclaves sont spécifiées à l'aide du buffer de commandes, sur 8 bits, avec le bit R/W positionné selon le besoin.
Le fichier d'entête fournit les définitions suivantes pour le bit R/W :

#define I2C_READ_BIT 0x01
#define I2C_WRITE_BIT 0x00

Valeurs de retour

Les fonctions i2c_read() et i2c_write() renvoie le nombre d'octets lus ou écrits si tout se passe normalement.
En cas d'erreur, ces fonctions renvoie un entier négatif avec les significations suivantes :

  • -EBADFD : Bus I²C non initialisé (-77)
  • -EBUSY : Bus I²C occupé ou problème d'arbitration du Bus I²C (-16)
  • -EAGAIN : Bus I²C occupé (-11)
  • -EINVAL : Argument invalide (pas de buffer de contrôle ou de buffer de données (-22)
  • -EREMOTEIO : Pas d'acknowledge reçu depuis l'esclave (-121)
  • -EIO : Bad one: Problème avec la machine d'état (-5)

Utilisation : Lecture

int i2c_read(uint8_t bus_num, const void *cmd_buf, size_t cmd_size, const void* ctrl_buf, void* inbuff, size_t count)

Le paramètre 'bus_num' permet de sélectionner le Bus I²C à utiliser (I2C0, I2C1, ....). Certains micro-contrôleurs ont un seul Bus I²C et ignorent ce paramètre.
Le paramètre 'cmd_buf' correspond au buffer de commande, dont la taille est spécifiée dans le paramètre 'cmd_size'. Ce buffer contient le plus souvent l'adresse du périphérique sans le bit de lecture, suivie d'un octet de commande, puis à nouveau l'adresse du périphérique avec le bit de lecture positionné.
Le paramètre 'ctrl_buf' correspond au buffer de contrôle de la communication, qui doit avoir la même taille que le buffer de commande 'cmd_buf' si il est utilisé, et permet d'indiquer à quel moment le driver I²C doit effectuer le "Repeated Start" pour signifier au périphérique que le sens de communication va changer.
Attention : Le fonctionnement décrit ci-dessus n'est pas applicable à tous les périphériques. Référez vous à la documentation du périphérique auquel vous voulez accéder pour déterminer le contenu de ces buffers en fonction du protocole de communication utilisé par le périphérique en question.
Le paramètre 'inbuff' correspond au buffer dans lequel seront placées les données reçues depuis le périphérique. Sa taille est 'count'.

Exemple :

#define I2C_DEV_ADDR 0x94  /* Adresse du périphérique */
#define DEV_ID_REG 0x06    /* Adresse du registre "device ID" dans la mémoire du périphérique */
#define CMD_BUF_SIZE  3
char cmd_buf[CMD_BUF_SIZE] = { I2C_DEV_ADDR, DEV_ID_REG, (I2C_DEV_ADDR | I2C_READ_BIT), };
char ctrl_buf[CMD_BUF_SIZE] = { I2C_CONT, I2C_DO_REPEATED_START, I2C_CONT, };
uint16_t dev_id = 0;
int ret = 0;

ret = i2c_read(I2C0, &cmd_buf, CMD_BUF_SIZE, ctrl_buf, &dev_id, 2);
if (ret != 2) {
    uprintf(UART0, "Device ID read error for device %d: %d\n", I2C_DEV_ADDR, ret);
}

Utilisation : Écriture

int i2c_write(uint8_t bus_num, const void *buf, size_t count, const void* ctrl_buf)

Le paramètre 'bus_num' permet de sélectionner le Bus I²C à utiliser (I2C0, I2C1, ....). Certains micro-contrôleurs ont un seul Bus I²C et ignorent ce paramètre.
Le paramètre 'buf' correspond à la fois au buffer de commande et au buffer de données. Sa taille est spécifiée dans le paramètre 'count'. Ce buffer contient le plus souvent l'adresse du périphérique sans le bit de lecture, suivie d'un octet définissant l'ofset en mémoire interne du périphérique, puis l'ensemble des données à écrire.
Le paramètre 'ctrl_buf' correspond au buffer de contrôle de la communication. Ce buffer est le plus souvent inutilisé (Voir explications plus haut). S'il est utilisé, sa taille doit être la même que celle du buffer 'buf'.
Attention : Le fonctionnement décrit ci-dessus n'est pas applicable à tous les périphériques. Référez vous à la documentation du périphérique auquel vous voulez accéder pour déterminer le contenu de ces buffers en fonction du protocole de communication utilisé par le périphérique en question.

Exemple :

#define I2C_DEV_ADDR 0x94  /* Adresse du périphérique */
#define DEV_EN_REG 0x06    /* Adresse du registre "device enable" dans la mémoire du périphérique */
#define BUF_SIZE  3
#define DEV_EN      (0x01 << 0)
#define DEV_IT_OFF  (0x01 << 2)
char buf[BUF_SIZE] = { I2C_DEV_ADDR, DEV_EN_REG, (DEV_EN | DEV_IT_OFF), };
int ret = 0;

ret = i2c_write(I2C0, &buf, BUF_SIZE, NULL);
if (ret != 2) {
    uprintf(UART0, "Device enable error for device %d: %d\n", I2C_DEV_ADDR, ret);
}

Utilisation : Libération du Bus

void i2c_release_bus(uint8_t bus_num);

Certains périphériques ne relâchent pas le Bus I²C en fin de transmission si ils ne reçoivent pas une condition "START" immédiatement suivie d'une condition "STOP".

Cette fonction permet d'envoyer ces deux conditions successives sur le Bus 'bus_num' pour forcer ces périphériques à libérer le bus I²C.


Spécificités liées aux différents micro-contrôleurs

LPC82x

  • Nombre de liaisons I²C : 4
  • Modes de fonctionnement : I2C_MASTER, I2C_SLAVE, I2C_MONITOR
  • "True open Drain" : Bus 0 seulement

LPC11A04

  • Nombre de liaisons I²C :
  • Modes de fonctionnement :
  • "True open Drain" :

LPC122x

  • Nombre de liaisons I²C : 1
  • Modes de fonctionnement : I2C_MASTER, I2C_SLAVE, I2C_MONITOR
  • "True open Drain" : Bus 0 seulement

LPC176x

  • Nombre de liaisons I²C :
  • Modes de fonctionnement :
  • "True open Drain" :