Vous êtes sur la page 1sur 79

Systèmes Embarqués

SYSTEMES TEMPS REEL

2ème année
Spécialité Électronique et Physique Appliquée
Majeure SATE

Responsable de Cours :
Hugo Descoubes, hugo.descoubes@ensicaen.fr - 02 31 45 27 61

Équipe pédagogique :
Gabriel Frey, freyg.it@gmail.com – 06 80 95 61 56
Basile Dufay, basile.dufay@unicaen.fr - 02 31 45 26 91
2015-2016
Systèmes Temps Réel

PLAN

• COURS

• TRAVAUX PRATIQUES

• ANNEXES

Les documents présents dans ce document sont librement téléchargeables sur la plateforme
d'enseignement de l'ENSICAEN via un accès anonyme. Utiliser l'onglet de recherche en utilisant les
mots clés ''système temps réel'' :

http://foad.ensicaen.fr/

Ce document est protégé par une licence Creative Common, néanmoins les différents supports
restent librement réutilisables à des fins pédagogiques. Merci cependant de me prévenir par mail
(hugo.descoubes@ensicaen.fr) et de citer le nom de l'ENSICAEN dans vos documents de cours.
Systèmes Temps Réel

INTRODUCTION FREERTOS
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

SOMMAIRE

1. PREAMBULE

2. SYSTEME D'EXPLOITATION TEMPS REEL

2.1. Tâche
2.2. Gestion mémoire
2.3. Gestion du tas
2.4. Création de tâche
2.5. Mode préemptif

3. QUEUE DE MESSAGES

3.1. API de FreeRTOS


3.2. Timeout

4. SEMAPHORE

4.1. Sémaphore binaire


4.2. MUTEX
4.3. Sémaphore à compteur

-1-
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

-2-
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

1. PREAMBULE

Durant la lecture de cette partie, nous allons nous intéresser à l'exécutif temps réel ou RTOS
(Real Time Operating System) FreeRTOS. La traduction littérale en Français de RTOS est Système
d'Exploitation Temps Réel. Il serait néanmoins plus rigoureux d'appeler ce type d'outil scheduler ou
ordonnanceur, plus que système d'exploitation, à l'image par exemple de systèmes comme
GNU/Linux, Android, Windows, MacOS. Néanmoins, l'acronyme OS est un abus de langage
fréquemment utilisé dans le monde de l'embarqué pour parler des systèmes d'exploitation temps
réel.
Un scheduler ou ordonnanceur nous propose des services logiciel (tâches, queues de
messages, sémaphores ...). Bien maîtrisé, il s'agit d'une aide précieuse durant les phases de
développement d'un projet (évolutivité, modélisation, gestion optimale des ressources CPU ...).
Néanmoins, encore beaucoup de systèmes autour de nous fonctionnent sans OS (cf. sondage ci-
dessous, UBM Tech). La question d'utiliser ou pas un ordonnanceur dépend bien sûr de l'application.
Dès que les spécifications fonctionnelles d'une application mettent en avant un certain nombre
(difficile à estimer) de traitements pouvant potentiellement s'exécuter en parallèle, la question
d'utiliser un RTOS se pose. Pour des applications communicantes (Bluetooth, WIFI, réseaux de
terrains ...), l'utilisation d'un OS peut s'avérer très utile.

Il existe un grand nombre de RTOS, libres, open Sources et propriétaires (RTX, MicroC/OS III,
FreeRTOS, VxWorks...) possédant des jeux d'avantages et d'inconvénients différents afin de s'adapter
au très grand nombre de problématiques du marché. Nous avons de notre côté à l'école porté notre
attention sur FreeRTOS, un petit scheduler temps réel offrant un certain nombre d'avantages. La
documentation de FreeRTOS est directement accessible en ligne depuis le site internet
(http://www.freertos.org/).

-3-
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

En 2014, FreeRTOS est l'un des RTOS leader sur le marché de l'embarqué. FreeRTOS est libre
de droit d'utilisation et open source (sous licence). Il est officiellement supporté par 34 architectures
(TI, Microchip, Atmel, NXP, Intel ...) et 18 chaînes de compilation. Il a par exemple été téléchargé plus
de 100000 fois l'année passée, cela implique une communauté assez riche d'utilisateurs. Il existe de
plus en tout 4 variantes de FreeRTOS :

● FreeRTOS : cf. ci-dessus

● FreeRTOS + Trace : idem FreeRTOS avec des outils propriétaires permettant


d'instrumenter le code. Par exemple des outils graphique de trace.

● OpenRTOS : version commerciale sous licence de FreeRTOS

● SafeRTOS : version certifié SIL3 TUV

De plus en 2016, FreeRTOS est le RTOS actuellement le plus utilisé et celui le plus regardé pour
démarrer de nouveaux projets. Observons le marché en 2015 des OS et RTOS pour l'embarqué
(www.eetimes.com) :

-4-
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

2. SYSTEME D'EXPLOITATION TEMPS REEL

FreeRTOS, comme n'importe quel autre noyau, est un outil purement logiciel, ce n'est qu'un
système de fichiers. FreeRTOS nous propose une API de programmation pour gérer un environnement
multitâches. La notion de tâche sera présentée par la suite. Vous trouverez ci-dessous le systèmes de
fichiers du noyau :

-5-
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

2.1. Tâche

Dans un environnement multitâches, l'application est découpée en plusieurs tâches


correspondant à des actions à effectuer. Le rôle de l'ordonnanceur est alors de gérer cet environnent
sachant que potentiellement, plusieurs d'entre-elles chercheront à s'exécuter en même temps.
N'oublions pas qu'un PIC32 ne possède qu'un seul CPU, l'ordonnanceur ne pourra donc donner la
main qu'à une seule tâche à la fois. Vous constaterez qu'à première vue, une tâche ressemble
beaucoup à une simple fonction. Nous verrons par la suite qu'une tâche est bien plus que ça.
Observons un exemple de tâche sous FreeRTOS :

void Task1( void *pvParameters ){

// Faire toujours
for( ;; ){
// code utilisateur
}
}

Une tâche est le plus souvent implémentée sous forme d'une boucle infinie. De plus,
l'ordonnanceur a la capacité de pouvoir faire passer une tâche dans différents états :

● Running (en cours) : il s'agit de la tâche en cours d'exécution par le CPU. Une seule tâche
peut-être dans cet état.

● Ready (prêt) : les tâches dans cet état sont prêtes à être exécutées. Il suffit que la tâche à
l'état en cours redonne la main à l'ordonnanceur ou que celui-ci la reprenne et selon le
contexte d'exécution (priorité supérieure, round-robin ...) une nouvelle tâche s'exécutera.

● Blocked (bloqué) : les tâches dans cet état sont en attentes d'un événement pour se réveiller
(queue de messages, sémaphores, timeout ...). Une fois l'événement arrivé, la tâche
concernée repasse alors à l'état prêt.

● Suspended (suspendu) : Cet état, peu utilisé, est propre à FreeRTOS et est à manier avec
précaution. Une tâche dans cet état n'est plus vue de l'ordonnanceur.

-6-
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

États d'une tâche sous FreeRTOS :

Une différence très importante entre une simple fonction et une tâche est qu'à chaque tâche
est associée un TCB (Task Control Block). Un TCB est une structure de données décrivant une tâche
(descripteur de tâche). L'ordonnanceur utilise ensuite les TCB pour le management de son
environnement multitâches. Sous FreeRTOS, un TCB comporte par exemple :

● la priorité de la tâche

● le ou les événements qu'elle attend

● le pointeur de base de la pile associée à la tâche

● le pointeur de sommet de pile

● ...

-7-
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

2.2. Gestion mémoire

Ce sont les TCB que l'ordonnanceur analyse afin de savoir à quelle tâche prendre ou donner
du temps CPU. Depuis la première année, tous les programmes que vous avez développés sur MCU
n'étaient constitués que d'un main() voir d'ISR's, aucun OS n'était embarqué. Effectuons quelques
rapides rappels sur le fonctionnement du main() et notamment les mécanismes de gestion mémoire
réalisés conjointement par la chaîne de compilation et le processeur.

● Sans noyau, si une application n'est constituée que d'un main(), la mémoire des données
peut-être découpée en deux grandes zones. La zone où se trouvent les variables statiques
(variables globales, locales static ...) et celle nommée pile ou stack où sont notamment gérées
les variables locales (dynamiques). Selon l'application, un tas peut également être utilisé.
Toutes les variables locales du main() ou des fonctions appelées depuis le main() sont allouées
dynamiquement dans la pile du main() ou pile système. Il en est de même des variables
locales, paramètres de fonction et des sauvegardes de contexte des fonctions d'interruption.
Prenons un exemple de mapping mémoire pour une application sans OS et sans Tas système :

unsigned char stringBuffer[100] = "FreeRTOS test !";

/**
* @fn main
* @brief main entry point
*/
int main(void){

// Configurations matérielles
UserInit();

// envoi d'une chaîne de caractères via UART


UARTputs(stringBuffer);

// On reste bloqué ici ... pour le moment !


while(1);
}

● Sous FreeRTOS, le noyau utilise une zone de taille configurable nommée Tas ou Heap.
Attention, en fonction de la stratégie de gestion du tas choisie (fichiers heap_1.c, heap_2.c,
heap_3.c ou heap_4.c) le tas peut-être le tas système ou une simple très large variable
globale. Chaque tâche possède sa propre pile dans le Tas du kernel. Chaque tâche possède
donc un environnement d'exécution indépendant.

-8-
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

void Task1( void *pvParameters );


void Task2( void *pvParameters );

/**
* @fn main
* @brief main entry point
*/
int main(void){
// Création de 2 tâches
xTaskCreate( Task1, "Task 1", configMINIMAL_STACK_SIZE, ...);
xTaskCreate( Task2, "Task 2", configMINIMAL_STACK_SIZE, ...);

// Démarrage ordonnanceur
vTaskStartScheduler();

while(1); // ... Nous ne reviendrons jamais ici !


}

void Task1( void *pvParameters ){


// Faire toujours
for( ;; ){ ... }
}

void Task2( void *pvParameters ){


// Faire toujours
for( ;; ){ ... }
}

2.3. Gestion du Tas

Dans le cas de FreeRTOS, le Tas ou heap n'est qu'un tableau déclaré en variable globale
(stratégies heap_1.c et heap_2.c). En tant que développeur, vous n'aurez pas directement accès à ces
fonctions d'allocation. Durant la création d'une tâche, le noyau génère un espace pour la TCB et la
pile de celle-ci dans le Tas.

Attention, en fonction de l'application et du MCU il faut être très prudent à l'espace alloué au
Tas et aux piles de chaque tâche. Par exemple, si la taille d'une pile est trop faible, en cas de
débordement de pile (stack overflow) nous pouvons écraser le contenu de la TCB de la tâche
suivante dans le Tas ... et donc faire tomber l'application. FreeRTOS propose 3 principales
techniques pour la gestion du Tas. Il suffit pour cela d'inclure à votre projet l'un des trois fichiers
sources ci-dessous :

● heap1.c : seules des allocations dynamiques sont possibles (exemple, créations de tâches).
Nous utiliserons ce fichier durant la trame de TP.
● heap2.c : allocations et désallocations dynamiques sont possibles (exemple, créations et
suppressions de tâches). Soyez très prudent avec la désallocation de ressources et la gestion
par le kernel d'une mémoire fragmentée.
● heap3.c : idem heap2.c, mais utilise les API standards malloc() et free() proposées par la
chaîne de compilation.

-9-
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

Exemple de mapping mémoire après la création de 2 tâches sous FreeRTOS :

void Task1( void *pvParameters );


void Task2( void *pvParameters );

/**
* @fn main
* @brief main entry point
*/
int main(void){

// Création de 2 tâches
xTaskCreate( Task1, "Task 1", configMINIMAL_STACK_SIZE, ...);
xTaskCreate( Task2, "Task 2", configMINIMAL_STACK_SIZE, ...);

// Démarrage ordonnanceur
vTaskStartScheduler();

// Nous ne reviendrons jamais ici !


while(1);
}

void Task1( void *pvParameters ){


// Faire toujours
for( ;; ){
// code utilisateur
}
}

void Task2( void *pvParameters ){


// Faire toujours
for( ;; ){
// code utilisateur
}
}

Vous constaterez que nous n'avons créé que deux tâches alors que le noyau en a créé trois. En
effet juste avant de démarrer l'ordonnanceur, le noyau crée une ultime tâche nommée tâche Idle qui
est la tâche de plus basse priorité de l'application. Lorsque aucune tâche ne tourne (tâches bloquées),
c'est en fait la tâche Idle qui est en cours d'exécution. Nous ne reviendrons donc jamais dans le
main(). Nous verrons dans la trame de TP qu'il est d'ailleurs possible de détourner la tâche Idle. Pour
information, certains noyau considèrent le main() comme une tâche, ce n'est pas le cas de FreeRTOS.

- 10 -
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

2.4. Création de tâche

Nous avons précédemment vu qu'à la création d'une tâche, le noyau alloue un espace pour la
TCB et la pile dans le Tas. Découvrons maintenant le rôle des paramètres passés à l'API de création de
tâche (xTaskCreate()) :

void Task1( void *pvParameters );


const char *pvParametersTask1 = "Passage d'un pointeur sur une chaîne de caractères !";
/**
* @fn main
* @brief main entry point
*/
int main(void){

// Création d'une tâche


xTaskCreate( Task1, // Pointeur sur la fonction implémentant la tâche
"Tache 1", // Chaîne de caractères associée à la tâche (debug).
configMINIMAL_STACK_SIZE, // Taille de la pile associée à la tâche
pvParametersTask1, // Paramètre passé à la tâche
tskIDLE_PRIORITY + 1, // Priorité associée à la tâche
NULL); // "handle" pour la gestion de la tâche
...
}

● Task1 : pointeur sur la fonction implémentant le tâche

● ''Tache 1'' : chaîne de caractères associée à la tâche (sauvée dans la TCB). Utilisé par des outils
de trace ou pour de l'instrumentation de code (par exemple, stack overflow).

● configMINIMAL_STACK_SIZE: taille de la pile associée à la tâche. Cette macro est définie dans
le fichier FreeRTOSConfig.h. Il s'agit par défaut de la taille de la pile pour la tâche Idle.
Attention, cette taille est donnée en ''Words'' et non en octets. La taille d'un Word dépend de
l'architecture matérielle utilisée. Dans notre cas un Word = 32bits (les PIC32MX sont des
MCU's 32bits).

● pvParametersTask1: possibilité de passer un paramètre à la tâche.

● tskIDLE_PRIORITY + 1 : priorité de la tâche. tskIDLE_PRIORITY ou ''0'' est la priorité minimale


qui correspond à la priorité de la tâche Idle. La priorité maximale vaut configMAX_PRIORITIES
définie dans FreeRTOSConfig.h.

● NULL : il s'agit d'un outil de préemption permettant de passer la tâche en cours de création à
l'état suspendu. A manipuler avec précaution.

- 11 -
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

2.5. Mode préemptif

En mode coopératif, chaque tâche doit explicitement permettre à une autre tâche de
s'exécuter. Ce mode de fonctionnement était encore très rencontré notamment jusqu'à MS-DOS et
Mac OS 9 qui étaient tout deux des OS coopératifs. Cependant ce mode peut amener de gros
problèmes de robustesse. Par exemple, imaginons que nous restons bloqué dans une tâche (bug). Les
autres tâches ne pourront donc jamais prendre la main ... nous venons de faire tomber l'application.

En mode préemptif, l'OS prend périodiquement la main et force un réordonnancement. La


référence de temps utilisée est nommée tick (timer clock). Ce mode de fonctionnement est plus
robuste, les principaux OS sur ordinateur sont préemptif (Windows 8, Mac OS X, Linux ...). Exemple
d'exécution en mode préemptif sous FreeRTOS :

Dans notre cas, FreeRTOS configure et utilise un timer du processeur. Ce timer interrompt
périodiquement le programme en cours d'exécution en envoyant une demande d'interruption au
CPU. Une demande d'interruption ou IRQ peut arriver n'importe quand. Ce qui signifie que, sauf dans
certains cas (par exemple sections critiques ...), n'importe quelle tâche peut être interrompue à
n'importe quel moment pour donner la main à l'ordonnanceur. Quelque soit la priorité de la tâche en
cours d'exécution.

- 12 -
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

3. QUEUE DE MESSAGES

Une queue de messages (messages queue ou queue) ou boîte aux lettres (mailboxe) est un
outil logiciel asynchrone permettant des communications voir synchronisations entre tâches. Il lui
est associé deux files d'attentes, une préservant l'ordre d'arrivée des messages et une seconde
préservant l'ordre d'arrivée des tâches. Les deux appellations sont très rencontrées. A titre indicatif,
DSP/BIOS ou SYS/BIOS le RTOS embarqué sur le DSP TMS320C6xxx de Texas Instruments étudié en
deuxième année parle de ''Mailbox'' contrairement à FreeRTOS qui parle de queue. Nous parlerons
donc de préférence de queues de messages durant cet enseignement.

Une queue de messages (ou file d'attente) contient un nombre fini d'éléments dont la taille
est configurable. Elle est de façon générale régit par le principe de fonctionnement d'une FIFO (First
In First Out). Le premier entré dans la file sera le premier à en sortir. Nous constaterons que FreeRTOS
propose si nécessaire des alternatives à ce fonctionnement. De plus, sachez que FreeRTOS créé les
queues de messages et alloue les ressources mémoire nécessaires dans le Tas.

Une queue de messages peut avoir plusieurs écrivains et plusieurs lecteurs. Cependant, de
façon générale, elles sont utilisées avec des écrivains multiples et un seul lecteur. Les écrivains sont
les tâches pouvant écrire dans une queue de messages. Les lecteurs sont donc celles susceptibles de
la lire. Un élément lu est retiré de la file d'attente. Si un lecteur cherche à lire une queue de messages
vide, il se fait bloquer jusqu'à l'arrivée d'un nouveau message. Pour des tâches de même priorité, ce
sera la première bloquée qui sera la première réveillée (FIFO). FreeRTOS étant un exécutif temps réel,
si une tâche de plus haute priorité se fait bloquer, elle passe en tête de file. Exemple de scénario :

3.1. API de FreeRTOS

Les deux principales fonctions proposées par FreeRTOS sont :

• xQueueSend() ou xQueueSendToBack() : envoi d'une donnée vers une queue de messages à


la suite des éléments déjà présents. Cette fonction n'est bloquante que si la queue de
messages est pleine.
• XQueueReceive() : Récupère la donnée en tête d'une queue de messages. L'élément lu est
retiré de la file d'attente. Le second élément passe alors en tête de file. Cette fonction n'est
bloquante que si la queue de messages est vide.

- 13 -
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

Illustrons maintenant ces concepts. Dans l'exemple ci-dessous le noyau travaille en mode
coopératif. Ce scénario présente une application avec deux écrivains et un lecteur :

...

- 14 -
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

FreeRTOS propose également des fonctions permettant de rendre prioritaire des données
envoyées à une queue de messages. Par exemple xQueueSendToFront() écrit une donnée en tête de
file d'attente.

3.2. Timeout

Certaines fonctions pour la gestion de queue de messages et de sémaphores utilisent un


Timeout ou temps mort. Lorsqu'une tâche est bloquée après l'appel de l'une de ces fonctions, celle-ci
se réveillera (passage à l'état prêt) automatiquement après un laps de temps nommé Timeout, même
si l'événement attendu n'est pas arrivé. L'utilisation du Timeout permet de garantir la robustesse
d'un code en forçant par exemple le réveil d'une tâche en attente d'un événement devant être
envoyé par une tâche boguée. Prenons l'exemple de l'API suivante :

portBASE_TYPE xQueueReceive(
xQueueHandle xQueue,
void *pvBuffer,
portTickType xTicksToWait
);

Le paramètre xTicksToWait permet de fixer le Timeout. Sous FreeRTOS, le Timeout est donné
en ticks. Si nous ne souhaitons pas utiliser cette fonctionnalité (Timeout infini), il suffit de passer en
paramètre la macro portMAX_DELAY (définie dans portmacro.h).

- 15 -
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

4. SEMAPHORES

Un Sémaphore est un outil logiciel couramment (mais pas seulement !) utilisé pour la
protection de ressources partagées (variables, périphériques, espaces mémoires ...). Le principe de
fonctionnement des sémaphores est très proche de celui des queues de messages. La preuve en est,
sous FreeRTOS vous ne trouverez aucun fichier source propre aux sémaphores. Les API pour la
gestion des sémaphores ne sont que des macros appelant des fonctions propres aux queues de
messages (queue.c).

4.1. Sémaphore binaire

Un sémaphore binaire peut-être vu comme une variable booléenne associée à une file
d'attente préservant l'ordre d'arrivée des tâches (cf. queues de messages). Un sémaphore binaire Pris
(Take) par une tâche ne peut plus l'être par une autre, ni même par elle même tant qu'il n'est pas
explicitement Vendu (Give). Une tâche cherchant à prendre un sémaphore binaire déjà pris se verra
bloquée (blocked) jusqu'à ce que la ressource soit relâchée. Prenons un exemple de scénario :

...etc

- 16 -
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

Le scénario précédent reflète par exemple une application où 3 tâches de même priorité
cherchent simultanément à envoyer des données via un UART. La ressource partagée est alors l'UART
qui est protégé par un sémaphore binaire. Durant ce laps de temps nous nous trouvons dans une
section critique qui peut cependant être préemptée par le noyau. Les différentes tâches utiliseront
donc l'UART à tour de rôle (exclusion mutuelle) .

4.2. MUTEX

Mutex signifie MUTual EXclusion (ou exclusion mutuelle), il s'agit du concept très rapidement
présenté durant le scénario présenté ci-dessus. Une exclusion mutuelle traduit la notion de
protection de ressources partagées. Sous FreeRTOS, elle peut notamment être réalisée à partir d'un
sémaphore binaire (inversion de priorité) ou d'un mutex (héritage de priorité). Pour FreeRTOS, le
principe de fonctionnement de ces deux outils est exactement le même à ceci près que le Mutex
effectue un héritage de priorité. Illustrons le concept d'héritage de priorité :

● Héritage de priorité : La tâche Task Low2 vient de prendre une ressource (Mutex) et elle ne la
rendra qu'une fois avoir fini ce pourquoi elle l'a pris. Cependant la tâche Task Low1 est
également prête (état ready), l'ordonnanceur applique donc le round-robin et partage le
temps CPU entre les deux tâches de même priorité.

Imaginons maintenant que la tâche Task High (de priorité supérieure) cherche
également à prendre la ressource (Mutex). Ceci est impossible, le MUTEX ayant déjà été pris et
elle se fait donc bloquer, c'est ce que l'on appel l'inversion de priorité. Une tâche de haute
priorité se fait bloquer par une tâche de plus basse priorité, le système de priorité choisi par le
développeur est inversé. Cependant avec l'héritage de priorité, la tâche Task Low2 hérite
temporairement de la priorité de Task High et pourra donc potentiellement finir de s'exécuter
plus rapidement que sans héritage (plus de round-robin avec la tâche de même priorité). De
façon général, dans un système temps réel une tâche ne doit jamais (ou le moins longtemps
possible !) rester bloquée par une tâche de moindre priorité.

- 17 -
Systèmes Temps Réel
Exécutif temps réel FreeRTOS

4.3. Sémaphore à compteur

Le principe de fonctionnement d'un sémaphore à compteur est identique à celui d'un


sémaphore binaire sauf que la ressource protégée peut maintenant être prise (Take) à plusieurs
reprise. Elle peut être prise soit par la même tâche, soit par une nouvelle. Exemple de sémaphore à 4
jetons :

- 18 -
Systèmes Temps Réel

TRAVAUX PRATIQUES
Systèmes Temps Réel

SOMMAIRE
Attention, des travaux préparatoires seront à préparer avant l'arrivée en séance !

1. MODE COOPERATIF - séance n°1

1.1. Interface de communication


1.2. Mode coopératif
1.3. État bloqué
1.4. Tâche idle

2. MODE PREEMPTIF ET GESTION MEMOIRE - séance n°2

2.1. Mode préemptif


2.2. Gestion mémoire

3. QUEUE DE MESSAGE ET SEMAPHORE - séance n°3

3.1. Queue de Message


3.2. Timeout
3.3. Section critique
3.4. Sémaphore
3.5. Bibliothèque UART avec appels système

4. PROJET - séance n°4 et plus

4.1. Présentation
4.2. Spécifications

APPLICATION RESEAU - facultatif

5. PILE RESEAU MICROCHIP

5.1. Présentation
5.1.a. Pile Réseau Microchip
5.1.b. Berkeley sockets
5.2. Serveur TCP
5.3. Services TCP/IP
5.3.a Serveur UDP
5.3.b Serveur HTTP

6. PROJET RTOS ET PILE RESEAU

7. PORTAGE PILE RESEAU MICROCHIP

7.3. Présentation
7.4. Spécifications
Systèmes Temps Réel
Travaux Pratiques

SOMMAIRE

1. MODE COOPERATIF - séance n°1

1.1. Interface de communication


1.2. Mode coopératif
1.3. État bloqué
1.4. Tâche idle

2. MODE PREEMPTIF ET GESTION MEMOIRE - séance n°2

2.1. Mode préemptif


2.2. Gestion mémoire

3. QUEUE DE MESSAGE ET SEMAPHORE - séance n°3

3.1. Queue de Message


3.2. Timeout
3.3. Section critique
3.4. Sémaphore
3.5. Bibliothèque UART avec appels système

4. PROJET - séance n°4 et plus

4.1. Présentation
4.2. Spécifications

APPLICATION RESEAU - facultatif

5. PILE RESEAU MICROCHIP

5.1. Présentation
5.1.a. Pile Réseau Microchip
5.1.b. Berkeley sockets
5.2. Serveur TCP
5.3. Services TCP/IP
5.3.a Serveur UDP
5.3.b Serveur HTTP

6. PROJET RTOS ET PILE RESEAU

7. PORTAGE PILE RESEAU MICROCHIP

7.3. Présentation
7.4. Spécifications

-1-
Systèmes Temps Réel
Travaux Pratiques

-2-
Systèmes Temps Réel
Travaux Pratiques

1. MODE COOPERATIF

Travail préparatoire

• 1. (0,5pt) Quels états peu prendre une tâche sous FreeRTOS ?

• 2. (1,5pts) Ces états sont-ils les mêmes quelque soit l'OS ou le RTOS utilisé ? Donner un
exemple pour un autre RTOS.

• 3. (0,5pt) Que se passe-t-il sous FreeRTOS lorsqu'aucune tâche, précédemment créée via
xTaskCreate(), ne s'exécute (état running) ?

• 4. (0,5pt) Qu'est-ce qu'un TCB ?

• 5. (1pt) Que trouve-t-on en général dans un TCB (prendre l'exemple de FreeRTOS) ?

-3-
Systèmes Temps Réel
Travaux Pratiques

1. MODE COOPERATIF
Travail en séance
1.1. Interface de communication

Avant de commencer à découvrir FreeRTOS, un micro-noyau temps réel libre et open source,
nous allons devoir mettre en place une interface de communication avec l'ordinateur de
développement (ordinateur host). Même à notre époque, l'une des premières interfaces mise en
œuvre lors de développement sur MCU est une communication série asynchrone via UART. La
rapidité de mise en œuvre, la simplicité du protocole et sa robustesse en font sa force. Cet exercice
ayant déjà été réalisé en première année à l'école sur architecture PIC18 de Microchip, le programme
de configuration et de gestion de l'UART sur architecture PIC32 de Microchip vous est donné. Il vous
est seulement demandé de l'éditer, d'en comprendre le fonctionnement tout en réalisant quelques
tests après compilation.

• Créer un projet uart dans le répertoire rtos/peripherals/uart/explorer16/ ou


rtos/peripherals/uart/pic32maxiweb/ en fonction de la plateforme de développement
utilisée. Ce projet doit inclure les fichiers sources uart.c, main.c présents dans ./src/ et le
fichier d'en-tête uart.h présent dans ./h/

• Ouvrir un terminal asynchrone de communication côté ordinateur (TeraTerm, PuTTY, minicom,


kermit …) et s'assurer de sa bonne configuration afin d'analyser les données envoyées depuis
la maquette. Prenons l'exemple de TeraTerm :

• Compiler et interpréter le fonctionnement du programme. Ne pas hésiter à modifier le fichier


main.c afin de bien comprendre le fonctionnement de l'API de gestion de l'UART.

• Pour information, lors de développement sur processeurs pour l'embarqué, nous utilisons des
convertisseurs USB-serial afin de communiquer avec l'ordinateur de développement. Ces
interfaces nécessitent l'installation de drivers sous Windows et sont nativement reconnus sous
Linux en apparaissant à la racine dans le répertoire /dev sous le nom ttyXXXX (teletypewriter
terminal) :

-4-
Systèmes Temps Réel
Travaux Pratiques

1.2. mode coopératif

Nous allons maintenant découvrir pas à pas les principaux services proposés par FreeRTOS.
Dans un premier temps, intéressons-nous au mode coopératif, très peu utilisé pour des problèmes
de robustesse et d'égalité de partage de temps CPU, problèmes que nous illustrerons dès le premier
exercice. En mode coopératif, chaque tâche doit explicitement permettre à une autre tâche de
s'exécuter en effectuant un appel système, sans quoi, aucune autre tâche ne pourra prendre la main.
Nous allons dans un premier temps créer 3 tâches de même priorité. Chaque tâche enverra une
chaîne de caractères à l'ordinateur par liaison série.

• Créer un projet cooperative dans le répertoire rtos/cooperative/pjct. Ce projet doit inclure les
fichiers sources uart.c, utask.c (user tasks), ktrap.c (kernel trap), main.c présents dans
rtos/cooperative/src et les fichiers d'en-tête uart.h, utask.h, FreeRTOSConfig.h présent dans
rtos/cooperative/h

• Inclure à votre projet les sources de FreeRTOS sans oublier de configurer vos chaînes de
compilation C et ASM avec les chemins vers les différents répertoires contenant des fichiers
d'en-tête. Ne pas hésiter à s'aider des documents d'annexe.

• La documentation du noyau est accessible en ligne sur le site officiel de la société proposant
FreeRTOS :

http://www.freertos.org/

-5-
Systèmes Temps Réel
Travaux Pratiques

• Créer 3 tâches de priorité 1. Les fonctions implémentant les tâches se nommeront task1(),
task2() et task3(). Chaque tâche ne fera qu'envoyer une chaîne de caractères à l'ordinateur
puis attendre un délai de quelques centaines de millisecondes via une temporisation logicielle
avant de répéter l'opération. Prenons l'exemple de la tâche 1 :

uartPutS("\r\ntask1\r\n");

// wait few 100ms


int i;
for (i=0; i<4000000; i++);

• Compléter, compiler et interpréter le fonctionnement du programme en visualisant les


données reçues côté ordinateur.

Pour ce premier exercice, l'analyse du fonctionnement du programme est donnée. Ce travail


sera bien entendu à votre charge pour le totalité des exercices qui suivent :

Les traits pleins apparaissant sur les chronogrammes représentent le code en cours
d'exécution par le CPU. Nous constatons que nous sommes bloqué dans la tâche 3. Du coup, trois
questions se soulèvent :

• Pourquoi sommes-nous bloqué ? tout simplement car en mode coopératif, la tâche


doit appeler elle même l'ordonnanceur ou une fonction système réalisant un appel du
scheduler.

• Pourquoi dans la tâche 3 ? Avec FreeRTOS, au démarrage si plusieurs tâches de même


priorité sont susceptibles de prendre la main, c'est la dernière créée qui sera la
première à démarrer. Cette politique est différente en fonction de l'OS rencontré.

• Dans quel état se trouvent les tâches 1 et 2 ? elles se trouvent à l'état prêt (ready).
Elles sont toutes les deux prêtes à prendre la main si la tâche 3 le leur donne.

-6-
Systèmes Temps Réel
Travaux Pratiques

• Nous allons maintenant forcer des commutations de contexte en appelant l'ordonnanceur.


Dans chaque tâche, à la suite de la temporisation logicielle, appelez la fonction suivante :

taskYIELD();

Vous constaterez que le noyau donne la main à chaque tâche à tour de rôle. Beaucoup d'OS
temps réel légers travaillent ainsi, il s'agit de la technique dîtes du round-robin qui suit le principe
de fonctionnement d'un tourniquet. Chaque tâches de même priorité prêtes ou en court d'exécution
prendra la main à tour de rôle. Le principal avantage de cette technique est de ne nécessiter qu'une
intelligence très réduite au niveau du code du kernel.

Nous venons d'illustrer le principe de la coopération entre tâches ainsi que le principal
problème amené si une boucle infinie (bug) intervient dans le code d'une tâche. Les tâches bloquées
ou prêtes ne peuvent plus prendre la main et votre application tombe !

• Pour information, durant la totalité de la trame de TP, nous étudierons le fonctionnement de


nos programmes à l'aide de chronogrammes comme ci-dessus. Sachez néanmoins qu'il existe
des outils dédiés, souvent propriétaires et donc payant permettant ce type d'analyses. Prenez
quelques minutes pour visualiser la vidéo présentant les outils de trace proposés par
FreeRTOS (outils payant en fonctions des services demandés) :

http://www.youtube.com/watch?feature=player_embedded&v=WTNc1PwoMG4

-7-
Systèmes Temps Réel
Travaux Pratiques

1.3. État bloqué

Intéressons-nous à la fonction bloquante vTaskDelay(). Afin de pouvoir utiliser cette fonction,


ne pas oublier de mettre à 1 la macro INCLUDE_vTaskDelay présente dans le fichier d'en-tête
FreeRTOSConfig.h.

• Compléter le programme précédent en remplaçant dans la tâche 1 la temporisation logicielle


et taskYIELD() par :

uartPutS("\r\ntask1 delay 3s\r\n");

// task blocked during 3000 ticks


vTaskDelay(3000);

• Compléter le chronogramme ci-dessous en étant prudent aux quelques pièges pouvant


apparaître. Pour information, 3000 signifie 3000 ticks donc 3 secondes dans notre cas (1 tick =
1ms cf. FreeRTOSConfig.h). Préciser à chaque fois les appels des fonctions taskYIELD() et
vTaskDelay(3000) ainsi que l'état pris par chaque tâche (R = ready et B = blocked) :

• Remplacer maintenant les temporisations logicielles et taskYIELD() par vTaskDelay(3000) dans


chaque tâche. Compléter le chronogramme suivant et préciser l'état pris par chaque tâche (R
= ready et B = blocked) :

• Quel code s'exécute lorsque nous nous trouvons dans aucune des 3 tâches ?

-8-
Systèmes Temps Réel
Travaux Pratiques

1.4. Tâche idle

Intéressons-nous à la tâche Idle et découvrons comment la détourner afin d'y insérer du code
utilisateur. Par défaut en mode coopératif la tâche Idle ne fait que forcer des commutations de
contexte en appelant la fonction taskYIELD().

• Mettre à 1 la macro configUSE_IDLE_HOOK présente dans le fichier d'en-tête


FreeRTOSConfig.h.

• Créer alors une fonction (et non une tâche !) nommée vApplicationIdleHook(). Attention ce
nom est imposé par le système. Cette fonction ne fera qu'envoyer une chaîne de caractères :

/**
* @fn void vApplicationIdleHook( void )
* @brief function called by idle task
*/
void vApplicationIdleHook( void ){
uartPutS("i");
}

• Tester votre code et compléter le chronogramme ci-dessous :

• Proposer des cas d'applications et exemples d'utilisation de la tâche Idle. Ne pas hésiter à
s'aider du web et d'exemples de détournement de la tâche Idle sur d'autres noyaux temps
réel.

-9-
Systèmes Temps Réel
Travaux Pratiques

- 10 -
Systèmes Temps Réel
Travaux Pratiques

2. MODE PREEMPTIF ET GESTION MEMOIRE


Travail préparatoire

• 1. (0,5pt) Quels sont les inconvénients et avantages d'un OS coopératif (aidez-vous du Web) ?

• 2. (0,5pt) Quels sont les inconvénients et avantages d'un OS préemptif (aidez-vous du Web) ?

• 3. (1pt) Que trouve-t-on sur le Tas ?

• 4. (1,5pt) Les stratégies de gestion du tas par FreeRTOS sont implémentées dans les fichiers
heap_1.c, heap_2.c, heap_3.c et heap_4.c présents dans le répertoire
/rtos/FreeRTOS/Source/portable/MemMang de notre arborescence de TP.

• Quelles sont les différences entre les stratégies utilisant heap_1.c ou heap_2.c ?
• Quelles sont les différences entre les stratégies utilisant heap_2.c ou heap_3.c ?

• 5. (1pt) Qu'est-ce qu'une pile ou stack et que trouve-t-on sur la pile ?

• 6. (1,5pt) Qu'elle est la taille par défaut de la pile de la tâche Idle dans le cadre de notre trame
de TP ? Expliquez votre démarche pour répondre à cette question.

- 11 -
Systèmes Temps Réel
Travaux Pratiques

2. MODE PREEMPTIF ET GESTION MEMOIRE


Travail en séance
2.1. mode préemptif

A partir de maintenant et jusqu'à la fin de la trame de TP nous travaillerons exclusivement en


mode préemptif (macro configUSE_PREMPTION à 1 dans le fichier FreeRTOSConfig.h). En mode
préemptif, le scheduler prend périodiquement la main, interrompant ainsi une tâche en cours
d'exécution, puis force un ré-ordonnancement. Cette périodicité se nomme tick (timer clock) et est
configurable sous FreeRTOS à travers la macro configTICK_RATE_HZ présente dans FreeRTOSConfig.h.

• Créer un projet preemptive dans le répertoire rtos/preemptive/pjct. Ce projet doit inclure les
fichiers sources uart.c, utask.c (user tasks), ktrap.c (kernel trap), main.c présents dans
rtos/preemptive/src et les fichiers d'en-tête uart.h, utask.h, FreeRTOSConfig.h présent dans
rtos/preemptive/h

• Inclure à votre projet les sources de FreeRTOS sans oublier de configurer vos chaînes de
compilation C et ASM avec les chemins vers les différents répertoires contenant des fichiers
d'en-tête. Ne pas hésiter à s'aider des documents d'annexe.

• Créer 3 tâches, une de priorité 2 et deux de priorité 1. Les fonctions implémentant les tâches
se nommeront respectivement task1(), task2() et task3(). Chaque tâche appellera une fonction
bloquante puis ne fera qu'envoyer une chaîne de caractères à l'ordinateur.

• Prenons l'exemple des tâche 2 et 3 (exemple de la tâche 2) :

// task blocked during 1000 ticks


uartPutS("\r\ntask2\r\n");
vTaskDelay(1000);

• La tâche 1 sera bloquée quant-à elle durant 3000 ticks :

// task blocked during 3000 ticks


uartPutS("\r\ntask1\r\n");
vTaskDelay(3000);

- 12 -
Systèmes Temps Réel
Travaux Pratiques

• Compléter, compiler et interpréter le fonctionnement du programme en visualisant les


données reçues côté ordinateur. Le comportement du programme peut sembler étrange dans
un premier temps, mais s'explique bien entendu très bien !

• Compléter le chronogramme suivant et préciser l'état pris par chaque tâche (R = ready et B =
blocked). Attention aux pièges :

• Dans notre cas, la tâche 1 est-elle périodique ?

• De quoi dépend la périodicité d'une tâche appelant la fonction vTaskDelay()?

• FreeRTOS propose la fonction xTaskGetTickCount() permettant de récupérer la valeur


courante du tick. Récupérer à chaque réveil de la tâche 1 cette valeur, puis l'envoyer à
l'ordinateur (s'aider de la fonction standard sprintf) :

uartPutS("\r\ntask1 prio, current tick value ");

// get and send current tick value



uartPutS("\r\n");

• Utiliser maintenant la fonction vTaskDelayUntil() puis interpréter le résultat obtenu.

- 13 -
Systèmes Temps Réel
Travaux Pratiques

2.2. Gestion mémoire

La partie qui suit est extrêmement importante et sujette à énormément de bugs et mauvais
développement en milieu industriel, notamment lorsque nous travaillons sur de petits exécutifs
temps réel comme FreeRTOS. Problématique différente sur OS évolué (GNU\Linux, Android …) et
processeur avec MMU (Memory Managment Unit). Sur RTOS, le développeur doit avoir une très
bonne gestion et maîtrise des ressources mémoire réalisées par la chaîne de compilation et le
système. Prenons un petit programme d'exemple et observons le mapping mémoire de données du
processeur.

int gbl;

/**
* @fn int main(void)
*/
void main(void){
int lclMain;
xTaskCreate(task, "task", 100, NULL, 1, NULL);
vTaskStartScheduler();
}

/**
* @fn void task(void *pvParameters)
*/
void task(void *pvParameters){
int lclTask;
}

• Représenter ci-contre un découpage du mapping mémoire en


faisant apparaître : tas de FreeRTOS, pile fonction main, pile de
la tâche, TCB de la tâche

• Que trouve-t-on dans le reste de la mémoire (hors zones


spécifiées dans la question précédente) ?

• Où si situe physiquement la chaîne de caractères ''task'' ?


Mettre à jour le schéma ci-contre.

• Où si situe physiquement la variable globale gbl ? Mettre à


jour le schéma ci-contre.

• Où si situe physiquement la variable locale lclMain ? Mettre à


jour le schéma ci-contre.

• Où si situe physiquement la variable locale lclTask ? Mettre à


jour le schéma ci-contre.

- 14 -
Systèmes Temps Réel
Travaux Pratiques

FreeRTOS propose une API de programmation permettant de détecter certaines exceptions


du noyau et d'appeler des fonctions de callback en cas d’occurrence. Le kernel permet notamment
de détecter certains stack overflow (débordement de pile) et heap overflow. Pour information, les
stack overflow font partis des bugs les plus répandus durant des développement sur STR et peuvent
être délicats à mettre au jour dans certains cas. Il vous est très très très fortement conseillé
d'implémenter ce type de détection durant vos phases de développement. Malheureusement,
lorsque vous vous trouvez dans l'une de ces fonctions de callback, il est déjà trop tard !

• Nous allons maintenant mettre en place les mécanismes de détection de débordement de


pile. Forcer à 1 ou 2 la macro configCHECK_FOR_STACK_OVERFLOW présente dans le fichier
FreeRTOSConfig.h. En fonction de la valeur choisie différentes stratégies de détection de stack
overflow seront appliquées par le kernel :

http://www.freertos.org/Stacks-and-stack-overflow-checking.html

• Dé-commenter la fonction vApplicationStackOverflowHook présente dans le fichier ktrap.c


(kernel trap).

/**
* @fn void vApplicationStackOverflowHook ...
* @brief kernel hook here if stack overflow detection
*/
void vApplicationStackOverflowHook( xTaskHandle xTask, signed char *pcTaskName ){
uartPutS("\r\nerror stack overflow by ");
uartPutS(pcTaskName);
uartPutS(" \r\n");
while(1); // it's a trap
}

• Éditer la fonction suivante et l'appeler dans la tâche 1. Interpréter et illustrer le


comportement du programme sur le schéma ci-contre :

/**
* @fn void growStack( void )
* @brief current stack allocation until overflow
*/
void growStack( void ) {
vTaskDelay( 1 );
return growStack();
}

• Effectuer le même exercice avec la fonction suivante. Interpréter et


illustrer le comportement du programme sur le schéma ci-contre :

void growStack( void ) {


return growStack();
}

- 15 -
Systèmes Temps Réel
Travaux Pratiques

• Nous allons maintenant mettre en place les mécanismes de détection de débordement de tas.
Forcer à 1 la macro configUSE_MALLOC_FAILED_HOOK présente dans le fichier
FreeRTOSConfig.h. Dé-commenter la fonction vApplicationMallocFailedHook dans le fichier
ktrap.c (kernel trap).

/**
* @fn vApplicationMallocFailedHook()
* @brief kernel hook here if malloc allocation failed detection
*/
void vApplicationMallocFailedHook( void ){
uartPutS("\r\nerror malloc failed \r\n");

// it's a trap
while(1);
}

• Éditer le code suivant dans la tâche 1. Nous allons créer une tâche
depuis la tâche 1 dont la pile dépasse la taille du tas. Interpréter et
illustrer le comportement du programme sur le schéma ci-contre :

// force heap allocation failed


uartPutS("\r\ntask creation with a too large stack\r\n");
xTaskCreate(task1, "mfailed",
configTOTAL_HEAP_SIZE, \
NULL, \
tskIDLE_PRIORITY + 2, \
NULL);

- 16 -
Systèmes Temps Réel
Travaux Pratiques

3. QUEUE DE MESSAGE ET SEMAPHORE


Travail préparatoire

• 1. (2pts) Exemple de communication entre 3 tâches via queue de messages :

void prodTask1( void *pvParam ){ void prodTask2( void *pvParam ){ void consTask( void *pvParam ){
int x=1; int x=2; int y;
char sBuffer[20];
while(1){ while(1){
if (xQueueSend(xQueue, \ if (xQueueSend(xQueue, \ while(1){
&x, 0) == pdTRUE ){ &x, 0) == pdTRUE ){ xQueueReceive(xQueue, &y, \
x += 2; x += 2; portMAX_DELAY );
vTaskDelay( 1 ); vTaskDelay( 1 ); sprintf(sBuffer, ''%d'', y);
} } uartPuts(sBuffer) ;
} } }
} } }

L'application présentée ci-dessus met en œuvre 2 tâches producteur de priorité 1


(prodTask1() et prodTask2()) et une tâche consommateur de priorité 2 (consTask()) sachant
que le kernel fonctionne en mode préemptif. Représenter la séquence d'exécution des tâches
à partir du démarrage de l'application. Notez bien sur le chronogramme les instants clés ainsi
que les appels de fonction associés (R = ready et B = blocked) :

• 2. (0,5pt) Qu'observerait-on au niveau d'un terminal asynchrone côté ordinateur ?

- 17 -
Systèmes Temps Réel
Travaux Pratiques

• 3. (1,5pt) En utilisant 3 sémaphores binaires, proposez une solution permettant de chaîner


l'exécution de 3 tâches en respectant l'ordre suivant : task3, task1, task2, task3, task1, task2,
task3 ...

void task1( void *pvParam ){ void task2( void *pvParam ){ void task3( void *pvParam ){

while(1){ while(1){ while(1){

} } }
} } }

• 4. (0,5pt) Comment faire pour chaîner 6 tâches ?

• 5. (1,5pt) Compléter le chronogramme ci-dessous de la totalité des prises et ventes de


sémaphores sachant qu'avant le démarrage de l'ordonnanceur le sémaphore 3 (S3) a été
vendu une fois (Give) et les deux autres ont déjà été pris (Take). Ne pas oublier de représenter
les états de chaque tâche (R = ready et B = blocked) :

- 18 -
Systèmes Temps Réel
Travaux Pratiques

3. QUEUE DE MESSAGE ET SEMAPHORE


Travail en séance
3.1. Queue de message

Intéressons-nous maintenant aux outils de communication, synchronisation et protection


proposés par FreeRTOS. Dans cette partie nous allons nous attarder sur les files d'attente (ou queue
de message ou boîte aux lettres ou mail boxes selon le système utilisé) ainsi que sur les sémaphores,
qui ne sont qu'un dérivé sans message des files d'attente. D'ailleurs, sous FreeRTOS il n'existe aucun
fichier source propre aux sémaphores. Les sémaphores sont implémentés et utilisent les mêmes
sources que les files d'attente, seul un fichier d'en-tête existe permettant de wrapper l'API de gestion
des sémaphores vers celle pour le queue (simple skin).

• Créer un projet queue dans le répertoire rtos/queue/pjct. Ce projet doit inclure les fichiers
sources uart.c, utask.c (user tasks), ktrap.c (kernel trap), main.c présents dans rtos/queue/src
et les fichiers d'en-tête uart.h, utask.h, FreeRTOSConfig.h présent dans rtos/queue/h

• Inclure à votre projet les sources de FreeRTOS sans oublier de configurer vos chaînes de
compilation C et ASM avec les chemins vers les différents répertoires contenant des fichiers
d'en-tête. Ne pas hésiter à s'aider des documents d'annexe.

• Créer 3 tâches, une périodique de priorité 2 et deux de priorité 1. Les fonctions implémentant
les tâches se nommeront respectivement task1(), task2() et task3(). Chaque tâche ne fera
qu'envoyer une chaîne de caractères à l'ordinateur puis se bloquer.

• La tâche 3 ne fera qu'envoyer un chaîne de caractères côté ordinateur puis se bloquera


durant 1s :

// task blocked during 1000 ticks


vTaskDelay(1000);

uartPutS("\r\ntask3\r\n");

• La tâche 1 devra être périodique avec un périodicité de 5s. Elle devra récupérer la
valeur courante du tick (sans l'envoyer à l'ordinateur) puis la postera dans une queue
de message pour la tâche 2. La fonction d'écriture dans la file d'attente ne devra pas
être bloquante.

// block periodically current task during 5000 ticks


vTaskDelayUntil( … );

uartPutS("\r\ntask1 prio, message queue post for task2\r\n");

// post current tick value by message queue


// ...

- 19 -
Systèmes Temps Réel
Travaux Pratiques

• La tâche 2 devra être synchronisée avec la tâche 1 et récupérera la valeur courante du


tick avant de la renvoyer à l'ordinateur via liaison série. Le reste du temps, cette
fonction devra rester bloqué.

// ...
uartPutS(''\r\ntask2, current tick value '');
// print current tick value ...
uartPutS(''\r\n'');

• Ne pas oublier de créer un queue de message. A vous de fixer la taille de la file


d'attente ainsi que la taille de chaque élément.

• Compléter, compiler et interpréter le fonctionnement du programme en visualisant les


données reçues côté ordinateur.

• Compléter le chronogramme ci-dessous (R = ready et B = blocked). Attention aux pièges :

• Quel est la période d'exécution de la tâche 2 ?

Nous venons ici d'illustrer deux concepts important dans le domaine des systèmes
d'exploitation, la synchronisation et la communication. La synchronisation permet notamment de
synchroniser l'exécution d'une tâche (par exemple implémentant un traitement long) suite à
l'exécution d'une autre tâche ou d'une ISR (traitement toujours court). La communication inter-tâche
consiste quant-à-elle en la capacité d’effectuer des échanges sécurisés d'informations entre
différentes tâches de l'application. Notion de partage d'information dans des cas d'usage (use case)
avec plusieurs écrivains et/ou plusieurs lecteurs.

- 20 -
Systèmes Temps Réel
Travaux Pratiques

3.2. Timeout

Certaines fonctions pour la gestion de queue de messages ou de sémaphores utilisent un


Timeout. La notion de timeout ne s'applique qu'à des appels système bloquant. Lorsqu'une tâche est
bloquée, celle-ci se réveillera (passage à l'état prêt) automatiquement après un laps de temps nommé
Timeout, même si l'événement attendu n'est pas arrivé (libération de sémaphore, écriture dans une
file d'attente ...).

• Forcer le réveil de la tâche 2 toutes les secondes en utilisant le Timeout associé à la fonction
xQueueReceive(). Après avoir testé la nature du réveil de la tâche, envoyer l'une des deux
chaînes de caractères suivantes :

• Réveil par lecture du message présent dans la queue :

uartPutS(''\r\ntask2, current tick value '');


// print current tick value ...
uartPutS(''\r\n'');

• Réveil par timeout :

uartPutS(''\r\ntask2, timeout'');

• Que se passe-t-il si nous forçons à 0 le Timeout d'une fonction bloquante ?

• Que se passe-t-il si nous forçons à portMAX_DELAY le Timeout d'une fonction bloquante (ainsi
que la macro INCLUDE_vTaskSuspend à 1) ? À quelle valeur théorique de timeout correspond
cet argument ?

• Peut-on trouver un timeout sur une fonction système non bloquante ?

- 21 -
Systèmes Temps Réel
Travaux Pratiques

3.3. Section Critique

Une section critique est une région de code pour laquelle nous devons garantir sa bonne
exécution et l'intégrité des données à sa sortie. Il s'agira le plus souvent de protéger une ressource
partagée (variable globale, accès à un périphérique …). Une section critique peut-être protégée par
différents outils système :

• Sémaphores
• Mutex (mutual exclusion)
• fonctions dédiées le plus souvent par masquage d'interruption

Vous avez normalement dû constater que les tâches 2 et 3 étant de même priorité, elles se
partagent à tour de rôle l'accès à l'UART. Nous allons donc protéger l'accès à ce périphérique. Cela
signifie qu'une tâche ayant pris cette ressource matérielle la gardera jusqu'à-ce qu'elle ait fini le
traitement en cours.

• Pour les tâches 2 et 3, placer la fonction d'envoi de données à l'ordinateur dans une section
critique. Utiliser pour cela les macros taskENTER_CRITICAL() et taskEXIT_CRITICAL().

• Compléter le chronogramme suivant et préciser l'état pris par chaque tâche (R = ready et B =
blocked). Attention aux pièges :

• Cette implémentation des sections critiques par FreeRTOS est assez dangereuse, notamment
dans l'exemple actuellement présenté, vu que les Ticks (générés par timer matériel) ne sont
plus vus de l'ordonnanceur pendant la durée d'exécution de la section (section longue en
temps d'exécution). Quel problème cela peut-il poser ?

Nous découvrirons par la suite une solution à base de sémaphores plus douce et surtout
interruptible par le kernel. Attention, une section critique doit-être la plus courte possible par
principe. Ne pas oublier qu'elle peut potentiellement être partagée avec d'autres tâches voir ISR's.
Les solutions utilisant le principe de masquage d'interruption sont donc à utiliser pour des sections
de code très courtes en temps d'exécution.

- 22 -
Systèmes Temps Réel
Travaux Pratiques

3.4. Sémaphore

Durant l'exercice précédent vous avez été amené à manipuler des sections critiques en
utilisant les fonctions taskENTER_CRITICAL() et taskEXIT_CRITICAL(). Cependant sous FreeRTOS, ces
deux fonctions sont à manier avec précaution car une région critique ainsi créée ne peut plus être
préemptée par le noyau, ni par les interruptions matérielles en dessous d'un certain niveau de
priorité système (section non interruptible). Ceci peut donc devenir très dangereux en cas de
mauvaise programmation et en fonction de la criticité de l'application. A l'aide de sémaphores, nous
allons créer des sections critiques pouvant être préempté par le système et également interrompues
par les périphériques matériels.

Dans l'exercice qui suit, nous allons réécrire en partie la bibliothèque C de gestion de l'UART et
donc modifier le fichier source uart.c ainsi que le fichier d'en-tête uart.h.

• retirer les sections critiques précédemment insérées

• copier les fichiers uart.c et uart.h dans le répertoire du projet actuel et renommer
respectivement les fichiers kuart.c et kuart.h (kernel uart). Modifier dans un premier temps
les sources voire la configuration de la chaîne de compilation afin d'assurer une bonne
compilation du projet modifié.

• Créer un sémaphore binaire en choisissant un nom adapté au travail en cours puis modifier le
code source de la fonction uartPutS afin de s'assurer qu'une seule tâche à la fois puisse
prendre en main l'UART en transmission.

• Interpréter le fonctionnement du programme puis compléter le chronogramme suivant en


précisant l'état pris par chaque tâche (R = ready et B = blocked) :

• Sous FreeRTOS, qu'elle différence existe-t-il entre un sémaphore binaire et un mutex ?

• Dans notre cas, est-il plus intéressant d'utiliser un sémaphore binaire ou un mutex ? Justifier
votre réponse puis modifier si nécessaire le programme.

- 23 -
Systèmes Temps Réel
Travaux Pratiques

3.5. Bibliothèque UART avec appels système

Nous allons, dans cet ultime exercice, modifier plus profondément les sources de la librairie de
gestion du module UART. Le but étant d'obtenir une bibliothèque optimisée pour travailler avec
FreeRTOS (pas en vitesse d'exécution mais en robustesse et efficacité).

A titre indicatif, beaucoup d'applications font cohabiter bibliothèque réseau (ou stack réseau)
et système d'exploitation. Microchip propose par exemple un librairie réseau libre et open source
indépendante de tout OS, qui n'est donc pas optimisée pour travailler avec notre kernel. FreeRTOS
propose en revanche une librairie réseau implémentant des appels système qui est donc optimisée
pour cohabiter avec le noyau, néanmoins cette stack est un outil propriétaire. Observons rapidement
le coût de certains de ces services en 2014 :

• Supprimer dans les fichiers /peripherals/kuart/<board-selection>/src/kuart.c et


/peripherals/kuart/<board-selection>/h/kuart.h toute référence à l'utilisation du buffer
circulaire permettant l'échange d'information entre l'ISR de réception de l'UART et la fonction
uartGetC.

• Modifier l'ISR ainsi que la fonction uartGetC en synchronisant par queue de message les
réveils de la fonction d'interruption avec l'appel de la fonction uartGetC. Chaque caractère
reçu sera posté dans la file d'attente et la fonction de réception de caractères implémentera
donc un appel système bloquant en vidant cette queue de message.

• Une fois ce travail réalisé, modifier le code de la tâche 3 de façon à réceptionner puis renvoyer
des chaînes de caractères envoyées depuis l'ordinateur. S'assurer du bon fonctionnement du
programme. Ultime test, envoyer un fichier texte depuis l'ordinateur et s'assurer de sa bonne
réception et renvoi par l'application embarquée. Le fichier est présent dans le répertoire
rtos/queue/rxfile.txt. Sous TeraTerm, aller dans Fichier → Envoyer un fichier...

// received string
uartGetS(strTmp);

// echo of received string


uartPutS("\r\ntask3, received message : ");
uartPutS(strTmp);
uartPutS("\r\n");

- 24 -
Systèmes Temps Réel
Travaux Pratiques

4. PROJET
Travail préparatoire

• 1. (0,5pt) Sachant que le capteur de température utilisé est un TC1047, si en sortie du capteur
je mesure 0,85V, quelle température fait-il approximativement au niveau du boîtier ?

• 2. (0,5pt) Sachant que la plage d'acquisition analogique d'entrée de l'ADC 10bits dans le cadre
de notre application est comprise entre Vref+ - Vref- = VCC - 0 = 3,3V, quelle serait la valeur
numérique précédemment obtenue après conversion ?

• 3. (3pts) Comme dans la plupart des projets industriels utilisant des systèmes temps réel, les
premières ébauches de l'environnement multitâches de l'application sont réalisées par
l'architecte système logiciel sur un bout de papier.

En utilisant le formalisme imposé ci-dessous, représenter graphiquement


l'environnement logiciel de votre application ainsi que les différents mécanismes de
synchronisation, communication et protection mis en œuvre.

A titre indicatif, vous pouvez trouver un exemple de réalisation de projet industriel et


d'environnement multitâches proposé par FreeRTOS à partir de leur solution (Real Time Application
Design Tutorial). Le projet est présenté sous plusieurs angles, solution pleinement préemptive,
optimisée au regard de l'usage de la RAM ...

http://www.freertos.org/tutorial/index.html

- 25 -
Systèmes Temps Réel
Travaux Pratiques

4. PROJET
Travail en séance
4.1. Présentation

Il vous est demandé durant ce projet de mettre en place une plateforme d'acquisition de
température communicante avec un ordinateur muni d'un terminal asynchrone de communication.
Le capteur de température instrumenté est un TC1047 présent sur la maquette de développement
explorer 16.

• Capteur de température

Le capteur de température TC1047 est physiquement connecté à la broche AN4 du MCU qui
est elle même mappée vers une entrée de l'ADC interne du processeur. Nous nous trouvons
actuellement dans un enseignement de découverte et mise œuvre de système temps réel, le travail
n'est donc pas de passer du temps sur la configuration et la gestion de périphérique interne. La
gestion du module ADC sur MCU Microchip a d'ailleurs déjà été vue en première année à l'école. Vous
trouverez donc une librairie C permettant par défaut de lire les valeurs converties présentent sur la
broche AN4 du microcontrôleur. Cette librairie se trouve dans le répertoire
rtos/peripherals/adc/<board-selection>/, charge à vous de la prendre en main.

Si vous le souhaitez durant vos phases de développement, un potentiomètre est également


connecté à la broche AN2 du MCU. Par simple modification des sources de la librairie ADC (cf.
librairie) vous pouvez également effectuer des acquisitions sur cette broche.

- 26 -
Systèmes Temps Réel
Travaux Pratiques

Observons maintenant la réponse tension/température du capteur TC1047. Le schéma


présenté ci-dessous est directement issu de la documentation technique du capteur.

• Analog to Digital Converter

Le convertisseur analogique numérique de donnée interne aux PIC32MX de Microchip est un


ADC 10bits. Cela implique une plage numérique de conversion comprise entre 0 et 1023 (format
entier non signé). La plage analogique de conversion a quant-à-elle été fixée après configuration
entre 0 et 3,3V.

• Reset logiciel

Afin d'effectuer un reset logiciel du MCU, il vous suffit d'appeler la fonction standard
SoftReset() proposée avec la chaîne de compilation.

• Light Emitting Diode

La maquette de développement explorer 16 propose 8 LED's utilisateur. Utiliser la LED de


gauche physiquement reliée à la broche RA7 du MCU pour répondre au cahier des charges.

- 27 -
Systèmes Temps Réel
Travaux Pratiques

4.2. Spécifications

L'application devra être multitâches et réalisera les traitements suivants. Création du projet
dans le répertoire rtos/tempserver :

• une LED servira d'interface utilisateur. Si la température courante est supérieure à


38°C, la LED restera allumée. Si la température est inférieure, la LED devra clignoter
avec une périodicité de 0,5s.

• L'application devra réaliser des acquisitions toutes les 20ms et devra toujours garder
en mémoire les 100 dernières mesures converties.

• L'application devra proposer un interpréteur de commande (console) accessible de


tout ordinateur muni d'un terminal asynchrone (TeraTerm, PuTTY, GTKTerm, minicom,
kermit ...). Cet interpréteur sera relativement simple et ne proposera à l'opérateur
qu'un jeu de 6 commandes :

• read : retourne la dernière valeur convertie

• dump : retourne les 100 dernières valeurs converties

• stream : retourne toutes les 20ms la dernière valeur convertie en effaçant côté
terminal la précédente valeur affichée. Il suffira d'appuyer sur la touche
<Entrée> côté ordinateur pour quitter le mode stream

• reset : force un reset logiciel de l'application

• baudrate : modifie le débit de la liaison série pour la communication avec


l'ordinateur

• help : retourne le menu des commandes supportées par l'application

Au démarrage de l'application, le programme devra proposer l'interface ci-


dessous. L'application sera alors en attente de saisie d'une commande par l'opérateur.

- 28 -
Systèmes Temps Réel
Travaux Pratiques

Exemple d'échanges avec l'application :

• A partir de maintenant, débrouillez-vous et bon courage !

- 29 -
Systèmes Temps Réel
Travaux Pratiques

5. PILE RESEAU MICROCHIP - facultatif

5.1. Présentation

Dans cette ultime partie facultative (uniquement pour les curieux et votre CV), nous allons
nous intéresser aux outils et piles réseaux proposées pour le monde des systèmes embarqués.
Plusieurs types de solutions logicielles sont proposés à notre époque sur le marché (fin 2013).

• Fondeurs (NXP, STmicro ...) ne développant pas de solutions logicielles et passant de des
sociétés tierces (Keil, IAR …). Ces sociétés assurent un support technique sur leurs outils de
développement et bibliothèques fournies. Ces outils sont souvent très onéreux.

• Fondeurs (Microchip, Texas Instruments, Stmicro, NXP … ) développant et proposant des


solutions logicielles à des prix plus ou moins attractifs (IDE, pile réseaux, pile USB, pile
graphique ...).

• Solutions libres, le plus souvent open sources, pouvant être multiplateformes. Le support se
fait en ligne par forum interposés, le plus souvent par la communauté d'utilisateurs voir par
les équipes de développeurs et mainteneurs.

Prenons l'exemple de deux sociétés de développement de suites logicielles très rencontrées


dans le domaine de l'embarqué, Keil et IAR (développement sur MCU's, SoC's, DSP's … notamment
sur architectures ARM). Illustrons les services proposés par Keil, notamment le contenu de la librairie
réseau (TCP/IP Networking Suite) :

- 30 -
Systèmes Temps Réel
Travaux Pratiques

A titre indicatif, une grande partie des services proposés sont payants et très coûteux. Une
version complète, au tarif éducation, n'incluant pas les sources des librairies (sources payants) mais
seulement les binaires, avoisine un coût de ~4000-5000€ par poste. Compter ~12000€ afin d'obtenir
une bibliothèque réseau avec fichiers sources. Des tarifs légèrement plus attractifs sont néanmoins
possibles via des licences à jeton.

5.1.a Pile réseau Microchip

Nous allons quant à nous utiliser les outils Microchip (IDE, chaîne de compilation, pile
réseau ...), développés par Microchip, outils gratuits, libres (sous quelques conditions) et open
sources. Il faut savoir que cette stratégie reste très peu rencontrée dans le domaine de l'embarqué,
même si de plus en plus de fondeurs franchissent le pas. Observons par exemple les services
proposés par la bibliothèque réseau Microchip :

Une bibliothèque ou stack réseau propose au développeur une API de fonctions


implémentant les différents services de chaque couche réseau. Cette pile réseau est supportée par
grand nombre de processeurs Microchip (PIC18, PIC24, dsPIC, PIC32) et l'empreinte mémoire de la
pile complète avoisine sur PIC32 les 90Ko, contre 15Ko pour la couche TCP et couches inférieures.
Néanmoins, les couches basses de la pile nécessitent une communication entre matériel et couches
logicielles supérieures (drivers). La stack Microchip ne propose que le support de quelques
contrôleurs PHY externes (implémentent la couche physique) ou contrôleurs Ethernet MAC/PHY
externes (implémentent les couches MAC et physique).

- 31 -
Systèmes Temps Réel
Travaux Pratiques

Prenons l'exemple de notre maquette de développement (PIC32 MAXI WEB de Olimex) :

5.1.b Berkeley sockets

Berkeley sockets ou BSD sockets est une API de programmation C (supportée par d'autres
langages) implémentant des sockets internet et sockets UNIX. De même, cette API très standard reste
très proche de l'API POSIX. Il faut savoir que Microchip propose une API propriétaire (syntaxe et
fonctionnement propre à Microchip), mais supporte également l'API BSD. Il s'agit en fait d'une
redirection d'une API BSD vers leur librairie. Observerons le descriptif succinct des fonctions BSD
proposées :

• accept : accepte les requêtes de connexion et les place en file d'attente pour une socket en
cours d'écoute.

• Bind : assigne un nom à un descripteur de socket

• closesocket : ferme une socket existante

• connect : connecte une communication appairée

• gethostname : retourne le nom du host au système

• listen : écoute une socket ciblée

• recv : réception de données ayant été mises en file d'attente pour une socket

• recvfrom : réception des données ayant été mises en file d'attente pour une socket

• send : envoie de données vers une socket actuellement connectée

• socket : création d'une nouvelle socket BSD

- 32 -
Systèmes Temps Réel
Travaux Pratiques

Observons un exemple de machine d'état présentant la connexion entre un client (client TCP
par exemple) et un serveur.

- 33 -
Systèmes Temps Réel
Travaux Pratiques

5.2. Serveur TCP

Nous allons maintenant embarqué, dans notre MCU, une partie des services proposés par la
stack réseau de Microchip et mettre en œuvre un serveur TCP. Le client se trouvera quant-à-lui côté
ordinateur. Les premières phases de validation se feront via Telnet, afin de s'assurer du bon
fonctionnement de notre serveur.

• Observons rapidement l'arborescence du projet :

• Créer un projet tcp dans le répertoire network/tcp/pjct. Ce projet doit inclure les fichiers
sources uart.c, main.c, tcp.c. Concernant l'UART, utiliser les fichiers présents dans
../peripherals/uart/<board-selection>/src et le fichier d'en-tête uart.h présent dans
../peripherals/uart/<board-selection>/h

• Ajouter maintenant à votre projet les sources strictement nécessaires de la pile réseau
Microchip. Pour réaliser cet exercice, loin d'être trivial, s'aider de la documentation technique
de la pile (network/Microchip/Help/TCPIP Stack Help) dans la rubrique Using the stack –
Required files.

- 34 -
Systèmes Temps Réel
Travaux Pratiques

• Lister ci-dessous le système de fichiers minimal permettant une première implémentation et


compilation de la pile réseau de Microchip :

• Compléter maintenant le fichier main.c puis s'assurer de la bonne compilation du projet.


S'aider de la documentation technique de la pile (TCPIP Stack Help) dans la rubrique Using
the stack – Main File.

• Lister ci-dessous les appels de fonctions nécessaires à une bonne configuration et utilisation
de la pile :

- 35 -
Systèmes Temps Réel
Travaux Pratiques

• Spécifier le travail réalisé par chacune de ces fonctions. Ne pas hésiter à ouvrir les sources de
chaque fonction afin d'en démystifier leur travail !

• Compiler votre projet et appeler cycliquement la pile. Néanmoins, elle n'implémente pour le
moment aucun service. Nous allons rajouter les services TCP, ICMP (afin de pouvoir réaliser
des ping depuis l'ordinateur) ainsi que l'utilisation de l'API BSD. Pour ce faire, à chaque famille
de contrôleurs réseau supporté par la librairie correspond un fichier d'en-tête de configuration
utilisé pour savoir quels services rajouter à la compilation. Celui nous concernant est
network/Microchip/Configs/TCPIP ETH795.h. Étudions son contenu :

/* Application Level Module Selection


* Uncomment or comment the following lines to enable or
* disabled the following high-level application modules.
*/
//#define STACK_USE_UART // Application demo using UART for IP address ...
//#define STACK_USE_UART2TCP_BRIDGE // UART to TCP Bridge application example
//#define STACK_USE_IP_GLEANING
//#define STACK_USE_ICMP_SERVER // Ping query and response capability
//#define STACK_USE_ICMP_CLIENT // Ping transmission capability
//#define STACK_USE_HTTP2_SERVER // New HTTP server with POST, Cookies, Authenticati...
//#define STACK_USE_SSL_SERVER // SSL server socket support (Requires SW300052)
//#define STACK_USE_SSL_CLIENT // SSL client socket support (Requires SW300052)
//#define STACK_USE_AUTO_IP // Dynamic link-layer IP address automatic configur...
//#define STACK_USE_DHCP_CLIENT // Dynamic Host Configuration Protocol client ...
//#define STACK_USE_DHCP_SERVER // Single host DHCP server
//#define STACK_USE_FTP_SERVER // File Transfer Protocol (old)
//#define STACK_USE_SMTP_CLIENT // Simple Mail Transfer Protocol for sending email
//#define STACK_USE_SNMP_SERVER // Simple Network Management Protocol ...
//#define STACK_USE_SNMPV3_SERVER // Simple Network Management Protocol v3 Agent
//#define STACK_USE_TFTP_CLIENT // Trivial File Transfer Protocol client
//#define STACK_USE_GENERIC_TCP_CLIENT_EXAMPLE // HTTP Client example in GenericTCPClient.c
//#define STACK_USE_GENERIC_TCP_SERVER_EXAMPLE // ToUpper server example in
//#define STACK_USE_TELNET_SERVER // Telnet server
//#define STACK_USE_ANNOUNCE // Microchip Embedded Ethernet Device ...
//#define STACK_USE_DNS // Domain Name Service Client for resolving hostna...
//#define STACK_USE_DNS_SERVER // Domain Name Service Server for redirection to...
//#define STACK_USE_NBNS // NetBIOS Name Service Server for repsonding to …
//#define STACK_USE_REBOOT_SERVER // Module for resetting this PIC remotely. Primarily...
//#define STACK_USE_SNTP_CLIENT // Simple Network Time Protocol for obtaining ...
//#define STACK_USE_UDP_PERFORMANCE_TEST // Module for testing UDP TX performance...
//#define STACK_USE_TCP_PERFORMANCE_TEST // Module for testing TCP TX performance...
//#define STACK_USE_DYNAMICDNS_CLIENT // Dynamic DNS client updater module
//#define STACK_USE_BERKELEY_API // Berekely Sockets APIs are available
//#define STACK_USE_ZEROCONF_LINK_LOCAL // Zeroconf IPv4 Link-Local Addressing
//#define STACK_USE_ZEROCONF_MDNS_SD // Zeroconf mDNS and mDNS service discovery

En dé-commentant les macros correspondants aux services désirés et en incluant les sources
associés au projet, nous pouvons ainsi rajouter à la compilation les services souhaités. Dé-
commenter les services en fonction de nos besoins (ICMP, TCP et BSD API). Vous constaterez à la
compilation que l'utilisation de l'API BSD nécessite l'ajout d'un fichier source supplémentaire.

- 36 -
Systèmes Temps Réel
Travaux Pratiques

• Nous sommes maintenant prêt à développer un serveur TCP. Pour ce faire, rien de compliquer,
nous allons utiliser les fichiers d'exemples fournis par Microchip. Compléter le fichier source
tcp.c présent dans notre projet en vous aidant du fichier source de démonstration fourni avec
la stack (network/Microchip/Demo App). Prendre celui qui semble le plus proche du cahier
des charges puis analyser le code ainsi importé.

• Représenter sous forme graphique (rectangle et flèches) le fonctionnement de la machine


d'état implémentée par le serveur TCP BSD du programme précédent :

• Quel traitement réalise ce programme ?

• Avant de tester votre application, réaliser un ping sur l'adresse du serveur et s'assurer de la
bonne réponse du système.

• Pour tester votre serveur, votre allons établir une communication depuis Telnet. Ouvrir un
client Telnet sur votre machine puis établir une communication avec le serveur embarqué.

• Modifier le code du serveur afin qu'il réalise un echo vers l'UART des caractères reçus. Voilà,
vous venez d'implémenter un bridge TCP/UART !

- 37 -
Systèmes Temps Réel
Travaux Pratiques

5.3. Services TCP/IP

5.3.a Serveur UDP

• Sans pour autant le tester, expliquer rigoureusement ci-dessous quelle aurait été votre
démarche afin d'implémenter un serveur UDP utilisant l'API BSD.

5.3.b Serveur HTTP

Un serveur web est une application dont le service de base est de distribuer des fichiers
écrits en HTML. On se propose d'écrire un programme affichant des relevés de températures.
Lorsqu'un utilisateur tape ceci dans la barre d'URL de son navigateur :

http://machine.nomDeDomaine:1999/repertoire/fichier.html

Le navigateur essaye de se connecter à la machine ''machine.nomDedomaine'' et à un


programme écoutant le port 1999. Ensuite, il envoie une série de chaînes de caractères dont la
première est :
''GET /repertoire/fichier.html HTTP/1.1\n\n''

Le serveur renvoie alors une entête HTTP qui est une chaîne de caractères qui précise entre
autre la version du protocole HTTP, un code d’erreur (200 : pas d’erreur) et le type de document
transporté. Par exemple :
''HTTP/1.1 200 OK \n content-type: text/html \n\n"

Ensuite, le serveur envoie le fichier d'un seul bloc, puis ferme la connexion. Si le fichier est
absent, il renvoie la chaîne suivante à la place et ferme la connexion. Le port par défaut des serveurs
web est 80 et non pas 1999.
"http/1.1 404 ERROR\n\n"

• Écrire un programme qui écoute le port 80 et envoie sur l'UART la première ligne qu'il reçoit.

• Se connecter au précédent programme via un navigateur web (modifier les paramètres du


proxy : connexion direct à internet). Écrire un programme qui renvoie une page web statique,
quelque soit la requête du navigateur. Attention à bien transmettre l'entête HTTP avant le
code HTML.

- 38 -
Systèmes Temps Réel
Travaux Pratiques

6. PROJET RTOS ET PILE RESEAU

Voilà, nous arrivons à la fin de cet exercice complémentaire. Dernier travail à réaliser, intégrer
au projet réalisé sous FreeRTOS (serveur de température via UART) un serveur TCP. Comme pour le
projet précédent, l'application devra proposer non seulement un shell vers l'UART mais également un
shell TCP sur le port 5151.

Attention, après intégration à votre projet de FreeRTOS et de la pile réseau de Microchip, vous
allez rencontré un problème à la compilation. En effet, la stack et le RTOS utilisent le même timer afin
d'implémenter leurs références internes de comptage (Timer1). Utiliser le fichier TickTimer2.c
présent dans /network/Microchip/TCPIP Stack au lieu de Tick.c. Ce fichier à été modifié par nos soins
et ne fait que reconfigurer le timer 2 ainsi que l'ISR associée au lieu du Timer1 (niveau première
année).

- 39 -
Systèmes Temps Réel
Travaux Pratiques

7. PORTAGE PILE RESEAU MICROCHIP

Intéressons-nous à la méthodologie de portage de la pile réseau proposée par Microchip.


Cette méthodologie peut bien entendu être étendue à d'autres stack proposées par Microchip voir
d'autres fondeurs.

• Télécharger la pile réseau sur le site officiel de Microchip (travail déjà réalisé sur les postes
école). Si vous attaquez un nouveau projet, toujours utiliser (si possible) la dernière version
disponible, le plus souvent plus robuste. Garder toujours les anciennes versions pour soucis de
compatibilité avec vos anciens projets :

www.microchip.com/tcpip

Vous constaterez que Microchip concentre toutes ses librairies évoluées (stack
graphique, USB, SD card …) dans un même outils, appelé MAL (Microchip Application Libraries,
www.microchip.com/mal). A l'installation, vous pouvez choisir de n'installer que la pile
réseau.

• Voici le contenu de l'arborescence de fichiers, si vous ne téléchargez que la pile réseau.


L'installation se fait par défaut à la racine du disque c:\ sous Windows. Ne pas hésiter à aller
observer le contenu de ce système de fichiers sur votre machine de développement :

- 40 -
Systèmes Temps Réel
Travaux Pratiques

• Si seule la pile réseau nous intéresse, vous pouvons choisir de n'importer vers vos projets que
les sources et fichiers d'en-tête nécessaires. Il faut néanmoins garder l'arborescence imposée
par Microchip par soucis de dépendance des fichiers d'en-tête. Ne pas oublier de rapatrier
également le contenu du répertoire C:\microchip_solutions_v2013-06-15\TCPIP\Demo
App\Configs contenant des headers propres aux contrôleurs externes PHY ou MAC/PHY
supportés par la stack. Observons l'arborescence minimale pour réaliser du développement
sur la pile réseau Microchip :

• Après importation de la pile vers votre répertoire de projet, nous sommes maintenant prêt à
le créer. Ouvrir MPLABX, créer un nouveau projet et ajouter les fichiers sources strictement
nécessaires à une utilisation minimale de la pile. Pour réaliser cet exercice, loin d'être trivial,
s'aider de la documentation technique de la pile (Help\TCPIP Stack Help) dans la rubrique
Using the stack – Required files.

• main.c
• APR.c
• Delay.c
• Physical layer files ? (vu juste après)
• Helper.c
• IP.c
• StackTsk.c
• Tick.c

- 41 -
Systèmes Temps Réel
Travaux Pratiques

• Observons une capture d'écran de MPLABX à ce niveau là du projet :

• La partie qui suit peut en revanche être délicate en fonction du contrôleur matériel externe
PHY ou MAC/PHY que vous souhaitez interfacer (composant entre MCU et connecteur RJ45).

• Si votre contrôleur est supporté par la pile réseau (ENC28J60, ENCX24J600, ETH97J60,
SMSC8700 ...),nous n'avons qu'à rajouter les fichiers sources et headers propres au
contrôleur

• Si votre contrôleur n'est pas supporté par la pile réseau et n'est pas compatible
broche à broche et registre à registre avec un des contrôleurs supportés, nous avons à
développer nous même les drivers. Ce travail peut prendre plusieurs jours de
développement. Toujours s'inspirer de drivers proches de celui en cours de
développement. Ne jamais réinventer la poudre.

• Si votre contrôleur n'est pas supporté par la pile réseau mais est compatible broche à
broche et registre à registre avec un des contrôleurs supportés (notre cas sur la
maquette PIC32 MAXI WEB), nous n'avons qu'à rajouter les fichiers sources et headers
propres au contrôleur déjà supporté.

Par exemple, le contrôleur PHY présent sur la maquette est un KS8721B et est
compatible (broche/broche et registre/registre) avec le SMSC8700 qui lui est supporté.
En ajoutant la macro CFG_INCLUDE_PIC32_ETH_SK_ETH795 à la configuration de votre
projet, vous pouvez pré-configurer, avant compilation, l'inclusion de tous les fichiers
d'en-tête nécessaires :

- 42 -
Systèmes Temps Réel
Travaux Pratiques

• Inclure les fichiers sources propres au contrôleur utilisé. Dans notre cas, nous utiliserons le
contrôleur MAC interne aux PIC32 et un contrôleur PHY externe. Observons le projet après
inclusion des sources nécessaires :

• Ajouter maintenant les fichiers d'en-tête nécessaires à une bonne compilation du projet. Ces
fichiers sont présents dans les répertoires Microchip/Configs, Microchip/Include et
Microchip/Include/TCPIP Stack. Cette étape n'a pour but que de proposer des raccourcis vers
les headers, ne pas oublier donc de configurer la chaîne de compilation.

- 43 -
Systèmes Temps Réel
Travaux Pratiques

• Configurer maintenant sous L'IDE les chemins vers les tous les fichiers d'en-tête nécessaires au
projet. Cette étape configure les paths/chemins de votre chaîne de compilation et dépend de
l'arborescence et du système de fichier du projet :

• Voilà, nous sommes enfin prêt pour une première compilation.

• Afin de commencer à compléter le fichier main.c, s'aider de l'aide fournie avec la stack (TCPIP
Stack Help) via la rubrique Using the stack – Main File :

- 44 -
Systèmes Temps Réel

ANNEXES
Systèmes Temps Réel

SOMMAIRE

1. CREATION DE PROJET MPLABX IDE

2. INTRODUCTION MPLABX IDE

3. INTRODUCTION FREERTOS

4. PORTAGE FREERTOS

5. FICHIER FreeRTOSConfig.h

REGLES DE CODAGE

GLOSSAIRE
Systèmes Temps Réel Systèmes Temps Réel
Annexes Annexes

1. CREATION DE PROJET MPLABX IDE • Sélectionner l'architecture et le MCU cible. Cette étape est à adapter en fonction de vos
projets. Dans l'exemple ci-dessous il s'agit de la famille PIC32 sur MCU PIC32MX795F512L :

• Créer un répertoire au nom de votre projet et importer vos fichiers sources et fichiers d'en-
tête. Dans les captures d'écrans suivantes, le répertoire du projet se nomme example ainsi
que le fichier source principal. Ne pas hésiter à créer une arborescence plus riche en fonction
de la complexité de votre projet. Par exemple : example/h, example/src et example/pjct

• Connecter la sonde de programmation à l'ordinateur de développement puis ouvrir MPLABX : • Sélectionner la sonde de programmation à utiliser :

• Créer un nouveau projet : File -> New Project -> Next • Sélectionner la chaîne de compilation à utiliser. Cette étape est à adapter en fonction des
outils installées sur la machine de développement. Il faut toujours essayer d'attaquer de
nouveaux projets avec les dernières versions proposées tout en gardant les anciennes pour
des problèmes de compatibilité pour vos anciens projets :

-1- -2-
Systèmes Temps Réel Systèmes Temps Réel
Annexes Annexes

• Donner un nom au projet tout en étant prudent à la localité du répertoire de travail. Sur les • Si le projet ne possède pas de dépendances avec des fichiers d'en-tête, il est alors possible de
machine de TP, vous avez la possibilité de travailler sur le répertoire Z: (lecteur réseau le compiler dès maintenant.
accessible de n'importe quel poste) ou dans le répertoire C:/…/Documents localement
présent sur la machine.
• En cas de dépendances avec des headers, ne pas oublier de configurer les chemins ou path de
la chaîne de compilation :

• Cliquer sur Finish, pour terminer la création du projet.


• Effectuer le même travail avec la chaîne d'assemblage si le projet possède des fichiers sources
assembleur.
• Ajouter maintenant les fichiers sources au projet : Clic droit sur Sources Files -> Add Existing
Item …

-3- -4-
Systèmes Temps Réel Systèmes Temps Réel
Annexes Annexes

2. INTRODUCTION MPLABX IDE

Nous allons travailler sous MPLABX qui est l'environnement de développement ou IDE
(Integrated Development Environment) libre proposé par Microchip pour toute sa gamme de MCU's.
Comme tout IDE, MPLABX doit être associé à une chaîne de compilation ou toolchain. Par exemple
C18 ou XC18 pour la famille PIC18 et C32 ou XC32 pour la gamme PIC32. Tous les outils logiciel
proposés par Microchip sont gratuits et librement téléchargeables sur le site du fondeur. Seules
certaines versions des chaînes de compilation proposées sont payantes et ouvrent la porte à de
meilleures performances d'optimisation à la compilation.

http://www.microchip.com/

Vous pouvez d'ailleurs développer et pré-compiler vos sources chez vous du moment que
vous restez au stade de la compilation ou de la simulation. Si vous le souhaitez, les TP peuvent
également être réalisés sur votre machine personnelle du moment que l'installation des outils ait
été faite avant l'arrivée en séance et que votre machine offre des performances suffisantes.

• Présentation des principaux raccourcis à connaître sur MPLABX :

-5- -6-
Systèmes Temps Réel Systèmes Temps Réel
Annexes Annexes

3. INTRODUCTION FREERTOS • Types de données

Pour assurer une portabilité du noyau, les développeurs de FreeRTOS ont utilisé des
définitions de type. Par exemple sur XC18 (sur PIC18) un int est un entier sur 16bits, sous XC32
(sur PIC32) il s'agit d'un entier sur 32bits. Sous XC32, les types utilisés par FreeRTOS sont les
• États possibles pour une tâche sous FreeRTOS : suivants :

• portCHAR char (entier sur 8bits)


• portSHORT short (entier sur 16bits)
• portLONG long (entier sur 64bits)
• portBASE_TYPE int (entier sur 32bits)
• ...

Le type portBASE_TYPE change d'un MCU à un autre et dépend de l'architecture du


CPU. Par exemple sur un cœur 8bits ce type vaudra probablement 8bits et donc 32bits sur un
cœur 32bits ...

• Préfixes de type :

Afin d'éviter de longues recherches au sein du système de fichiers de FreeRTOS, les


variables et les fonctions utilisées par le noyau sont préfixées. Cela signifie qu'avant de donner
le nom de la variable ou de la fonction, des caractères sont insérés. Prenons quelques
exemples, ''xSemaphore xBinSem'' (variable) ou encore
xQueueReceive() (fonction). Découvrons les principaux préfixes :

• c: char
• s: short
• l: long
• x: portBASE_TYPE
• p: pointeur
• v: void (fonction ne retournant aucun paramètre)
• u: unsigned
• uc : unsigned char
• pc : pointeur sur un char ...
• État Suspendu ou Suspended state :
• Préfixes de localité :
Cet état est propre à FreeRTOS. Une tâche dans cet état n'est plus vue du noyau est ne
fait plus partie des tâches gérées par l’ordonnanceur. Cet état est donc à manier avec grande Afin de localiser rapidement le fichier de définition d'une variable, d'une macro ou
précaution sachant qu'il reste de plus relativement peu utilisé. Les seules fonctions d'une fonction un préfixe suit celui du type (cf. ci-dessus). Prenons quelques exemples :
permettant de mettre une tâche dans cet état sont les suivantes :
• vTaskPrioritySet() retourne un void et est définie dans task.c
• vTaskSuspend() • xQueueReceive() retourne un portBASE_TYPE et est définie dans Queue.c
• vTaskSuspendAll() • vSemaphoreCreateBinary() retourne un void et est définie dans semphr.h
• vTaskResume()
• vTaskResumeAll() Découvrons les principaux préfixes (macros et fonctions) :
• vTaskResumeFromISR()
• config : FreeRTOSConfig.h
• task ou Task : task.h ou task.c
• pd : projdefs.h ...

-7- -8-
Systèmes Temps Réel Systèmes Temps Réel
Annexes Annexes

4. PORTAGE FREERTOS • Copier le système de fichiers (après avoir fait du vide) dans votre répertoire de travail. Cette
étape n'est pas obligatoire mais offre l'avantage d'assurer la portabilité de votre projet vers
une autre machine.

Nous allons maintenant présenter une méthodologie de portage de FreeRTOS vers votre
application. Nous verrons que cette méthode n'est pas unique et que certaines étapes peuvent
différées en fonction des habitudes de chaque développeur.

• Télécharger les sources du noyau sur le site officiel :

www.freertos.org
http://sourceforge.net/projects/freertos/files/FreeRTOS/

• Voici ci-dessous le système de fichiers du noyau. Les répertoires marqués d'une croix rouge ne
sont pas utiles à la bonne compilation d'un projet.

• Après avoir créé un projet sous MPLABX, nous allons y-intégrer les sources du noyau. Créer
également des sous-répertoires dans votre arborescence du projet afin de faciliter
d'éventuelles futures recherches.

-9- - 10 -
Systèmes Temps Réel Systèmes Temps Réel
Annexes Annexes

• Arborescence du projet sous MPLABX. Remarque, nous travaillerons avec le fichier heap_1.c 5. FICHIER FreeRTOSConfig.h
pour la stratégie de gestion du tas :

Ce fichier comportant que des macros est le seul physiquement sorti du système de fichiers de
FreeRTOS. Il est essentiel et assure la configuration du noyau avant compilation. Pour bien
comprendre son rôle, illustrons deux cas de figure :

• toutes (ou presque) les macros sont à ''1'' : Si toutes les macros sont forcées à 1 (ou valeur
propre à la macro) nous pouvons alors utiliser toutes l'API et fonctionnalités proposées par
FreeRTOS. Cependant, la taille du code sera maximale. En effet toutes les fonctions auront été
compilées, linkées et seront embarquées dans la mémoire programme du processeur, qu'on
les utilise ou pas.

• Toutes les macros sont à ''0'' : Nous en pourrons utiliser que les principales fonctionnalités de
FreeRTOS. Les services système (et donc les macros associées) devront être rajoutées au fur et
à mesure des besoins afin de ne pas gaspiller inutilement les ressources mémoire du
processeur.

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

#define configUSE_PREEMPTION 0
#define configTICK_RATE_HZ ( ( portTickType ) 1000 )
#define configPERIPHERAL_CLOCK_HZ (80000000UL)
#define configCPU_CLOCK_HZ (80000000UL)

#define configUSE_16_BIT_TICKS 0
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configUSE_COUNTING_SEMAPHORES 0
#define configUSE_MUTEXES 0
• Spécifier à la chaîne de compilation les chemins ou path vers les fichiers d'en-tête de
FreeRTOS. Attention, cette étape est à adapter en fonction de l'arborescence de votre projet. #define configMINIMAL_STACK_SIZE ( 240 )
Se rendre dans File >> Project Properties : #define configISR_STACK_SIZE ( 400 )
#define configKERNEL_INTERRUPT_PRIORITY 0x01
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 0x04

#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 6 )


#define configTOTAL_HEAP_SIZE ( ( size_t ) 24000 )
#define configMAX_TASK_NAME_LEN (8)
#define configIDLE_SHOULD_YIELD 0
#define configCHECK_FOR_STACK_OVERFLOW 0

/* Co-routine definitions. *
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES (2)

/* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */
#define INCLUDE_uxTaskPriorityGet 0
#define INCLUDE_vTaskDelete 0
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend 0
#define INCLUDE_vTaskDelayUntil 0
#define INCLUDE_vTaskDelay 0
#define INCLUDE_uxTaskGetStackHighWaterMark 0

#endif /* FREERTOS_CONFIG_H */

- 11 - - 12 -
Systèmes Temps Réel Systèmes Temps Réel
Annexes Annexes

REGLES DE CODAGE ● Structures de contrôle : règles spécifiant l'indentation ainsi que les espaces à respecter
pour l'écriture de structures de contrôle.

do {
Ce document à pour objectif de fixer un cadre et des règles de codage en langage C pour les if (a == b) {
enseignements de Systèmes Embarqués à l'ENSICAEN. Cette démarche reflète les contraintes que ...
vous aurez d'ici quelques années à suivre dans le monde de l'entreprise. La plupart des entreprises } else if (a > b) {
travaillant dans le domaine du développement logiciel, dont l'embarqué fait parti, imposent à leurs ...
} else {
développeurs des règles semblables à celles-ci (beaucoup plus exhaustives en général). L'objectif
...
étant de standardiser, clarifier, cadrer et faciliter le partage de codes sources au sein d'une équipe }
voir de l'entreprise. Les règles de codage imposées sont inspirées du ''Linux Kernel Coding Style'' et
du ''GNU Coding Standard''. Voici le sommaire de ce document : /* single statement */
if (condition)
action1();
1. Indentation
else
2. Dénomination action2();
3. Commentaire
4. Divers } while (condition);

INDENTATION
DENOMINATION

● Tabulation : 8 caractères (à régler dans les préférences de l'éditeur de texte). ● Fonctions : Toujours débuter par une minuscule. Pour donner un nom complexe,
utiliser comme séparateur une Majuscule ou un ''_''.
switch (data) {
case 'A': ● Variables locales : Toujours débuter par une minuscule. Les variables servant de
case 'B':
/* comment */ compteur de boucle peuvent avoir un nom sans sens précis, par exemple ''i''. Sinon,
data <<= 20; toujours donner à une variable un nom court permettant d'identifier clairement son
break; rôle. Déclarez vos variables locales en début de fonction (portabilité de code).
default:
break;
● Variables globales : Toujours débuter par une minuscule. Toujours donner à une
}
variable globale un nom permettant d'identifier clairement son rôle (séparateurs ''_''
ou Majuscules). Bien évidemment, éviter tant que faire se peut les variables globales
● Nombres de niveaux d'indentation : Éviter plus de 3 niveaux d'indentation imbriqués. (ressources partagées).
Facilite la lisibilité du code.
int tempProcessA, temp_process_B;
● Nombres de colonnes par page : 80 caractères/colonnes par page (à régler dans les
préférences de l'éditeur de texte). void lm4567_codec_ init (void)
{
temp_process_B++;
● procédures : cas spécial pour le fonctions, ouvrir l’accolade au début de la ligne …
suivante }

int function (int x, int y) ● Définition de type : Toujours débuter par une Majuscule. Toujours définir un nom
{
int z ; permettant d'identifier clairement le type des variables déclarés.

...
HandleSpiModule a; // Bien !
return 0;
Hmod a; // Pas Bien !
}

- 13 - - 14 -
Systèmes Temps Réel Systèmes Temps Réel
Annexes Annexes

● Macros : Toujours en Majuscule. Utiliser comme séparateur un ''_'' pour les noms ● Quelques tags supplémentaires (cf. www.doxygen.org ):
complexes. Pour les macros fonctions, appliquer les même règles de dénomination que
pour les fonctions. /**
* @example example insertion
#define UART_BAUDRATE 0xFFFF * @warning warning insertion
#define mul (x, y) x*y * @li bullet point insertion
* @mainpage main page comments insertion
* @image picture insertion
COMMENTAIRES * @include code insertion
*/

● Toujours penser à expliquer ce que votre code fait et non comment il le fait !
DIVERS
● C99 style : Ne pas utiliser ''//'' (problème de portabilité)

● C89 style : Toujours utiliser ''/* ... */'' (solution portable) ● Valeur de retour : Essayer de faire en sorte que la valeur de retour d'une fonction soit
représentative de son bon traitement. Par exemple, retourne zéro (ou pointeur nul) en
● Balise pour la documentation de code (exemple de Doxygen) : Insérer dans vos cas d'échec et différent de zéro en cas de succès. Les résultats des procédures seront
cartouches quelques tags standards, par exemple ceux de Doxygen. Attention, seuls les retournés par pointeur via les paramètres d'entrée.
fichiers d'en-tête doivent contenir des balises pour la génération de documentation.
Doxygen permet la génération automatique de documentation vers différents formats
(HTML, PDF, CHM ...). Ne pas utiliser de caractères accentués dans vos commentaires.

/**
* @file example.h
* @brief demo header file
* @author
*/

int temp_conv; /* converted data from temperature sensor */

/**
* @struct Str_data_buffer
* @brief Objet latch converted data from temperature sensor
*/
typedef struct {
int buffSize
int* allocCnvTab
} Str_data_buffer;

/**
* @brief read data codec LM4567 controller
* @param resetVal imput value
* @param cnvResult converted value
* @return null if data conversion error
*/
Handle_spi_module lm4567_codec_read (char resetVal, float cnvResult);

- 15 - - 16 -
Systèmes Temps Réel Systèmes Temps Réel
Annexes Annexes

GLOSSAIRE • FPU : Floating Point Unit


• FLOPS : Floating-Point Operations Per Second
• FMA: Fused Multiply-Add

A G

• ABI : Application Binary Interface • GCC : Gnu Collection Compiler


• ADC : Analog to Digital Converter • GLCD : Graphical Liquid Crytal Display
• ALU : Arithmetic and Logical Unit • GNU : GNU's Not UNIX
• AMD : Advanced Micro Devices • GPIO : General Purpose Input Output
• ANSI : American National Standards Institute • GPP : General Purpose Processor
• API : Application Programming Interface • GPU : Graphical Processing Unit
• APU : Accelerrated Processor Unit
• ARM : société anglaise proposant des architectures CPU RISC 32bits
• ASCII : American Standar Code for Information Interchange I

B • IA-64 : Intel Architecture 64bits


• I2C : Inter Integrated Circuit
• ICC : Intel C++ Compiler
• BP : Base Pointer
• IDE : Integrated Development Environment
• BSL : Board Support Library
• IDMA : Internal Direct memory Access
• IRQ : Interrupt ReQuest
C • ISR : Interrupt Software Routine
• ISR : Interrupt Service Routine
• CCS : Code Composer Studio
• CEM : Compatibilité ElectroMagnétique L
• CISC : Complex Instruction Set Computer
• CPU : Central Processing Unit
• L1D : Level 1 Data Memory
• CSL : Chip Support Library
• L1I : Level 1 Instruction Memory (idem L1P)
• L1P : Level 1 Program Memory (idem L1I)
D • Lx : Level x Memory
• LCD : Liquid Crytal Display
• DAC : Digital to Analog Converter • LRU : Least Recently Used
• DDR : Double Data Rate
• DDR SDRAM: Double Data Rate Synchronous Dynamic Random Access Memory M
• DMA : Direct Memory Access
• DSP : Digital Signal Processor
• MAC: Multiply Accumulate
• DSP : Digital Signal Processing
• MCU : Micro Controller Unit
• MIMD : Multiple Instructions on Multiple Data
E • MIPS : Mega Instructions Per Second
• MMU : Memory Managment Unit
• EDMA : Enhanced Direct Memory Access • MPLABX : MicrochiP LABoratory 10, IDE Microchip
• EUSART : Enhanced Universal Synchronous Asynchronous Receiver Transmitter • MPU : Micro Processor Unit ou GPP
• EMIF : External Memory Interface • MPU : Memory Protect Unit
• EPIC : Explicitly Parallel Instruction Computing
O
F
• OS : Operating System

- 17 - - 18 -
Systèmes Temps Réel
Annexes

• PC : Program Counter
• PC : Personal Computer
• PIC18 : Famille MCU 8bits Microchip
• PLD : Programmable Logic Device
• POSIX : Portable Operating System Interface, héritage d'UNIX (norme IEEE 1003)
• PPC : Power PC

• RAM : Random Access Memory


• RISC : Reduced Instruction Set Computer
• RS232 : Norme standardisant un protocole de communication série asynchrone
• RTOS : Real Time Operating System

• SDK : Software Development Kit


• SIMD : Single Instruction Multiple Date
• SOB : System On Board
• SOC : System On Chip
• SOP : Sums of products
• SP : Stack Pointer
• SPI : Serial Peripheral Interface
• SRAM : Static Random Access Memory
• SSE : Streaming SIMD Extensions
• STM32 : STMicroelectronics 32bits MCU

• TI : Texas Instruments
• TNS : Traitement Numérique du Signal
• TSC : Time Stamp Counter
• TTM : Time To Market

• UART : Universal Asynchronous Receiver Transmitter


• USB : Universal Serial Bus

• VHDL : VHSIC Hardware Description langage


• VHSIC : Very High Speed Integrated Circuit
• VLIW : Very Long Intruction Word

- 19 -

Vous aimerez peut-être aussi