Le Relais 2 x 5 V … dans l’IoT ou l’art de piloter en BLE les périphériques de la WaRP7 – Partie 1/2

L’important choix de cartes intégrant des capteurs/actionneurs, en fait aujourd’hui, un choix difficile pour l’utilisateur final. C’est pour ces raisons que MikroElektronika a créé un standard : MikroBUS. Il facilite l’interaction entre microcontrôleur ou microprocesseur et les cartes d’extensions, appelées « add-ons », utilisant cette connectique. Cet article se propose d’explorer la partie MikroBUS d’un des tous derniers SBC (Single Board Computer) du marché : la WaRP7 (« WearAble Reference Platform »). On commencera dans un premier temps par une succincte présentation de la WaRP7 et d’une partie « board bring-up » (via Yocto/OE). Puis, viendra la partie MikroBUS qui sera mise en avant à travers un mini projet architecturé autour du Bluetooth Low Energy et du framework Qt5 pour Android tout en y intégrant une carte add-ons, carte qui se base sur le standard MikroBUS.

Le présent article s’inscrit dans la continuité des manipulations ayant permis la rédaction d’un article précédent paru dans le n°20 d’Open Silicium [1], les auteurs renverront vers celui-ci les lecteurs qui désirent avoir de plus amples connaissances sur la diversité que propose la cible utilisé dans ce numéro de Linux Magazine. Dans le premier article, il était question de découvrir la WaRP7 et ses capteurs au travers une application « IoT » minimaliste (récupération d’une température, la pression atmosphérique ainsi qu’une valeur représentant le rythme cardiaque), ceci en utilisant la connectivité Bluetooth et le framework Qt5, le tout basé sur une distribution Yocto/OE mis à disposition par les auteurs.

Que le lecteur ne pouvant pas se procurer le premier article soit rassuré, on se permettra tout de même ici de faire des rappels (ouf !) quant aux éléments essentiels (présentation de la cible, génération et installation de l’image sur notre cible, une partie Bluetooth, puis quelques mots sur le SDK Yocto/Qt5).

1. Introduction

1.1 La cible : « WaRP7 », petit rappel

La plateforme cible [2] est composée de 2 cartes :

  • Une carte « fille », qui est construite autour d’un System on Chip NXP i.MX7 Solo [3] (avec un coeur Cortex A7 + un coeur Cortex M4). De plus, cette carte embarquera la gestion de la connectivité (Wifi/BLE) ;
  • Une carte « mère », qui contiendra l’ensemble des capteurs (Gyroscope, Altimètre, etc.), ainsi que l’extension MikroBUS (qui nous intéresse particulièrement dans cet article).

Fig. 1: Non, la WaRP7 n’est pas timide

1.2 Construction de notre distribution « IoT »

La génération de la distribution pour notre cible, repose sur l’utilisation du BSP (Board Support Package) NXP articulé autour du projet Yocto [4] et de deux couches supplémentaires (nous ne ferons pas ici, de détails quant à l’utilisation de Yocto/OE, le lecteur pourra en outre, se référer aux différents articles parus dans les précédents numéros d’open silicium).

La première étape consiste donc à récupérer l’ensemble des sources contenues dans le BSP. Pour ce faire, NXP utilise l’utilitaire repo (outil Python développé par Google [5]), ceci afin de permettre une meilleure gestion des référentiels Git compris dans celui-ci :

Comme prévu, après récupération de notre base logicielle, nous pouvons maintenant télécharger les deux couches supplémentaires essentielles à la bonne construction de notre image.

Téléchargeons dans un premier temps la couche distribution mis à disposition par les auteurs [6], pour rappel, cette couche spécifique est intimement liée à l’article (ceci afin de ne pas se perdre dans le framework qu’est Yocto/OE) :

Dans un second temps, récupérons la couche permettant d’intégrer l’environnement Qt5 à notre distribution :

Nous voilà maintenant en possession de l’ensemble des sources. L’étape d’après consiste en la création de l’environnement, on retrouve ci-après les différentes étapes :

  • création du dossier de construction warp7-build/,
  • appel du script oe-init-build-env,
  • mise à jour de la variable MACHINE,
  • puis un prompt concernant la licence FSL EULA (à accepter).

La commande suivante s’occupera donc de nous placer dans un environnement de travail spécifique à notre plateforme de développement :

Il reste maintenant à définir les chemins vers les couches précédemment téléchargées, pour ce faire, modifions le fichier conf/bblayers.conf pour y rajouter les deux lignes suivantes :

Dernière étape avant de pouvoir lancer la construction de l’image, il nous faut spécifier la distribution utilisée (dans notre cas une distribution spécifique à l’article dérivé de la distribution poky) dans conf/local.conf, en mettant à jour la variable DISTRO :

Lançons maintenant la construction de notre image par le biais de la commande bitbake :

Après cette longue étape qu’est la construction, l’utilisateur pourra retrouver très facilement l’ensemble des fichiers utiles au bon démarrage de la plateforme (Bootloader, Kernel, RootFileSystem) dans tmp/deploy/images/imx7s-warp.

 

1.3 Premier Flash, premier Boot, …

Rappelons qu’afin de mettre à jour le système avec l’ensemble des binaires compilés, les étapes se déroulent comme suit :

  • Connexion en liaison série (via un émulateur de terminal comme microcom), puis arrêt de l’auto-boot au niveau du bootloader (u-boot) :

  • Montage de la partition eMMC côté bootloader :

  • Décompression et opération de copie coté système hôte sur le device spécifique :

Une fois la copie terminée, l’utilisateur pourra redémarrer la carte pour voir apparaître la séquence de démarrage :

1.4 Activation de l’interface Bluetooth

Rappelons ici, comment attacher, initialiser et activer notre interface Bluetooth, afin que celle-ci soit accessible par les autres périphériques compatibles :

1.5 SDK Qt5

1.5.1 Génération

Nous avons évoqué lors de l’article précédent la notion de SDK et chaîne de compilation croisée (mais pas que). Ceci afin de pouvoir générer du code Qt5 sur notre cible. La commande ci-dessous permettra la génération d’un SDK générique et compatible Qt5 :

Une fois la génération terminée, le script d’installation du SDK se trouvera dans tmp/deploy/sdk.

1.5.2 Installation

Elle se fera tout simplement en exécutant le script suivant où il conviendra de spécifier le chemin d’installation (/opt/iot/sdk dans cet exemple) :

1.5.3 Intégration à l’IDE Qt creator

Afin de se voir l’environnement de compilation croisée, intégré à notre IDE préféré, il nous faudra :

  • Dans Outils > Options > Compiler et Exécuter
  • Puis dans la section Compilateurs > Ajouter , choisir « GCC »
  • On donnera un nom à notre GCC spécifique (par exemple WaRP7_GLMF200),
  • Puis nous spécifierons le chemin du compilateur : /opt/iot/sdk/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-gcc
  • Dans Versions de Qt, Qt est normalement automatiquement détecté. Sinon le lecteur devra ajouter le chemin vers qmake : /opt/iot/sdk/sysroots/x86_64-pokysdk-linux/usr/bin/qt5/qmake
  • Dans Kits, il ne reste plus qu’à choisir les éléments précédemment mis en place (Compilateur et version), il sera aussi recommandé de spécifier le mkspecs « linux-oe-g++ » :

2. MikroBUS

Dans cette partie nous aborderons, dans un premier temps, le standard MikroBUS, nous présenterons autant les aspects matériels que les aspects logiciels que propose celui-ci. Nous ferons ensuite un bref tour d’horizon sur les modules que propose MikroElektronika.

2.1 Le standard : introduction

Le standard MikroBUS définit les connectiques des cartes principales (on parle souvent de carte mère) ainsi que celles des cartes additionnelles (add-on) utilisées pour l’interfaçage du microcontrôleur ou du microprocesseur avec les circuits et modules complémentaires. De plus, il spécifie la disposition physique du brochage, les broches de communication et les broches d’alimentation utilisées.

On remarque, bien évidemment, que l‘objectif de mikroBUS est de jouer sur la flexibilité matérielle, permettant ainsi un interfaçage plus facile avec un grand nombre de cartes complètes, qui plus est, standardisées (plus de 200 modèles commercialisés par MikroElektronika tout de même !), chacune avec un simple capteur (humidistance), un module radio (RFID), un écran (OLED), une connectique (RS232), ou tout autre module électronique[7].

Remarque
A noter que mikroBUS est un standard ouvert et donc n’importe qui peut prétendre implémenter mikroBUS dans sa conception matérielle, à condition bien sûr de respecter les conditions de MikroElektronika.

2.2 Le standard : Description du connecteur MikroBUS

Le connecteur MikroBUS est composé de 16 broches (2×8). L’ensemble de celles-ci est toujours positionné de la même manière comme le montre la figure 2.

Fig. 2: pinout du standard MikroBUS


On retrouvera sur chaque module :

  • Des broches par type de bus de communication : SPI, UART, I2C.
  • 4 broches complémentaires : PWM (ou MLI en français), interruption matérielle (INT), entrée analogique (AN) et reset (RST).
  • Puis un couple pour les alimentations :
  • 3,3V / GND
  • 5V / GND

2.3 Quelques Examples :

Il est bien évidemment compliqué de présenter ici l’ensemble des modules proposés par la firme MikroElektronika. Afin de donner au lecteur un bref aperçu des cartes disponibles, les auteurs auront choisi d’en exposer 2 au travers de cet article :

2.3.1 La « Relay Click Board » :

Fig. 3: La Relay Click sous les projecteurs


Cette carte embarque deux relais de puissance (G6D1AASI-5DC de référence Omron). Le pilotage vers la carte principale (dans notre cas la WaRP7) s’effectue via les broches suivantes du connecteur MikroBUS :

  • Broche PWM pour le Relais 1 (RL1),
  • Broche CS pour le Relais 2 (RL2).

De notre point de vue, ce ne sera ni plus ni moins que l’activation (état haut ou état bas) d’une broche GPIO (ouverture ou fermeture du relais).

2.3.2 La « custom » :

Fig. 4: L’inconnu au bataillon


Comme remarqué précédemment, il est possible de réaliser sa propre carte autour du standard MikroBUS. Dans cet exemple, le module est composé d’un gpio expander (microchip mcp23s08) pilotable au travers d’une interface SPI (mais aussi via le bus i2c). Cette option permet d’étendre les capacités de la carte principale quand celle-ci arrive à ses limites (ou si aucune GPIO physique n’est présente sur la carte mère).

3. Jouons un peu avec la « relay click board »

Viens maintenant le temps de jouer un peu avec notre module MikroBUS, celui-ci permettant d’étendre les capacités de notre WaRP7, nous mettant ainsi des relais à disposition (ceci afin de commander par exemple une lampe, ou tout autre objet …). Dans ce chapitre nous verrons comment les piloter de façon simpliste en accédant aux GPIO depuis l’espace utilisateur. Nous aborderons ensuite le sujet du device tree et l’accès à la configuration des GPIO depuis celui-ci.

3.1 Plug !

Insérons notre module relais et constatons qu’il est très facile d’intégration entre notre plateforme cible et les modules MikroBUS (WaRP7 <-> Relay Click Board), ceci grâce à la standardisation :

Fig. 5 : La WaRP7 en position !

3.2 And Play !

Sous GNU/Linux, l’accès aux GPIO [8] s’effectue dans /sys/class/gpio/gpioN où N représente le numéro de la GPIO (à condition que le driver associé soit présent → GPIO_SYSFS).

Nous savons par le biais de la schématique (disponible en [2]), que le relais 1 et sur la broche CPU « GPIO7_IO8 », qui, en espace utilisateur devient gpio200.

Comment calculer le numéro de gpio utilisé en mode userspace ?
Le calcul est sous la forme :
((port_GPIO – 1)*32) + n°gpio.
Exemple pour le relais 1 : ((7-1)*32) + 8 = 200

La première étape consistera à exporter cette GPIO pour la rendre accessible depuis le système de fichier virtuel /sys, la commande si après créera donc un point d’accès gpio200 :

L’interface étant disponible, il nous faut la paramétrer en tant que broche de sortie :

Une fois configurée, il nous est possible de la piloter, ceci en agissant simplement sur la tension de sortie de la broche, via la commande suivante :

La broche de sortie passée à l’état haut, il nous est facile de constater le résultat sur la carte relais (led REL1), comme nous le montre la figure 6 :

Fig. 6: Relais 1 en fonctionnement


Nous ferons de même pour le relais numéro 2 (RL2 sur la « relay click ») qui lui est sur « GPIO4_IO23 » :

Fig. 7 : Relais 2 en fonctionnement

3.2 Intégration au device-tree : « gpio-exporter & pin-muxing »

L’inconvénient des étapes (export/direction) précédentes réside dans le fait qu’il nous est obligatoire de les réexécuter à chaque démarrage de la WaRP7, car non statique au sein de la configuration matérielle. Il serait donc intéressant d’avoir une entrée statique. Nous irons un peu plus loin que la simple configuration des GPIO.

En effet, il serait aussi plaisant de pouvoir associer un nom à nos GPIO lors de la configuration de celles-ci, pour ce faire, nous intégrerons le travail de Martin FUZZEY[9] (qu’on ne manquera pas de remercier pour le travail effectué), qui a en effet développé un driver Kernel permettant d’avoir au sein de l’espace utilisateur, un lien nom/numéro de GPIO. L’avantage de cette solution est que finalement, l’utilisateur ne se soucie plus du numéro de la GPIO, de ce fait, la configuration est beaucoup plus portable et maintenable.

3.2.1 Device tree : une petite introduction

L’arbre de périphériques (device tree ou encore DT) est une structure de données permettant de décrire le matériel d’un système, dérivée du format utilisé par Open Firmware pour encapsuler les informations de plateforme et les transmettre au noyau, qui utilise alors les données du DT pour trouver et enregistrer les périphériques du système.

La structure de données elle-même est un arbre de nœuds nommés et de propriétés. Chaque nœud contient des propriétés de simples paires « nom-valeur » et des nœuds fils. Afin d’être interprétée correctement par le noyau, l’arborescence doit suivre une structure prédéfinie. Une « liaison » (en anglais, binding) est une description de la façon dont un périphérique est décrit dans le DT. Un grand nombre de périphériques disposent de liaisons bien établies et documentées.

3.2.2 Anatomie de notre fichier dts « imx7s-warp-relay.dts »

Afin de ne pas surcharger le fichier dts (device tree source) principal (imx7s-warp.dts), les auteurs auront choisi de créer un fichier dts spécifique à l’intégration du module « relay click », en voici sa constitution :

Essayons de détailler celui-ci :

  • #include « imx7s-warp.dts » fera référence au fichier principal la WaRP7 (définition de la carte), qui lui-même inclus la définition du SoC (System on Chip) i.MX7 (imx7d.dtsi).
  • Au niveau du contenu du fichier :
  • La création d’un nœud (node) avec son label associé, que l’on appellera gpio-exporter :

  • Le mot clé compatible est une propriété qui permettra de faire le lien avec la partie driver (respectant la règle du plateform driver comme présenté par Pierre Ficheux en [10]). Ceci via la structure of_device_id qui sera utilisée avec le tableau gpio_exporter_dt_ids[]. Le lecteur curieux pourra jeter un coup d’oeil au code source dans tmp/work/imx7s_warp-polky-linux-gnueabi/linux-fslc-imx/4.1-1.0.x+gitAUTOINC+9d3f7f9343-r0/git/drivers/gpio/gpio-exporter.c :

  • La propriété pinctrl-0 permet de donner la liste des broches qui seront soumises à une définition spécifique de leur état, ceci grâce au sous-système pinctrl qui permet de gérer le multiplexage des broches. Dans notre cas, la configuration s’effectuera dans le nœud fils pinctrl_gpioexporter_relay

  • Il convient ensuite de créer un nœud fils (child node), le nom de celui-ci représentera le nom exposé au sein de l’espace utilisateur, nous garderons la même syntaxe que la carte « relay click », à savoir RL1 pour le pilotage du relais 1 :

Il nous faudra aussi renseigner les propriétés à notre nœud fils :

  • gpios : Référence vers la GPIO à exporter (binding standard défini dans les sources du Noyau Linux : Documentation/devicetree/bindings/gpio/gpio.txt). En plus du phandle (nœud vers le contrôleur associé), nous retrouverons le numéro de GPIO, 8 pour notre application. Puis le second argument signifie que celle-ci est active sur un niveau haut (GPIO_ACTIVE_HIGH).
  • output : pour spécifier que l’on désire la positionner en sortie,
  • initial-state : où on fixera sont état initial (état bas dans notre cas)

Il en sera de même pour le relais numéro deux, où seul le nom du sous-nœud et de la GPIO associé seront donc à modifier pour le piloter :

Nous en resterons là quant à la présentation du fichier device tree, le lecteur pourra se référer au très bon article écrit par Thomas Petazzoni paru dans le n°17 d’Open Silicium [11].

Pierre-Jean TEXIER
[Ingénieur Linux Embarqué, Intervenant Linux Embarqué à ESTEI Bordeaux ,
Co-auteur de l’ouvrage « Yocto For Raspberry-pi »]

Jean CHABRERIE
[Ingénieur Systèmes Embarqués, Qt Enthousiaste]


La seconde partie de cet article sera publiée prochainement sur le blog, restez connectés 😉

Retrouvez cet article (et bien d’autres) dans GNU/Linux Magazine n°200, disponible sur la boutique et sur la plateforme de lecture en ligne Connect !