Le noyau Temps Réel
Instructions
Utilisation
Exemple
Principe
Le noyau temps réel développé
dans ce système est relativement simple. Son principe est
de faire un balayage d'une liste chaînée de descripteurs de tâches toutes les
millisecondes. Ces descripteurs contiennent 5 informations par tâche:
- un mot (16 bits) donnant le niveau
de priorité de la tâche ce qui permet d'avoir 65535
niveaux différents. Le niveau 0 est réservé à l'interpréteur/compilateur FORTH.
- un mot (16 bits) donnant
la durée en millisecondes (jusqu'à 8192) à
attendre avant de lancer la tâche. Ce nombre est
initialisé à chaque activation de la tâche
(instruction "T_ACTIVE" ou "T_PERIODE") et
décrémenté toutes les millisecondes par le noyau
temps réel. La tâche est lancée lorsque sa valeur
est nulle et que le niveau de priorité est supérieur au
niveau des tâches en cours d'exécution. Cette valeur est
mise à "-1" lorsque la tâche est effectivemen
lancée.
- un long mot (32 bits) donnant l'adresse
du descripteur de la tâche suivante. Sa valeur est 0 à la fin de la liste.
- un mot (16 bits) donnant la
périodicité de la tâche en millisecondes
(jusqu'à 8192) lorsqu'elle est initialisée par
l'instruction "T_PERIODE".
- un mot (16 bits) donnant la
prochaine durée en millisecondes (jusqu'à 8192) à
attendre lors d'une relance de la tâche par l'instruction
"T_ACTIVE".
Toutes
les millisecondes, le noyau
temps réel incrémente la variable "TEMPS" puis scrute
cette liste pointée par la variable
"TACHE". Le niveau de priorité de la tâche en cours
d'exécution est stocké dans la variable "PRIORITE". La liste est automatiquement ordonnée par
ordre de priorité décroissante afin d'optimiser les temps d'exécution
des tâches les plus prioritaires.
Si le niveau de priorité scruté
est nul, il considère qu'il n'y a pas de tâche à
gérer. Sinon, il lit le nombre de millisecondes.
Si le nombre de millisecondes es
strictement supérieur à zéro, il le décrémente
et passe à la tâche suivante. S'il est négatif,
c'est que la tâche est endormie. S'il est nul, il compare
le niveau de priorité à celui qui est mémorisé.
Si le
niveau de priorité de
la nouvelle tâche est inférieur ou égal au
niveau mémorisé, le séquenceur se contente de
décrémenter les compteurs des tâches suivantes.
A la fin du balayage, le séquenceur
examine l'adresse mémorisée. Si elle est nulle,
c'est qu'aucune tâche ne doit être lancée.
Sinon, il empile dans la pile de retour le niveau de priorité
de la variable "PRIORITE" qui est ensuite chargée avec le nouveau
niveau. Il lance ensuite l'exécution de la nouvelle tâche.
Une fois la tâche terminée, il dépile depuis
la pile de retour le niveau de priorité précédent
et le remet dans la variable "PRIORITE".
Les experts l'auront compris, pour
que cela fonctionne, le noyau temps réel est ré-entrant.
Instructions
- TEMPS
adresse
Variable contenant la valeur d'un compteur
tournant (32 bits) incrémenté toutes les millisecondes
par le noyau temps réel
- PRIORITE
adresse
Variable indiquant le niveau de priorité
courant au noyau temps réel
- T_SUSPEND
adresse
Variable permettant de suspendre le noyau
temps réel (si différente de 0)
- TACHE
adresse
Adresse du début de la liste chaînée
des tâches du noyau temps réel
- TACHE: "nom" -
Entête de définition d'une tâche,
le mot suivant cette instruction donne le nom de la tâche
Cette définition sera terminée
avec l'instruction ";"
ATTENTION: une tâche doit laisser
la pile dans le même état avant et après son
exécution (ce qui ne l'empêche pas de l'utiliser)
Lorsque la tâche est appelée
par son nom, elle ne retourne que l'adresse d'exécution
tâche
T_EXECUTE
-
Exécution de la tâche spécifiée
(utilisé pour mise au point)
tâche, niveau T_AJOUTE -
Ajout de la tâche spécifiée
dans la table des tâches avec le niveau de priorité
spécifié (1 à 65535)
tâche, millisecondes T_ACTIVE
-
Activation de la tâche spécifiée
dans le nombre de millisecondes spécifié (1 à 8192)
millisecondes,
tâche T_PERIODE -
Activation périodique de la tâche
spécifiée dans le nombre de millisecondes spécifié
(1 à 8192)
tâche T_RETIRE -
Retrait de la tâche spécifiée
de la table des tâches
- TLIST
-
Liste les tâches gérées
par le noyau en indiquant leur niveau de priorité et leur
état d'activité
Utilisation
Le noyau temps réel décrit
dans cette page est efficace par sa simplicité de fonctionnement.
Ceci ne va pas sans nécessiter une certaine rigueur du
développeur.
C'est en effet au développeur
de gérer correctement les différentes durées
d'exécution des tâches et de leur endormissement.
Il faut considérer que plus la tâche est prioritaire,
plus elle doit être rapidement exécutée et
plus la durée d'endormissement doit être longue (proportionnellement)
pour permettre l'exécution des tâches les moins prioritaires.
Par exemple, une tâche de gestion
d'un périphérique sera de priorité élevée
et se contentera de dialoguer avec le système par l'intermédiaire
d'une pile de type premier entré premier sorti (First In
First Out).
Par contre, une tâche d'impression,
relativement longue car les données doivent en générale
être converties (image par exemple) dans le format de l'imprimante
qui, la plupart du temps, est relativement lente, sera quant à
elle de priorité basse avec de nombreux temps morts optimisés
selon le temps de réponse de l'imprimante.
Dans le système présenté
sur ce site, toutes les tâches faisant accès à
l'écran graphique sont au même niveau de priorité,
fixé arbitrairement à 32768, ce qui permet de synchroniser
les rafraîchissement des différentes fenêtres.
Les tâches d'accès aux périphériques,
comme la liaison série, sont donc de niveau supérieur
à 32768 et les tâches de fond, comme l'impression,
sont de niveau inférieur à 32768.
Exemple
Afin de mieux appréhender les
possibilités du noyau temps réel, voici un programme
simple qui utilise toutes les instructions de gestion des tâches.
Il s'agit d'un programme permettant
d'émettre un bip sonore (instruction "BELL")
toutes les secondes.
La fenêtre d'édition
donne le contenu du programme. L'instruction "BIP_BIP_ON"
déclare la tâche "T_BIP_BIP" dans la table
des tâches et l'instruction "BIP_BIP_OFF" permet de
la retirer (utile quand ça commence à casser les
pieds...).

Il est aussi possible d'utiliser l'instruction T_PERIODE qui active et relance automatiquement la tâche:
TACHE: T_BIP_BIP
BELL
;
: BIP_BIP_ON
49152 T_BIP_BIP T_AJOUTE 1000 T_BIP_BIP T_PERIODE
;