| PICOS18 > Internals |
|
|
PICos & PICos18 : Internals Ce qui suit à pour objectif de présenter l'architecture
interne de PICOS, afin de permettre aux développeurs de mieux comprendre
les interractions entre le noyau et les applications, pour faciler le
débuggage, et enfin pour favoriser la participation au développement
de nouvelles fonctionnalités de ce noyau. |
![]() |
| > La norme OSEK / VDX |
Dans le début des années 90, des constructeurs automobiles européens
cherchent à définir un noyau temps-réel pour systèmes
embarqués. Des constructeurs allemands comme BMW, Bosch, Opel et Siemens
créent alors la norme OSEK (Offene Systeme und deren Schnittstellen
fur die Elektronik im Kraftfahrzeug). De leur côté, les sociétés
françaises comme PSA et Renault développent un système
similaire batisé VDX (Vehicle Distributed eXecutive).
Finalement les projets finirent par fusionner pour ne devenir qu'une seule norme
: la norme OSEK / VDX.
Afin de développer le noyau PICOS18 conformément à cette norme, je me suis basé sur les 2 documents suivants :
|
La norme OSEK
/ VDX 2.1 révision 1
|
Le livre de Joseph LEMIEUX des éditions
CMPbooks.
Ce livre détaille la réalisation d'un jeux de cartes sur le noyau OsekWorks de la société WindRiver. |
La norme OSEK / VDX repose sur 4 sous-ensembles :
... et bientôt sur 3 sous-ensembles supplémentaires :
Les versions actuelles de PICos & PICos18 ne respectent que la norme
OS de OSEK.
L'objectif premier est donc de répondre parfaitment à cette norme,
puis d'intégrer les moyens de communications définis par COM et
enfin ajouter à PICOS des services réseaux conformément
à la norme NM.
| > Performances du noyau PICos |
Le noyau PICos présente les performances suivantes :
| Type de noyau : |
Multi-tâche préemptif
|
| Processeurs cibles : |
Familles des PIC18 - PIC24 - PIC30
et PIC33 (Microchip)
|
| Taille du noyau (ROM) : |
< 1 Ko
|
| Taille du noyau (RAM) : |
7 octets
|
| Taille des service (ROM) : |
4 Ko
|
| Taille des services (RAM) : |
121 octets
|
| Taille de la pile hardware : |
32 appels de fonctions pour toutes
les tâches
|
| Taille de la pile software : |
128 octets
|
| Temps de latence du scheduler : |
24, 5 µs (Freq = 40 MHz)
|
| Nombre de tâches : |
16
|
| Nombre d'évènements par tâche : |
8
|
| Nombre de priorités : |
15
|
| Nombre de timers logiciels : |
Pas de limites
|
| Taille (contexte+pile) d'une tâche : |
entre 128 et 256 octets
|
Ces performances sont suffisantes pour le développements d'applications
sur PIC. Le noyau, les services et la pile logicielle ne monopolisent que la
première banque de RAM. Le noyau et les services prennent moins
de 5 Ko de mémoire de code.
Le nombre de tâches gérables par le scheduler est de 16, ce qui n'est pas une grande limitation en soit. Créer une application avec plus de 16 tâches synchronisées et dialogant entre elles n'est pas une chose aisée ! Découper une application en 20 ou 30 tâches distinctes n'est pas forcément une bonne idée, et il vaut mieux concentrer les actions similaires au sein de même tâche (affichage sur LCD, gestion des communication, traitement du signal,..).
Enfin le temps de latence permet de belles performances pour des applications critiques. En effet le temps de latence du scheduler (temps prie par le noyau afin de déterminer la prochaine tâche active, puis de l'activer pour finalement arriver dans la tâche) est meilleure que celui de QNX sur un 386EX à 33 MHz !!
| > La gestion des tâches |
Toutes les informations concernant les tâches de l'application sont contenues sur une seule ligne de donnée en RAM. Cette zone de la RAM réservée au noyau est appelée la zone de description de tâches en RAM.

Sur la partie de droite, on retourve 8 octets (1 octet par tâche),
dont 3 sont non nuls. L'application comporte donc 3 tâches. Ces tâches
sont en fait classées de gauche à droite, de la plus prioritaire
à la moins prioritaire. Sur 8 bits, les 4 bits de poids forts représentent
l'ID de la tâche, tandis que les points faibles représentent l'état
de la tâche.
Dans cet exemple issu du tutorial,
nous pouvons en déduire que :
Sur la partie de gauche, on retouve encore 8 octets (1 octet par tâche), dont 3 sont non nuls. A chaque octet correspond la tâche décrite par le même octet dans la zone de droite. Sur 8 bits, les 3 bits de poids forts indiquent la priorité de la tâche, et les 5 bits restants représentent l'adresse du pointeur de pile hardware (STKPTR) de la tâche.
Au vu de l'image ci-dessus, nous pouvons dire que :
Remarque :
La zone du descripteur de tâche en RAM contient donc 2octets de description
par tâche. Or ces octets sont rangés en mémoire de la tâche
la plus prioritaire à la moins prioritaire. Or la norme OSEK ne précaunise
pas de pouvoir manipuler la priorité des tâches en fonctionnement.
Il ne devrait alors pas être nécessaire de garder en mémoire
la priorité de chaque tâche ! Toutefois la norme OSEK stipule l'emploi
d'un méchanisme de CEILING PROTOCOL dans le cas d'accès aux ressources
(entrée en région critique), ce qui conduit à des modifications
temporaire des priorités...
Afin de pouvoir construire la zone de description des tâches en RAM (construction effectuée par le noyau), il faut nécessairement déclarer et paramétrer les tâches de l'application dans une zone de code : c'est la zone de description des tâches en ROM (fichier taskdesc.c).
/***************************************************** * ------------- TASK DESCRIPTOR SECTION ------------ ****************************************************/ #pragma romdata DESC=0x50 /***************************************************** * ------------------- Led_ON task ------------------ ****************************************************/ rom_desc_tsk rom_desc_led_ON = { 0x04, /* prioinit from 0 to 7 */ 0x04, /* stacksize in word [32 bits] */ 0x1000, /* adr_tsk in 16 bits */ 0x00, /* state at init phase */ 0x01, /* id_tsk from 1 to 8 */ 0x0100 /* ctx_tsk in 16 bits */ };
Cet exemple est issu du tutorial. Il déclare une tâche Led_ON
dont l'ID est 1. C'est la déclaration de la tâche la moins prioritaire
vue précédemment.
Nous pouvons remarquer que les informations concordent avec celles de la zone
de description en RAM :
En parcourant cette structure pour chaque tâche, le noyau place l'adresse du point d'entrée de la tâche directement dans la zone de la pile hardware affectée à la tâche. Pour passer du noyau à la prochaine tâche, le noyau place donc le pointeur de pile sur la valeur STKPTR mémorisée dans la zone de descrition de tâches en RAM, puis appel l'instruction RETURN.
| > Architecture du noyau |
Le noyau PICOS18 est découpé en plusieurs blocs :

Concernant le coeur du noyau :
Tout le code relatif au coeur du noyau est rassemblé dans le fichier kernel.asm.
Comme nous l'avons vu précédemment, la déclaration des tâches se fait dans une zone de description des tâches en ROM (fichier taskdesc.c). La première effectuée par le noyau lors de la phase d'INIT est donc de parser cette zone en vu d'établir la liste des tâches de l'application.
Ensuite le SCHEDULER entre en action afin de déterminer la prochaine tâche à exécuter. L'algorithme du SCHEDULER est simple : la prochaine tâche à exécuter est la tâche prête la plus prioritaire. Il n'y a aucun algorithme de vieillissement des tâches qui consisterait à prendre en compte le temps de fonctionnement des tâches dans leurs gestions.
Enfin l'action du coeur du noyau se termine par la mise en oeuvre du TASK MANAGER. Celui-ci n'a rien à voir avec le PROCESS MANAGER. Son action se borne à restituer ou sauvegarder le contexte et la zone de pile de chaque tâche. Ceci se fait au moment du basculement d'une tâche ou bien lors du saut dans une nouvelle tâche.
| > Service PROCESS MANAGEMENT |
A suivre ...
| > Service EVENT MANAGEMENT |
A suivre ...
| > Service ALARM MANGEMENT |
A suivre ...
| > Service INT MANGEMENT |
A suivre ...
| > Service CEILING PROTOCOL |
A suivre ...
| > Les HOOK-ROUTINES |
A suivre ...