Depuis plusieurs mois, on m’interroge régulièrement sur le support de Xenomai sur Raspberry Pi 3 tant durant mes sessions de formations sur Xenomai que dans des messages par mail. J’avais l’habitude de répondre que Xenomai ne fonctionnait pas encore sur ce modèle de Raspberry Pi.
Une remarque récente de Syrine dans les commentaires de l’article « Xenomai 3 sur Raspberry Pi 2 » a attiré mon attention sur un site japonais qui utilise les mêmes commandes que celles présentées dans cet article et fait fonctionner l’ensemble sur un Raspberry Pi 3. J’ai voulu tenter également cette installation. Le résultat est un peu mitigé : Xenomai fonctionne parfaitement avec une bonne stabilité, sauf en ce qui concerne la gestion des interruptions des GPIO qui n’est pas supportée encore. Si vous êtes néanmoins tentés par l’expérience, voici comment procéder simplement.
Compilation et installation
Dans le cadre d’une mise en œuvre professionnelle pour un client je travaillerais en cross-compilation sur une machine de développement de type PC pour produire l’image qui serait installée ensuite sur la cible. Pour ce petit article, j’ai préféré simplifier la mise en œuvre et réaliser une compilation native directement sur le Raspberry Pi 3. Le temps de construction est plus long, mais il reste très raisonnable (2h tout compris pour cette expérience).
Tout d’abord, installons une image de la distribution Raspbian toute neuve. N’utilisez pas la distribution Noob, l’organisation des partitions est différente.
[~]$ sudo dd if=2017-02-16-raspbian-jessie-lite.img of=/dev/sdc bs=4M
Nous démarrons à présent le Raspberry pi 3 sur cette nouvelle distribution. Elle va rebooter automatiquement pour agrandir la partition et occuper tout la carte SD. Connectons-nous
raspberrypi login: pi Password: raspberry
Il nous faudra quelques outils supplémentaires à ajouter à la distribution d’origine :
pi@raspberrypi:~$ sudo apt install -y git ncurses-dev bc autoconf libtool
Téléchargeons les sources de Xenomai. Je prends la dernière version disponible à ce jour :
pi@raspberrypi:~$ wget http://xenomai.org/downloads/xenomai/stable/xenomai-3.0.3.tar.bz2 pi@raspberrypi:~$ tar xjf xenomai-3.0.3.tar.bz2 pi@raspberrypi:~$ ls xenomai-3.0.3/kernel/cobalt/arch/arm/patches/ ipipe-core-3.10.32-arm-13.patch ipipe-core-3.18.20-arm-9.patch README ipipe-core-3.14.44-arm-16.patch ipipe-core-4.1.18-arm-4.patch
Le patch ipipe
le plus récent proposé par Xenomai s’applique sur un noyau Linux 4.1. Nous avons de la chance, il existe une branche 4.1 pour le kernel spécifiquement modifié pour Raspberry Pi. Téléchargeons cette branche. L’option --depth 1
raccourcit le temps de téléchargement (2 à 3 minutes) en limitant l’historique au seul dernier commit :
pi@raspberrypi:~$ git clone https://github.com/raspberrypi/linux.git -b rpi-4.1.y --depth 1 pi@raspberrypi:~$ head -4 linux/Makefile VERSION = 4 PATCHLEVEL = 1 SUBLEVEL = 21 EXTRAVERSION = pi@raspberrypi:~$
Le noyau est un 4.1.21. Il n’y a pas beaucoup de différences avec le 4.1.18, Xenomai fonctionnera. Néanmoins une option de configuration a été modifiée, et pour que le patch ipipe
puisse s’applique nous devons le modifier. Pour cela, j’ai préparé un petit patch (un patch de patch, cela explique qu’il contienne un signe '+'
décalé) que nous téléchargeons :
pi@raspberrypi:~$ wget https://www.blaess.fr/christophe/files/article-2017-03-20/001-adapt-4.1.18-patch-to-rpi-4.1.21-kernel.patch
Appliquons ce mini-patch à Xenomai.
pi@raspberrypi:~$ ls 001-adapt-4.1.18-patch-to-rpi-4.1.21-kernel.patch linux xenomai-3.0.3 xenomai-3.0.3.tar.bz2 pi@raspberrypi:~$ cd xenomai-3.0.3/ pi@raspberrypi:~/xenomai-3.0.3$ patch -p1 < ../001* patching file kernel/cobalt/arch/arm/patches/ipipe-core-4.1.18-arm-8.patch pi@raspberrypi:~/xenomai-3.0.3$
Nous pouvons maintenant appliquer le patch ipipe
modifié au noyau Linux que nous avons téléchargé :
pi@raspberrypi:~/xenomai-3.0.3$ ./scripts/prepare-kernel.sh --arch=arm --linux=../linux --ipipe=kernel/cobalt/arch/arm/patches/ipipe-core-4.1.18-arm-8.patch
Il y a quelques messages indiquant un décalage entre le noyau standard et le noyau pour Raspberry Pi (offset xx lines
) mais la commande patch
arrive à résoudre ces problèmes (Hunk #x succeeded
).
Un second patch va être nécessaire. Comme je l’indiquais dans cet article, il s’agit d’une gestion des timers spécifique au Raspberry Pi.
pi@raspberrypi:~/xenomai-3.0.3$ cd .. pi@raspberrypi:~$ wget https://www.blaess.fr/christophe/files/article-2017-03-20/002-xenomai-3-on-bcm-2709.patch pi@raspberrypi:~$ cd linux pi@raspberrypi:~/linux$ patch -p1 < ../002*
Nous allons compiler ce noyau. Pour cela, j’ai préparé un fichier de configuration qui regroupe les options nécessaires. Il s’agit d’une configuration un peu allégée pour réduire le temps de compilation ; s’il vous manque des fonctionnalités, n’hésitez pas à l’éditer (avec make menuconfig
) et la modifier :
pi@raspberrypi:~/linux$ wget https://www.blaess.fr/christophe/files/article-2017-03-20/linux.config pi@raspberrypi:~/linux$ mv linux.config .config
Pour la compilation proprement dite, le Raspberry Pi 3 va être très sollicité, d’autant que nous occupons ses quatre cœurs au maximum (option -j 4
pour quatre jobs en parallèle).
Vu la chaleur qu’il dégage, je vous conseille de le placer de façon à ce que le processeur soit bien ventilé (pas de boîtier fermé). L’idéal consiste à placer sur le processeur un petit radiateur de dissipation comme celui-ci.
Pour un Raspberry Pi 3 dans un boîtier fermé sans dissipateur, j’aurais tendance à supprimer l’option -j 4
de la ligne suivante, afin de soulager la charge du processeur, au prix d’un temps de compilation plus long.
pi@raspberrypi:~/linux$ time make -j 4 [...] IHEX2FW firmware/keyspan_pda/keyspan_pda.fw IHEX2FW firmware/keyspan_pda/xircom_pgs.fw real 103m36.178s user 277m51.420s sys 13m39.250s pi@raspberrypi:~/linux$ pi@raspberrypi:~/linux$
Comme vous le voyez, il faut environ 1h30 de compilation sur un Raspberry Pi 3 pour obtenir notre noyau. Ne soyez pas surpris de voir passer pendant la compilation des warnings indiquant du code douteux. Ils se produisent tous dans des modules spécifiques au Raspberry Pi ; c’est leur niveau inégal de qualité qui a empêché leur intégration dans le noyau Linux standard.
Nous allons installer ce nouveau kernel à côté de celui de la distribution Raspbian afin de pouvoir revenir en arrière en cas de problème :
pi@raspberrypi:~/ipipe$ sudo cp arch/arm/boot/zImage /boot/kernel-xenomai.img pi@raspberrypi:~/ipipe$ sudo make modules_install pi@raspberrypi:~/ipipe$ sudo make dtbs_install pi@raspberrypi:~/ipipe$ ls /boot/dtbs/4.1.21-xenomai+/ bcm2709-rpi-2-b.dtb bcm2710-rpi-3-b.dtb overlays
Le nouveau noyau, ses modules et son device tree étant installés, nous devons modifier le fichier de configuration du bootloader pour lui indiquer quel kernel charger :
pi@raspberrypi:~/ipipe$ sudo nano /boot/config.txt
Ajoutez les deux lignes suivantes à la fin du fichier :
kernel=kernel-xenomai.img device_tree=dtbs/4.1.21-xenomai+/bcm2710-rpi-3-b.dtb
Testons notre noyau incluant ipipe
:
pi@raspberrypi:~/ipipe$ sudo reboot
Si le système ne redémarre pas, montez la carte SD sur un PC, mettez en commentaire les deux lignes ci-dessus (en les précédant d’un '#'
) pour redémarrer sur la distribution Raspbian initiale. Vérifiez bien l’emplacement du noyau, du device tree, et le contenu du fichier config.txt
.
Le Raspberry Pi 3 ayant bien redémarré sur le noyau patché avec ipipe
, nous pouvons vérifier sa présence ainsi
raspberrypi login: pi Password: raspberry [...] pi@raspberrypi:~$ uname -a Linux raspberrypi 4.1.21-xenomai+ #1 SMP PREEMPT Sat Mar 18 10:12:21 UTC 2017 armv7l GNU/Linux pi@raspberrypi:~$ cat /proc/ipipe/version 8 pi@raspberrypi:~$ cat /proc/xenomai/version 3.0.3 pi@raspberrypi:~$
Le travail n’est pas terminé pour autant, nous devons compiler les bibliothèques et les outils de tests de Xenomai.
pi@raspberrypi:~$ cd xenomai-3.0.3/ pi@raspberrypi:~/xenomai-3.0.3$ ./scripts/bootstrap
Cette étape reste silencieuse durant quelques minutes. Laissez le script travailler, il n’est pas bloqué.
pi@raspberrypi:~/xenomai-3.0.3$ ./configure --enable-smp pi@raspberrypi:~/xenomai-3.0.3$ make pi@raspberrypi:~/xenomai-3.0.3$ sudo make install
Deux heures après le début de notre expérience, Xenomai est prêt à être utilisé. Le test le plus simple – et l’un des plus représentatifs – consiste à mesure les fluctuations d’un timer. Pour cela un outil est directement fourni. Je le lance en lui demandant de s’exécuter pendant 60 secondes :
pi@raspberrypi:~/xenomai-3.0.3$ sudo /usr/xenomai/bin/latency -T 60 == Sampling period: 1000 us == Test mode: periodic user-mode task == All results in microseconds warming up... RTT| 00:00:01 (periodic user-mode task, 1000 us period, priority 99) RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst RTD| -3.594| -2.786| 1.822| 0| 0| -3.594| 1.822 RTD| -3.647| -2.923| 0.051| 0| 0| -3.647| 1.822 RTD| -3.595| -2.920| 1.613| 0| 0| -3.647| 1.822 RTD| -3.648| -2.946| -0.106| 0| 0| -3.648| 1.822 [...] RTD| -3.616| -2.936| -0.230| 0| 0| -5.017| 1.863 RTD| -3.616| -2.871| 1.488| 0| 0| -5.017| 1.863 RTD| -3.669| -2.848| 0.186| 0| 0| -5.017| 1.863 ---|-----------|-----------|-----------|--------|------|------------------------- RTS| -5.017| -2.893| 1.863| 0| 0| 00:01:00/00:01:00 pi@raspberrypi:~/xenomai-3.0.3$
Ces premiers résultats sont intéressants, ce sont les deux dernières colonnes qui sont les plus significatives.
La dernière colonne indique la pire latence mesurée, c’est à dire le pire retard de déclenchement d’un timer périodique. La valeur de 1,863 microsecondes est excellente, mais le système est au repos et ce n’est pas représentatif.
L’avant-dernière valeur montre la meilleure latence observée. Elle est négative (-5,017 microsecondes), ce qui indique que le timer s’est déclenché plus tôt que prévu. En effet, Xenomai anticipe les retards inhérents au matériel en déclenchant les timers un peu en avance. Ceci est intéressant pour avoir une bonne précision, mais nécessite une calibration. Nous pouvons consulter l’avance par défaut :
pi@raspberrypi:~/xenomai-3.0.3$ cat /proc/xenomai/latency 10052
La valeur est de 10052 nanosecondes soit 10,052 microsecondes. Tous les timers sont donc anticipés de 10 microsecondes environ. Ceci peut être intéressant en production, mais dans un cadre expérimental, ce sont les vraies valeurs de latences qui m’intéressent. Je désactive donc cette avance :
pi@raspberrypi:~/xenomai-3.0.3$ sudo -i root@raspberrypi:~# echo 0 > /proc/xenomai/latency root@raspberrypi:~# cat /proc/xenomai/latency 0 root@raspberrypi:~# exit
Je relance la mesure pendant une minute pour vérifier :
[...] RTD| 6.385| 7.073| 9.979| 0| 0| 5.405| 35.980 RTD| 6.437| 7.077| 10.499| 0| 0| 5.405| 35.980 RTD| 6.436| 7.074| 9.561| 0| 0| 5.405| 35.980 RTD| 6.384| 7.083| 9.874| 0| 0| 5.405| 35.980 ---|-----------|-----------|-----------|--------|------|------------------------- RTS| 5.405| 7.142| 35.980| 0| 0| 00:01:00/00:01:00
Presque 36 microsecondes de latence, voilà qui est plus réaliste (et très bien, notons-le).
Je vais lancer une nouvelle mesure pendant une heure en conservant un histogramme des latences observées :
pi@raspberrypi:~$ sudo /usr/xenomai/bin/latency -T 3600 -g histo-01.plot [...] RTD| 6.492| 7.145| 9.825| 0| 0| 4.229| 36.862 RTD| 6.439| 7.146| 9.877| 0| 0| 4.229| 36.862 RTD| 6.491| 7.166| 9.877| 0| 0| 4.229| 36.862 HSH|--param|--samples-|--average--|---stddev-- HSS| min| 3600| 5.972| 0.205 HSS| avg| 3600017| 6.586| 0.870 HSS| max| 3600| 9.651| 1.783 ---|-----------|-----------|-----------|--------|------|------------------------- RTS| 4.229| 7.199| 36.862| 0| 0| 01:00:00/01:00:00 pi@raspberrypi:~/xenomai-3.0.3$
L’histogramme peut être dessiné par Gnuplot. En abscisse la latence observée en microsecondes et en ordonnée le nombre d’occurrences de chaque classe. Le résultat est le suivant :
Il est intéressant de voir que très peu d’occurrences se produisent au-delà de 10 microsecondes. Pour avoir un aperçu plus précis sur ce qui se passe au-delà de 13 microsecondes, il est préférable de faire une représentation logarithmique en ordonnée qui va dilater et rendre plus visibles les faibles occurrences :
La mesure a été faite alors que le système était au repos, ce qui ne reflète pas un comportement en production. Je relance la mesure en ajoutant une très forte charge du système avec le script dohell
fourni avec Xenomai :
pi@raspberrypi:~$ sudo /usr/xenomai/bin/dohell 3600 & sudo /usr/xenomai/bin/latency -T 3600 -g histo-02.plot RTD| 7.690| 14.418| 49.044| 0| 0| 5.644| 62.846 RTD| 7.637| 14.028| 37.637| 0| 0| 5.644| 62.846 RTD| 7.585| 14.297| 44.356| 0| 0| 5.644| 62.846 RTD| 8.261| 14.237| 33.939| 0| 0| 5.644| 62.846 HSH|--param|--samples-|--average--|---stddev-- HSS| min| 3600| 7.507| 0.799 HSS| avg| 3600006| 14.871| 5.938 HSS| max| 3600| 41.476| 4.462 ---|-----------|-----------|-----------|--------|------|------------------------- RTS| 5.644| 15.366| 62.846| 0| 0| 01:00:00/01:00:00
En outre, des rafales de ping
en mode flood provenaient régulièrement d’un PC, produisant de nombreuses interruptions réseau.
Nous voyons donc qu’il y a une latence intrinsèque de l’ordre de 4.2 microsecondes au repos, et qu’en fonction de la charge du système elle peut aller jusqu’à une soixantaine de microsecondes. Ces résultats sont tout à fait cohérents avec ceux que l’on peut obtenir avec Xenomai sur d’autres cartes à processeur ARM et correspondent bien à ce que l’on attend d’un système d’exploitation complet comme Linux sous des contraintes temps réel fortes.
J’ai également fait l’essai d’ajouter sur la ligne de commande du kernel les options dwc_otg.fiq_enable=0
et dwc_otg.fiq_fsm_enable=0
afin d’éviter l’utilisation des Fast Interrupt Request qui perturbent le déterminisme du traitement des autres interruptions par Xenomai. Cela n’a pas changé les performances observées.
Conclusion
Xenomai 3.0.3 s’installe bien sur un Raspberry Pi 3. La gestion des timers est précise et présente peu de latences, même sous une forte charge système et interruptive.
Toutefois, il y a un point très décevant : je ne suis pas arrivé à gérer (avec l’API RTDM
) les handlers d’interruptions des GPIO. Je suppose que le patch ipipe
n’a pas encore été ajusté pour le Raspberry Pi 3. Il va nous falloir patienter encore un peu, je continuerai à utiliser des Raspberry Pi 2 pour les exemples de mes formations sur le temps réel.
Bonjour,
Est-ce que par « sauf en ce qui concerne la gestion des interruptions des GPIO qui n’est pas supportée encore. » vous voulez dire que toute forme d’interruption n’est pas possible? Par exemple un module externe qui genere une interruption?
you said: (translated in english)
However, there is one very disappointing point: I have not managed to manage (with the RTDM API) the GPIO interrupt handlers . I guess the patch ipipe has not yet been adjusted for the Raspberry Pi 3. We will have to wait a little longer, I will continue to use Raspberry Pi 2
Does this mean that you did get the GPIO interrupt handlers working for the Raspberry Pi 2?
In your RPI2 article I couldn’t find any references to GPIO?
Yes, the GPIO handling works with Raspberry Pi 2 and RTDM.
I’ll try to find an example tomorrow.
I tried to get the rpi2 and RTDM working, however I didn’t succeeded.
I managed to read and write gpio pins from realtime, but everytime I try to trigger an interrupt my pi hangs. I don’t understand what is going wrong???
Could send me an gpio interrupt example which works on the rpi2?
It would really help me!
Much thanks for your this fine page, it already helped a lot!!
best regards,
Harco Kuppens
Hi,
I’m trying to compile a certain code, https://github.com/severinson/VLC-driver after successfully compiling a xenomai-3 based kernel on a raspberry pi 3 as in your article.
My issue is that I believe the code is on an older version of xenomai ( i was able to compile it using xenomai 2.6.3 to be exact). But the raspberry pi 3 needs a newer version of the kernel ( v 4 + ) to boot.
I wasn’t able to find any articles regarding compiling xenomai v2 with linux kernel v4 for raspberry pi 3. If you can guide me on this I would be grateful.
Bonjour,
Merci pour cette procédure d’installation détaillée qui m’a été très utile.
Cependant, j’ai plusieurs erreurs lors de phase de compilation de Xenomai que je n’arrive pas à résoudre :
#make
xenomai-3.0.3/lib/cobalt/arch/arm/include/asm/xenomai/features.h:51:2: error: #error « Could not find current ARM architecture »
#error « Could not find current ARM architecture »
^
/home/queudet-a/Documents/Enseignements-Recherche/Enseignements_2017-2018/EMN/TP/xenomai-3.0.3/lib/cobalt/arch/arm/include/asm/xenomai/features.h:55:2: error: #error « SMP not supported below armv6, compile with -march=armv6 or above »
#error « SMP not supported below armv6, compile with -march=armv6 or above »
^
features.c: In function ‘cobalt_check_features’:
features.c:63:3: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
(__xn_rdtsc_t *)(0xffff1004 –
^
cc1: all warnings being treated as errors
Makefile:486 : la recette pour la cible « libarch_la-features.lo » a échouée
Pourriez-vous m’aider svp ? Pour information, j’utilise la chaîne de compilation croisée Buildroot pour laquelle j’ai lancé au départ un make raspberrypi3_defconfig.
D’avance merci,
Audrey Queudet
Il te faut spécifier l’architecture cible à GCC. Cela ce fait via les Makefiles, eux-même configuré par un autotools.
=> Ce qui implique que tu dois ajouter l’option suivante (pour du 32 bits) lors de l’éxecution du ./configure, soit :
(*1) CFLAGS=’-march=armv7-a -mfpu=vfp3′
Dans Buildroot (version 2017-02) tu peux y parvenir en faisant :
– $ make menuconfig
– Target Package > Real-Time > Additional configure options = (*1)
EDIT : -march=armv7 (4.1.21) & -march=armv7-a (4.9.21)
Quelqu’un sait s’il y a du nouveau sur les interuptions du GPIO avec Xenomai + RPi 3 depuis ce post ? Je n’ai trouvé aucune information ailleurs.
Merci!
Dear sir,
I followed your installation steps of xenomai in raspberry pi 3 preinstalled with noobs but after the kernel compilation successfully, it does not reboot.
pls assist me in solving the above issue.
Regards,
Satish D
Dear sir,
I followed the above steps, but after reboot command, not rebooting. using raspbian jessy latest and raspberry pi 3.
Kindly guide me.
Regards,
Satish D
Hi Christophe,
I’m struggling to find a solution to a freeze for the last 2 weeks or so. My RbPi’s freeze when calling rt_task_set_affinity. Could you please try to run this simple code on yours:
RT_TASK t;
cpu_set_t s;
rt_printf(« Doing dangerous stuff.\n »);
rt_print_flush_buffers();
rt_task_create(&t, NULL, 0, T_HIPRIO, T_JOINABLE);
CPU_ZERO(&s);
CPU_SET(2, &s);
rt_task_set_affinity(&t, &s);
rt_task_delete(&t);
rt_printf(« Done dangerous stuff, goodbye.\n »);
rt_print_flush_buffers();
return 0;
and tell me if you RbPi freezes entirely like mine does?
Thank you,
Corneliu.
I’ve just followed your steps precisely (I was using Raspbian desktop and cross-compiled both the kernel and Xenomai) and doing it _exactly_ as you describe here instead renders a system which does _NOT_ reproduce the freezing!
Given that I’ve spent significant time trying to make this work I’ll slowly move towards my initial setup from this working one and try to identify the exact issue. Finally, I have a reasonable starting point to debug from :).
Afterwards I’ll get back here and post what the actual problem behind the freeze was.
Thank you,
Corneliu.
Ok, so the problem was Xenomai 3.0.5. Apparently there’s a bug in this version.
I actually expected this to be a problem with the kernel or the i-pipe patch, the issue lies only within the Xenomai user-land binaries (tested this by actually only installing 3.0.3 user binaries over a kernel which was already prepped with 3.0.5 version and it worked).
GDB still freezes though if I try to step over in-between a call to rt_task_create() and rt_task_set_affinity() for that task, but this is acceptable for the moment since it only happens if GDB is attached.
Maybe this will help someone.
Cheers, Corneliu.
Bonjour Christophe,
Merci pour cet article très détallé qui m’a permis d’installer sans difficulté Xenomai sur une RPI 3.
Je m’intéresse depuis peu à la question des OS temps réel pour la physique dans le but de simplifier le matériel mais en suivant la démarche de votre livre « Solutions temps réel sous linux » j’ai pu obtenir un premier résultat intéressant sur la mesure de signaux analogiques dans la gamme des 100 Hz.
L’expérience a consisté à faire acquérir à partir d’un CAN 8 voies très bon marché (un mcp 3008) un ensemble de 8 signaux analogiques. En utilisant la fonction CLOCK_REALTIME à chaque mesure on obtient une échelle des temps de précision suffisante. Plus exactement si 2 voies sur les 8 du CAN sont reliées à une même entrée analogique, la reconstitution donne bien des signaux complètement superposables.
Cependant, je souhaiterais aller plus loin et dans le but de paralléliser des acquisitions (plusieurs raspberry en parallèle reliées chacune à un oscillloscope) j’aurais besoin de synchroniser à partir d’un signal reçu sur une broche GPIO. Or il semble que les fonctions RTDM qui gèrent les interruptions ne fonctionnent pas sur mon installation de Xenomai. Y-a-t-il une solution à ce problème ?
Merci d’avance et encore bravo pour le travail réalisé.
Cordialement.
Denis Parenthoine.