Vous êtes sur la page 1sur 13

COOCOX COOS

CooCox CoOS est un système d’exploitation embarqué multitâches temps réel préemptif conçu
spécialement pour l’architecture ARM cortex M. Il supporte deux types d’ordonnancement à priorité et
round-robin. Les tâches prêtes sont mises dans une liste doublement chainée ; cela permet de garantir
que le premier élément de la liste correspond à la tâche la plus prioritaire. Les tâches qui partagent la
même priorité sont placées par ordre (FIFO).

1 Gestion des tâches


1.1 Tâche CooCox CoOS
Pour développer une application basée sur un OS, on décompose l’application en un ensemble de tâches.
Dans CoOS une tâche est fonction C contenant une boucle infinie et ne renvoie pas un résultat.
void MyTask (void *pdata)
{

for( ; ; )
{

}
}

1.2 Etat d’une tâche


Une tâche CooCox CoOs peut se trouver dans l’un des états suivants :
Prête (Task_Ready) : une tâche qui possède toutes les ressources nécessaires à son exécution. Elle lui
manque seulement le processeur.
Active (Task_Running) : Tâche en cours d’exécution, elle est actuellement en possession du processeur.
Attente (Task_Waitting) : Tâche en attente d’un événement.
Inactive (Task_Dormant) : l’état d’une tâche après suppression. La tâche ne fait pas partie de l’ensemble
des tâches ordonnançables.

www.espacetechnologue.com - 30 -
2 Les API systèmes
Le développement d’une application temps réel s’appuie sur les services (primitives) fournis par le système
d’exploitation temps afin de gérer les tâches, de les faire communiquer, se synchroniser, de gérer le temps,
de traiter les interruptions matérielles. Ces services influencent l’état des tâches, sur lequel s’appuie
l’ordonnanceur afin de gérer l’exécution du système. CooCox CoOS fournit un ensemble des primitives
appelées les API système (API : Application Programming System).
Une structure générale de programme est donnée ci-après :
/******************************************************************************/
/* Structure d’un programme contenant 2 tâches
//=============================================================================
/* Inclure les fichiers entêtes de l’application
#include <CoOS.h>
...
//=============================================================================
/* déclaration des variables et des constantes de l’application */
#define STK_SIZE_DEFAULTS 128
...
/*Pour chaque tâches, déclarer un tableau de type OS_STK pour la zone de pile*/
OS_STK Task1_stk[STK_SIZE_DEFAULTS];
OS_STK Task2_stk[STK_SIZE_DEFAULTS];
...
/* déclarer l’ID de chaque tâche */
OS_TID Task1ID ;
OS_TID Task2ID ;
...
//=============================================================================
/* définir les procédures et fonctions */

www.espacetechnologue.com - 31 -
void Initialisation()
{
// dans cette procédure on initialise les périphériques
}
/* définition des tâches */
void Task1 (void* pdata)
{ ...
while(1)
{
...
}
}
void Task2 (void* pdata)
{ ...
while(1)
{
...
}
}

//=========================== Programme principale ============================


int main(void)
{
initialisation(); // initialisation du système

CoInitOS() ; // initialisation du noyau temps réel

/* Création des tâches */


Task1ID = CoCreateTask( Task1,
void*)0,
0,
&Task1_stk[STK_SIZE_DEFAULTS-1],
STK_SIZE_DEFAULTS);
Task2ID = CoCreateTask( Task2,
void*)0,
1,
&Task2_stk[STK_SIZE_DEFAULTS-1],
STK_SIZE_DEFAULTS);
...

CoStartOS(); // lancement de l’ordonnanceur


}
L’initialisation du noyau temps réel « CoInitOS() », la création des tâches « CocreateTask(…)» et la
lancement du noyau «CoStartOS()» doivent se faire dans l’ordre.

Remarque : la primitive CoInitOS() initialise le noyau et crée une tâche de fond (Idle-Task). Cette tâche
est exécutée lorsque la liste des tâches prêtes est vide.

2.1 Gestion des tâches


2.1.1 Création des tâches
Pour créer une tâche, il faut invoquer la primitive CoCreateTask( ). Après sa création la tâche est placée
dans la liste des tâches prêtes.
OS_TID CoCreateTask( FUNCPtr task, /* fonction qui crée la tâche */
void* argv, /* liste des paramètres de la fonction */
U8 prio, /* priorité de la tâche */
OS_STK* stk, /* l’adresse de départ de la pile */
U16 stkSz /* taille de la pile en word */

www.espacetechnologue.com - 32 -
);
Cette primitive retourne, l’identificateur « Task_ID » si la tâche est créée avec succès, ou -1 dans le cas
contraire.

Avec la primitive CoCreateTaskEx(…) il est possible de placer la tâche à l’état d’attente lors de sa
création.
OS_TID CoCreateTaskEx( FUNCPtr task, /* fonction qui crée la tâche */
void* argv, /* liste des paramètres de la fonction */
U8 prio, /* priorité de la tâche */
OS_STK* stk, /* l’adresse de départ de la pile */
U16 stkSz, /* taille de la pile en word */
U16 timeSlice, /* temps d’exécution de la tâche, */
/* une valeur 0, initie le système de */
/* placer une valeur par défaut */
BOOL isWaitting /* True : met la tâche à l’état d’attente*/
/* False : met la tâche à l’état prêt */
);
Pour chaque tâche, il faut créer un tableau pour la zone de pile de type OS_STK et une variable
identificateur de type OS_TID.
Exemple de création de la tâche « Task1 » :
/************************ variable globales ***************************/
OS_STK Task1_stk[STK_SIZE_DEFAULTS];
OS_TID Task1ID ;
...
/* après l’initialisation du noyau temps réel */
Task1ID = CoCreateTask( Task1, /* fonction qui crée la tâche */
(void*) 0, /* sans paramètres */
0, /* priorité de la tâche */
&Task1_stk[STK_SIZE_DEFAULTS-1], /* l’adresse de départ
de la pile */
STK_SIZE_DEFAULTS /* taille de la pile en word */
);

2.1.2 Suppression des tâches


Une tâche peut être supprimée (mise à l’état dormant), par l’une des primitives :
- void CoExitTask(void) : supprimer la tâche courante.
- StatusType CoDelTask(OS_TID Task_ID) : Supprimée à partir d’une autre tâche.

Paramètre : L’identificateur de la tâche


Valeur de retour : E_INVALID_ID : ID tâche non valide.
E_PROTECTED_TASK : Protégé par le système, ne peut pas être supprimée.
E_OK : Supprimée avec succès.
Exemple :
void Task1 (void* pdata)
{ ...
while(1)
{
CoExitTask() ; // supprimer Task1
...
}
}
void Task2 (void* pdata)

www.espacetechnologue.com - 33 -
{ ...
while(1)
{
CoDelTask(Task1ID) ; // supprimer Task1
...
}
}

Une tâche supprimée (désactivée) peut être réactivée à nouveau par la primitive :
StatusType CoActivateTask (OS_TID task_ID, void *argv );

Paramètres : l’ID de la tâche et le paramètre à passer comme argument


Valeur de retour : E_INVALID_ID : ID tâche non valide..
E_OK : Tâche réactivée avec succès.
void Task2 (void* pdata)
{ ...
while(1)
{
CoActiviteTask(Task1ID, NULL) ; // réactiver Task1 déjà supprimée
...
}
}

2.1.3 Changer la priorité d’une tâche


StatusType CoSetPriority (OS_TID task_ID, U8 priority);

Paramètres : l’ID de la tâche, Nouvelle valeur de priorité


Valeur de retour : E_INVALID_ID : ID tâche non valide.
E_OK : Modifiée avec succès.
2.1.4 Suspendre une tâche
Faire passer une tâche de l’état prêt ou de l’état actif à l’état d’attente :
StatusType CoSuspendTask (OS_TID task_ID);

Paramètres : l’ID de la tâche

Valeur de retour : E_INVALID_ID : ID tâche non valide.


E_ALREADY_IN_WAITING : La tâche est déjà suspendue.
E_OK : suspendue avec succès.

2.2 Gestion de temps


Trois primitives peuvent être utilisées pour insérer une attente, l’appel de l’une de ces primitives met la
tâche en question à l’état d’attente.
StatusType CoTickDelay(U32 ticks);

Paramètres : Nombre de ticks (la valeur du tick est définie par le paramètre CFG_SYSTICK_FREQ dans le
fichier OSConfig.h ; par défaut SYSTICK = 10ms).

Valeur de retour : E_CALL : déjà appelée par une ISR.


E_OK : exécutée correctement.
StatusType CoResetTaskDelayTick(OS_TID taskID, U32 ticks); : modifie le délai d’attente

Paramètres : l’ID de la tâche, Nouveau nombre de ticks


www.espacetechnologue.com - 34 -
Valeur de retour : E_INVALID_ID : ID tâche non valide.
E_NOT_IN_DELAY_LIST : La tâche n’est pas dans la liste d’attente.
E_OK : exécutée avec succès.
StatusType CoTimeDelay(U8 hour,U8 minute,U8 sec,U16 millsec);

Paramètres : Heure, minute, seconde, milliseconde.

Valeur de retour : E_CALL : déjà appelée par une ISR.


E_INVALID_PARAMETER : paramètre invalide.
E_OK : exécutée avec succès.

2.3 Synchronisation des inter-tâches


2.3.1 Les sémaphores
Les sémaphores est un moyen simple de synchronisation et de protection des ressources partagées. Un
sémaphore est créé par la primitive CoCreateSem(…) dans CooCox CoOS. une fois le sémaphore est créé
on peut appeler les primitives CoAcceptSem() ou CoPendSem() pour prendre la ressource. Si la
ressource n’est pas libre la primitive CoPendSem() met la tâche dans la liste d’attente ; alors que
CoAcceptSem() retourne immédiatement une erreur.

OS_EventID CoCreateSem(U16 initCnt,U16 maxCnt,U8 sortType);:création d’un sémaphore

Paramètres : valeur initiale, valeur maximale, sélection de la tâche par ordre ou par priorité.
sortType : EVENT_SORT_TYPE_FIFO : la tâche est sélectionnée selon son ordre de demande
de la ressource
EVENT_SORT_TYPE_PRIO : la tâche est sélectionnée selon sa priorité

Valeur de retour :l’ID du sémaphore s’il est créé avec succès, sinon -1.
StatusType CoDelSem(OS_EventID id, U8 opt); : supprime un sémaphore

Paramètres : ID du sémaphore.
opt : EVENT_DEL_NO_PEND : Supprimer lorsque la liste d’attente est vide.

EVENT_DEL_ANYWAY : Suppression inconditionnelle.


Valeur de retour : E_INVALID_ID : ID Sémaphore non valide.
E_INVALID_PARAMETER : Paramètre invalide.
E_TASK_WAITING : Liste d’attente non vide.
E_OK : Supprimée avec succès.
StatusType CoAcceptSem(OS_EventID id,); : obtenir le sémaphore.

Paramètres : ID du sémaphore.
Valeur de retour : E_INVALID_ID : ID Sémaphore non valide.
E_SEM_EMPTY : Ensemble des ressources vide.
E_OK : Ressources obtenues avec succès.
StatusType CoPendSem(OS_EventID id, U32 timeout); : obtenir le sémaphore.

Paramètres : ID du sémaphore,
timeout : attente de la ressource pendant un timeout, si timeout=0, alors attente infinie.

www.espacetechnologue.com - 35 -
Valeur de retour : E_INVALID_ID : ID Sémaphore non valide.
E_TIMEOUT : délai d’attente de la ressource dépassé.
E_OK : Ressources obtenues avec succès

StatusType CoPostSem(OS_EventID id); : libérer la ressource

Paramètres : ID du sémaphore.
Valeur de retour : E_INVALID_ID : ID Sémaphore non valide.
E_SEM_FULL : le sémaphore a atteint sa valeur maximale.
E_OK : Ressource libérée avec succès.
Exemple : synchronisation des tâches
OS_EventID semID ;
void Task1(void* pdata)
{
..........
semID = CoCreateSem(0,1,EVENT_SORT_TYPE_FIFO);
CoPendSem(semID,0); //intCnt = 0, Task1 est placée dans la file d’attente
..........
}
void Task2(void* pdata)
{
......
CoPostSem(semID); // incrémente cnt,Task1 passe donc à l’état prête
......
}
2.3.2 Les flags
Les Flags sont utilisés lorsqu’on veut synchroniser des tâches par des événements. Les flags sont associés
avec les opérateurs OU (|) ou ET (&). CooCox coOs supporte 32 flags au maximum. Lorsqu’un flag est
positionné (mis à l’état prêt), la tâche en attente est mise à l’état prêt. Le flag peut être remis à zéro
automatiquement ou manuellement.
Création d’un flag :
OS_FlagID CoCreateFlag(BOOL bAutoReset, BOOL bInitialState);

Paramètres : bAutoReset : mode de reset, 1 : automatique, 0 : manuel


bInitialState : 1 : flag prêt, 0 : non prêt
Valeur de retour : l’ID du flag s’il est créé avec succès, sinon -1.
Remarque : si plusieurs tâches en attente d’un flag à remise à 0 manuelle ; lorsque ce flag devient prêt,
toutes les tâches en attente passe à l’état prêt. Par contre si le flag est à remise à zéro automatique, une
seule tâche parmi les tâches en attente passe à l’état prêt.
StatusType CoDelFlag(OS_FlagID id, U8 opt); : supprime un flag

Paramètres : ID du flag et l’option.


opt : EVENT_DEL_NO_PEND : Supprimer lorsque la liste d’attente est vide.

EVENT_DEL_ANYWAY : Suppression inconditionnelle.


Valeur de retour : E_INVALID_ID : ID flag non valide.
E_INVALID_PARAMETER : Paramètre invalide.
E_TASK_WAITING : Liste d’attente non vide.

www.espacetechnologue.com - 36 -
E_OK : Supprimé avec succès

StatusType CoAcceptSingleFlag(OS_FlagID id); : demande d’un flag unique sans attente.

Paramètres : ID du flag.
Valeur de retour : E_INVALID_ID : ID du flag non valide.
E_FLAG_NO_READY : le flag n’est pas à l’état prêt.
E_OK : flag obtenu avec succès.

U32 CoAcceptMultipleFlags(U32 flags, U8 waitType, StatusType* perr); : demander des


flags multiples sans attente
Paramètres : flag qu’on attend
Type d’attente : OPT_WAIT_ALL : attendre tous les flags.
OPT_WAIT_ANY : attendre un seul flag.
Type d’erreur : E_INVALID_PARAMETER : flag non valide.
E_FLAG_NOT_READY : Le flag n’est pas dans l’état prêt.
E_OK : flag obtenu avec succès.

Valeur de retour : le flag qui déclenche la fonction.


StatusType CoWaitForSingleFlag(OS_FlagID id, U32 timeout); : demande d’un flag unique
avec attente.
Paramètres : ID du flag et délai d’attente, si timeout =0 alors une attente infinie.
Valeur de retour : E_CALL : déjà appelé par une ISR.
E_INVALID_ID : ID invalide.
E_TIMEOUT : délai d’attente dépassé.
E_OK : flag obtenu avec succès.
U32 CoWaitForMultipleFlags(U32 flags,U8 waitType,U32 timeout,StatusType* perr); :
attente de flags multiples.
Paramètres : les flags qu’on doit attendre
Type d’attente : OPT_WAIT_ALL : attendre tous les flags.
OPT_WAIT_ANY : attendre un seul flag.
Délai d’attente : si timeout =0, alors attente infinie.
Type d’erreur : E_CALL : déjà appelé par une ISR.
E_INVALID_PARAMETER : flag non valide.
E_TIMEOUT : délai d’attente dépassé.
E_FLAG_NOT_READY : Le flag n’est pas dans l’état prêt.
E_OK : flag obtenu avec succès.

StatusType CoClearFlag(OS_FlagID id); : mettre le flag à l’état non prêt.


Paramètres : ID du flag.
Valeur de retour : E_INVALID_ID : ID du flag non valide.
E_OK : flag remis à zéro avec succès.
StatusType CoSetFlag(OS_FlagID id); : mette le flag à l’état prêt

Paramètres : ID du flag.

www.espacetechnologue.com - 37 -
Valeur de retour : E_INVALID_ID : ID du flag non valide.
E_OK : flag positionné avec succès.
Exemple1 : Attente d’un flag unique
OS_flagID flagID ;
void Task1(void* pdata)
{
..........
flagID = CoCreateFlag(0,0);
CoWaitForSingleFlag(flagID,0);
CoClearFlag(flagID) ;
..........
}
void Task2(void* pdata)
{
......
CoSetFlag(flagID);
......
}
Exemple2 : Attente des flags multiples

OS_flagID flagID1, flagID2, flagID3;

void Task1(void* pdata)


{
U32 flag;
StatusType err;
..........
flagID1 = CoCreateFlag(0,0);
flagID2 = CoCreateFlag(0,0);
flagID3 = CoCreateFlag(0,0);
flag = (1<<flagID1) | (1<<flagID2) | (1<<flagID3);
CoWaitForMultipleFlags(flag,OPT_WAIT_ANY,0,&err);
..........
}
void Task2(void* pdata)
{
......
CoSetFlag(flagID1);
......
}
2.3.3 Le Mutex
Le mutexe est utilisé pour résoudre le problème d’exclusion mutuelle. Il donne l’accès à une seule tâche
d’entrer dans une section critique. Le mutex résous le problème d’inversion de priorité par la méthode de
priorité hérité.
OS_MutexID CoCreateMutex(void); : créer un mutex

StatusType CoEnterMutexSection(OS_MutexID mutexID); : entrer dans une section critique

Paramètres : ID du mutex.
Valeur de retour : E_CALL : déjà appelé par une ISR.
E_INVALID_ID : ID section mutex non valide.
E_OK : entrée dans la section critique avec succès.
StatusType CoLeaveMutexSection(OS_MutexID mutexID); : sortir de la section critique
Paramètres : ID du mutex.

www.espacetechnologue.com - 38 -
Valeur de retour : E_CALL : déjà appelé par une ISR.
E_INVALID_ID : ID section mutex non valide.
E_OK : sortie de la section critique avec succès.
Exemple :
OS_MutexID mutexID ;
void Task1(void* pdata)
{
mutexID = CoCreateMutex();
CoEnterMutexSection(mutexID ); // enter dans la section critique
........... // code critique
CoLeaveMutexSection(mutexID ); // sortir de la section critique
}
void Task2(void* pdata)
{
CoEnterMutexSection(mutexID ); // enter dans la section critique
........... // code critique
CoLeaveMutexSection(mutexID ); // sortir de la section critique
}

Problème d’inversion de priorité


Soient trois tâches TaskA (haute priorité), TaskB et taskC (Basse priorité) et R une ressource partagée par
les trois tâches. Supposons que TaskC est en possession de la ressource R ; TaskC est préemptée par TaskA
plus prioritaire, lorsque TaskA souhaite prendre la ressource R elle sera bloquée à cause de la non
disponibilité de R (déjà pris par TaskC), dans ce cas TaskB peut être exécutée si elle est prête. Ce
phénomène est appelé inversion de priorité.

TaskA
blocage
R
t
TaskB

t
TaskC
R R R
t
TaskC libére R
Arrivé de TaskB
taskA demande R, Blocage
Arrivée TaskA préemption
TaskC Demande R

Pour pallier ce défaut, on attribue à la tâche en possession de ressource (TaskC), la priorité de la tâche la
plus prioritaire des tâches demandant la ressource (héritage de priorité). Dans ce cas, lorsque TaskA est
bloquée, c’est la TaskC qui reprend son exécution et non pas TaskB (TaskC à la même priorité que TaskA).
TaskC revient à sa priorité ordinaire quand elle sort de la section critique (libère la ressource).

www.espacetechnologue.com - 39 -
TaskA
R
t
TaskB

t
TaskC
R R
t
TaskA terminée
TaskA libére R
TaskC libére R
TaskB prête
taskA demande R, Blocage
Arrivée TaskA préemption
TaskC Demande R

2.4 Communication inter-tâches


CooCox CoOS fournit les boîtes aux lettres et le message queues comme moyen de transfert
d’informations entre les tâches.

CooCox CoOS permet de créer une boîte aux lettres avec la primitive CocreateMbox() ; une fois créée
vous pouvez utiliser la primitive CoPostMail() pour envoyer un messages et les primitives
CoPendMail() ou CoAcceptMail() pour l’obtenir.

OS_EventID CoCreateMbox(U8 sortType);: création d’une boîte aux lettres.


Paramètres : sortType : EVENT_SORT_TYPE_FIFO : la tâche est sélectionnée selon son ordre.
EVENT_SORT_TYPE_PRIO : la tâche est sélectionnée selon sa priorité

Valeur de retour : l’ID de la boîte aux lettres ou -1 en cas d’échec.


StatusType CoDelMbox(OS_EventID id, U8 opt); : suppression d’une boîte aux lettre.
Paramètres : ID de la boîte aux lettres.
opt : EVENT_DEL_NO_PEND : Supprimer lorsque la liste d’attente est vide.
EVENT_DEL_ANYWAY : Suppression inconditionnelle.
Valeur de retour : E_INVALID_ID : ID Mbox non valide.
E_INVALID_PARAMETER : Paramètre invalide.
E_TASK_WAITING : Liste d’attente non vide.
E_OK : Supprimé avec succès.

void* CoAcceptMail(OS_EventID id, StatusType* perr);: obtenir un message sans attente

Paramètres : ID de la boîte aux lettres.

www.espacetechnologue.com - 40 -
perr : E_INVALID_ID : ID non valide
E_MBOX_EMTY : boîte aux lettres vide
E_OK : message obtenu avec succès
Valeur de retour : pointeur sur le message dans la boîte aux lettres désignée. .
void* CoPendMail(OS_EventID id, U32 timeout, StatusType* perr); : attente d’un message
Paramètres : ID de la boîte aux lettres.
Délai d’attente : si timeout =0, alors attente infinie.
Type d’erreur : E_CALL : déjà appelé par une ISR.
E_INVALID_ID : ID de la boîte aux lettres non valide.
E_TIMEOUT : délai d’attente dépassé.
E_OK : message obtenu avec succès.
Valeur de retour : pointeur sur le message dans la boîte aux lettres désignée. .
StatusType CoPostMail(OS_EventID id,void* pmail); : envoyer un message.
Paramètres : ID de la boîte aux lettres.
pmail : pointeur sur le message.
Valeur de retour : E_INVALID_ID : ID de la boîte aux lettres non valide.
E_MBOX_FULL : la boîte aux lettres est pleine.
E_OK : message insérer avec succès
Exemple :
OS_EventID mboxID ;
void Task1(void* pdata)
{
void* pmail;
StatusType err;
..........
mboxID = CoCreateMbox(EVENT_SORT_TYPE_PRIO);
pmail = CoPendMail(mboxID,0,&err);
..........
}
void Task2(void* pdata)
{ ......
CoPostMail(mboxID,"hello,world");
......
}

3 Section critique
Une section critique est une portion du code particulièrement importante que l’on souhaite exécuter
entièrement sans préemption. CooCox CoOS gère les sections critiques en bloquant l’ordonnanceur.
L’entrée à la section critique est marquée par l’appel de la primitive CoSchedLock(), et la sortie par
CoSchedUnlock(). A l’intérieur de la section critique il ne faut jamais appeler les API système.

Exemple :
void Task1(void* pdata)
{ ...............
CoSchedLock(); // Entrer dans la section critique
............... // Code critique
CoSchedUnlock(); // sortir de la section critique
...............
}

www.espacetechnologue.com - 41 -
4 Les interruptions
Dans CooCox CoOS les interruptions sont divisées en deux catégories, selon qu’elles appellent les API
système ou non.
Les ISR (Interrupt Service Routine) dans lesquelles on n’appelle pas les API système, fonctionnent comme
s’il n’y a pas de système d’exploitation.

Pour les ISR qui font appel aux API système, il est demande d’appeler les primitives CoEnterISR() et
COExitISR() à l’entrée et à la sortie de l’ISR. Les primitives appelées par l’ISR doivent commencer par
« isr_» (isr_DelTask(), isr_PendSem() …).
Exemple :
void USART1_IRQHandler(void)
{
CoEnterISR(); // Entrée d’interruption
isr_SetFlag(flagID); // API système
..................; // Interrupt service routine
CoExitISR(); // sortie l’interruption
}

www.espacetechnologue.com - 42 -

Vous aimerez peut-être aussi