{"id":5144,"date":"2018-10-15T06:00:40","date_gmt":"2018-10-15T05:00:40","guid":{"rendered":"https:\/\/www.blaess.fr\/christophe\/?p=5144"},"modified":"2019-01-27T09:06:32","modified_gmt":"2019-01-27T08:06:32","slug":"pilotage-de-gpio-avec-lapi-libgpiod-partie-1","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2018\/10\/15\/pilotage-de-gpio-avec-lapi-libgpiod-partie-1\/","title":{"rendered":"Pilotage de GPIO avec l&rsquo;API Libgpiod (partie 1)"},"content":{"rendered":"\n<p>J&rsquo;ai assist\u00e9 il y a quelques jours, lors de l&rsquo;\u00e9dition 2018 des <em><a href=\"https:\/\/kernel-recipes.org\/en\/2018\/\" target=\"_blank\">Kernel Recipes<\/a><\/em> \u00e0 une pr\u00e9sentation par Bartosz Golaszewski&nbsp; de la nouvelle interface des GPIO pour l&rsquo;espace utilisateur de Linux. J&rsquo;en avais eu un bref aper\u00e7u il y a quelques mois mais je n&rsquo;avais pas encore pris le temps d&rsquo;essayer cette API. Cet article est donc une br\u00e8ve pr\u00e9sentation et mise en \u0153uvre de ces outils.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>Disponible depuis le noyau 4.8, cette API est amen\u00e9e \u00e0 remplacer l&rsquo;acc\u00e8s via <code>\/sys\/class\/gpio<\/code> qui est dor\u00e9navant consid\u00e9r\u00e9 comme <em>deprecated<\/em>.<\/p>\n\n\n\n<p>L&rsquo;acc\u00e8s se fait via le syst\u00e8me de fichiers <code>devtmpfs<\/code> mont\u00e9 sur le r\u00e9pertoire <code>\/dev<\/code>. On y trouve une entr\u00e9e par contr\u00f4leur de GPIO.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Voici un exemple sur une carte Raspberry Pi 3, sur laquelle est install\u00e9e la distribution Raspbian <code>2018-06-27<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>uname -a<\/strong>\nLinux raspberrypi 4.14.34-v7+ #1110 SMP Mon Apr 16 15:18:51 BST 2018 armv7l GNU\/Linux\n$ <strong>ls -l \/dev\/gpiochip*<\/strong>\ncrw-rw---- 1 root gpio 254, 0 Sep 16 08:34 \/dev\/gpiochip0\ncrw-rw---- 1 root gpio 254, 1 Sep 16 08:34 \/dev\/gpiochip1\ncrw-rw---- 1 root gpio 254, 2 Sep 16 08:34 \/dev\/gpiochip2<br>$<br><\/pre>\n\n\n\n<p>Trois contr\u00f4leurs sont donc pr\u00e9sents sur cette carte.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Acc\u00e8s depuis la ligne de commandes<\/h2>\n\n\n\n<p>[EDIT 2019] Dans les distributions Raspbian r\u00e9centes, il suffit d&rsquo;installer les packages n\u00e9cessaires ainsi&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>sudo  apt  install  -y  gpiod  libgpiod-dev<\/strong><\/pre>\n\n\n\n<p>Dans les versions pr\u00e9c\u00e9dentes, la biblioth\u00e8que Libgpiod et ses utilitaires n&rsquo;\u00e9taient pas encore <em>packag\u00e9s<\/em> par Raspbian, il \u00e9tait alors n\u00e9cessaire de faire les op\u00e9rations suivantes. Je les laisse ici pour m\u00e9moire, d&rsquo;autant que la version fournie par Raspbian 2018.11.13 est Libgpiod 1.0.1, et que la version actuelle est Libgpiod 1.2. Il y a des incompatibilit\u00e9s entre ces deux versions conduisant \u00e0 des erreurs de compilation lorsqu&rsquo;on emploie les fonctionnalit\u00e9s trait\u00e9es dans le second article de cette s\u00e9rie. En attendant l&rsquo;actualisation de Raspbian, je vous conseille de compiler la derni\u00e8re version stable comme suit.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>git clone https:\/\/git.kernel.org\/pub\/scm\/libs\/libgpiod\/libgpiod<\/strong><br>Cloning into 'libgpiod'\u2026<br>remote: Counting objects: 3909, done.<br>remote: Total 3909 (delta 0), reused 0 (delta 0)<br>Receiving objects: 100% (3909\/3909), 569.10 KiB | 0 bytes\/s, done.<br>Resolving deltas: 100% (2691\/2691), done.<br>$ <strong>cd libgpiod\/<\/strong><br>$ <strong>ls<\/strong><br>autogen.sh  bindings  configure.ac  COPYING  Doxyfile  include  libgpiod.pc.in  Makefile.am  NEWS  README  src  tests<br><\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>sudo apt install autoconf autoconf-archive libtool<\/strong><br>[...]<br> $ <strong>.\/autogen.sh --enable-tools=yes --prefix=\/usr<\/strong><br>autoreconf: Entering directory `.'<br>autoreconf: configure.ac: not using Gettext<br>autoreconf: running: aclocal --force -I m4<br>[...]<br>config.status: creating config.h<br>config.status: executing depfiles commands<br>config.status: executing libtool commands<br><br>$ <strong>make<\/strong><br>make  all-recursive<br>make[1]: Entering directory '\/home\/pi\/libgpiod'<br>Making all in include<br>[...]<br>make[2]: Entering directory '\/home\/pi\/libgpiod'<br>make[2]: Leaving directory '\/home\/pi\/libgpiod'<br>make[1]: Leaving directory '\/home\/pi\/libgpiod'<br> $ <strong>sudo make install<\/strong><br>Making install in include<br>make[1]: Entering directory '\/home\/pi\/libgpiod\/include'<br>make[2]: Entering directory '\/home\/pi\/libgpiod\/include'<br>make[2]: Nothing to be done for 'install-exec-am'.<br>[...]<br> \/usr\/bin\/install -c -m 644 libgpiod.pc '\/usr\/lib\/pkgconfig'<br>make[2]: Leaving directory '\/home\/pi\/libgpiod'<br>make[1]: Leaving directory '\/home\/pi\/libgpiod'<br>$<br><\/pre>\n\n\n\n<p>Nous pouvons v\u00e9rifier tout de suite la liste des nouveaux outils install\u00e9s en tapant <code>gpio<\/code> suivi de deux tabulations pour que le shell propose les compl\u00e9tions disponibles.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>gpio <em>[TAB]<\/em> <em>[TAB]<\/em><\/strong>\ngpio  gpiodetect  gpiofind  gpioget  gpioinfo  gpiomon  gpioset     <br>\n$<\/pre>\n\n\n\n<p>Hormis la commande <code>gpio<\/code> elle-m\u00eame qui est associ\u00e9e \u00e0 la biblioth\u00e8que <em>WiringPi<\/em> sp\u00e9cifique au Raspberry Pi, toutes les commande disponibles viennent d&rsquo;\u00eatre ajout\u00e9es. Nous allons les examiner l&rsquo;une apr\u00e8s l&rsquo;autre.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">gpiodetect<\/h3>\n\n\n\n<p>La commande <strong><code>gpiodetect<\/code><\/strong> affiche la liste des contr\u00f4leurs GPIO d\u00e9tect\u00e9s, et pour chacun d&rsquo;entre-eux le nom du driver associ\u00e9 et le nombre de lignes GPIO g\u00e9r\u00e9es.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>gpiodetect<\/strong><br>gpiochip0 [pinctrl-bcm2835] (54 lines)<br>gpiochip1 [brcmexp-gpio] (8 lines)<br>gpiochip2 [brcmvirt-gpio] (2 lines)<br>\n$ <\/pre>\n\n\n\n<p>Il s&rsquo;agit bien s\u00fbr de la m\u00eame liste que celle de <code>\/dev\/gpio*<\/code>. Ces informations \u00e9taient d\u00e9j\u00e0 accessibles dans l&rsquo;arborescence <code>\/sys\/<\/code> ainsi&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>cd \/sys\/class\/gpio\/<\/strong><br>\n$ <strong>for chip in gpiochip*; do echo $chip $(cat $chip\/label) $(cat $chip\/ngpio); done<\/strong><br>gpiochip0 pinctrl-bcm2835 54<br>gpiochip100 brcmvirt-gpio 2<br>gpiochip128 brcmexp-gpio 8<br><br>$ <\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">gpioinfo<\/h3>\n\n\n\n<p>La commande <strong><code>gpioinfo<\/code><\/strong> pr\u00e9sente l&rsquo;\u00e9tat des lignes GPIO du contr\u00f4leur demand\u00e9.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>gpioinfo gpiochip2<\/strong><br>gpiochip2 - 2 lines:<br>  line 0:  unnamed   \"led0\"  output  active-high [used]<br>  line 1:  unnamed   unused   input  active-high <br>\n$<\/pre>\n\n\n\n<p>Si on ne pr\u00e9cise aucun contr\u00f4leur sur sa ligne de commande, <code>gpioinfo<\/code> affiche les informations pour tous les contr\u00f4leurs.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>gpioinfo<\/strong><br>gpiochip0 - 54 lines:<br>line 0: unnamed unused input active-high <br>line 1: unnamed unused input active-high <br>line 2: unnamed unused input active-high <br>line 3: unnamed unused input active-high <br>line 4: unnamed unused input active-high <br>line 5: unnamed unused input active-high <br>line 6: unnamed unused input active-high <br>line 7: unnamed unused input active-high <br>line 8: unnamed unused input active-high <br>line 9: unnamed unused input active-high <br>line 10: unnamed unused input active-high <br>line 11: unnamed unused input active-high <br>line 12: unnamed unused input active-high <br>line 13: unnamed unused input active-high <br>line 14: unnamed unused input active-high <br>line 15: unnamed unused input active-high <br>line 16: unnamed unused input active-high <br>line 17: unnamed unused input active-high <br>line 18: unnamed unused input active-high <br>line 19: unnamed unused input active-high <br>line 20: unnamed unused input active-high <br>line 21: unnamed unused input active-high <br>line 22: unnamed unused input active-high <br>line 23: unnamed unused input active-high <br>line 24: unnamed unused input active-high <br>line 25: unnamed unused input active-high <br>line 26: unnamed unused input active-high <br>line 27: unnamed unused input active-high <br>line 28: unnamed unused input active-high <br>line 29: unnamed unused input active-high <br>line 30: unnamed unused input active-high <br>line 31: unnamed unused input active-high <br>line 32: unnamed unused input active-high <br>line 33: unnamed unused input active-high <br>line 34: unnamed unused input active-high <br>line 35: unnamed unused input active-high <br>line 36: unnamed unused input active-high <br>line 37: unnamed unused input active-high<br>line 38: unnamed unused input active-high<br>line 39: unnamed unused input active-high<br>line 40: unnamed unused input active-high<br>line 41: unnamed unused input active-high<br>line 42: unnamed unused input active-high<br>line 43: unnamed unused input active-high<br>line 44: unnamed unused input active-high<br>line 45: unnamed unused input active-high<br>line 46: unnamed unused input active-high<br>line 47: unnamed unused output active-high<br>line 48: unnamed unused input active-high<br>line 49: unnamed unused input active-high<br>line 50: unnamed unused input active-high<br>line 51: unnamed unused input active-high<br>line 52: unnamed unused input active-high<br>line 53: unnamed unused input active-high<br>gpiochip1 - 8 lines:<br>line 0: unnamed unused output active-high<br>line 1: unnamed unused output active-high<br>line 2: unnamed unused output active-high<br>line 3: unnamed unused output active-high<br>line 4: unnamed unused input active-high<br>line 5: unnamed unused output active-high<br>line 6: unnamed unused output active-high<br>line 7: unnamed \"led1\" input active-high [used]<br>gpiochip2 - 2 lines:<br>line 0: unnamed \"led0\" output active-high [used]<br>line 1: unnamed unused input active-high<br>$<br><\/pre>\n\n\n\n<p><br><\/p>\n\n\n\n<p>Les informations affich\u00e9es sont les suivantes.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><em>Offset<\/em> : le num\u00e9ro de la ligne GPIO pour le contr\u00f4leur. Dans la documentation de la plupart des <em>Systems-On-Chip<\/em>, les GPIO sont identifi\u00e9es par un couple <em>contr\u00f4leur<\/em>:<em>offset<\/em>. Par exemple <code>IO03:05<\/code> pour indiquer la sixi\u00e8me ligne (la num\u00e9rotation commence \u00e0 z\u00e9ro) du contr\u00f4leur 3. C&rsquo;est la valeur que l&rsquo;on obtient ici. <br>Pour le Raspberry Pi, nous avons eu l&rsquo;habitude jusqu&rsquo;ici d&rsquo;utiliser directement les offsets du premier contr\u00f4leur <code>gpiochip0<\/code>. Par exemple, la broche 16 du connecteur H1 du Raspberry Pi 3 est accessible par la GPIO <code>gpiochip0:23<\/code>.<\/li><li><em>Name<\/em> le nom attribu\u00e9 \u00e0 cette ligne GPIO. Ce nom est configurable dans le <em>device tree<\/em>. Nous en reparlerons plus loin.<\/li><li><em>Consumer<\/em> : le nom du driver ou du sous-syst\u00e8me qui a r\u00e9serv\u00e9 l&rsquo;acc\u00e8s \u00e0 cette ligne GPIO. Nous voyons par exemple \u00ab\u00a0<code>led1<\/code>\u00a0\u00bb et \u00ab\u00a0<code>led0<\/code>\u00a0\u00bb pour les lignes <code>gpiochip1:7<\/code> et <code>gpiochip2:0<\/code>.<br>Lorsqu&rsquo;une ligne est export\u00e9e dans l&rsquo;arborescence <code>\/sys<\/code>, la r\u00e9servation est faite au nom de <code>sysfs<\/code>.<\/li><li><em>Direction<\/em> : <code>input<\/code> ou <code>output<\/code> en fonction du sens d&rsquo;utilisation de la ligne GPIO. Au boot les <em>Systems-On-Chip<\/em> configurent la plupart de leurs lignes en entr\u00e9es.<br><\/li><li><em>Active state<\/em> : <code>active-high<\/code> ou <code>active-low<\/code> selon le type d&rsquo;activation de la ligne GPIO.<\/li><li>flags: une s\u00e9rie d&rsquo;attributs peuvent \u00eatre indiqu\u00e9es entre crochets&nbsp;:<ul><li><code>used<\/code> : la ligne GPIO est en cours d&rsquo;utilisation par un driver ou sous-syst\u00e8me du noyau.<\/li><li><code>open-drain<\/code> (collecteur ouvert)&nbsp;: la sortie de la GPIO est assur\u00e9e par un transistor simplement connect\u00e9 \u00e0 la masse. \u00c9crire un <code>1<\/code> sur la ligne GPIO la reliera \u00e0 la masse. \u00c9crire un <code>0<\/code>&nbsp; la laissera flottante. Il faut g\u00e9n\u00e9ralement ajouter une r\u00e9sistance de <em>pull-up<\/em>. Ceci est principalement utile lorsque plusieurs sorties doivent \u00eatre reli\u00e9es ensemble, comme dans le cas d&rsquo;un bus.<\/li><li><code>open-source<\/code> (emetteur ouvert): configuration inverse de la pr\u00e9c\u00e9dente, le collecteur du transistor de sortie est reli\u00e9 \u00e0 l&rsquo;alimentation (+3.3V par exemple) et l&rsquo;\u00e9metteur est flottant. On ajoute g\u00e9n\u00e9ralement une r\u00e9sistance de <em>pull-down.<\/em><em><\/em><\/li><\/ul><\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">gpioget<\/h3>\n\n\n\n<p>La commande <strong><code>gpioget<\/code><\/strong> sert \u00e0 lire l&rsquo;\u00e9tat d&rsquo;une broche GPIO. Nous allons l&rsquo;utiliser pour lire la valeur d&rsquo;entr\u00e9e de la broche num\u00e9ro 16, qui correspond \u00e0 la ligne 23 du contr\u00f4leur <code>gpiochip0<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"500\" src=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2018\/10\/IMG_20180928_071252_HDR.jpg\" alt=\"\" class=\"wp-image-5157\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2018\/10\/IMG_20180928_071252_HDR.jpg 800w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2018\/10\/IMG_20180928_071252_HDR-300x188.jpg 300w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2018\/10\/IMG_20180928_071252_HDR-768x480.jpg 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption>Lignes GPIO non connect\u00e9es<\/figcaption><\/figure><\/div>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>gpioget gpiochip0 23<\/strong><br>0<br>\n$ <\/pre>\n\n\n\n<p>L&rsquo;entr\u00e9e est libre et les broches du connecteur du Raspberry Pi disposent d&rsquo;une r\u00e9sistance de <em>pull-down<\/em>. Nous lisons donc une valeur nulle.<\/p>\n\n\n\n<p>Relions \u00e0 pr\u00e9sent cette entr\u00e9e et la broche num\u00e9ro 1 (+3.3V).<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"500\" src=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2018\/10\/IMG_20180928_071101_HDR.jpg\" alt=\"\" class=\"wp-image-5158\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2018\/10\/IMG_20180928_071101_HDR.jpg 800w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2018\/10\/IMG_20180928_071101_HDR-300x188.jpg 300w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2018\/10\/IMG_20180928_071101_HDR-768x480.jpg 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption>Ligne GPIO 16 reli\u00e9e \u00e0 Vcc<\/figcaption><\/figure>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>gpioget gpiochip0 23<\/strong><br>1<br><br>$<\/pre>\n\n\n\n<p>Nous pouvons donc lire facilement la valeur d&rsquo;entr\u00e9e. Notez qu&rsquo;il est possible de lire plusieurs entr\u00e9es en une seule fois. Ce qui est plus simple qu&rsquo;avec l&rsquo;interface <code>\/sys\/class\/gpio<\/code>.<br><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>gpioget gpiochip0 23 22 21 20<\/strong>\n  1 0 0 0<br>\n  $<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">gpioset<\/h3>\n\n\n\n<p>Tout naturellement, la commande <strong><code>gpioset<\/code><\/strong> sert \u00e0 fixer une valeur de sortie sur une ligne GPIO. Toutefois son comportement est un peu surprenant a priori.<\/p>\n\n\n\n<p>L&rsquo;un des principaux reproches que l&rsquo;on faisait \u00e0 l&rsquo;API reposant sur <em>sysfs<\/em> \u00e9tait que l&rsquo;acc\u00e8s \u00e0 une GPIO n&rsquo;\u00e9tait pas associ\u00e9 \u00e0 un processus. Une fois qu&rsquo;une valeur \u00e9tait inscrite dans <code>\/sys\/class\/gpio\/gpio23\/value<\/code> elle restait inscrite sur la broche correspondante (16 en l&rsquo;occurrence) m\u00eame si l&rsquo;application qui g\u00e9rait les entr\u00e9es-sorties \u00e9tait finie depuis longtemps.<\/p>\n\n\n\n<p>L&rsquo;id\u00e9e avec la nouvelle API est qu&rsquo;\u00e0 la fin du processus ayant ouvert une GPIO (fin volontaire sur <code>exit()<\/code> ou crash involontaire par signal), la ligne GPIO soit automatiquement lib\u00e9r\u00e9e. Suivant la configuration du contr\u00f4leurs GPIO elle pourra alors reprendre imm\u00e9diatement un \u00e9tat de haute imp\u00e9dance par mesure de pr\u00e9caution.<\/p>\n\n\n\n<p>La commande <code>gpioset<\/code> propose donc plusieurs modes de fonctionnement&nbsp;:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><em>exit<\/em> : comportement par d\u00e9faut, o\u00f9 sit\u00f4t la sortie configur\u00e9e la commande se termine et lib\u00e8re la GPIO. Il s&rsquo;agit donc d&rsquo;un mode utilis\u00e9 pour g\u00e9n\u00e9rer des impulsions sur une ligne de sortie.<br><\/li><li><em>wait<\/em> : apr\u00e8s activation de la GPIO de sortie, la commande attend un retour chariot sur son entr\u00e9e standard. Ce mode est utile pour un pilotage interactif depuis la ligne de commande.<\/li><li><em>time<\/em> : la commande <code>gpioset<\/code> attend avant de se terminer une dur\u00e9e que l&rsquo;on pr\u00e9cise avec ses options <code>-s<\/code> suivie d&rsquo;une dur\u00e9e en seconde ou <code>-u<\/code> suvie d&rsquo;une dur\u00e9e en microsecondes. Il est possible d&rsquo;ajouter une option <code>-b<\/code> (pour <em>background<\/em>) afin que l&rsquo;attente se fasse \u00e0 l&rsquo;arri\u00e8re-plan.<\/li><li><em>signal<\/em> : une fois la GPIO configur\u00e9e la commande attend de recevoir un signal <code>SIGINT<\/code> (que le terminal envoie lors d&rsquo;une pression sur <em>Contr\u00f4le-C<\/em>) ou <code>SIGTERM<\/code> (signal envoy\u00e9 par d\u00e9faut par la commande <code>kill<\/code>). Comme pour le mode <em>time<\/em>, l&rsquo;ajout de l&rsquo;option <code>-b<\/code> permet de laisser la commande en attente \u00e0 l&rsquo;arri\u00e8re-plan. C&rsquo;est le mode le plus utile pour les scripts.<\/li><\/ul>\n\n\n\n<p>&nbsp;&nbsp; <\/p>\n\n\n\n<p>Je relie la broche 16 du Raspberry Pi (ligne 23 du contr\u00f4leur <code>gpiochip0<\/code>) et la broche 15 (ligne 22 du m\u00eame contr\u00f4leur). Je vais \u00e9crire un signal sur la sortie 22, et profiter du d\u00e9lai de cinq secondes o\u00f9 la commande sera \u00e0 l&rsquo;arri\u00e8re-plan pour consulter l&rsquo;entr\u00e9e 23.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"500\" src=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2018\/10\/IMG_20180928_071207_HDR.jpg\" alt=\"\" class=\"wp-image-5159\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2018\/10\/IMG_20180928_071207_HDR.jpg 800w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2018\/10\/IMG_20180928_071207_HDR-300x188.jpg 300w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2018\/10\/IMG_20180928_071207_HDR-768x480.jpg 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption>Ligne GPIO 16 reli\u00e9e \u00e0 la ligne 15<\/figcaption><\/figure>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>gpioget gpiochip0 23<\/strong><br>0<br>\n$ <strong>gpioset -m time -s 5 -b gpiochip0 22=1<\/strong><br>$ <strong>gpioget gpiochip0 23<\/strong><br>1<br>    (attente cinq secondes)<br>\n$ <strong>gpioget gpiochip0 23<\/strong><br>0<br>\n$<\/pre>\n\n\n\n<p>Dans ce second essai, je vais laisser la commande en attente d&rsquo;un signal. Pour conna\u00eetre son PID et lui envoyer ult\u00e9rieurement un signal, je vais consulter la variable <code>$!<\/code> du shell qui contient le PID du dernier processus envoy\u00e9 \u00e0 l&rsquo;arri\u00e8re-plan par le shell. C&rsquo;est pour cette raison que je vais utiliser le <code>&amp;<\/code> du shell et non pas l&rsquo;option <code>-b<\/code> de <code>gpioset<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>gpioset -m signal gpiochip0 22=1 &amp;<\/strong><br><br>$ <strong>PID=$!<\/strong><br>$ <strong>gpioget gpiochip0 23<\/strong><br>1<br><br>$ <strong>kill $PID<\/strong><br><br>$ <strong>gpioget gpiochip0 23<\/strong><br>0<br><br>$<\/pre>\n\n\n\n<p>J&rsquo;ai l\u00e9g\u00e8rement \u00e9dit\u00e9 la capture d&rsquo;\u00e9cran pour supprimer les messages parasites du shell lorsqu&rsquo;il envoie un processus \u00e0 l&rsquo;arri\u00e8re-plan ou que ce dernier se termine.<\/p>\n\n\n\n<p>On notera \u00e9galement que <code>gpioset<\/code> permet de configurer la sortie en mode <em>active-low<\/em> avec son option <code>-l<\/code> ainsi l&rsquo;\u00e9criture d&rsquo;un <code>0<\/code> activera la sortie (qui passera \u00e0 +3.3V) et un <code>1<\/code> la ram\u00e8nera \u00e0 la masse.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">gpiomon<\/h3>\n\n\n\n<p>La commande <strong><code>gpiomon<\/code><\/strong> permet de r\u00e9aliser un travail qui n&rsquo;\u00e9tait pas possible directement depuis la ligne de commande avec l&rsquo;API reposant sur <em>sysfs<\/em> mais n\u00e9cessitait d&rsquo;\u00e9crire un programme sp\u00e9cifique (comme je l&rsquo;avais fait dans l&rsquo;article \u00ab\u00a0<a href=\"https:\/\/www.blaess.fr\/christophe\/2013\/04\/15\/attentes-passives-sur-gpio\/\" target=\"_blank\">Attente passive sur une GPIO<\/a>\u00ab\u00a0).<\/p>\n\n\n\n<p>Il s&rsquo;agit de monitorer les \u00e9v\u00e9nements se passant sur une ou plusieurs broches d&rsquo;entr\u00e9e, d&rsquo;afficher ou d&rsquo;attendre l&rsquo;arriv\u00e9e d&rsquo;un front montant ou descendant. Par d\u00e9faut, <code>gpiomon<\/code> affiche les \u00e9v\u00e9nements au fur et \u00e0 mesure qu&rsquo;ils se produisent (avec un format configurable). Il est possible d&rsquo;utiliser son option <code>-n<\/code> suivi d&rsquo;un nombre d&rsquo;occurrences pour demander que la commande se termine une fois le nombre d&rsquo;\u00e9v\u00e9nements survenus.<\/p>\n\n\n\n<p>Par d\u00e9faut, les \u00e9v\u00e9nements sont des changements d&rsquo;\u00e9tat de la ligne d&rsquo;entr\u00e9e. Il est possible d&rsquo;utiliser l&rsquo;option <code>-r<\/code> (pour <em>rising<\/em>) afin de ne consid\u00e9rer que les transitions montantes (0 vers 1) ou l&rsquo;option <code>-f<\/code> (pour <em>falling<\/em>) pour ne conserver que les transitions descendantes.<\/p>\n\n\n\n<p>Dans l&rsquo;exemple suivant, je vais invoquer <code>gpioset<\/code> pour qu&rsquo;il active la sortie sur la ligne GPIO 22 (broche 15) pendant cinq secondes puis se termine. La broche 15 est reli\u00e9e \u00e0 la broche 16 comme pr\u00e9c\u00e9demment. J&rsquo;invoque <code>gpiomon<\/code> pour qu&rsquo;il attende la transition descendante quand la premi\u00e8re commande se terminera.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>gpioset -m time -s 5 -b  gpiochip0 22=1<\/strong><br>\n$ <strong>gpiomon  -f -n 1 gpiochip0 23<\/strong>\n    (Cinq secondes s'\u00e9coulent)\nevent: FALLING EDGE offset: 23 timestamp: [1538116251.893018202]<br>\n$ <\/pre>\n\n\n\n<p>Dans ce second exemple, je laisse la commande <code>gpiomon<\/code> afficher les \u00e9v\u00e9nements observ\u00e9s sur la ligne GPIO 23 tandis que, depuis un autre terminal, je fais basculer la ligne GPIO 22 reli\u00e9e \u00e0 la pr\u00e9c\u00e9dente.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[1]$ <strong>gpiomon gpiochip0 23<\/strong><br>&nbsp;&nbsp;&nbsp;&nbsp; [2]$ <strong>for i in $(seq 1 10); do gpioset -m time -s 1 gpiochip0 22=1; done<\/strong><br>event: RISING EDGE offset: 23 timestamp: [1538119622.397979178]<br>event: FALLING EDGE offset: 23 timestamp: [1538119623.399084866]<br>event: RISING EDGE offset: 23 timestamp: [1538119623.406256964]<br>event: FALLING EDGE offset: 23 timestamp: [1538119624.407333330]<br>event: RISING EDGE offset: 23 timestamp: [1538119624.414514282]<br>event: FALLING EDGE offset: 23 timestamp: [1538119625.415573773]<br>event: RISING EDGE offset: 23 timestamp: [1538119625.422415612]<br>event: FALLING EDGE offset: 23 timestamp: [1538119626.423968121]<br>event: RISING EDGE offset: 23 timestamp: [1538119626.431198291]<br>event: FALLING EDGE offset: 23 timestamp: [1538119627.432301011]<br>event: RISING EDGE offset: 23 timestamp: [1538119627.439238110]<br>event: FALLING EDGE offset: 23 timestamp: [1538119628.440283122]<br>event: RISING EDGE offset: 23 timestamp: [1538119628.447077045]<br>event: FALLING EDGE offset: 23 timestamp: [1538119629.448084557]<br>event: RISING EDGE offset: 23 timestamp: [1538119629.455423946]<br>event: FALLING EDGE offset: 23 timestamp: [1538119630.456473697]<br>event: RISING EDGE offset: 23 timestamp: [1538119630.463395900]<br>event: FALLING EDGE offset: 23 timestamp: [1538119631.464926222]<br>event: RISING EDGE offset: 23 timestamp: [1538119631.472085872]<br>event: FALLING EDGE offset: 23 timestamp: [1538119632.473167915]<br><em>(Contr\u00f4le-C)<\/em><br>$<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">gpiofind<\/h3>\n\n\n\n<p>Dans l&rsquo;exemple d&rsquo;utilisation de la commande <code>gpioinfo<\/code>, nous avons pu voir que la colonne des noms des lignes GPIO est remplie de <em>unnamed<\/em>. Ces noms doivent \u00eatre attribu\u00e9s dans le <em>device tree<\/em> mais il n&rsquo;y en a pas dans celui livr\u00e9 avec la distribution Raspbian. Je me suis amus\u00e9 \u00e0 remplir les noms des lignes GPIO qui apparaissent sur le connecteur H1. Apr\u00e8s avoir recompil\u00e9 mon <em>device tree<\/em> et avoir reboot\u00e9, j&rsquo;obtiens la liste suivante.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>gpioinfo<\/strong><br>  gpiochip0 - 54 lines:<br>    line   0:    unnamed     unused   input  active-high<br>    line   1:    unnamed     unused   input  active-high<br>    line   2:  \"PIN-#03\"     unused   input  active-high<br>    line   3:  \"PIN-#05\"     unused   input  active-high<br>    line   4:  \"PIN-#07\"     unused   input  active-high<br>    line   5:  \"PIN-#29\"     unused   input  active-high<br>    line   6:  \"PIN-#31\"     unused   input  active-high<br>    line   7:  \"PIN-#26\"     unused   input  active-high<br>    line   8:  \"PIN-#24\"     unused   input  active-high<br>    line   9:  \"PIN-#21\"     unused   input  active-high<br>    line  10:  \"PIN-#19\"     unused   input  active-high<br>    line  11:  \"PIN-#23\"     unused   input  active-high<br>    line  12:  \"PIN-#32\"     unused   input  active-high<br>    line  13:  \"PIN-#33\"     unused   input  active-high<br>    line  14:  \"PIN-#08\"     unused   input  active-high<br>    line  15:  \"PIN-#10\"     unused   input  active-high<br>    line  16:  \"PIN-#36\"     unused   input  active-high<br>    line  17:  \"PIN-#11\"     unused   input  active-high<br>    line  18:  \"PIN-#12\"     unused   input  active-high<br>    line  19:  \"PIN-#35\"     unused   input  active-high<br>    line  20:  \"PIN-#38\"     unused   input  active-high<br>    line  21:  \"PIN-#40\"     unused   input  active-high<br>    line  22:  \"PIN-#15\"     unused   input  active-high<br>    line  23:  \"PIN-#16\"     unused   input  active-high<br>    line  24:  \"PIN-#18\"     unused   input  active-high<br>    line  25:  \"PIN-#22\"     unused   input  active-high<br>    line  26:  \"PIN-#37\"     unused   input  active-high<br>    line  27:  \"PIN-#13\"     unused   input  active-high<br>    line  28:    unnamed     unused   input  active-high<br>    line  29:    unnamed     unused   input  active-high<br>    line  30:    unnamed     unused   input  active-high<br>    [\u2026]<br>   <\/pre>\n\n\n\n<p style=\"color:#606060;font-size:12px;text-align:right\" class=\"has-text-color\">En r\u00e9alit\u00e9 un bug dans le kernel que j&rsquo;utilisais emp\u00eachait d&rsquo;avoir une liste partielle de lignes GPIO nomm\u00e9es. La correction est dans la branche <em>linux-next<\/em> et devrait appara\u00eetre dans le noyau 4.20 (ou 5.0 si la logique de changement de num\u00e9ro majeur est la m\u00eame que pour le passage de la branche 3.x \u00e0 la branche 4.x).<\/p>\n\n\n\n<p>J&rsquo;ai laiss\u00e9 les broches non apparentes sur le connecteur H1 non nomm\u00e9es. La commande <strong><code>gpiofind<\/code><\/strong> permet de rechercher le num\u00e9ro de contr\u00f4leur et le num\u00e9ro de ligne GPIO en indiquant son nom.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>gpiofind PIN-#16<\/strong><br>gpiochip0 23<br>\n$ <strong>gpiofind PIN-#15<\/strong><br>gpiochip0 22<br>\n$ <strong>gpiofind PIN-#00<\/strong><br>\n$<\/pre>\n\n\n\n<p>Comme on le voit, la recherche d&rsquo;un nom inexistant \u00e9choue sans afficher d&rsquo;erreur. N\u00e9anmoins le code de retour de la commande est z\u00e9ro si elle r\u00e9ussit \u00e0 trouver une ligne GPIO et <code>1<\/code> sinon.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>gpiofind PIN-#16<\/strong><br>gpiochip0 23<br>\n$ <strong>echo $?<\/strong><br>0<br>\n$ <strong>gpiofind PIN-#00<\/strong><br>\n$ <strong>echo $?<\/strong><br>1<br>\n$<\/pre>\n\n\n\n<p>Notez que l&rsquo;on peut imbriquer cette commande dans l&rsquo;invocation de <code>gpioget<\/code> ou <code>gpioset<\/code>, en prenant la pr\u00e9caution de v\u00e9rifier sa valeur de retour.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>LINE=$(gpiofind \"PIN-#16\")<\/strong><br><br>$ <strong>if [ $? -eq 0 ]; then VALUE=$(gpioget $LINE); else VALUE=-1; fi<\/strong><br><br>$ <strong>echo $VALUE<\/strong><br>0<br><br>$<\/pre>\n\n\n\n<p>La m\u00eame op\u00e9ration avec un nom inexistant donne&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ <strong>LINE=$(gpiofind \"PIN-#00\")<\/strong><br>\n$ <strong>if [ $? -eq 0 ]; then VALUE=$(gpioget $LINE); else VALUE=-1; fi<\/strong>&gt;<br>\n$ <strong>echo $VALUE<\/strong><br>-1<br>\n$<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Nous voyons dans ce premier article que ces nouvelles commandes permettent de piloter efficacement et ais\u00e9ment les GPIO depuis le shell. Dans <a href=\"https:\/\/www.blaess.fr\/christophe\/2018\/10\/22\/pilotage-de-gpio-avec-lapi-libgpiod-partie-2\/\">le prochain article<\/a> je pr\u00e9senterai l&rsquo;acc\u00e8s depuis un programme C.<\/p>","protected":false},"excerpt":{"rendered":"<p>J&rsquo;ai assist&eacute; il y a quelques jours, lors de l&rsquo;&eacute;dition 2018 des Kernel Recipes &agrave; une pr&eacute;sentation par Bartosz Golaszewski&nbsp; de la nouvelle interface des GPIO pour l&rsquo;espace utilisateur de Linux. J&rsquo;en avais eu un bref aper&ccedil;u il y a quelques mois mais je n&rsquo;avais pas encore pris le temps d&rsquo;essayer cette API. Cet article [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,19,8,11],"tags":[],"class_list":["post-5144","post","type-post","status-publish","format-standard","hentry","category-embarque","category-kernel","category-linux-2","category-raspberry-pi"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/5144","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/comments?post=5144"}],"version-history":[{"count":28,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/5144\/revisions"}],"predecessor-version":[{"id":5472,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/5144\/revisions\/5472"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=5144"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=5144"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=5144"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}