Introduction au Sous-système IIO
Avec la prolifération des appareils mobiles, de l'IoT et de l'IIoT, la demande de capteurs a explosé. Des capteurs tels que les accéléromètres, les capteurs de lumière, les gyroscopes, les baromètres et les magnétomètres, couramment présents dans les smartphones et les appareils portables, sont essentiellement des convertisseurs analogique-numérique (CAN). Ils transmettent leurs données brutes converties via des interfaces telles que I2C ou SPI.
Pour gérer cette complexité croissante, le noyau Linux a introduit le sous-système Industrial I/O (IIO). Le sous-système IIO est conçu pour les périphériques dont le composant fondamental est un CAN, transformant les signaux analogiques bruts en données numériques qui sont ensuite transmises via des interfaces de communication standard.
Architecture du Sous-système IIO
- IIO sysfs : Fournit une interface pour que l'espace utilisateur accède et configure les périphériques IIO.
- IIO Core : Gère l'allocation, l'initialisation et l'enregistrement des périphériques IIO, des déclencheurs IIO et des tampons IIO. Les fichiers principaux incluent
industrialio-core.c,industrialio-buffer.cetindustrialio-event.c. - IIO Driver : Ce sont les pilotes spécifiques à chaque périphérique IIO.
Structures de Données Clés
struct iio_dev : Description du Périphérique IIO
La structure iio_dev décrit un périphérique IIO spécifique. Elle contient des informations essentielles telles que l'identifiant du périphérique, le module du pilote, les modes de fonctionnement pris en charge, les tampons, les déclencheurs, la liste des canaux et le nom du périphérique.
struct iio_dev {
int id;
struct module *driver_module;
int modes; // Modes pris en charge par le périphérique
int currentmode; // Mode actuel du périphérique
struct device dev;
struct iio_event_interface *event_interface;
struct iio_buffer *buffer; // Tampon
struct list_head buffer_list; // Liste des tampons correspondants
int scan_bytes; // Nombre d'octets capturés et fournis au tampon
struct mutex mlock;
const unsigned long *available_scan_masks; // Masques de balayage disponibles
// ... autres membres
struct iio_trigger *trig; // Déclencheur IIO actuel
struct iio_poll_func *pollfunc;
struct iio_chan_spec const *channels; // Liste des canaux du périphérique IIO
int num_channels; // Nombre de canaux du périphérique IIO
// ... autres membres
const char *name;
const struct iio_info *info;
// ... autres membres
};
Les modes de fonctionnement sont définis comme suit :
INDIO_DIRECT_MODE: Accès via l'interface sysfs.INDIO_BUFFER_TRIGGERED: Prise en charge du déclenchement de tampon matériel.INDIO_BUFFER_SOFTWARE: Prise en charge du déclenchement de tampon logiciel.INDIO_BUFFER_HARDWARE: Prise en charge des tampons matériels.
struct iio_buffer_setup_ops
Ces opérations sont appelées lors de l'activation ou de la désactivation des tampons, permettant une configuration avant et après ces actions.
struct iio_buffer_setup_ops {
int (*preenable)(struct iio_dev *); // Appelée avant l'activation du tampon
int (*postenable)(struct iio_dev *); // Appelée après l'activation du tampon
int (*predisable)(struct iio_dev *); // Appelée avant la désactivation du tampon
int (*postdisable)(struct iio_dev *); // Appelée après la désactivation du tampon
bool (*validate_scan_mask)(struct iio_dev *indio_dev, const unsigned long *scan_mask); // Vérifie la validité du masque de balayage
};
struct iio_info : Attributs et Fonctions d'Implémentation
La structure iio_info contient les attributs et les fonctions d'implémentation pour un périphérique IIO spécifique. Elle définit les opérations de lecture et d'écriture brutes, la gestion des événements et la validation des déclencheurs.
struct iio_info {
struct module *driver_module;
// ... autres membres
int (*read_raw)(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask); // Fonction principale de lecture/écriture
// ... autres fonctions de lecture/écriture et de gestion d'événements
int (*validate_trigger)(struct iio_dev *indio_dev,
struct iio_trigger *trig);
// ... autres membres
};
Les fonctions read_raw et write_raw utilisent val et val2 pour représenter les données. Le noyau Linux ne gérant pas directement les opérations en virgule flottante, val2 est utilisé pour représenter la partie fractionnaire, multipliée par une puissance de 10 prédéfinie par les macros suivantes :
IIO_VAL_INT: Valeur entière simple.IIO_VAL_INT_PLUS_MICRO: La partie fractionnaire est multipliée par 1 000 000.IIO_VAL_INT_PLUS_NANO: La partie fractionnaire est multipliée par 1 000 000 000.IIO_VAL_FRACTIONAL: La valeur estval / val2.IIO_VAL_FRACTIONAL_LOG2: La valeur estval >> val2.
Le paramètre mask est utilisé pour spécifier quel type d'information est lu ou écrit (par exemple, IIO_CHAN_INFO_RAW pour les données brutes, IIO_CHAN_INFO_SCALE pour l'échelle/résolution).
struct iio_chan_spec : Attributs du Canal
Chaque canal d'un périphérique IIO est décrit par struct iio_chan_spec. Cette structure définit le type de canal (tension, courant, accélération, etc.), l'adresse du registre, le format des données balayées et les masques d'informations partagées.
enum iio_chan_type {
IIO_VOLTAGE, IIO_CURRENT, IIO_ACCEL, IIO_ANGL_VEL,
IIO_TEMP, // Et bien d'autres...
};
struct iio_chan_spec {
enum iio_chan_type type; // Type de canal
int channel;
int channel2; // Peut être un modificateur de canal
unsigned long address; // Adresse du registre du périphérique
int scan_index; // Index dans le tampon de balayage
struct {
char sign; // 's' pour signé, 'u' pour non signé
u8 realbits; // Nombre de bits de données réels
u8 storagebits; // Nombre total de bits de stockage
u8 shift; // Décalage à droite
u8 repeat;
enum iio_endian endianness; // Boutisme (BE/LE)
} scan_type;
long info_mask_separate; // Masque d'informations spécifiques à ce canal
long info_mask_shared_by_type; // Masque d'informations partagées par type de canal
// ... autres masques d'information
unsigned modified:1; // Indique si channel2 est un modificateur
unsigned indexed:1; // Indique si channel est un index
unsigned output:1; // Indique si c'est un canal de sortie
// ... autres drapeaux
};
Les modificateurs de canal comme IIO_MOD_X, IIO_MOD_Y, IIO_MOD_Z sont utilisés pour différencier les axes des capteurs multi-axes.
Les masques d'information (info_mask_separate, info_mask_shared_by_type, etc.) permettent de définir quelles propriétés sont accessibles pour un canal donné et si elles sont partagées avec d'autres canaux.
struct iio_trigger : Déclenchement de l'Acquisition de Données
Les déclencheurs IIO initient l'acquisition de données en réponse à un événement, tel qu'une interruption de fin de données, une interruption périodique ou une opération d'écriture sysfs.
struct iio_trigger {
const struct iio_trigger_ops *ops;
// ... autres membres
};
struct iio_buffer : Stockage des Données Acquises
Le tampon IIO stocke les données acquises avant qu'elles ne soient lues par l'espace utilisateur. Il gère la taille, le nombre d'octets par donnée et l'interface d'accès.
API du Sous-système IIO
Enregistrement et Désenregistrement de iio_dev
Les fonctions iio_device_alloc et devm_iio_device_alloc sont utilisées pour allouer la structure iio_dev. L'enregistrement se fait avec iio_device_register ou devm_iio_device_register, et le désenregistrement avec iio_device_unregister ou devm_iio_device_unregister.
L'enregistrement via sysfs crée les entrées correspondantes dans /sys/bus/iio/devices/, permettant l'interaction avec le périphérique.
Initialisation du Sous-système IIO
L'initialisation du sous-système IIO implique l'enregistrement du bus IIO, l'allocation d'un numéro de périphérique caractère, et la création du répertoire debugfs pour IIO.
Exemple de Pilote : ICM20608
L'exemple de pilote pour le capteur ICM20608 (accéléromètre, gyroscope, température) illustre l'utilisation du sous-système IIO.
Configuration du Noyau
Pour utiliser IIO, il faut activer les options correspondantes dans la configuration du noyau Linux :
Device Drivers -> Industrial I/O support- Cocher
Enable buffer support within IIO - Cocher
Industrial I/O buffering based on kfifo
Analyse du Code du Pilote (ICM20608)
Le pilote ICM20608 définit les canaux pour la température, le gyroscope (axes X, Y, Z) et l'accéléromètre (axes X, Y, Z). Chaque canal est configuré avec son type, son masque d'information et son type de balayage.
struct icm20608_dev: Structure privée du pilote contenant le pointeur vers le périphérique SPI, la configuration duregmapet un mutex.icm20608_channels[]: Tableau de structuresiio_chan_specdécrivant chaque canal du capteur.- Fonctions
*_read_rawet*_write_raw: Implémentent la logique pour lire et écrire les données brutes, l'échelle et les biais de calibration via l'interface sysfs. Les échelles (résolutions) sont définies en utilisant les macrosIIO_VAL_INT_PLUS_MICROetIIO_VAL_INT_PLUS_NANO. - Fonction
icm20608_write_raw_get_fmt: Spécifie comment les données écrites par l'espace utilisateur doivent être interprétées (par exemple, par quel facteur multiplier les valeurs fractionnaires). - Fonction
probe: Initialise le périphérique, enregistre le pilote IIO et configure leregmappour la communication SPI. - Fonction
remove: Nettoie les ressources lors du retrait du pilote.
Test du Pilote ICM20608
Après compilation et chargement du module, les périphériques IIO apparaissent dans /sys/bus/iio/devices/. Pour l'ICM20608, un appareil comme iio:device1 sera créé. Les fichiers tels que in_accel_x_raw, in_accel_scale, in_anglvel_x_raw, etc., permettent de lire et écrire les données et les configurations du capteur.
Un programme d'application C peut lire ces fichiers pour obtenir les données brutes et calculées du capteur.
Exemple de Pilote : ADC VF610
L'exemple du pilote pour le contrôleur ADC VF610 sur les plateformes NXP i.MX6ULL illustre l'utilisation du sous-système IIO pour les convertisesurs analogique-numérique.
Description du DTS
Le Device Tree Source (DTS) décrit le matériel ADC, y compris son adresse mémoire, ses interruptions, ses horloges, le nombre de canaux et les ressources d'alimentation (régulateurs).
Activation du Pilote ADC
Le pilote doit être activé dans la configuration du noyau :
Device Drivers -> Industrial I/O support -> Analog to digital converters -> Freescale vf610 ADC driver
Analyse du Code du Pilote (VF610 ADC)
Le pilote vf610_adc.c :
- Fonction
probe: Alloue et initialise la structureiio_dev, récupère les ressources matérielles (registres, interruptions, horloges, alimentation) via le DTS, configure le contrôleur ADC et enregistre le périphérique IIO. - Fonction
vf610_read_raw: Implémente la logique pour lire les données brutes du CAN. Les valeurs sont généralement exprimées en tension. L'échelle (résolution) est fournie pour convertir les données brutes en tension réelle.
Test de l'ADC VF610
Les données de l'ADC VF610 sont accessibles via sysfs dans /sys/bus/iio/devices/iio:device0/. Des fichiers comme in_voltage1_raw (données brutes du canal 1) et in_voltage_scale (résolutoin en mV) permettent d'interagir avec le CAN.
Une application C peut lire ces fichiers pour obtenir la tension mesurée par l'ADC. Il est important de noter que le calcul final de la tension réelle implique des opérations en virgule flottante, qui doivent être gérées correctement lors de la compilation de l'application.