{"id":2173,"date":"2012-05-14T06:19:39","date_gmt":"2012-05-14T05:19:39","guid":{"rendered":"http:\/\/www.blaess.fr\/christophe\/?p=2173"},"modified":"2012-05-14T06:19:39","modified_gmt":"2012-05-14T05:19:39","slug":"gpio-pandaboard-et-temps-reel-2-sorties-depuis-lespace-kernel","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2012\/05\/14\/gpio-pandaboard-et-temps-reel-2-sorties-depuis-lespace-kernel\/","title":{"rendered":"GPIO, Pandaboard et temps r\u00e9el &#8211; 2 &#8211; sorties depuis l&rsquo;espace kernel"},"content":{"rendered":"<p style=\"text-align: justify;\"><a href=\"http:\/\/www.blaess.fr\/christophe\/2012\/05\/14\/gpio-pandaboard-et-temps-reel-2-sorties-depuis-lespace-kernel\/\"><img loading=\"lazy\" decoding=\"async\" class=\"alignright size-medium wp-image-2445\" title=\"GPIO Pandaboard et temps-r\u00e9el\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-01.jpg\" alt=\"GPIO Pandaboard et temps-r\u00e9el\" width=\"150\" height=\"201\" \/><\/a>Nous avons observ\u00e9 dans <a title=\"GPIO, Pandaboard et temps r\u00e9el \u2013 1 \u2013 Sorties depuis l\u2019espace utilisateur\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/05\/09\/gpio-pandaboard-temps-reel-1\/\">l&rsquo;article pr\u00e9c\u00e9dent<\/a> comment programmer et commander depuis l&rsquo;espace utilisateur les <em>GPIO<\/em>. Il s&rsquo;agit, nous l&rsquo;avons vu, de broches du microprocesseur que nous pouvons affecter au choix en entr\u00e9e ou en sortie et sur lesquelles il est possible de lire ou d&rsquo;\u00e9crire des valeurs \u00e9lectriques.<\/p>\n<p>\n<!--more-->\n<\/p>\n<p style=\"text-align: justify;\">Nous avons utilis\u00e9 l&rsquo;interface offerte par le noyau \u00e0 travers le pseudo-syst\u00e8me de fichiers <code>\/sys<\/code> pour \u00e9crire un oscillateur s&rsquo;ex\u00e9cutant dans l&rsquo;espace utilisateur. Nos premiers essais r\u00e9alis\u00e9s avec un script shell souffrait d&rsquo;une granularit\u00e9 excessive (plusieurs millisecondes) dans la gestion du temps. Un programme en C offrait une bien meilleure r\u00e9solution (de l&rsquo;ordre de la centaine de microsecondes). Ordonnanc\u00e9 en temps partag\u00e9 les fluctuations \u00e9taient parfois tr\u00e8s importantes (plusieurs millisecondes au pire). En utilisant l&rsquo;ordonnancement temps r\u00e9el souple de Linux, les fluctuations \u00e9taient beaucoup plus limit\u00e9es.<\/p>\n<p style=\"text-align: justify;\">Nous allons \u00e0 pr\u00e9sent r\u00e9aliser les m\u00eames op\u00e9rations depuis l&rsquo;espace kernel, en \u00e9crivant d&rsquo;abord des modules pour le noyau Linux standard puis en nous int\u00e9ressant \u00e0 un module pour Xenomai.<\/p>\n<h1>Timer du noyau Linux vanilla<\/h1>\n<p style=\"text-align: justify;\">Le noyau Linux classique nous offre une interface simple pour programmer des actions diff\u00e9r\u00e9es, et \u00e9ventuellement r\u00e9p\u00e9titives, les structures <code>timer_list<\/code>. Notre premier exemple est construit autour de ces structures. Il programme l&rsquo;ex\u00e9cution p\u00e9riodique d&rsquo;une fonction toutes les millisecondes. Cette fonction basculera une sortie GPIO comme nous l&rsquo;avons fait dans l&rsquo;article pr\u00e9c\u00e9dent, mais en s&rsquo;appuyant sur l&rsquo;API kernel <code>&lt;linux\/gpio.h&gt;<\/code>.<\/p>\n<pre><strong><a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-05-14\/oscillateur-gpio-timer.c\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-05-14\/oscillateur-gpio-timer.c\" target=\"_blank\">oscillateur-gpio-timer.c :<\/a> <\/strong>\n#include &lt;linux\/cdev.h&gt;\n#include &lt;linux\/device.h&gt;\n#include &lt;linux\/fs.h&gt;\n#include &lt;linux\/gpio.h&gt;\n#include &lt;linux\/module.h&gt;\n#include &lt;linux\/sched.h&gt;\n#include &lt;linux\/version.h&gt;\n#include &lt;asm\/uaccess.h&gt;\n\nstatic void timer_oscillateur(unsigned long);\nstatic <strong>struct timer_list<\/strong> timer;\n\n\/\/ 138 Broche 10 du port J3 (Expansion A) de la Pandaboard\n#define GPIO_OSCILLATEUR 138\n\nstatic int __init init_oscillateur (void)\n{\n  int err;\n\n  if ((err = <strong>gpio_request<\/strong>(GPIO_OSCILLATEUR, THIS_MODULE-&gt;name)) != 0) {\n    return err;\n  }\n  if ((err = <strong>gpio_direction_output<\/strong>(GPIO_OSCILLATEUR, 1)) != 0) {\n    gpio_free(GPIO_OSCILLATEUR);\n    return err;\n  }\n  <strong>init_timer<\/strong> (&amp; timer);\n  <strong>timer.function<\/strong> = timer_oscillateur;\n  timer.data = 0;\n  <strong>timer.expires<\/strong> = jiffies + HZ\/1000;\n  <strong>add_timer<\/strong>(&amp; timer);\n\n  return 0;\n}\n\nstatic void __exit exit_oscillateur (void)\n{\n  <strong>del_timer<\/strong>(&amp; timer);\n  <strong>gpio_free<\/strong>(GPIO_OSCILLATEUR);\n}\n\nstatic void timer_oscillateur(unsigned long unused)\n{\n  static int value = 0;\n  <strong>gpio_set_value<\/strong>(GPIO_OSCILLATEUR, value);\n  value = 1 - value;\n  mod_timer(&amp; timer, jiffies + HZ\/1000);\n}\n\nmodule_init(init_oscillateur);\nmodule_exit(exit_oscillateur);\nMODULE_LICENSE(\"GPL\");<\/pre>\n<p style=\"text-align: justify;\">Comme nous le voyons, la dur\u00e9e de ces timers s&rsquo;expriment en <em>jiffies<\/em>, en <em>ticks<\/em> syst\u00e8me, dont la fr\u00e9quence est contenue dans la constante symbolique <code>HZ<\/code>. IL y a <code>HZ<\/code> ticks par seconde. En programmant un d\u00e9clenchement dans <code>HZ\/1000<\/code> ticks, on diff\u00e8re donc l&rsquo;action d&rsquo;une milliseconde.<\/p>\n<p><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-13.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2181\" title=\"Connecteur d'extension de la Pandaboard\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-13.jpg\" alt=\"Connecteur d'extension de la Pandaboard\" width=\"600\" height=\"407\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Pour compiler ce code (et les modules suivants), il va falloir utiliser un fichier <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-05-14\/Makefile\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-05-14\/Makefile\" target=\"_blank\"><code>Makefile<\/code><\/a> sp\u00e9cifique. Lors de l&rsquo;invocation de la commande <code>make<\/code>, nous devrons indiquer:<\/p>\n<ul>\n<li style=\"text-align: justify;\"><code><strong>ARCH<\/strong>=arm<\/code> pour la Pandaboard<\/li>\n<li style=\"text-align: justify;\"><code><strong>CROSS_COMPILE<\/strong>=<\/code> suivi du pr\u00e9fixe \u00e0 employer pour utiliser la cha\u00eene de compilation crois\u00e9e<\/li>\n<li style=\"text-align: justify;\"><code><strong>KERNEL_DIR<\/strong><\/code>= suivi du chemin d&rsquo;acc\u00e8s au r\u00e9pertoire contenant les sources du noyau de la Pandaboard<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">\u00c0 titre d&rsquo;exemple, sur mon poste l&rsquo;invocation de <code>make<\/code> se fait ainsi:<\/p>\n<pre>$ <strong>make ARCH=arm CROSS_COMPILE=~\/cross-panda\/usr\/bin\/arm-linux- KERNEL_DIR=~\/Projets\/Panda\/linux-2.6.38.8<\/strong>\nmake -C \/home\/cpb\/Projets\/Panda\/linux-2.6.38.8 SUBDIRS=\/home\/cpb\/Documents\/Livres\/Articles\/Blog\/article-2012-05-14  modules\nmake[1]: entrant dans le r\u00e9pertoire \u00ab \/home\/cpb\/Projets\/Panda\/linux-2.6.38.8 \u00bb\n  CC [M]  \/home\/cpb\/Documents\/Articles\/Blog\/article-2012-05-14\/oscillateur-gpio-timer.o\n  CC [M]  \/home\/cpb\/Documents\/Articles\/Blog\/article-2012-05-14\/oscillateur-gpio-hrtimer.o\n  CC [M]  \/home\/cpb\/Documents\/Articles\/Blog\/article-2012-05-14\/oscillateur-gpio-rtdm.o\n  Building modules, stage 2.\n  MODPOST 3 modules\n  CC      \/home\/cpb\/Documents\/Articles\/Blog\/article-2012-05-14\/oscillateur-gpio-hrtimer.mod.o\n  LD [M]  \/home\/cpb\/Documents\/Articles\/Blog\/article-2012-05-14\/oscillateur-gpio-hrtimer.ko\n  CC      \/home\/cpb\/Documents\/Articles\/Blog\/article-2012-05-14\/oscillateur-gpio-rtdm.mod.o\n  LD [M]  \/home\/cpb\/Documents\/Articles\/Blog\/article-2012-05-14\/oscillateur-gpio-rtdm.ko\n  CC      \/home\/cpb\/Documents\/Articles\/Blog\/article-2012-05-14\/oscillateur-gpio-timer.mod.o\n  LD [M]  \/home\/cpb\/Documents\/Articles\/Blog\/article-2012-05-14\/oscillateur-gpio-timer.ko\nmake[1]: quittant le r\u00e9pertoire \u00ab \/home\/cpb\/Projets\/Panda\/linux-2.6.38.8 \u00bb\n$<\/pre>\n<p style=\"text-align: justify;\">Il faut ensuite transf\u00e9rer le code sur la cible, s&rsquo;y connecter et charger le module.<\/p>\n<pre>$ <strong>scp oscillateur-gpio-timer.ko root@192.168.5.152:\/root<\/strong>\nroot@192.168.5.152's password:\noscillateur-gpio-timer.ko                                          100%   92KB  92.4KB\/s   00:00\n$ <strong>ssh root@192.168.5.152<\/strong>\nroot@192.168.5.152's password:\n[Panda]# <strong>\/sbin\/insmod \/root\/oscillateur-gpio-timer.ko <\/strong>\n[Panda]#<\/pre>\n<p style=\"text-align: justify;\">Sur l&rsquo;oscilloscope, nous voyons bien un signal carr\u00e9 sur la broche 10 du connecteur d&rsquo;extension de la Pandaboard.<\/p>\n<p><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-14.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2182\" title=\"Oscillateur kernel avec API timer\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-14.jpg\" alt=\"Oscillateur kernel avec API timer\" width=\"600\" height=\"444\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Pourtant ce signal est plut\u00f4t d\u00e9cevant. Nous avons demand\u00e9 au noyau d&rsquo;invoquer notre routine qui bascule l&rsquo;\u00e9tat de la sortie toutes les millisecondes, et nous observons que les fronts successifs du signal sont espac\u00e9s d&rsquo;un peu moins de 4 carreaux, ce qui correspond \u00e0 8 millisecondes (r\u00e9glage <em>Sweep<\/em> sur 2ms\/division).<\/p>\n<p style=\"text-align: justify;\">Ceci s&rsquo;explique par le fait que l&rsquo;API <em>timer<\/em> du noyau s&rsquo;appuie sur des ticks syst\u00e8me. Or nous ne connaissons pas leur dur\u00e9e. Mais la constante symbolique <code>HZ<\/code> doit nous renseigner. Elle est configur\u00e9e lors de la pr\u00e9paration de la compilation du noyau et se trouve donc dans fichier <code>.config<\/code> associ\u00e9. Par habitude, j&rsquo;active toujours les options \u00ab\u00a0<em>Kernel .config support<\/em>\u00a0\u00bb et \u00ab\u00a0<em>Enable access to .config through \/proc\/config.gz<\/em>\u00a0\u00bb (menu <em>General setup<\/em>) des noyaux que je compile afin d&#8217;embarquer une copie du fichier de configuration sur la cible.<\/p>\n<pre>[Panda]# <strong>zcat config.gz | grep CONFIG_HZ<\/strong>\nCONFIG_HZ=128\n[Panda]#<\/pre>\n<p style=\"text-align: justify;\">Le tick du syst\u00e8me est donc de 1\/128 secondes, ce qui correspond \u00e0 7,81 millisecondes. Le noyau ne peut pas nous fournir de timer de r\u00e9solution plus fine avec cette configuration.<\/p>\n<p style=\"text-align: justify;\">Retirons notre module du kernel et essayons d&rsquo;am\u00e9liorer le fonctionnement.<\/p>\n<pre>[Panda]# <strong>\/sbin\/rmmod \/root\/oscillateur-gpio-timer.ko <\/strong>\n[Panda]#<\/pre>\n<h1>Les timers de haute pr\u00e9cision du noyau Linux<\/h1>\n<p style=\"text-align: justify;\">Heureusement des timers de meilleure pr\u00e9cision sont disponibles sous Linux. Ils ont \u00e9t\u00e9 d\u00e9velopp\u00e9s par Thomas Gleixner et Ingo Molnar dans le cadre de <em>Linux-rt<\/em> puis int\u00e9gr\u00e9s dans le noyau standard aux alentours de la version 2.6.26. Il s&rsquo;agit de l&rsquo;API <code>&lt;hrtimer.h&gt;<\/code> utilisable si l&rsquo;option \u00ab\u00a0<em>High Resolution Timer Support<\/em>\u00a0\u00bb du menu \u00ab\u00a0<em>Kernel Features<\/em>\u00a0\u00bb a \u00e9t\u00e9 activ\u00e9e lors de la compilation du kernel.<\/p>\n<p style=\"text-align: justify;\">Cette fois la d\u00e9finition des dur\u00e9es se fait en nanosecondes (ce qui ne signifie \u00e9videmment pas que le noyau soit capable de respecter la pr\u00e9cision de la nanoseconde). En voici un petit exemple, o\u00f9 la p\u00e9riode peut \u00eatre pr\u00e9cis\u00e9e au chargement du module (en microsecondes pour conserver une meilleure lisibilit\u00e9).<\/p>\n<pre><a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-05-14\/oscillateur-gpio-hrtimer.c\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-05-14\/oscillateur-gpio-hrtimer.c\" target=\"_blank\"><strong>oscillateur-gpio-hrtimer.c :<\/strong><\/a>\n#include &lt;linux\/cdev.h&gt;\n#include &lt;linux\/device.h&gt;\n#include &lt;linux\/fs.h&gt;\n#include &lt;linux\/hrtimer.h&gt;\n#include &lt;linux\/gpio.h&gt;\n#include &lt;linux\/ktime.h&gt;\n#include &lt;linux\/module.h&gt;\n#include &lt;linux\/sched.h&gt;\n#include &lt;linux\/version.h&gt;\n#include &lt;asm\/uaccess.h&gt;\n\nstatic enum hrtimer_restart timer_oscillateur(struct hrtimer *);\nstatic <strong>struct hrtimer<\/strong> htimer;\n\nstatic int periode_us = 1000;\nmodule_param(periode_us, int, 0644);\nstatic <strong>ktime_t<\/strong> kt_periode;\n\n\/\/ 138 Broche 10 du port J3 (Expansion A) de la Pandaboard\n#define GPIO_OSCILLATEUR 138\n\nstatic int __init init_oscillateur (void)\n{\n  int err;\n\n  kt_periode = <strong>ktime_set<\/strong>(0, 1000 * periode_us);\n\n  if ((err = gpio_request(GPIO_OSCILLATEUR, THIS_MODULE-&gt;name)) != 0) {\n    return err;\n  }\n  if ((err = gpio_direction_output(GPIO_OSCILLATEUR, 1)) != 0) {\n    gpio_free(GPIO_OSCILLATEUR);\n    return err;\n  }\n  <strong>hrtimer_init<\/strong> (&amp; htimer, CLOCK_REALTIME, HRTIMER_MODE_REL);\n  <strong>htimer.function<\/strong> = timer_oscillateur;\n  <strong>hrtimer_start<\/strong>(&amp; htimer, kt_periode, HRTIMER_MODE_REL);\n\n  return 0;\n}\n\nstatic void __exit exit_oscillateur (void)\n{\n  <strong>hrtimer_cancel<\/strong>(&amp; htimer);\n  gpio_free(GPIO_OSCILLATEUR);\n}\n\nstatic enum hrtimer_restart timer_oscillateur(struct hrtimer * unused)\n{\n  static int value = 0;\n  gpio_set_value(GPIO_OSCILLATEUR, value);\n  value = 1 - value;\n  <strong>hrtimer_forward_now<\/strong>(&amp; htimer, kt_periode);\n  return HRTIMER_RESTART;\n}\n\nmodule_init(init_oscillateur);\nmodule_exit(exit_oscillateur);\nMODULE_LICENSE(\"GPL\");<\/pre>\n<p style=\"text-align: justify;\">Apr\u00e8s compilation (comme pr\u00e9c\u00e9demment) et transfert sur la cible, nous chargeons le module.<\/p>\n<pre>[Panda]# <strong>\/sbin\/insmod \/root\/oscillateur-gpio-hrtimer.ko<\/strong>\n[Panda]#<\/pre>\n<p style=\"text-align: justify;\">Nous voyons tout de suite la diff\u00e9rence.<\/p>\n<p><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-15.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2186\" title=\"Timer Kernel HrTimer 1000 microsecondes\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-15.jpg\" alt=\"Timer Kernel HrTimer 1000 microsecondes\" width=\"600\" height=\"445\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Notre oscillateur semble bien basculer toutes les millisecondes, puisqu&rsquo;il y a un cycle complet sur chaque division durant 2ms. V\u00e9rifions avec un calibre plus pr\u00e9cis.<\/p>\n<p><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-16.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2187\" title=\"Timer Kernel HrTimer 1000 microsecondes\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-16.jpg\" alt=\"Timer Kernel HrTimer 1000 microsecondes\" width=\"600\" height=\"446\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Le <em>hrtimer<\/em> est bien d\u00e9clench\u00e9 toutes les millisecondes. Essayons de diminuer cette dur\u00e9e en commen\u00e7ant par une p\u00e9riode de 100 microsecondes.<\/p>\n<pre>[Panda]# <strong>\/sbin\/rmmod \/root\/oscillateur-gpio-hrtimer.ko<\/strong>\n[Panda]# <strong>\/sbin\/insmod \/root\/oscillateur-gpio-hrtimer.ko periode_us=100<\/strong>\n[Panda]#<\/pre>\n<p style=\"text-align: justify;\">Le r\u00e9sultat est concluant. Le calibre de l&rsquo;oscilloscope est cette fois sur 20 microsecondes\/division.<\/p>\n<p><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-17.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2188\" title=\"Timer Kernel HrTimer 100 microsecondes\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-17.jpg\" alt=\"Timer Kernel HrTimer 100 microsecondes\" width=\"600\" height=\"442\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Continuons \u00e0 diminuer la p\u00e9riode avec 10 microsecondes.<\/p>\n<pre>[Panda]# <strong>\/sbin\/rmmod \/root\/oscillateur-gpio-hrtimer.ko<\/strong>\n[Panda]# <strong>\/sbin\/insmod \/root\/oscillateur-gpio-hrtimer.ko periode_us=10<\/strong>\n[Panda]#<\/pre>\n<p style=\"text-align: justify;\">L&rsquo;oscillateur conserve sa pr\u00e9cision. C&rsquo;est remarquable.<\/p>\n<p><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-18.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2189\" title=\"Timer Kernel HrTimer 10 microsecondes\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-18.jpg\" alt=\"Timer Kernel HrTimer 10 microsecondes\" width=\"600\" height=\"455\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Toutefois lorsque la charge syst\u00e8me augmente ou si de nombreuses interruptions surviennent, les fronts du signal se d\u00e9calent sensiblement. Pour charger fortement en appels syst\u00e8me notre carte, il y a une astuce simple&nbsp;: invoquer la commande&nbsp;:<\/p>\n<pre>[Panda]# <strong>top -d 0<\/strong><\/pre>\n<p style=\"text-align: justify;\">Il y a alors des fluctuations assez importantes sur notre oscillateur. Voici une capture sur laquelle on voit que le niveau haut du signal dure pr\u00e8s de onze microsecondes, et le niveau bas presque douze. Il y a d&rsquo;autres fluctuations beaucoup plus grandes (mais difficiles \u00e0 capturer&nbsp;!).<\/p>\n<p><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-19.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2190\" title=\"Timer Kernel HrTimer 10 microsecondes\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-19.jpg\" alt=\"Timer Kernel HrTimer 10 microsecondes\" width=\"600\" height=\"435\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Cette sensibilit\u00e9 aux interruptions et \u00e0 la quantit\u00e9 d&rsquo;appels syst\u00e8me est typique des syst\u00e8mes temps-r\u00e9el souples comme le noyau Linux classique.<\/p>\n<h1>Un timer avec Xenomai et RTDM<\/h1>\n<p style=\"text-align: justify;\">Pour obtenir une meilleure tenue de notre signal, nous allons utiliser l&rsquo;extension temps r\u00e9el strict Xenomai. Pour l&rsquo;installer sur la Pandaboard, on se reportera \u00e0 <a title=\"Xenomai sur Pandaboard\" href=\"http:\/\/www.blaess.fr\/christophe\/2011\/11\/27\/xenomai-sur-pandaboard\/\">cet article<\/a>.<\/p>\n<p style=\"text-align: justify;\">Xenomai offre une API pour le d\u00e9veloppement de drivers temps r\u00e9el nomm\u00e9e RTDM (<em>Real Time Driver Model<\/em>). Nous en avons d\u00e9j\u00e0 eu un aper\u00e7u dans <a title=\"Mesure de pr\u00e9cision des timers de RTDM \/ Xenomai\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/05\/07\/mesure-de-precision-des-timers-de-rtdm-xenomai\/\">cet article<\/a>. Nous allons utiliser ce principe pour basculer notre broche GPIO.<\/p>\n<pre><a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-05-14\/oscillateur-gpio-rtdm.c\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-05-14\/oscillateur-gpio-rtdm.c\" target=\"_blank\"><strong>oscillateur-gpio-rtdm.c :<\/strong><\/a>\n#include &lt;linux\/version.h&gt;\n#include &lt;linux\/device.h&gt;\n#include &lt;linux\/module.h&gt;\n#include &lt;linux\/sched.h&gt;\n#include &lt;linux\/cdev.h&gt;\n#include &lt;linux\/gpio.h&gt;\n#include &lt;linux\/fs.h&gt;\n#include &lt;asm\/uaccess.h&gt;\n#include &lt;rtdm\/rtdm_driver.h&gt;\n\nstatic int periode_us = 1000;\nmodule_param(periode_us, int, 0644);\n\nstatic void timer_oscillateur(rtdm_timer_t *);\nstatic <strong>rtdm_timer_t<\/strong> rtimer;\n\n\/\/ 138 Broche 10 du port J3 (Expansion A) de la Pandaboard\n#define GPIO_OSCILLATEUR 138\n\nstatic int __init init_oscillateur (void)\n{\n  int err;\n\n  if ((err = <strong>gpio_request<\/strong>(GPIO_OSCILLATEUR, THIS_MODULE-&gt;name)) != 0) {\n    return err;\n  }\n  if ((err = <strong>gpio_direction_output<\/strong>(GPIO_OSCILLATEUR, 1)) != 0) {\n    gpio_free(GPIO_OSCILLATEUR);\n    return err;\n  }\n\n  if ((err = <strong>rtdm_timer_init<\/strong>(&amp; rtimer, timer_oscillateur, \"Oscillateur\")) != 0) {\n    gpio_free(GPIO_OSCILLATEUR);\n    return err;\n  }\n\n  if ((err = <strong>rtdm_timer_start<\/strong>(&amp; rtimer, periode_us*1000, periode_us*1000, RTDM_TIMERMODE_RELATIVE)) != 0) {\n    rtdm_timer_destroy(&amp; rtimer);\n    gpio_free(GPIO_OSCILLATEUR);\n    return err;\n  }\n  return 0;\n}\n\nstatic void __exit exit_oscillateur (void)\n{\n  <strong>rtdm_timer_stop<\/strong>(&amp; rtimer);\n  <strong>rtdm_timer_destroy<\/strong>(&amp; rtimer);\n <strong> gpio_free<\/strong>(GPIO_OSCILLATEUR);\n}\n\nstatic void timer_oscillateur(rtdm_timer_t * unused)\n{\n  static int value = 0;\n  gpio_set_value(GPIO_OSCILLATEUR, value);\n  value = 1 - value;\n}\n\nmodule_init(init_oscillateur);\nmodule_exit(exit_oscillateur);\nMODULE_LICENSE(\"GPL\");<\/pre>\n<p style=\"text-align: justify;\">Il n&rsquo;y a rien de compliqu\u00e9 dans ce module. Nous le compilons avec le m\u00eame <code>Makefile<\/code> que pr\u00e9c\u00e9demment, mais il doit pouvoir trouver les fichiers d&rsquo;en-t\u00eate de Xenomai, en interrogeant le script <code>xeno-config<\/code>. Chargeons notre module (apr\u00e8s avoir d\u00e9charg\u00e9 le pr\u00e9c\u00e9dent), en lui demandant directement une p\u00e9riode de 10 microsecondes.<\/p>\n<pre>[Panda]# <strong>\/sbin\/rmmod \/root\/oscillateur-gpio-hrtimer.ko <\/strong>\n[Panda]# <strong>\/sbin\/insmod \/root\/oscillateur-gpio-rtdm.ko periode_us=10<\/strong>\n[Panda]#<\/pre>\n<p>Nous observons que le signal est bien net et r\u00e9gulier, et ne fluctue pas avec la charge syst\u00e8me.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-20.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2192\" title=\"Timer Xenomai RTDM de 10 microsecondes\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-20.jpg\" alt=\"Timer Xenomai RTDM de 10 microsecondes\" width=\"600\" height=\"442\" \/><\/a><\/p>\n<p>Il est possible d&rsquo;utiliser des p\u00e9riodes encore plus courtes. La capture ci-dessous a \u00e9t\u00e9 obtenue avec un timer de p\u00e9riode 2 microsecondes, alors qu&rsquo;un <code><strong>top -d 0<\/strong><\/code> tournait sur la carte.<\/p>\n<p><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-21.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2193\" title=\"Timer Xenomai RTDM \u00e0 2 microsecondes\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/05\/img-21.jpg\" alt=\"Timer Xenomai RTDM \u00e0 2 microsecondes\" width=\"600\" height=\"447\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Nous voyons que l&rsquo;activit\u00e9 en appels syst\u00e8me du noyau Linux (<code>top<\/code>) ne perturbe pas le timer impl\u00e9ment\u00e9 par Xenomai.<\/p>\n<h1>Conclusion<\/h1>\n<p style=\"text-align: justify;\">Nous avons examin\u00e9 plusieurs m\u00e9thodes pour r\u00e9aliser des sorties sur une broche GPIO de la Pandaboard. Il nous reste \u00e0 pr\u00e9sent \u00e0 nous int\u00e9resser aux entr\u00e9es&#8230; Ce sera l&rsquo;objet du <a title=\"GPIO, Pandaboard et temps r\u00e9el \u2013 3 \u2013 Lecture sur des entr\u00e9es\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/05\/21\/gpio-pandaboard-et-temps-reel-3-lecture-sur-des-entrees\/\">prochain article<\/a>.<\/p>\n<p>Si vous souhaitez plus d&rsquo;information sur les aspects temps r\u00e9el abord\u00e9s ici, je ne peux que vous conseiller mon nouveau livre \u00ab\u00a0<a title=\"Solutions temps r\u00e9el sous Linux\" href=\"http:\/\/www.blaess.fr\/christophe\/livres\/solutions-temps-reel-sous-linux\/\" target=\"_blank\">Solutions temps r\u00e9el sous Linux<\/a>\u00a0\u00bb qui sera disponible en librairie (quel heureux hasard) \u00e0 partir de demain&nbsp;!<\/p>","protected":false},"excerpt":{"rendered":"<p>Nous avons observ&eacute; dans l&rsquo;article pr&eacute;c&eacute;dent comment programmer et commander depuis l&rsquo;espace utilisateur les GPIO. Il s&rsquo;agit, nous l&rsquo;avons vu, de broches du microprocesseur que nous pouvons affecter au choix en entr&eacute;e ou en sortie et sur lesquelles il est possible de lire ou d&rsquo;&eacute;crire des valeurs &eacute;lectriques.<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,8,10,14],"tags":[],"class_list":["post-2173","post","type-post","status-publish","format-standard","hentry","category-embarque","category-linux-2","category-microprocesseur","category-temps-reel"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/2173","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=2173"}],"version-history":[{"count":0,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/2173\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=2173"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=2173"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=2173"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}