enserb3.gif (5977 octets)

 

LE NOYAU TEMPS REEL uC/OS - uC/OS II

 

Y.BENABEN - Stage IUT GEII Bordeaux 1

Patrice KADIONIK kadionik@enseirb.fr

http://www.enseirb.fr/~kadionik

 

barre.gif (2311 octets)

 

arrowleft.gif (977 octets)

 

8 - Mise en place d’un noyau multitâche temps réel µC/OS - µC/OS II.

 

    8.1 - Introduction : qu'est ce qu'un système temps réel ?

    Pour expliquer brièvement le rôle d'un système multitâche, je vais présenter le logiciel µC/OS-II (version 68HC11) conçu et mis au point par Labrosse. Le logiciel µC/os-II est un noyau temps réel qui permet d'effectuer une exécution de plusieurs tâches sur un microcontrôleur 68HC11 ou un microprocesseur (680x0 par exemple). On peut trouver sur le site Internet de µC/OS II ( http://www.ucos-ii.com/ports.htm ) les différentes versions de µC/OS II portées sur des systèmes différents (Motorola famille 680x0, 68HC11/16, Power PC 860, Intel 80x86, Philips XA...). Ce noyau multitâche est fourni gratuitement sur le site Internet et un manuel écrit par l'auteur peut être commandé à l'adresse précédente.

 

   8.2 - Le rôle du µC/OS sur le 68HC11.

    Le multitâche / monoprocesseur permet d'effectuer à l'échelle humaine plusieurs tâches simultanément. En effet l'utilisateur peut alors diviser son projet en plusieurs tâches indépendantes. Au niveau du processeur, une seule tâche est effectuée à la fois mais le multitâche permet d'éliminer les temps machines inutilisés (boucle d'attente...).


 
 

ucos1.gif (26639 octets)

Figure 7 – les différents états des tâches
( source : http://www.on-time.com/index.html )

Le fonctionnement du noyau temps réel sur le 68HC11 est le suivant :

arrowr.gif (868 octets) lors de l'initialisation du programme µC/OS-II, les différents programmes de l'utilisateur sont considérés comme des tâches qui sont toutes créées pendant cette période d'initialisation. Le programmeur doit alors spécifier le point d'entrée de la tâche, l'emplacement des données pour cette tâche, l'adresse haute de la pile de la tâche et le degré de priorité de la tâche. Ainsi la tâche de plus haut degré de priorité et prête est exécutée par le microcontrôleur ( on dit que le noyau est préemptif ). La figure 7 montre les différents états des tâches lors du fonctionnement du noyau multitâche.
 
 

eye.gif (1122 octets)Remarque : dans le noyau µC/OS, l'utilisateur dispose de 64 tâches (56 réellement disponibles) où chaque degré de priorité correspond à une tâche, c’est-à-dire que 2 tâches ne peuvent pas avoir le même degré de priorité ( pas de "round-robin" ou "méthode du tourniquet").
 
 

    Les caractéristiques essentielles du noyau temps réel µC/OS sont les suivantes :

arrowr.gif (868 octets) création et gestion de 63 tâches maximum.

arrowr.gif (868 octets) création et gestion de sémaphores binaires et comptés.

arrowr.gif (868 octets) fonction d'attente de tâche.

arrowr.gif (868 octets) changement de priorité des tâches.

arrowr.gif (868 octets) effacement de tâches.

arrowr.gif (868 octets) suspension et continuation de tâches.

arrowr.gif (868 octets) envoi de messages depuis une routine d'interruption (ISR) ou d'une tâche vers une autre tâche.
 
 

    Les tâches peuvent ainsi communiquer avec d’autres tâches (grâce aux sémaphores, boîtes aux lettres, files d’attentes…) ou bien avec des périphériques grâce aux ISR ( Interrupt Service Routine) dont la liste complète est disponible dans la note d'application AN711 de chez Philips.

Top

    8.3 -  Notion de temps réel.

   La notion de temps réel correspond à la façon dont les tâches sont exécutées dans le temps : le temps d'exécution des tâches étant déterminant pour la commutation des tâches, le noyau temps réel exécute en premier les tâches dont le temps d'exécution est critique.

 

    Le fonctionnement du noyau préemptif est illustré à la figure suivante :
 
 

ucos2.gif (8770 octets)

Figure 8 – illustration d’un noyau préemptif.
( source : note d'application Philips AN711  )

    Comme nous le voyons, une tâche de faible priorité est exécutée en (1) alors qu’une interruption asynchrone intervient en (2). Le microprocesseur saute donc au vecteur d'interruption exécutant alors une tâche prête de degré plus important que la tâche précédente (3). A la fin de la routine d'interruption, l'ISR (Interrupt Service Routine) invoque un service du noyau (4) qui décide de retourner à la tâche de plus haute priorité et non à la tâche précédente de plus basse priorité. La tâche de plus haut degré s'exécute donc (5) de manière normale à moins qu'une nouvelle interruption n'arrive. A la fin de la tâche de haute priorité, le noyau reprend l'exécution de la tâche de plus faible priorité qui est prête depuis son interruption (6). Comme on peut le voir, le noyau garantit que les tâches dont le temps d'exécution est critique sont effectuées en premier.
 

    Un noyau temps réel assure principalement 2 fonctions : l'ordonnancement et le changement de contexte. L'ordonnancement permet de déterminer quelle tâche prête a le plus haut degré de priorité. Quand une tâche de plus haute priorité doit être exécutée, le noyau doit sauvegarder toutes les informations nécessaires de la tâche en cours d'exécution afin de permettre une éventuelle continuation. Les informations sauvegardées (appelées contexte de la tâche) sont généralement les registres (A, B, X, Y, CCR pour le HC11), la pile et le pointeur de pile de la tâche qui va être suspendue. Lors de l'exécution d'une nouvelle tâche à un plus haut degré de priorité, le contexte de la nouvelle tâche est chargé puis l'exécution reprend là où elle s'était interrompue.
 

Top

    8.4 - La création des tâches.

    La création d'une tâche se fait grâce à la fonction suivante :

OSTaskCreate(AppTask1, (void *)0, (void *)&AppTask1Stk[255], 10);

    Le premier paramètre est le point d'entrée du programme utilisateur (nom de l'étiquette), le second paramètre indique l'adresse des données, le troisième paramètre indique l'adresse du haut de la pile de la tâche et le dernier paramètre indique le degré de priorité de la tâche (ici 10). Pour plus de précision, on pourra consulter le fichier OS_CPU_C.C (contenu dans c68hc11.zip), le fichier 68hc11.c (contenu dans 68hc11_1.zip) ou bien dans le manuel adéquat de µC/OS.


 
 

    Le corps de la tâche est constitué de la manière suivante :

arrowr.gif (868 octets)une zone d'initialisation de la tâche.

arrowr.gif (868 octets) une zone permettant d'initialiser les variables du programme utilisateur.

arrowr.gif (868 octets) une zone constituée d'une boucle infinie où l'utilisateur place le code de son programme.

arrowr.gif (868 octets) une instruction OSTimeDly(x) permettant de céder x coups d'horloge aux autres tâches.
 
 

eye.gif (1122 octets)remarque: cette instruction est obligatoire dans le contenu du programme de la tâche afin de basculer vers d'autres tâches.
 

Top

    8.5 - Les fonctions de µC/OS.

    Les fonctions de base du noyau temps réel employées dans le programme test.c (archive test.zip) sont les suivantes :

arrowr.gif (868 octets) OSinit(); initialisation globale du noyau

arrowr.gif (868 octets) OSTaskcreate (pointeur sur le programme utilisateur, pointeur données, adresse haut de la pile, priorité); permet de définir une tâche. Le pointeur "données" permet de faire passer des données à une tâche lors de son initialisation. La priorité est définie telle que plus le nombre est faible, plus le degré de priorité est élevé.

arrowr.gif (868 octets) OSStart(); permet de créer au moins une tâche en appelant OSTaskCreate();
 
 

    D'après la remarque précédente, le fonctionnement correct de µC/OS exige qu'une tâche doive obligatoirement appeler une fonction (un service du noyau) afin de :

arrowr.gif (868 octets) faire attendre la tâche d'un délai de n coups d'horloge (OSTimeDly).

arrowr.gif (868 octets) attendre un sémaphore.

arrowr.gif (868 octets) attendre un message d'une autre tâche ou d'une ISR (Interrupt Service Routine : il peut s'agir d'une fonction du noyau qui permet de modifier le statut d'une tâche comme le degré de priorité d'une tâche).

arrowr.gif (868 octets) suspendre l'exécution de cette tâche.
 
 

    Les fonctions du noyau commencent toutes par les lettres « OS » (Operating System), les lettres suivantes OS définissent les familles de fonctions de µC/OS II. La liste des fonctions de µC/OS II est la suivante :

arrowr.gif (868 octets) initialisation (OSinit, OSStart).

arrowr.gif (868 octets) la gestion des tâches (OSTaskCreate, OSTaskDel, OSTaskDelReq, OSTaskChangePrio, OSTaskSuspend, OSTaskResume, OSSchedlock, OSSchedUnlock).

arrowr.gif (868 octets) la gestion du temps (OSTimeDly, OSTimeDlyResume, OSTimeSet, OSTimeGet).

arrowr.gif (868 octets) la gestion des sémaphores (OSSemCreate, OSSemAccept, OSSemPost, OSSemPend, OSSemInit).

arrowr.gif (868 octets)la gestion des boîtes aux lettres (OSMboxcreate, OSMboxAccept, OSMboxPost, OSMboxPend).

arrowr.gif (868 octets) la gestion des files d'attente (OSQCreate, OSQAccept, OSQPost, OSQPend).

arrowr.gif (868 octets) la gestion d'interruption (OSIntEnter, OSIntExit).
 
  Les explications complètes, les exemples et la syntaxe des primitives figurent dans l'ouvrage "µC/OS-II book The real Time Kernel" de J. Labrosse. C'est l'ouvrage de référence !!!

 

La syntaxe succinte des primitives est aussi donnée dans la note d'application AN711 de chez Philips (http://www.ucos-ii.com/files/an711.pdf). Le fichier PostScript ucosman.ps (ftp://ftp.cygnus.com/pub/embedded/ucos/ucos-arm/) est aussi utile mais il faut faire attention car quelques primitives ont été modifiées pour des besoins spécifiques (voir sémaphores).

Top

    8.6 - La communication entre tâches.

    Voici un bref descriptif des moyens qu’offre µC/OS pour la communication entre tâches.

 

        8.6.1 - Les sémaphores.

   Un sémaphore est un objet qui permet de résoudre les problèmes de synchronisation entre plusieurs tâches concurrentes.

   Un sémaphore est constitué d'un compteur à valeur entière (valeur du sémaphore) et d'une file d'attente. Sur le compteur sont définies 2 opérations qui sont Prendre (P) et Vendre (V). Une valeur positive du sémaphore désigne le nombre d'accès disponibles à un instant donné ; une valeur négative représente par la valeur absolue le nombre de processus en attente de libération de la ressource. En effet, avant d'accéder à une donnée, un processus doit utiliser l'opération P. Si la valeur du sémaphore est 0, alors le processus doit attendre que cette valeur devienne supérieure à 0. Si la valeur est supérieure à 0, alors l'opération P décrémente la valeur du sémaphore et le processus continue son exécution. Après l'accès aux données, le processus doit appeler l'opération V qui incrémente le sémaphore autorisant ainsi aux autres processus l'accès aux données.

 

    Les sémaphores permettent donc soit de synchroniser des processus (échanges de données), soit d'exclure des processus concurrents (accès à une même variable en même temps). Un exemple d’utilisation de sémaphores est  disponible ici test2.c (archive test.zip).
 
 

        8.6.2 - Les boîtes aux lettres.

   Une boîte à lettre est une zone d'échange entre 2 processus et se compose de 2 files d'attente : une file d'attente de messages et une file d'attente de tâches. Les boîtes aux lettres permettent de synchroniser la communication entre des tâches asynchrones.


  

            8.6.3 - Les files d'attente.

   Une file d'attente constitue une suite de processus en attente d'un évènement, d'un sémaphore…On trouve alors des files d'attente d'évènements (les processus attendent un certain type d'évènement), des files d'attente sur sémaphore (les processus sont gérés par ordre d'arrivée : une opération Prendre non passante amène la tâche à la fin de la file et pour chaque opération Vendre c'est la première tâche en attente qui est activée) et enfin des files d'attente sur boîtes aux lettres.

 

Top

    8.7 - Mise en place du noyau µC/OS.

        8.7.1 - Modification des fichiers de compilation et d’édition de liens.

   Le noyau temps réel µC/OS est écrit en langage C (COSMIC SOFTWARE 4.5). Seuls les portages spécifiques au microcontrôleur (ici le 68HC11F1) sont écrits en langage d'assemblage. Le travail a consisté en premier lieu à adapter le noyau µC/OS au 68HC11Ax et Ex. Les lignes à modifier sont dans les fichiers start.s et build.bat.

 

    Le fichier start.s contient des initialisations propres au 68HC11F1 telles que :

arrowr.gif (868 octets) les bits de protection de la EEPROM (4 bits de poids fort du registre CONFIG).

arrowr.gif (868 octets) l'activation de la logique de décodage (rattachée au PORTG) des boîtiers de RAM et de ROM externes (pas besoin de 74HC138).

arrowr.gif (868 octets) le pointeur de pile et l’initialisation des 1024 octets de RAM.
 
 

    Les modifications à apporter ont consisté à enlever la configuration des bits de protection de la EEPROM et de la logique de décodage interne, l'initialisation des 256 octets de RAM interne et le pointeur de pile en $0FF.
 
 

eye.gif (1122 octets)Remarque: le mode étendu de la carte mère permet de prolonger la mémoire RAM interne jusqu'à l'adresse $0FFF soit 4Ko de RAM disponible. Il faudra donc prendre soin de ne pas faire "interférer" la pile du moniteur BUFFALO et celle de µC/OS.
 

   Le fichier build.bat doit être configuré pour appeler le fichier io.h (et non pas iof1.h) qui est situé dans le répertoire de Cosmic Software (ex : C:\logiciel\68HC11\cx32\H6811\IO.H ).
 

eye.gif (1122 octets)Remarque importante : lors de la compilation, l'archive de µC/OS II (c68hc11c.zip) ne contient pas les fichiers os_core.c, os_mbox.c... nécessaires lors de la compilation de Ucos_II.c mais le fichier objet est heureusement fourni sous le nom de Ucos_ii.o situé dans le répertoire UCOS-II/M68hc11/Cosmic/obj. Il faut donc "commenter" les lignes suivantes du fichier build.bat :

rem DEL ..\OBJ\uCOS_II.O

rem C:\logiciel\68HC11\cx32\CX6811 -cl..\LST -co..\OBJ -e -gv -l -ocv -v +nowiden +sprec +debug uCOS_II.C
 
 

Top

        8.7.2 - Programmes pour µC/OS II.

                a-Compilation et éditions de liens.

    La mise en place du noyau temps réel pour 68HC11Ax ou Ex s'est faite grâce à l'émulateur CT68HC11. Le programme µC/OS sera donc installé dans la mémoire interne de 64Ko de l'émulateur ou bien en RAM externe après avoir programmé correctement l'EPROM aux adresses $7FE8 (avec $206A) et $7FF6 (avec $2036) ainsi que le vecteur de RESET (pour plus de précisions se reporter au fichier vectors.c (dans l'archive test.zip). µC/OS-II est fourni avec un programme test.c (archive test.zip) qui permet de créer 3 tâches : une tâche de démarrage (AppStartTask) qui va créer 2 autres tâches (task#1 et task#2) lesquelles vont être mises en compétition avec des degrés de priorité différentes (Noter que la tâche de démarrage a le plus haut degré de priorité).


 

    La figure suivante illustre simplement l’ordonnancement des 3 tâches. L’ordonnanceur peut continuer ou suspendre une tâche grâce aux signaux « continue » et « suspend » représentés ici par des flèches en pointillés. Lorsqu’une tâche est suspendue, la suivante et continuée. Le schéma montre comment sont ordonnancées les tâches mais ne précise pas comment fonctionne la communication entre les tâches ou avec les périphériques.
 
 

ucos3.gif (6117 octets)

Figure 9- l’ordonnancement des tâches.
( source : A premptive kernel )

   Le programme mis au point pour la carte mère est basé sur l'exemple test.c fourni dans l'archive c68hc11.zip. Le programme crée une première tâche qui consiste à faire un écho sur la liaison série RS232 configurée à 9600bps, puis une deuxième tâche qui consiste à exécuter un chenillard 4/5 LEDs (PA7 est configurée par PACTL et PA3 est condamnée si on utilise le moniteur BUFFALO) enfin une troisième tâche qui recopie les interrupteurs du PORTE sur le PORTA.
 
 

    Le fichier test.lnk permet de configurer la mise en mémoire du noyau µC/OS :
 
 

+seg .bsct -b 0x0000 -m256 #zéro page

+seg .bss -b 0x7000 -m8192 #adresse de la pile

+seg .text -b 0x2000 -m32726 -n .text #adresse début du programme

+seg .const -a .text #début des données

../OBJ/START.O # routine de démarrage : initialisation de la RAM,

../OBJ/OS_CPU_A.O #du pointeur de pile...

../OBJ/OS_CPU_C.O

../OBJ/TEST.O

../OBJ/uCOS_II.O #fichier fourni avec l'archive c68hc11.zip à ne pas recompiler

../OBJ/hc11lib.o #bibliothèque de fonctions externes.

C:/logiciel/68HC11/cx32/LIB/LIBF.H11 #bibliothèques Cosmic software

C:/logiciel/68HC11/cx32/LIB/LIBI.H11

C:/logiciel/68HC11/cx32/LIB/LIBM.H11

#+seg .const -b 0xFFD6 -m42 #table des vecteurs d'interruption.

#../OBJ/VECTORS.O
 

    Les 2 dernières lignes ne sont à commenter que si µC/OS marche avec le moniteur BUFFALO en EPROM. En effet, les vecteurs d'interruptions doivent être programmés dans l'EPROM . Si les lignes ne sont pas commentées, l'émulateur ou BUFFALO renverra un message d'erreur d'écriture.

    La mise en place du programme multitâche se fait grâce à la commande  LOAD T du moniteur BUFFALO après avoir converti le fichier.hex en .S19.

    L'exécution du programme se fait par la commande G 2000. On observe alors le fonctionnement correct des tâches. L'utilisation de la fonction OSTimeDly permet donc de faire des temporisations dont l'unité est le tick, laissant ainsi ces cycles  d'attente à d'autres tâches.  

Top

                b - Quelques explications concernant le fonctionnement des sémaphores.

   Un deuxième programme a permis de mettre en évidence le fonctionnement des sémaphores avec µC/OS II. Le programme test2.c permet de synchroniser 3 tâches. La tâche #1 attend le sémaphore sem1 et lorsque celui - ci est validé, la tâche allume la LED PA5. De même pour la tâche #2 qui attend le sémaphore 2 (sem2) et allume la LED PA6. La tâche 3 attend le sémaphore 3 (sem3) et allume la LED PA7. La tâche principale (celle qui a la plus forte priorité) permet de valider les 3 sémaphores en « même temps » après avoir exécuté une temporisation ( fonction OSTimeDLy).

    Il est intéressant de se reporter au document ucosman.ps qui explique le fonctionnement des sémaphores. Lors de la création d’un sémaphore (initialisation), on spécifie la valeur du sémaphore qui est nulle dans l’exemple test2.c (archive test.zip).

    En effet une tâche peut être mise en attente avec la fonction OSSemPend qui décrémente la valeur du sémaphore si elle était nulle. Lorsque le sémaphore est négatif, la fonction OSSEmPend attend alors que la valeur du sémaphore redevienne nulle (elle attend l’incrémentation du sémaphore). Ceci est effectué par la tâche principale grâce à la fonction OSSemPost qui incrémente le sémaphore si sa valeur était nulle et donne la main à la tâche de plus haute priorité qui soit en attente de sémaphore.

    Par la suite, les tâches poursuivent leur exécution normale. Pour réutiliser les sémaphores, il faut les réinitialiser grâce à la fonction OSSemInit().

 

    Le noyau µC/OS II permet donc de développer des applications 68HC11 multitâches en langage C de Cosmic Software. Les fonctions de communications entre tâches et les ISR permettent de concevoir des programmes performants. Le portage du noyau µC/OS II a divers processeurs et microcontrôleurs le rend populaire pour le développement d’applications multitâches temps réel.
 

Top
 

arrowleft.gif (977 octets)