{"id":3444,"date":"2013-03-13T08:00:00","date_gmt":"2013-03-13T07:00:00","guid":{"rendered":"http:\/\/www.blaess.fr\/christophe\/?p=3444"},"modified":"2024-08-07T21:58:18","modified_gmt":"2024-08-07T20:58:18","slug":"mesure-de-latences-dinterruptions-gpio-rtdm","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2013\/03\/13\/mesure-de-latences-dinterruptions-gpio-rtdm\/","title":{"rendered":"Mesure de latences d&rsquo;interruptions avec un STM32"},"content":{"rendered":"<p style=\"text-align: justify;\"><a href=\"http:\/\/www.blaess.fr\/christophe\/2013\/03\/13\/mesure-de-latences-dinterruptions-gpio-rtdm\/\" rel=\"attachment wp-att-3481\"><img loading=\"lazy\" decoding=\"async\" class=\"alignright size-full wp-image-3481\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/Raspberry-Pi-STM32-01.jpg\" alt=\"Raspberry Pi - STM32 - 01\" width=\"300\" height=\"217\" \/><\/a>J&rsquo;ai continu\u00e9 mes exp\u00e9riences avec la gestion d&rsquo;interruptions par un driver RTDM-Xenomai sur les ports GPIO d&rsquo;un Raspberry Pi que j&rsquo;avais entam\u00e9es dans le <a title=\"Raspberry Pi \u2013 Interruptions GPIO avec RTDM\" href=\"http:\/\/www.blaess.fr\/christophe\/2013\/02\/15\/raspberry-pi-interruptions-gpio-avec-rtdm\/\">pr\u00e9c\u00e9dent article<\/a>. Jusqu&rsquo;alors j&rsquo;avais pu d\u00e9terminer \u00ab\u00a0\u00e0 l\u2019\u0153il\u00a0\u00bb en utilisant un oscilloscope que le temps de r\u00e9ponse \u00e9tait de l&rsquo;ordre de 3 \u00e0 4 micro-secondes, avec des pointes r\u00e9guli\u00e8res \u00e0 8 micro-secondes environ. Ce sont justement ces pointes &#8211; et celles plus longues &#8211; qui m&rsquo;int\u00e9ressent et j&rsquo;aimerais en avoir un aper\u00e7u plus complet. Mon objectif est de pouvoir d\u00e9terminer le temps de r\u00e9ponse que peut garantir dans le pire des cas un syst\u00e8me temps r\u00e9el construit sur Xenomai avec l&rsquo;API RTDM.<\/p>\n<p style=\"text-align: justify;\">\n<!--more-->\n<\/p>\n<p style=\"text-align: justify;\">Ceci pourrait \u00eatre r\u00e9alis\u00e9 avec un oscilloscope num\u00e9rique ou un analyseur logique \u00e0 m\u00e9moire. Toutefois, ces instruments ne m\u00e9morisent g\u00e9n\u00e9ralement qu&rsquo;un nombre assez faible (quelques centaines ou milliers) de valeurs. J&rsquo;aimerais avoir des statistiques sur plusieurs centaines de milliers, voire millions d&rsquo;\u00e9chantillons. En outre, je souhaite disposer \u00e9ventuellement d&rsquo;\u00e9l\u00e9ments statistiques plus complets (histogramme des latences, etc.).<\/p>\n<p style=\"text-align: justify;\">J&rsquo;ai donc d\u00e9cid\u00e9 de me construire un petit outil de mesure en utilisant un micro-contr\u00f4leur externe au Raspberry Pi. Ce micro-contr\u00f4leur devra envoyer un signal de d\u00e9clenchement d&rsquo;interruption et mesurer le plus pr\u00e9cis\u00e9ment possible le temps s&rsquo;\u00e9coulant avant la r\u00e9ponse du Raspberry Pi. L&rsquo;int\u00e9r\u00eat d&rsquo;utiliser un micro-contr\u00f4leur est que ce type de mat\u00e9riel est programm\u00e9 ais\u00e9ment pour r\u00e9aliser une seule t\u00e2che, sans perturbation externe, \u00e0 l&rsquo;inverse des micro-processeurs sur lesquels on fait tourner un syst\u00e8me d&rsquo;exploitation qui peut \u00eatre \u00ab\u00a0parasit\u00e9\u00a0\u00bb par des interruptions impr\u00e9vues (r\u00e9seau, vid\u00e9o, etc.).<\/p>\n<p style=\"text-align: justify;\">J&rsquo;ai choisi un micro-contr\u00f4leur assez puissant et peu co\u00fbteux&nbsp;: <a title=\"STM32 sur Wikipedia\" href=\"http:\/\/en.wikipedia.org\/wiki\/STM32\" target=\"_blank\" rel=\"noopener\">le STM 32<\/a>. L&rsquo;impl\u00e9mentation que j&rsquo;ai d\u00e9cid\u00e9 d&rsquo;utiliser est tr\u00e8s simple (et tr\u00e8s bon march\u00e9)&nbsp;: il s&rsquo;agit de la carte STM32-H103 d&rsquo;Olimex (on pourrait parfaitement r\u00e9aliser la m\u00eame exp\u00e9rience avec d&rsquo;autres cartes de d\u00e9veloppement).<\/p>\n<p style=\"text-align: justify;\">Ce petit micro-contr\u00f4leur est dot\u00e9 de plusieurs timers (dont le nombre varie suivant la cat\u00e9gorie du micro-contr\u00f4leur) capables notamment de fonctionner dans un mode appel\u00e9 \u00ab\u00a0<em>Input Capture<\/em>\u00a0\u00bb qui m&rsquo;int\u00e9ressera ici. Le timer \u00ab\u00a0tourne\u00a0\u00bb en permanence en comptant des cycles d&rsquo;horloge, et lorsqu&rsquo;un signal d&rsquo;entr\u00e9e sp\u00e9cifique se pr\u00e9sente, il m\u00e9morise l&rsquo;\u00e9tat du compteur dans un registre avant d&rsquo;appeler un handler d&rsquo;interruption. Ici j&rsquo;utiliserai deux signaux d&rsquo;entr\u00e9e diff\u00e9rents. Observons le fonctionnement sur la capture d&rsquo;oscilloscope suivante.<\/p>\n<p><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/oscillo.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3462\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/oscillo.png\" alt=\"R\u00e9ponse aux interruptions du Raspberry Pi\" width=\"500\" height=\"372\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/oscillo.png 500w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/oscillo-300x223.png 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Au point 1, le micro-contr\u00f4leur bascule l&rsquo;\u00e9tat d&rsquo;une sortie (signal du haut), qui est connect\u00e9e \u00e0 l&rsquo;entr\u00e9e d&rsquo;interruption du Raspberry Pi. Ce m\u00eame signal est reboucl\u00e9 en entr\u00e9e du premier canal du timer 1 du STM32. Le mode <em>Input Capture<\/em> m\u00e9morise la valeur du compteur et appelle une interruption du micro-contr\u00f4leur. Nous enregistrons alors cette valeur de compteur.<\/p>\n<p style=\"text-align: justify;\">Sur le Raspberry Pi, une interruption a \u00e9galement \u00e9t\u00e9 d\u00e9clench\u00e9e, et elle a fait basculer l&rsquo;\u00e9tat d&rsquo;un GPIO de sortie (au point 2 du graphique). Celui-ci est reli\u00e9 \u00e0 une entr\u00e9e du STM32, sur le second canal du timer 1. \u00c0 nouveau le timer m\u00e9morise la valeur de son compteur et appelle notre gestionnaire d&rsquo;interruption qui en d\u00e9duit la dur\u00e9e du traitement sur le Raspberry Pi. une fois cette latence mesur\u00e9e, le STM32 peut faire redescendre son signal (au point 3),\u00a0 et reprendre le m\u00eame travail apr\u00e8s avoir envoy\u00e9 la valeur mesur\u00e9e sur son port RS-232.<\/p>\n<p style=\"text-align: center;\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-3483 aligncenter\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/Raspberry-Pi-STM32-02.jpg\" alt=\"Raspberry Pi - STM32 - 02\" width=\"300\" height=\"197\" \/><\/p>\n<p style=\"text-align: justify;\">Le branchement r\u00e9alis\u00e9 est sch\u00e9matis\u00e9 sur la figure suivante.<\/p>\n<p><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/Connexions-Raspberry-Pi-STM-32.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3463\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/Connexions-Raspberry-Pi-STM-32.png\" alt=\"Raspberry-Pi &amp; STM-32\" width=\"494\" height=\"370\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/Connexions-Raspberry-Pi-STM-32.png 494w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/Connexions-Raspberry-Pi-STM-32-300x224.png 300w\" sizes=\"auto, (max-width: 494px) 100vw, 494px\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Le code de mon programme employ\u00e9 sur le STM 32 est le suivant.<\/p>\n<pre>\/****************************************************************************\\\n * Mesure de temps de reponse a un signal                                   *\n *                                                                          *\n * Christophe Blaess 2013.                                                  *\n\\****************************************************************************\/\n\n#include &lt;stdarg.h&gt;\n#include &lt;stdio.h&gt;\n#include &lt;string.h&gt;\n\n#include &lt;libopencm3\/cm3\/nvic.h&gt;\n#include &lt;libopencm3\/cm3\/systick.h&gt;\n#include &lt;libopencm3\/stm32\/timer.h&gt;\n#include &lt;libopencm3\/stm32\/usart.h&gt;\n#include &lt;libopencm3\/stm32\/f1\/rcc.h&gt;   \/\/ Reset and Clock Control.\n#include &lt;libopencm3\/stm32\/f1\/gpio.h&gt;\n\n\/\/ ---------------------------------------------------------------------------\n\/\/ \n<strong>void clock_setup(void)<\/strong>\n{\n\t\/\/ STM32-H103 use an external quartz at 8MHz\n\trcc_clock_setup_in_hse_8mhz_out_72mhz();\n\n\t\/\/ Enable clock for GPIO ports A &amp; C.\n\trcc_peripheral_enable_clock(&amp; RCC_APB2ENR, RCC_APB2ENR_IOPAEN);\n\trcc_peripheral_enable_clock(&amp; RCC_APB2ENR, RCC_APB2ENR_IOPCEN);\n\n}\n\n\/\/ ---------------------------------------------------------------------------\n\/\/ \n<strong>void usart_setup(void)<\/strong>\n{\n\trcc_peripheral_enable_clock(&amp; RCC_APB1ENR, RCC_APB1ENR_USART2EN);\n\trcc_peripheral_enable_clock(&amp; RCC_APB2ENR, RCC_APB2ENR_IOPAEN);\n\tgpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,\n\t              GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART2_TX);\n\tgpio_set_mode(GPIOA, GPIO_MODE_INPUT,\n\t              GPIO_CNF_INPUT_FLOAT, GPIO_USART2_RX);\n\tusart_set_baudrate (USART2, 115200);\n\tusart_set_databits (USART2, 8);\n\tusart_set_stopbits (USART2, USART_STOPBITS_1);\n\tusart_set_parity   (USART2, USART_PARITY_NONE);\n\tusart_set_flow_control (USART2, USART_FLOWCONTROL_NONE);\n\tusart_set_mode (USART2, USART_MODE_TX_RX);\n\tusart_enable (USART2);\n}\n\n<strong>int usart_printf(const char * format, ...)<\/strong>\n{\n\tva_list args;\n\tint r;\n\tint i;\n\tchar buffer[256];\n\n\tif (format == NULL) \n\t\treturn 0;\n\n\tva_start(args, format);\n\tr = vsnprintf(buffer, 256, format, args);\n\tva_end(args);\n\tif (r &lt;= 0)\n\t\treturn r;\n\n\tfor (i = 0; buffer[i] != '\\0'; i ++)\n\t\tusart_send_blocking(USART2, buffer[i]);\n\treturn i;\n}\n\n\/\/ ---------------------------------------------------------------------------\n\/\/\n\nstatic int systick_counter_ms = 0;\n\n<strong>static void systick_setup()<\/strong>\n{\n\t\/\/ 72 MHz with DIV 8 -&gt; systick clock source of 9MHz\n\tsystick_set_clocksource(STK_CTRL_CLKSOURCE_AHB_DIV8);\n\n\t\/\/ Systick interrupt period 1ms -&gt; 9MHz \/ 1kHz = 9000\n\tsystick_set_reload(9000 - 1);\n\tsystick_interrupt_enable();\n\tsystick_counter_enable();\n}\n\n<strong>void sys_tick_handler(void)<\/strong>\n{\n\tsystick_counter_ms ++;\n}\n\n\/\/ ---------------------------------------------------------------------------\n\/\/\n<strong>void tim1_setup_input_capture()<\/strong>\n{\n\t\/\/ Enable clock for Timer 1.\n\trcc_peripheral_enable_clock(&amp; RCC_APB2ENR,\n\t                            RCC_APB2ENR_TIM1EN);\n\n\t\/\/ Configure TIM1_CH1 and TIM1_CH2 as inputs.\n\tgpio_set_mode (GPIO_BANK_TIM1_CH1, GPIO_MODE_INPUT,\n\t               GPIO_CNF_INPUT_PULL_UPDOWN,\n\t               GPIO_TIM1_CH1);\n\n\tgpio_set_mode (GPIO_BANK_TIM1_CH2, GPIO_MODE_INPUT,\n\t               GPIO_CNF_INPUT_PULL_UPDOWN,\n\t               GPIO_TIM1_CH2);\n\n\t\/\/ Enable interrupts for TIM1 CC.\t\n\tnvic_enable_irq        (NVIC_TIM1_CC_IRQ);\n\n\ttimer_set_mode(TIM1,\n\t               TIM_CR1_CKD_CK_INT, \/\/ Internal 72 MHz clock\n\t               TIM_CR1_CMS_EDGE,   \/\/ Edge synchronization\n\t               TIM_CR1_DIR_UP);    \/\/ Upward counter\n\n\ttimer_set_prescaler     (TIM1, 72-1);  \/\/ Counter unit = 1 us.\n\ttimer_set_period        (TIM1, 0xFFFF);\n\ttimer_set_repetition_counter(TIM1, 0);\n\ttimer_continuous_mode   (TIM1);\n\n\t\/\/ Configure channel 1\n\ttimer_ic_set_input     (TIM1, TIM_IC1, TIM_IC_IN_TI1);\n\ttimer_ic_set_filter    (TIM1, TIM_IC1, TIM_IC_OFF);\n\ttimer_ic_set_polarity  (TIM1, TIM_IC1, TIM_IC_RISING);\n\ttimer_ic_set_prescaler (TIM1, TIM_IC1, TIM_IC_PSC_OFF);\n\ttimer_ic_enable        (TIM1, TIM_IC1);\n\ttimer_clear_flag       (TIM1, TIM_SR_CC1IF);\n\ttimer_enable_irq       (TIM1, TIM_DIER_CC1IE);\n\n\t\/\/ Configure channel 2\n\ttimer_ic_set_input     (TIM1, TIM_IC2, TIM_IC_IN_TI2);\n\ttimer_ic_set_filter    (TIM1, TIM_IC2, TIM_IC_OFF);\n\ttimer_ic_set_polarity  (TIM1, TIM_IC2, TIM_IC_RISING);\n\ttimer_ic_set_prescaler (TIM1, TIM_IC2, TIM_IC_PSC_OFF);\n\ttimer_ic_enable        (TIM1, TIM_IC2);\n\ttimer_clear_flag       (TIM1, TIM_SR_CC2IF);\n\ttimer_enable_irq       (TIM1, TIM_DIER_CC2IE);\n\n\ttimer_enable_counter   (TIM1);\n\n}\n\nvolatile int latency = 0;\nvolatile int latency_max = 0;\n\n<strong>void tim1_cc_isr(void)<\/strong>\n{\n\tstatic int last_value = 0;\n\tint value;\n\tif (timer_get_flag(TIM1, TIM_SR_CC1IF) != 0) {\n\t\t\/\/ Timer channel 1 interrupt -&gt; First edge (outcoming signal).\n\t\ttimer_clear_flag(TIM1, TIM_SR_CC1IF);\n\t\tlast_value = timer_get_counter(TIM1);\n\t}\n\tif (timer_get_flag(TIM1, TIM_SR_CC2IF)) {\n\t\t\/\/ Timer channel 2 interrupt -&gt; response (incoming signal).\n\t\ttimer_clear_flag(TIM1, TIM_SR_CC2IF);\n\t\tvalue = timer_get_counter(TIM1) - last_value;\n\t\tif (value &lt; 0)\n\t\t\tvalue = value + 0xffff;\n\t\tlatency = value;\n\t\tif (latency &gt; latency_max)\n\t\t\tlatency_max = latency;\n\t}\n}\n\n\/\/ ---------------------------------------------------------------------------\n\/\/\n<strong>int main(void)<\/strong>\n{\n\tclock_setup();\n\tusart_setup();\n\tsystick_setup();\n\ttim1_setup_input_capture();\n\n\t\/\/ Wait 3 seconds to allow Linux detecting \/dev\/ttyUSB\n\twhile (systick_counter_ms &lt; 3000)\n\t\t;\n\n\t\/\/ Output signal is on GPIO C 10 (EXT1-8)\n\tgpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ,\n\t              GPIO_CNF_OUTPUT_PUSHPULL, GPIO10);\n\n\twhile (1) {\n\t\t\/\/ If the input signal is high.\n\t\tif (gpio_get(GPIO_BANK_TIM1_CH2, GPIO_TIM1_CH2) != 0) {\n\t\t\t\/\/ Output a raising edge.\n\t\t\tgpio_set(GPIOC, GPIO10);\n\t\t\t\/\/ Wait for the input signal going down, max 2 ms.\n\t\t\tfor (systick_counter_ms = 0; systick_counter_ms &lt; 2; )\n\t\t\t\tif (gpio_get(GPIO_BANK_TIM1_CH2, GPIO_TIM1_CH2) == 0)\n\t\t\t\t\tbreak;\n\t\t\t\/\/ Output a falling edge.\n\t\t\tgpio_clear(GPIOC, GPIO10);\n\t\t} else {\n\t\t\tlatency = 0;\n\t\t\t\/\/ Output a raising edge (trigger signal).\n\t\t\tgpio_set(GPIOC, GPIO10);\n\t\t\t\/\/ Wait for the latency to be available.\n\t\t\tfor (systick_counter_ms = 0; systick_counter_ms &lt; 2; )\n\t\t\t\tif (latency != 0)\n\t\t\t\t\tbreak;\n\t\t\t\/\/ Output a falling edge.\n\t\t\tgpio_clear(GPIOC, GPIO10);\n\t\t\tif (latency != 0)\n\t\t\t\tusart_printf(\"%3d - %3d\\n\", latency, latency_max);\n\t\t}\n\n\t\t\/\/ Wait 1 ms before next trigger.\n\t\tfor (systick_counter_ms = 0; systick_counter_ms &lt; 1; )\n\t\t\t;\n\t}\n\treturn 0;\n}<\/pre>\n<p style=\"text-align: justify;\">Sur le Rapsberry Pi, le programme employ\u00e9 ici est le driver pour RTDM dont nous avons parl\u00e9 dans <a title=\"Raspberry Pi \u2013 Interruptions GPIO avec RTDM\" href=\"http:\/\/www.blaess.fr\/christophe\/2013\/02\/15\/raspberry-pi-interruptions-gpio-avec-rtdm\/\" target=\"_blank\" rel=\"noopener\">cet article<\/a>.<\/p>\n<p style=\"text-align: justify;\">Sur le PC Linux, reli\u00e9 au port s\u00e9rie du STM32, nous pouvons voir d\u00e9filer les latences mesur\u00e9es (en micro-secondes) ainsi que la latence maximale depuis le d\u00e9marrage du STM32.<\/p>\n<pre>$ <strong>sudo cat \/dev\/ttyUSB0<\/strong>\n 12 -  31\n  9 -  31\n  8 -  31\n  9 -  31\n  8 -  31\n  9 -  31\n  7 -  31\n  4 -  31\n  4 -  31\n  4 -  31\n  4 -  31\n  9 -  31\n  8 -  31\n  8 -  31\n  9 -  31\n 11 -  31\n 11 -  31\n  9 -  31\n  8 -  31\n  9 -  31\n 12 -  31\n 11 -  31\n  8 -  31<\/pre>\n<p style=\"text-align: justify;\">L&rsquo;int\u00e9r\u00eat de cette exp\u00e9rience est de conna\u00eetre la valeur maximale que nous risquons d&rsquo;atteindre. Aussi est-il indispensable de charger fortement le Raspberry Pi. C&rsquo;est le r\u00f4le du script <code>dohell<\/code> livr\u00e9 avec Xenomai, et que je fais tourner en s\u00e9quences r\u00e9guli\u00e8res de cinq minutes entrecoup\u00e9es de petits repos de trente secondes.<\/p>\n<pre># <strong>while true; do \/usr\/xenomai\/bin\/dohell 300; sleep 30; done<\/strong><\/pre>\n<h1>R\u00e9sultats<\/h1>\n<p style=\"text-align: justify;\">La premi\u00e8re exp\u00e9rience consiste \u00e0 faire une s\u00e9rie de mesures pendant <strong>une heure<\/strong>, avec un Raspberry Pi <strong>peu charg\u00e9<\/strong> (quelques acc\u00e8s au syst\u00e8me de fichiers et consultations d&rsquo;information de <code>\/proc<\/code>). Les r\u00e9sultats bruts se trouvent dans <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2013-03-13\/mesure-1h-faible-charge.txt.bz2\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2013-03-13\/mesure-1h-faible-charge.txt.bz2\" target=\"_blank\" rel=\"noopener\">ce fichier<\/a>. La latence maximale obtenue est de <strong>24 microsecondes<\/strong>.<\/p>\n<p style=\"text-align: justify;\">J&rsquo;ai utilis\u00e9 les petits outils d&rsquo;analyse des r\u00e9sultats que j&rsquo;avais d\u00e9velopp\u00e9s pour mon 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\" rel=\"noopener\">Solutions temps r\u00e9el sous Linux<\/a>\u00a0\u00bb afin d&rsquo;obtenir un histogramme des latences. L&rsquo;axe des ordonn\u00e9es est logarithmique, afin de mettre en \u00e9vidence les cas les plus rares (au dessus de 15 microsecondes environ).<\/p>\n<p style=\"text-align: justify;\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/mesure-1h-faible-charge.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3479\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/mesure-1h-faible-charge.png\" alt=\"Latences Xenomai Raspberry Pi - Faible charge\" width=\"800\" height=\"600\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/mesure-1h-faible-charge.png 800w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/mesure-1h-faible-charge-300x225.png 300w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">L&rsquo;exp\u00e9rience suivante a consist\u00e9 \u00e0 laisser le syst\u00e8me faire des mesures pendant <strong>vingt-quatre heures<\/strong>, avec une <strong>tr\u00e8s forte charge syst\u00e8me<\/strong> sur le Raspberry Pi. Pour cela j&rsquo;ai lanc\u00e9 le script <code>dohell<\/code> mentionn\u00e9 plus haut. Les r\u00e9sultats bruts se trouvent dans <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2013-03-13\/mesure-24h-forte-charge.txt.bz2\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2013-03-13\/mesure-24h-forte-charge.txt.bz2\" target=\"_blank\" rel=\"noopener\">ce fichier<\/a>. La latence maximale rencontr\u00e9e est de <strong>46 micro-secondes<\/strong>. L&rsquo;histogramme montre bien les r\u00e9partitions des latences mesur\u00e9es. Nous y retrouvons le premier pic centr\u00e9 sur 3-4 microsecondes obtenues pendant les p\u00e9riodes de repos entre l&rsquo;ex\u00e9cution de <code>dohell<\/code>.<\/p>\n<p style=\"text-align: justify;\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/mesure-24h-forte-charge.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3471\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/mesure-24h-forte-charge.png\" alt=\"Latences Xenomai Raspberry Pi - 24h - Forte charge\" width=\"800\" height=\"600\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/mesure-24h-forte-charge.png 800w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2013\/02\/mesure-24h-forte-charge-300x225.png 300w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a>Nous voyons que la latence de traitement d&rsquo;une interruption sur <strong>Raspberry Pi<\/strong> en utilisant l&rsquo;API <strong>RTDM de Xenomai<\/strong> est <strong>inf\u00e9rieure \u00e0 50 microsecondes<\/strong>, la valeur maximale \u00e9tant par ailleurs un cas isol\u00e9 et tr\u00e8s rare. Ces r\u00e9sultats sont tr\u00e8s corrects pour un syst\u00e8me embarqu\u00e9 peu co\u00fbteux et &#8211; rappelons-le &#8211; non pr\u00e9vu pour un usage industriel.<\/p>\n<h1>Conclusion<\/h1>\n<p style=\"text-align: justify;\">Pour valider un choix technologique ou v\u00e9rifier la mont\u00e9e en charge d&rsquo;un prototype, il est souvent n\u00e9cessaire de r\u00e9aliser ce type d&rsquo;exp\u00e9rience. On voit qu&rsquo;il est tout \u00e0 fait possible de construire ais\u00e9ment ses propres outils de mesure adapt\u00e9s, pour un prix de revient modique et une complexit\u00e9 relativement faible (le plus compliqu\u00e9 est la lecture et l&rsquo;interpr\u00e9tation du manuel de r\u00e9f\u00e9rence du micro-contr\u00f4leur). Je vous encourage \u00e0 utiliser ces petites plates-formes souples, performantes et bon march\u00e9 que sont le Raspberry Pi, le STM32, etc. pour vos propres <em>hacks<\/em>.<\/p>\n<p style=\"text-align: center;\">Comme toujours, les remarques, commentaires et retours d&rsquo;exp\u00e9riences sont les bienvenus.<\/p>","protected":false},"excerpt":{"rendered":"<p>J&rsquo;ai continu&eacute; mes exp&eacute;riences avec la gestion d&rsquo;interruptions par un driver RTDM-Xenomai sur les ports GPIO d&rsquo;un Raspberry Pi que j&rsquo;avais entam&eacute;es dans le pr&eacute;c&eacute;dent article. Jusqu&rsquo;alors j&rsquo;avais pu d&eacute;terminer &laquo;&nbsp;&agrave; l&rsquo;&oelig;il&nbsp;&raquo; en utilisant un oscilloscope que le temps de r&eacute;ponse &eacute;tait de l&rsquo;ordre de 3 &agrave; 4 micro-secondes, avec des pointes r&eacute;guli&egrave;res &agrave; 8 [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,8,16,10,11,14],"tags":[],"class_list":["post-3444","post","type-post","status-publish","format-standard","hentry","category-embarque","category-linux-2","category-microcontroleur","category-microprocesseur","category-raspberry-pi","category-temps-reel"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/3444","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=3444"}],"version-history":[{"count":26,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/3444\/revisions"}],"predecessor-version":[{"id":6431,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/3444\/revisions\/6431"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=3444"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=3444"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=3444"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}