{"id":3324,"date":"2013-01-26T04:55:56","date_gmt":"2013-01-26T03:55:56","guid":{"rendered":"http:\/\/www.blaess.fr\/christophe\/?p=3324"},"modified":"2024-08-07T21:59:29","modified_gmt":"2024-08-07T20:59:29","slug":"gerer-les-gpio-du-raspberry-pi-avec-rtdm","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2013\/01\/26\/gerer-les-gpio-du-raspberry-pi-avec-rtdm\/","title":{"rendered":"G\u00e9rer les GPIO du Raspberry Pi avec RTDM"},"content":{"rendered":"<p style=\"text-align: justify;\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/01\/Xenomai-Raspberry-Pi.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignright size-full wp-image-3336\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/01\/Xenomai-Raspberry-Pi.png\" alt=\"Xenomai Raspberry-Pi GPIO\" width=\"211\" height=\"150\" \/><\/a>Plusieurs personnes m&rsquo;ont demand\u00e9 r\u00e9cemment si l&rsquo;utilisation des GPIO du Raspberry Pi \u00e9taient possible en employant un driver RTDM pour Xenomai. Si le traitement des entr\u00e9es et sorties est effectivement simple, l&rsquo;utilisation des interruptions pose encore quelques soucis.<br \/>\n<!--more-->\n<br \/>\nG\u00e9rer les broches GPIO du Raspberry Pi avec le kernel Linux standard est simple, nous l&rsquo;avons vu dans <a title=\"Les GPIO du Raspberry Pi\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/11\/26\/les-gpio-du-raspberry-pi\/\">cet article<\/a>.<\/p>\n<p style=\"text-align: justify;\">L&rsquo;adaptation sur un noyau plus orient\u00e9 \u00ab\u00a0temps r\u00e9el\u00a0\u00bb avec le patch <code>PREEMPT_RT<\/code> est possible. Je vous conseille <a title=\"http:\/\/www.linuxembedded.fr\/2013\/01\/preempt-rt-sur-raspberry-pi\/\" href=\"http:\/\/www.linuxembedded.fr\/2013\/01\/preempt-rt-sur-raspberry-pi\/\" target=\"_blank\" rel=\"noopener\">cet article<\/a> de Pierre Ficheux sur son blog.<\/p>\n<p style=\"text-align: justify;\">On peut \u00e9galement employer l&rsquo;API RTDM (<em>Real Time Driver Model<\/em>) de Xenomai pour piloter simplement les broches en entr\u00e9es ou sortie.<\/p>\n<h1>Entr\u00e9es-sorties simples avec RTDM<\/h1>\n<p style=\"text-align: justify;\">Voici \u00e0 titre d&rsquo;exemple un petit <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2013-01-26\/oscillateur-gpio-rtdm.c\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2013-01-26\/oscillateur-gpio-rtdm.c\" target=\"_blank\" rel=\"noopener\">programme<\/a> qui sort sur la broche 15 du port d&rsquo;extension P1 un signal carr\u00e9 dont la p\u00e9riode est configurable sur la ligne de commande de chargement du module.<\/p>\n<pre><strong><a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2013-01-26\/oscillateur-gpio-rtdm.c\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2013-01-26\/oscillateur-gpio-rtdm.c\" target=\"_blank\" rel=\"noopener\">oscillateur-gpio-rtdm.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\n#include &lt;asm\/uaccess.h&gt;\n\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 rtdm_timer_t rtimer;\n\n\/\/ Broche 15 du port P1 du Raspberry Pi : GPIO 22\n#define GPIO_OSCILLATEUR 22\n\nstatic int __init <strong>init_oscillateur<\/strong> (void)\n{\n    int err;\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\n    if ((err = rtdm_timer_init(&amp; rtimer, timer_oscillateur, \"Oscillateur\")) != 0) {\n        gpio_free(GPIO_OSCILLATEUR);\n        return err;\n    }\n\n    if ((err = rtdm_timer_start(&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 <strong>exit_oscillateur<\/strong> (void)\n{\n    rtdm_timer_stop(&amp; rtimer);\n    rtdm_timer_destroy(&amp; rtimer);\n    gpio_free(GPIO_OSCILLATEUR);\n}\n\nstatic void <strong>timer_oscillateur<\/strong>(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;\">Ce module doit bien s\u00fbr \u00eatre compil\u00e9 et charg\u00e9 dans un noyau modifi\u00e9 pour incorporer Xenomai comme nous l&rsquo;avons vu dans <a title=\"Xenomai sur Raspberry Pi\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/08\/27\/xenomai-sur-raspberry-pi\/\">cet article<\/a>. Pour \u00eatre exact, je l&rsquo;ai install\u00e9 en employant Xenomai-2.6.2 plut\u00f4t que la version 2.6.1 d\u00e9crite dans l&rsquo;article pr\u00e9c\u00e9dent.<\/p>\n<p style=\"text-align: justify;\">Voici par exemple le chargement en pr\u00e9cisant une p\u00e9riode de 50 micro-secondes.<\/p>\n<pre>root@R-Pi [\/root]# <strong>insmod \/root\/oscillateur-gpio-rtdm.ko periode_us=50<\/strong>\nroot@R-Pi [\/root]#<\/pre>\n<p style=\"text-align: justify;\">Aussit\u00f4t nous voyons le signal suivant sur la sortie 15 du Raspberry Pi.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3329\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/01\/rpi-gpio-out-1.png\" alt=\"Sortie GPIO du Raspberry-Ri\" width=\"500\" height=\"375\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/01\/rpi-gpio-out-1.png 500w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/01\/rpi-gpio-out-1-300x225.png 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<p style=\"text-align: justify;\">Le timer a bien une p\u00e9riode de 50 micro-secondes, le signal de sortie n\u00e9cessitant deux d\u00e9clenchements du timer pour effectuer un cycle complet, sa p\u00e9riode est 100 microsecondes. Les fluctuations visibles sont tr\u00e8s faibles, bien inf\u00e9rieures \u00e0 10 microsecondes (mais mon syst\u00e8me n&rsquo;est pas tr\u00e8s charg\u00e9).<\/p>\n<h1>Interruptions GPIO avec RTDM<\/h1>\n<p>Tout d&rsquo;abord, pr\u00e9cisons tout de suite que cette partie est encore en cours de travail, j&rsquo;esp\u00e8re pouvoir progresser dessus tr\u00e8s prochainement.<\/p>\n<p style=\"text-align: justify;\">Pour pouvoir g\u00e9rer les interruptions du Raspberry Pi avec RTDM, il est n\u00e9cessaire de modifier un fichier du noyau Linux avant compilation. Ceci sera prochainement int\u00e9gr\u00e9 dans le patch Adeos (qui int\u00e8gre le support Xenomai dans le kernel Linux), mais pendant quelques temps encore, il faut faire la modification manuellement.<\/p>\n<p style=\"text-align: justify;\">Appliquez le <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2013-01-26\/patch-ipipe-demuxed-irq.patch\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2013-01-26\/patch-ipipe-demuxed-irq.patch\" target=\"_blank\" rel=\"noopener\">patch suivant<\/a> sur le noyau (pr\u00e9c\u00e9dement pr\u00e9par\u00e9 pour Xenomai)&nbsp;:<\/p>\n<pre>--- a\/arch\/arm\/mach-bcm2708\/bcm2708_gpio.c\t2013-01-20 08:57:35.114605274 +0100\n+++ b\/arch\/arm\/mach-bcm2708\/bcm2708_gpio.c\t2013-01-20 09:14:51.362655426 +0100\n@@ -13,6 +13,7 @@\n #include &lt;linux\/module.h&gt;\n #include &lt;linux\/list.h&gt;\n #include &lt;linux\/io.h&gt;\n<strong>+#include &lt;linux\/ipipe.h&gt;<\/strong>\n #include &lt;linux\/irq.h&gt;\n #include &lt;linux\/interrupt.h&gt;\n #include &lt;linux\/slab.h&gt;\n@@ -218,7 +219,7 @@\n \t\tedsr=readl(__io_address(GPIO_BASE)+GPIOEDS(bank));\n \t\tfor_each_set_bit(i, &amp;edsr, 32) {\n \t\t\tgpio=i+bank*32;\n<strong>-\t\t\tgeneric_handle_irq(gpio_to_irq(gpio));\n+\t\t\tipipe_handle_demuxed_irq(gpio_to_irq(gpio));\n<\/strong> \t\t}\n \t\twritel(0xffffffff,  __io_address(GPIO_BASE)+GPIOEDS(bank));\n \t}<\/pre>\n<p style=\"text-align: justify;\">Comme vous le voyez, outre l&rsquo;ajout du fichier d&rsquo;en-t\u00eate <code>ipipe.h<\/code>, ce patch remplace l&rsquo;appel \u00e0 la fonction <code>generic_handle_irq()<\/code> par <code>ipipe_handle_demuxed_irq()<\/code>.<\/p>\n<h2>Exemple de driver utilisant les GPIO en interruption<\/h2>\n<p style=\"text-align: justify;\">Voici un petit <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2013-01-26\/irq-gpio-rtdm.c\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2013-01-26\/irq-gpio-rtdm.c\" target=\"_blank\" rel=\"noopener\">module<\/a> qui commute l&rsquo;\u00e9tat de la broche 15 \u00e0 chaque fois qu&rsquo;un front montant se pr\u00e9sente sur la broche 16.<\/p>\n<pre><strong><a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2013-01-26\/irq-gpio-rtdm.c\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2013-01-26\/irq-gpio-rtdm.c\" target=\"_blank\" rel=\"noopener\">irq-gpio-rtdm.c<\/a> :<\/strong>\n#include &lt;linux\/fs.h&gt;\n#include &lt;linux\/gpio.h&gt;\n#include &lt;linux\/interrupt.h&gt;\n#include &lt;linux\/module.h&gt;\n\n#include &lt;rtdm\/rtdm_driver.h&gt;\n\n\/\/ GPIO IN 23 -&gt; Broche 16\n#define GPIO_IN  23\n\/\/ GPIO OUT 22 -&gt; Broche 15\n#define GPIO_OUT 22\n\nstatic rtdm_irq_t irq_rtdm;\n\nstatic int <strong>handler_interruption<\/strong>(rtdm_irq_t * irq)\n{\n    static int value = 0;\n    gpio_set_value(GPIO_OUT, value);\n    value = 1 - value;\n    return RTDM_IRQ_HANDLED;\n}\n\n    static int numero_interruption; \n\nstatic int __init <strong>exemple_init<\/strong> (void)\n{\n    int err;\n\n    numero_interruption = gpio_to_irq(GPIO_IN);\n\n    if ((err = gpio_request(GPIO_IN, THIS_MODULE-&gt;name)) != 0) {\n        return err;\n    }\n    if ((err = gpio_direction_input(GPIO_IN)) != 0) {\n        gpio_free(GPIO_IN);\n        return err;\n    }\n    if ((err = gpio_request(GPIO_OUT, THIS_MODULE-&gt;name)) != 0) {\n        gpio_free(GPIO_IN);\n        return err;\n    }\n    if ((err = gpio_direction_output(GPIO_OUT, 1)) != 0) {\n        gpio_free(GPIO_OUT);\n        gpio_free(GPIO_IN);\n        return err;\n    }\n\n    irq_set_irq_type(numero_interruption,  IRQF_TRIGGER_RISING);\n\n    if ((err = rtdm_irq_request(&amp; irq_rtdm, \n                     numero_interruption, handler_interruption, \n                     RTDM_IRQTYPE_EDGE,\n                     THIS_MODULE-&gt;name, NULL)) != 0) {\n        gpio_free(GPIO_OUT);\n        gpio_free(GPIO_IN);\n        return err;\n    }\n\n    rtdm_irq_enable(&amp; irq_rtdm);\n\n    return 0; \n}\n\nstatic void __exit <strong>exemple_exit<\/strong> (void)\n{\n    rtdm_irq_disable(&amp; irq_rtdm);\n    rtdm_irq_free(&amp; irq_rtdm);\n    gpio_free(GPIO_OUT);\n    gpio_free(GPIO_IN);\n}\n\nmodule_init(exemple_init);\nmodule_exit(exemple_exit);\nMODULE_LICENSE(\"GPL\");<\/pre>\n<h2>R\u00e9sultats<\/h2>\n<p style=\"text-align: justify;\">Ce module fonctionne, mais les performances ne sont pas satisfaisantes. Le temps de r\u00e9ponse est de plusieurs dizaines de micro-secondes, avec des fluctuations allant jusqu&rsquo;\u00e0 plus de 100 micro-secondes. Pour m\u00e9moire, le m\u00eame traitement r\u00e9alis\u00e9 par le noyau Linux Vanilla prend environ 7 micro-secondes.<\/p>\n<p style=\"text-align: justify;\">Je vais proc\u00e9der \u00e0 de nouveaux essais ce week-end. Plusieurs pistes ont \u00e9t\u00e9 sugg\u00e9r\u00e9es sur la mailing-list de Xenomai et je ne manquerai pas de poster les \u00e9volutions prochaines.<\/p>","protected":false},"excerpt":{"rendered":"<p>Plusieurs personnes m&rsquo;ont demand&eacute; r&eacute;cemment si l&rsquo;utilisation des GPIO du Raspberry Pi &eacute;taient possible en employant un driver RTDM pour Xenomai. Si le traitement des entr&eacute;es et sorties est effectivement simple, l&rsquo;utilisation des interruptions pose encore quelques soucis.<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,8,11,14],"tags":[],"class_list":["post-3324","post","type-post","status-publish","format-standard","hentry","category-embarque","category-linux-2","category-raspberry-pi","category-temps-reel"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/3324","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=3324"}],"version-history":[{"count":13,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/3324\/revisions"}],"predecessor-version":[{"id":6434,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/3324\/revisions\/6434"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=3324"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=3324"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=3324"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}