M'interrogeant sur la mise en œuvre d'une application sur un µC ColdFire, je me suis rendu compte que cela passait nécessairement par l'utilisation d'un RTOS. Après quelques recherches, j'ai fait quelques expériences que je vais relater ici avec deux RTOS libres : FreeRTOS et Helium que j'ai testés sur S08. Les liens sont donnés sur le forum microcontroleurs 8 bits de Freescale.
Nécessité des OS
Une application un tant soit peu complexe consiste en plusieurs tâches indépendantes. Par exemple, la gestion d'une station météo doit pouvoir assurer par exemple les tâches suivantes:
- La lecture de différents capteurs
- La scrutation d'un clavier
- La mise à jour d'un afficheur LCD
- L'envoi de données sur la liaison série,..
- Et, pour finir, la tâche qui occupe certainement la majorité du temps CPU : Ne rien faire du tout (attendre)
Il y a plusieurs moyens d'organiser tout cela, le plus simple étant l'architecture en boucle qui exécute séquentiellement les différentes tâches (appelée round-robin). C'est cette « architecture » de programme qui est implémentée sur les (tout) petits microcontrôleurs.
Mais cette architecture commence à poser des problèmes dès que le nombre de de tâches à gérer dépasse 2 ou 3, que des timings plus précis doivent être implémentés, et d'autre part, l'ajout d'une ou plusieurs tâches dans cette architecture est problématique [1].
Il faut donc faire appel à des systèmes d'exploitation « OS » (Operating Systems), capable d'ordonnancer les différentes tâches. Dans le cas de microcontrôleurs, ces OS sont qualifiées de « temps réel », dans la mesure où il y a des contraintes temporelles d'échéance pour l'exécution des tâches (durée de validité des données-temps de réponse) et de temps d'exécution de tâches [2].
Bref, l'objectif de cet article n'est pas de refaire toute la théorie des RTOS, que l'on trouvera aux différentes adresses données ci-dessous, mais plutôt de détailler la mise en pratique,d'ailleurs fort similaire de deux de ceux-ci, sur MC9S08.
Les 2 RTOS que j'ai testés sont préemptifs, dans la mesure où une tâche en cours d'exécution peut à tout moment être interrompue par une tâche plus prioritaire.
Mise en oeuvre pratique
Ce qui est spécifique aux différents microcontrôleurs est une routine d'interruptions périodiques, nécessaire à l'ordonnanceur. Sous Hélium, elle s'appelle TickISR, et est générée par le timer MTIM ou TPM, qui produit une interruption environ toutes les 15ms
Implémentation des tâches :
Chaque tâche est une fonction indépendante
- Chaque tâche a la structure d'une boucle infinie (round-robin)
- Chaque tâche possède sa propre pile
- Chaque tâche possède sa propre priorité
Le système d'exploitation (RTOS) fournit un certain nombre de fonctions spécifiques « API », pour la gestion des tâches. Ces API s'occupent, par exemple de:
- La création d'une tâche
- L'attente (blocage de la tâche) pendant un certain temps (nombre de « ticks »)
- La gestion de « mail box » (passage de données -communication- entre les tâches)
- La gestion de mémoire,
- La gestion de sémaphores
etc..
Plus le RTOS est complexe, plus les API sont sophistiquées. FreeRTOS possède par exemple des API capables d'allouer puis de libérer dynamiquement de la mémoire, de gérer des sémaphores, ... . Ce n'est pas le cas d'Helium.
Une tâche est commune à tous les OS : c'est la tâche d'attente : Idle.
Mes tests pratiques :
J'ai essayé deux RTOS : FreeRTOS et Helium, dans le but d'exécuter deux simultanément et indépendamment deux « tâches ». Chaque tâche consiste en le clignotement d'une LED (« tâche » certainement la plus connue et la plus courante dans le monde des microcontrôleurs).
FreeRTOS a été testé sur une carte DEMO9S08GB60, avec BDM OSBDM08. Le code a été
téléchargé de :
http://forums.freescale.com/freescale ... date_ascending&page=2
Post en bas de la page 2 : FreeRTOS_HC(S)08_Versionb_1.0.zip (293kb). Mis à part les tracasseries habituelles de portage d'un projet CW3.1 vers CW5.1 (Non, Alban, ce n'est pas immédiat), le chargement et l'exécution sur la carte d'essai GB60 n'ont posé strictement aucun problème. Sauf.. que le code généré « pèse » 8kB, ce qui fait que :
- Il est difficilement utilisable sur les µC avec peu de Flash
- Cela limite de facto à 8kb le code « utilisateur » de CW special edition.
Ceci dit, FreeRTOS est un OS très riche, très puissant et très sophistiqué. Je l'utiliserai pour les ColdFire. CW pour ColdFire est limité à 128k; m68k-gcc n'est pas limité. Bon, FreeRTOS sur CF fait quelques dizaines de Ko.
Face à cette constation, j'ai essayé un autre RTOS, HELIUM proposé également sur le forum Freescale et basé ici : http://helium.sourceforge.net/ . J'ai essayé la version 1.0 (chez moi, la version 1.1 provoque actuellement une erreur d'exécution). Helium occupe 1kb de code, donc bien implantable sur des petits uC même avec aussi peu que 4 ou 8 Kb de Flash.
Après avoir créé l'appel de la routine d'interruption « TickISR » suivant la procédure décrite dans le Programmer's Manual, j'ai élaboré le « main.c » suivant, que je vais commenter en détail. L'objectif est de faire clignoter 2 LEDS (sur PTB6 et PTB7) via 2 tâches indépendantes sur une carte DEMO9S08QG8.
Le main.c est le suivant :
L'on voit :
-1- : Implémentation de la tâche d'attente « Idle ». Sur Helium, elle n'existe pas dans l'OS; dans FreeRTOS, elle est générée automatiquement. Cette tâche peut, par exemple, calculer le taux d'occupation du processeur, ou appeler une autre fonction (appelée IdleHook dans FreeRTOS) qui place le CPU dans un mode basse consommation.
-2- : La déclaration des stacks. Dans la version 1.0 d'Helium, la taille est fixée et la même pour toutes les tâches. Dans la version 1.1, elle est variable pour chaque tâche.
-3- : La création des tâches, via l'appel de la fonction TaskCreate. Les arguments sont : La priorité de la tâche (0 est la priorité la plus élevée), un pointeur vers la tâche (nom de la fonction), et un pointeur vers la stack associée à chaque tâche.
-4- : StartExecution donne la main à l'OS.
MCUnit a été générée avec le « device initialisation », et lance, entre autre, le timer (MTIM ou TPM) pour une interruption (appel de TickISR) toutes les 15 msec.
Les deux « tâches » sont les suivantes (toujours dans le main.c) :
(Rem : Pour le clignotement des LEDS, ne pas oublier de mettre PTBDD=0b11000000 dans MCU_Init)
On remarque que :
- Elles sont déclarées comme des fonctions sans paramètres ni return,
- Ce sont des boucles infinies
- Il y a un appel à une fonction de l'OS : TimeBlock(n) : Cette fonction bloque l'extécution de la tâche pour « n » ticks (de la routine d'interruption). Ici, une interruption toutes les 15 msec : une led clignotera toutes les 0,3 sec, l'autre 1,2 sec.
Helium propose d'autre fonctions, notamment de communication entre les tâches « MsgBox ». RTOS a des implémentations plus compliquées de sémaphores par exemple.
La tâche la plus fréquente a la plus haute priorité. Elles interrompent toutes les deux la tâche « Idle »
Conclusion
Voilà qui résume mes premiers essais de mise en œuvre de RTOS. Ce n'est pas simple d'un point de vue théorique, mais c'est bien dans la continuation de la passionnante aventure des microcontrôleurs.
Helium est un beau petit RTOS , compact, facile à mettre en pratique. On voit qu'il est très facile d'ajouter des tâches et de régler les temporisations. Il doit être très facilement portable sur d'autres 9S08 et 908.
Quelques liens (il y en a bien d'autres, mais je ne cite que les plus intéressants d'après moi):
http://www.montefiore.ulg.ac.be/%7Eboigelot/cours/spe/ [1]
http://deptinfo.cnam.fr/~paradinas/cours/ [2]
http://www.freertos.org/
http://helium.sourceforge.net/
Dernière remarques : Il est amusant de constater que dans les « benchmarks FreeRTOS », l'âne de la classe n'est autre ... qu'un #.IC# 18.
Si quelqu'un est intéressé, me contacter, j'enverrai les projets CW 5.1 (par mail).
thierry