Mise en oeuvre de la bibliothèque graphique LittlevGL sur RaspberryPi

C’est en lisant un article sur le blog d’Olimex, un fabricant bulgare de carte linux embarqué réputé, que j’ai découvert la bibliothèque LittlevGL. La démonstration qu’ils en faisaient sur une de leur carte équipée d’un écran tactile m’a tout de suite convaincu. Je me suis donc mis en tête de tester cette bibliothèque sur un écran tactile TFT connecté à un raspberryPi.

Introduction

Notez bien que ce qui va suivre peut fonctionner sur n’importe quelle carte supportant GNU/Linux et un écran TFT géré par le noyau. Si l’écran dispose d’une dalle tactile résistive ou capacitive, elle sera gérée aussi par le noyau. Il faut juste s’assurer que les circuits intégrés utilisés pour l’écran et le tactile ont des pilotes dans le noyau Linux.

La bibliothèque LittlevGL

Le site officiel est disponible à cette adresse : https://littlevgl.com/
Je vous conseille dans un premier temps de parcourir la page d’accueil puis de vous rendre dans l’onglet « Live Demo » où vous pourrez tester tous les « widgets » mis à disposition par cette bibliothèque. Même si cette bibliothèque se destine plutôt à des microcontrôleurs un peu costauds, elle fonctionne aussi avec le framebuffer de Linux et propose la gestion des écrans tactiles à travers la bibliothèque libinput et/ou evdev : lisez https://blog.littlevgl.com/2018-01-03/linux_fb pour le framebuffer et le code disponible sur GitHub https://github.com/littlevgl/lv_drivers/tree/master/indev pour les périphériques d’entrées (evdev et libinput pour ce qui concerne Linux).

Choix du matériel et du logiciel pour réaliser ce test

La carte sera une raspberryPi 3B+, carte SD de 16Go, alimentation officielle, clavier usb. Pour simplifier l’installation de l’écran TFT tactile, je prends un écran qui est bien supporté par le noyau Linux et qui à déjà un fragment de « device tree » disponible pour le raspberryPi. Pour savoir quels écrans sont compatibles, il suffit de parcourir le fichier « README » dans /boot/overlays d’une carte Raspbian. Pour ma part j’avais de disponible un écran TFT tactile de chez Adafruit industry : https://www.adafruit.com/product/1601 . Il date un petit peu, c’est du résistif (il existe une version à écran capacitif) mais c’est surtout ce que j’avais de disponible. De plus il est disponible dans les « overlays » pour raspberryPi. Ci-dessous l’extrait du fichier README indiqué plus haut pour cet écran:

La version de raspbian lite utilisée pour ce test sera celle du 2019-09-26. Une fois la carte SD créée et les paramètres de bases ajustés avec raspi-config (activation ssh, changement nom et mot de passe, passage en francais), il faut éditer le fichier /boot/config.txt et rajouter la ligne « dtoverlay=pitft28-resistive » à la fin du fichier. Pour l’instant j’utilise les paramètres par défaut de cet écran. Redémarrez la raspberryPi….

Test de l’écran Adafruit PiTFT

Si tout se passe correctement, on devrait avoir un certain nombre de modules noyau chargés pour gérer cet écran. Tapons la commande « lsmod » et analysons sa sortie:

On remarque le module noyau fbtft qui permet de gérer les écrans tft de petite taille et le pilote de l’écran adafruit fb_ili9340. L’écran tactile est géré par le module stmpe_ts. L’écran est piloté à travers le bus SPI d’ou le module spi_bcm2835. Apparement, tout est chargé pour avoir un nouvel écran de disponible, on regarde donc ce que le noyau met à notre disposition comme « framebuffer » :

fb0 correspond au framebuffer de la pi donc il doit exister dans tous les cas. Le fb1 désigne un nouvel écran. Récupérons ces caractéristiques avec la commande « fbset », installez le paquetage auparavant :

L’écran est bien géré par le pilote fb_ili9340, sa résolution est de 320×240 pixels. Basculons la console sur cet écran puis revenons ensuite sur l’écran HDMI:

Si tout se passe correctement on peut passer à LittleVGL….

Installation, configuration et méthode de développement de la bibliothèque LittlevGL

J’ai choisi de développer à distance mon code : je travaille sur un PC fonctionnant sous Debian 9 avec l’IDE NetBeans8 (fonctionne aussi sous Microsoft Windows et Netbeans8.2). La compilation et l’exécution du code se feront sur la RPi3. Cette méthode de développement est expliquée dans cet article.

Je suis le tutoriel d’installation sur https://docs.littlevgl.com/en/html/get-started/quick-overview.html . En particulier je vais sur https://littlevgl.com/download et je télécharge les archives pour littlevGL version 6, les exemples et les pilotes (drivers) sur mon PC de développement. Je désarchive le tout dans un répertoire (par exemple /home/olivier/dev/littlevGL). Vous allez obtenir trois répertoires qui se terminent tous par « -master », renommez les répertoires en enlevant « -master ».

Créez un nouveau projet C++ avec Netbeans (par exemple TestLittlevGL). Je copie alors les répertoires « lvgl » et « lv_drivers » au niveau de mon projet. Dans le répertoire « lvgl », copiez le fichier « lv_conf_template.h » au même niveau que le répertoire lvgl et renommez-le en « lv_conf.h ». Dans le répertoire « lv_drivers », copiez le fichier « lv_drv_conf_templ.h » au même niveau que le répertoire lvgl et renommez-le en « lv_drv_conf.h ». Vous devez obtenir une arborescence qui ressemble à la suivante:

Vous pouvez suivre ce qui est indiqué sur cette page https://blog.littlevgl.com/2018-01-03/linux_fb mais elle ne semble pas tout à fait à jour. Je détaille donc mon installation.
Tout d’abord il faut éditer le fichier « lv_conf.h » et modifier les lignes suivantes:

  • #if 0 /Set it to « 1 » to enable content/ : passer le ‘0’ à ‘1’ pour activer ce fichier,
  • #define LV_HOR_RES_MAX (480) : je passe à 320,
  • #define LV_VER_RES_MAX (320) : je passe à 240,
  • #define LV_COLOR_DEPTH 16 : je laisse du 16 bits, mettre 32 si on travaille avec le framebuffer original du raspberrypi (/dev/fb0, sortie HDMI),
  • toutes les lignes qui concernent les polices embarquées disponibles : #define LV_FONT_ROBOTO_12, _16, _22 et _28 passent à 1.

Il faut ensuite éditer le fichier « lv_drv_conf.h » et modifiez les lignes suivantes pour l’affichage sur l’écran tft:

  • if 0 /Set it to « 1 » to enable the content/ : passer le ‘0’ à ‘1’ pour activer ce fichier,
  • #define USE_FBDEV 0 : passer le ‘0’ à ‘1’ pour activer le support du framebuffer,
  • #define FBDEV_PATH « /dev/fb0 » : remplacer ‘fb0’ par ‘fb1’ : nom du framebuffer de notre ecran TFT.

Pour l’instant je ne modifie rien concernant les périphériques d’entrées dans le fichier « lv_drv_conf.h ». Dans un premier temps on va se contenter d’afficher des widgets. Comme premier exemple de test, je reprend celui donné dans le lien précédent. Je donne le code ci-dessous avec une légère modification sur « #define DISP_BUF_SIZE (80*LV_HOR_RES_MAX) »:

Si vous lancez la compilation de ce projet, cela échoue car il ne trouve pas les fonctions « fbdev_xxx ». Il faut rajouter les deux répertoires « lvgl » et « lv_drivers » à l’ensemble des fichiers sources à compiler. Cela se fait en cliquant avec le bouton droit sur le nom du projet et en choisissant le menu « Add existing items from folders » (ma version de Netbeans est en anglais) et en choisissant les deux répertoires précédents. Il faut aussi rajouter les deux fichiers « lv_conf.h » et « lv_drv_conf.h ». Vous devez obtenir une arborescence du projet qui doit ressembler à celle-ci :

Cependant cela ne résout pas complètement le problème, il y un soucis d’include dans le fichier « lv_drivers/display/fbdev.h ». Il faut remplacer les lignes:

par

Relancez la compilation, cette fois-ci cela doit fonctionner. Vous obtenez un exécutable sur la RPi, pour moi ca sera dans le répertoire indiqué ci-dessous, à vous de l’adapter :

Pour exécuter le code:

Vous devez voir apparaître un écran qui ressemble à la capture ci-dessous. Tapez Ctrl+C pour quitter le programme.

Mise en oeuvre de la dalle tactile

On va maintenant modifier notre code pour mettre un « slider » et du coup tester le « tactile » avec la bibliothèque LittlevGL. Dans mon cas, j’ai choisi d’utiliser la bibliothèque « libinput » coté Linux pour la gestion de la dalle tactile. Mais avant cela il faut tester celle-ci sans programmation. Pour cela on va utiliser le logiciel evtest mais comme il est dit que ce logiciel est « déprécié » il faut passer au paquet « evemu-tools » et ces outils.

La commande « evemu-describe » détecte deux périphériques d’entrée : un clavier USB en event0 et la dalle tactile en event1. Avec la commande « evemu-record », on peut visualiser les événements de la dalle tactile sur la console pour voir si celle-ci renvoie bien des données : c’est le cas ici. On peut remarquer aussi quelque chose d’intéressant : les « event code » 0 et 1 correspondent à la coordonnée absolue en X (ABS_X) et en Y (ABS_Y). Ces coordonnées évoluent entre 0 et 4095 soit le résultat d’une conversion sur 12 bits.

Il y a cependant un problème qui pourrait apparaître par la suite. Si on débranche le clavier USB et que l’on redémarre, le périphérique d’entrée de la dalle tactile va passer de « event1 » à « event0 ». Il faudrait pouvoir fixer le nom pour la dalle tactile. Ce problème est évoqué dans un article sur le site d’Adafruit : https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi et plus particulièrement sur cette partie : https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi/resistive-touchscreen-manual-install-calibrate . On va donc créer une règle udev pour que notre dalle tactile gérée par un stmpe-ts apparaisse toujours sous le nom « /dev/input/touchscreen » :

On saisit la ligne suivante et on sauve:

Il faut redémarrer pour prendre en compte les changements. Puis on regarde si le lien symbolique est bien mis en place:

C’est bon, on va pouvoir s’intéresser à la mise en oeuvre de la dalle tactile dans LittlevGL. pour cela il faut éditer le fichier « lv_drv_conf.h » et faire les modifications suivantes:

par

Modifiez alors le code précédent pour mettre en place un slider et la gestion d’événements sur celui-ci:

Le code précédent ne compile pas. Il y a le même soucis d’include que précédemment dans le fichier « lv_drivers/indev/libinput_drv.h ». Il faut remplacer les lignes:

par

Au moment de la compilation, la bibliothèque « libinput » n’est pas trouvé sur le raspberryPi. Il faut donc l’installer avec la commande suivante:

Au niveau des options de compilation du projet dans Netbeans, il faut rajouter l’option « -linput » : clic droit sur le nom du projet puis choix « properties » puis rajouter dans « build » option « linker » dans le champ « Additional options » mettre « -linput » (la première lettre est un L minuscule). Relancez la compilation cette fois ci ça doit fonctionner et vous devez obtenir un exécutable. Lancez-le !

Le slider doit apparaître en haut de l’écran au dessus du label « hello world ». Lorsque vous essayez de le bouger avec votre doigt rien ne se passe ! Faites glisser votre doigt sur le coté droit de l’écran et vous verrez bouger le slider et les événements s’afficher dans la console.
Donc ça fonctionne presque correctement, les axes X et Y de la dalle tactile ne correspondent pas aux axes X et Y de l’écran !

Première solution : mettre l’écran en mode portrait : modifiez la ligne qui concerne l’écran pitft dans le fichier /boot/config.txt comme suit: dtoverlay=pitft28-resistive,rotate=0 puis modifiez les valeurs dans le fichier « lv_conf.h » en échangeant les valeurs X et Y de l’écran pour obtenir ceci:

Redémarrez puis lancez l’exécutable : ça fonctionne en mode portrait.

Deuxième solution : Cependant si vous souhaitez conserver le mode paysage (pas de paramètre supplémentaire sur la ligne dtoverlay=pitft28-resistive) ca va être un plus dur. Il faut configurer une matrice de transformation de coordonnées au niveau de la bibliothèque libinput. Après des recherches pénibles je suis arrivé sur cette page : https://wayland.freedesktop.org/libinput/doc/latest/api/group__config.html#ga09a798f58cc601edd2797780096e9804 . Elle présente comment manipuler les coordonnées renvoyées par la dalle tactile pour les adapter à l’orientation de l’écran. Par défaut l’écran a en fait une rotation de 90°, je vais donc prendre la matrice de transformation qui correspond à cette rotation : [0 -1 1] et [1 0 0]. Pour que cette transformation soit effective, il faut modifier la fonction « libinput_set_file » du fichier « lv_drivers/indev/libinput.c » en rajoutant ce qui suit avant la ligne « libinput_button = LV_INDEV_STATE_REL; » :

Recompilez et testez, votre slider doit maintenant se déplacer correctement avec votre écran en orientation paysage. La petite photo qui va bien ci-dessous mais elle ne prouve rien il faudrait une vidéo 🙂

Et la suite…

Cet article ne parle pas de la mise en oeuvre des widgets, les exemples et la documentation de LittlevGL sont là pour ça. Cet article s’est attaché à faire fonctionner la bibliothèque LittlevGL sur un écran TFT avec une dalle tactile. Les explications données ici doivent être valables pour n’importe quel écran et dalle tactile du moment qu’ils soient supportés par le noyau Linux.

En vous souhaitant un bon développement avec cette magnifique bibliothèque…

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.