Document fait avec Nvu Document made with Nvu




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
;