Logs
Consultez les logs.
OK
Liste des données
Consultez la liste des données.
OK
Loading...
Formulaire
Saisissez vos données.
Enregistrer
Annuler

Références TTA

Vues
178

TTA (Time-Triggered Architecture) ou (Architecture déclenchée par le temps) est une approche de conception utilisée dans les systèmes embarqués temps réel pour garantir la prévisibilité, la fiabilité et la tolérance aux pannes. Elle est particulièrement pertinente dans les applications critiques pour la sécurité, telles que l'automobile, l'aérospatiale et les systèmes de contrôle industriel, où la synchronisation et la fiabilité sont cruciales pour le bon fonctionnement du système.

Dans ce tutoriel, vous apprendrez à implémenter la structure logicielle de l'ordonnanceur multi-tâches temps-réel TTA en langage C pour générer un signal carré modulé à partir d'un système embarqué basé sur le microcontrôleur 8051  avec l'utilisation du timer T2.



Opérations sur les définitions



Architecture TTA (Time-Triggered Architecture)


TTA (Time-Triggered Architecture) ou (Architecture déclenchée par le temps) est une approche de conception utilisée dans les systèmes embarqués temps réel pour garantir la prévisibilité, la fiabilité et la tolérance aux pannes. Elle est particulièrement pertinente dans les applications critiques pour la sécurité, telles que l'automobile, l'aérospatiale et les systèmes de contrôle industriel, où la synchronisation et la fiabilité sont cruciales pour le bon fonctionnement du système.

Dans l'architecture TTA, les tâches ou activités sont exécutées selon des calendriers prédéfinis, garantissant ainsi la survenue déterministe des événements système. Cette approche temporelle permet de gérer la complexité, de réduire la latence du système et d'améliorer la tolérance aux pannes en isolant l'impact des pannes sur chaque composant.

Composants clés de l'architecture TTA


Heure globale synchronisée : l'architecture TTA s'appuie sur une référence temporelle globale synchronisée sur tous les composants du système. Cela permet une coordination précise des tâches et une communication entre les différents sous-systèmes ou noeuds.
Tâches déclenchées par le temps : dans l'architecture TTA, les tâches sont exécutées à des intervalles de temps prédéfinis, garantissant ainsi la prévisibilité et le déterminisme des événements système. Cela permet une meilleure utilisation des ressources et simplifie la conception du système, car les tâches peuvent être planifiées et optimisées en fonction de leurs contraintes temporelles.
Communication temporisée : l'architecture TTA utilise des protocoles de communication temporisés, tels que le protocole TTP (Time-Triggered Protocol) ou l'Ethernet TTE (Time-Triggered Ethernet), pour garantir une communication déterministe entre les composants du système. Ces protocoles assurent une communication prévisible et à faible latence, avec des mécanismes intégrés de tolérance aux pannes, tels que la détection d'erreurs et la redondance.
Tolérance aux pannes : l'architecture TTA est conçue pour assurer la tolérance aux pannes en isolant l'impact des pannes sur les composants individuels, empêchant ainsi leur propagation dans le système. Ce résultat est obtenu grâce à des techniques telles que la redondance, la détection et la récupération d'erreurs, qui contribuent à maintenir le fonctionnement du système même en cas de défaillance d'un composant.

Importance de l'architecture déclenchée par le temps


Prévisibilité et déterminisme : l'architecture TTA garantit que les tâches et les événements de communication se produisent de manière prévisible et déterministe, permettant aux concepteurs de systèmes de répondre à des exigences de timing strictes et de garantir les performances du système.
Fiabilité : En fournissant des mécanismes de tolérance aux pannes, l'architecture TTA contribue à améliorer la fiabilité du système, garantissant un fonctionnement continu même en présence de pannes de composants.
Conception de système simplifiée : l'architecture TTA simplifie la conception du système en permettant une meilleure utilisation des ressources et une planification prévisible des tâches, réduisant ainsi la complexité et facilitant le processus de développement.
Évolutivité : l'architecture TTA est hautement évolutif, car l'approche basée sur le temps peut être appliquée à des systèmes avec un nombre variable de composants, ce qui le rend adapté à une large gamme d'applications.

Exemples pour illustrer les concepts clés


Dans les systèmes automobiles, l'architecture TTA est utilisé dans les unités de contrôle électronique (ECU) pour assurer une communication déterministe et l'exécution des tâches, améliorant la fiabilité du système et répondant à des exigences de synchronisation strictes pour des fonctions telles que le contrôle du moteur, le freinage et l'assistance au conducteur.
Dans les systèmes aérospatiaux, l'architecture TTA est utilisé dans les systèmes de contrôle de vol et l'avionique pour fournir une communication déterministe et une tolérance aux pannes, garantissant la fiabilité et la sécurité du système dans les opérations de vol critiques.

Système RTOS (Real-Time Operating System)


L'architecture TTA est un système informatique qui exécute un ou plusieurs ensembles de tâches selon un planning prédéfini. La mise en oeuvre d'un système TT implique généralement l'utilisation d'une interruption unique liée au dépassement périodique d'un temporisateur (Timer). Cette interruption peut piloter un ordonnanceur de tâches (Scheduler), une forme restreinte de système d'exploitation temps réel RTOS (Real-Time Operating System). L'ordonnanceur libère ensuite les tâches système à des moments prédéterminés.

image.png

Editeur Keil µVision


Keil µVision est une plateforme de développement logiciel Windows qui combine un éditeur robuste et moderne avec un gestionnaire de projet et un outil de création . Elle intègre tous les outils nécessaires au développement d'applications embarquées, notamment un compilateur C/C++, un assembleur de macros, un éditeur de liens/localisateurs et un générateur de fichiers HEX.


Analyseur de Performances (Performance Analyzer)


L'analyseur de performances affiche les statistiques d'exécution, comme le temps et le nombre d'appels d'une fonction ou d'un module.

image.png

Les résultats sont affichés sous forme de graphiques à barres. Des statistiques, telles que le nombre d'appels, la durée minimale, la durée maximale et la durée moyenne, sont affichées pour la fonction ou la plage d'adresses spécifiée.

La plage d'adresses (unspecified) est générée automatiquement. Elle indique le temps passé à exécuter du code non inclus dans les fonctions ou plages d'adresses spécifiées.

Simulateur Proteus


Le logiciel Proteus est principalement connu pour éditer des schémas électriques. Par ailleurs, le logiciel permet également de simuler ces schémas ce qui permet de déceler certaines erreurs dès l'étape de conception.

La fonctionnalité la plus intéressante et la plus importante de Proteus est sa capacité à simuler l'interaction entre un logiciel exécuté sur un microcontrôleur et tout composant électronique analogique ou numérique qui lui est connecté. Le modèle du microcontrôleur est intégré au schéma, avec les autres éléments de conception de votre produit.


Opérations sur l'éditeur Kei µVision



Création d'un projet C51


image.png

image.png

image.png

image.png

image.png

Ajout d'un nouveau fichier source


image.png

image.png

image.png

image.png


Compilation du projet (Build)


image.png

Recompilation du projet (Rebuild)


image.png

Génération d'un fichier exécutable (HEX)


image.png

image.png

image.png

Utilisation du débogueur


Dans l'éditeur Keil µVision :

On place un point d'arrêt sur une ligne de code (1).
On démarre le débogueur (2).
On peut passes au prochain point d'arrêt (3).
Le débogueur s'arrête au prochain point d'arrêt (4).
On peut entrer à l'intérieur d'une fonction (5).

image.png

Dans l'éditeur Keil µVision :

On peut avancer à la ligne de code suivante (1).
Le débogueur s'arrête à la ligne de code souhaité (2).
On peut afficher le contenu d'une variable (3).
On peut sortir à l'extérieur d'une fonction (4).
On peut arrêter le débogueur (5).

image.png

Dans l'éditeur Keil µVision :

On peut visualiser la pile des appels (1).

image.png

Utilisation de l'analyseur de performances


Dans l'éditeur Keil µVision :

On démarre le débogueur (1).
On ouvre l'analyseur de performances (2).

image.png

Dans l'éditeur Keil µVision :

On ouvre l'interface de configuration de l'analyseur de performances (1).

image.png

Dans l'éditeur Keil µVision :

On double-clique pour sélectionner une fonction (1, main) à ajouter dans l'analyseur de performances.
La fonction apparaît dans la zone de saisie (2, Define Performance Analyzer Range).
On ajoute la fonction dans l'analyseur de performances (3, Define).
La fonction apparaît dans la zone de texte (4, Current PA Ranges).

image.png

Dans l'éditeur Keil µVision :

On démarre l'analyseur de performances (1).
On détermine la fonction gourmande en temps CPU (2, tta_go_to_sleep). Le microcontrôleur passe la majeur partie de son temps à dormir (mode IDLE).

Le planificateur TTA favorise à l'économie d'énergie tout en restant réactif face à l'exécution des tâches.

On sélectionne la fonction à analyser (3, tta_go_to_sleep).
On détermine la durée maximale d'exécution de la fonction (4, max time, 0.000325 s, 0.325 ms, tta_go_to_sleep).
On détermine la charge CPU consommée par la fonction (5, 98.3 %, tta_go_to_sleep).
On arrête l'analyseur de performances (6).
On arrête le débogueur (7).

image.png


Opérations sur le planificateur (TTA)



Mesure de la durée de l'horloge de synchronisation (TTA_TICK_MS)



Dans le simulateur Proteus :

On réalise les connexions électriques.
On réalise les réglages de l'oscilloscope.

image.png

Opérations sur les connexions électriques


Au niveau des connexions électriques :

On connecte le canal (1, A) de l'oscilloscope à la broche (2, P2.7) du microcontrôleur afin d'afficher la forme d'onde de l'horloge de synchronisation et de mesurer sa durée en millisecondes (TTA_TICK_MS).

Opérations sur les réglages de l'oscilloscope


Au niveau des réglages de l'oscilloscope :

On règle la base de temps de l'oscilloscope (1) à (5 ms / division).
On règle la base de tension sur le canal (2, A) de l'oscilloscope à (2 V / division).
On règle le mode sur le canal (3, A) de l'oscilloscope à (DC, courant continu).
On mesure la durée de l'horloge de synchronisation (4, TTA_TICK_MS) à (10 ms).

image.png

Dans l'éditeur Keil µVision :

On constate que la durée de l'horloge de synchronisation (1, TTA_TICK_MS) fixée à (10 ms) correspond à la durée mesurée dans le simulateur Proteus.

image.png

Mesure du retard pour une période d'exécution prévue (1 Tick)



Dans le simulateur Proteus :

On réalise les connexions électriques.
On réalise les réglages de l'oscilloscope.

Opérations sur les connexions électriques


Au niveau des connexions électriques :

On connecte le canal (1, A) de l'oscilloscope à la broche (2, P2.7) du microcontrôleur afin d'afficher la forme d'onde de l'horloge de synchronisation et de mesurer sa durée en millisecondes (TTA_TICK_MS).
On connecte le canal (3, B) de l'oscilloscope à la broche (4, P1.7) du microcontrôleur afin d'afficher la forme d'onde du signal généré par le répartiteur des tâches du TTA (tta_dispatch_tasks) pour une période d'exécution prévue de (1 Tick).

image.png

Opérations sur les réglages de l'oscilloscope


Au niveau des réglages de l'oscilloscope :

On règle la base de temps de l'oscilloscope (1) à (10 ms / division).
On règle la base de tension sur le canal (2, A) de l'oscilloscope à (2 V / division).
On règle le mode sur le canal (3, A) de l'oscilloscope à (DC, courant continu).
On règle la base de tension sur le canal (4, B) de l'oscilloscope à (2 V / division).
On règle le mode sur le canal (5, B) de l'oscilloscope à (DC, courant continu).
On mesure la durée de l'horloge de synchronisation (6, TTA_TICK_MS) à (10 ms).
On mesure la durée du signal généré par le répartiteur des tâches du TTA (tta_dispatch_tasks) à (7, 20 ms).

image.png

Dans l'éditeur Keil µVision :

On constate que la durée de la période d'exécution prévue pour la tâche (tick_delay_update) fixée à (1 Tick, TPrevue) soit (10 ms) correspond à (20 ms, 2 Tick, TMesuree) la durée de la période d'exécution mesurée dans le simulateur Proteus. On peut en déduire un retard d'une durée de (10 ms, 1 Tick, TRetard) telle que (TMesuree = TPrevue + TRetard) où (TRetard = 1 Tick).

Le planificateur TTA a besoin de (1 Tick) supplémentaire pour mettre à jour sa logique interne avant de prendre la décision d'exécuter une tâche.

image.png

Mesure du retard pour une période d'exécution prévue (2 Tick)



Dans le simulateur Proteus :

On réalise les connexions électriques.
On réalise les réglages de l'oscilloscope.

Opérations sur les connexions électriques


Au niveau des connexions électriques :

On connecte le canal (1, A) de l'oscilloscope à la broche (2, P2.7) du microcontrôleur afin d'afficher la forme d'onde de l'horloge de synchronisation et de mesurer sa durée en millisecondes (TTA_TICK_MS).
On connecte le canal (3, B) de l'oscilloscope à la broche (4, P1.7) du microcontrôleur afin d'afficher la forme d'onde du signal généré par le répartiteur des tâches du TTA (tta_dispatch_tasks) pour une période d'exécution prévue de (2 Tick).

image.png

Opérations sur les réglages de l'oscilloscope


Au niveau des réglages de l'oscilloscope :

On règle la base de temps de l'oscilloscope (1) à (10 ms / division).
On règle la base de tension sur le canal (2, A) de l'oscilloscope à (2 V / division).
On règle le mode sur le canal (3, A) de l'oscilloscope à (DC, courant continu).
On règle la base de tension sur le canal (4, B) de l'oscilloscope à (2 V / division).
On règle le mode sur le canal (5, B) de l'oscilloscope à (DC, courant continu).
On mesure la durée de l'horloge de synchronisation (6, TTA_TICK_MS) à (10 ms).
On mesure la durée du signal généré par le répartiteur des tâches du TTA (tta_dispatch_tasks) à (7, 30 ms).

image.png

Dans l'éditeur Keil µVision :

On constate que la durée de la période d'exécution prévue pour la tâche (tick_delay_update) fixée à (2 Tick, TPrevue) soit (20 ms) correspond à (30 ms, 3 Tick, TMesuree) la durée de la période d'exécution mesurée dans le simulateur Proteus. On peut en déduire un retard d'une durée de (10 ms, 1 Tick, TRetard) telle que (TMesuree = TPrevue + TRetard) où (TRetard = 1 Tick).

Le planificateur TTA a besoin de (1 Tick) supplémentaire pour mettre à jour sa logique interne avant de prendre la décision d'exécuter une tâche.

image.png

Calcul de la période exécution réelle du tâche TTA (TMesuree)


Si on considère la relation (TMesuree = TPrevue + TRetard) où (TRetard = 1 Tick).

La période d'exécution réelle d'une tâche du planificateur TTA (TMesuree) est égale à la période d'exécution prévue (TPrevue) augmentée de la durée d'un tick (TRetard).

Dans l'éditeur Keil µVision :

On configure un tick de (1 ms). 

image.png

Dans l'éditeur Keil µVision :

On prévoit une période d'exécution de (20 Tick) soit (20 ms).

image.png

Dans le simulateur Proteus :

On mesure une période d'exécution réelle de (21 ms).

image.png

Calcul de la période minimale réelle du planificateur TTA (TMesuree, minimale)


Si on considère la relation (TMesuree = TPrevue + TRetard) où (TRetard = 1 Tick).
La signal généré par le planificateur a une période minimale si (TMesuree) est minimale, c'est-à-dire si (TPrevue) est minimale.
On sait que la valeur minimale de (TPrevue) est de (1 Tick).
Alors, la valeur minimale de (TMesuree) est de (2 Tick).
Donc, la période minimale réelle du planificateur TTA est de (2 Tick).

Calcul de la fréquence maximale réelle du planificateur TTA (TMesuree, minimale)


Si on considère la relation (TMesuree = TPrevue + TRetard) où (TRetard = 1 Tick).
La fréquence générée par le planificateur est maximale si (TMesuree) est minimale, c'est-à-dire si (TPrevue) est minimale.
On sait que la valeur minimale de (TPrevue) est de (1 Tick).
Alors, la valeur minimale de (TMesuree) est de (2 Tick).
Donc, la fréquence maximale réelle du planificateur TTA est de (2 Tick).

Optimisation de la précision du planificateur TTA (TMesuree = TPrevue)


Si on considère la relation (TMesuree = TPrevue + TRetard) où (TRetard = 1 Tick).
On peut trouver des facteurs tels que (TMesuree = KMesuree x Tick) et (TPrevue = KPrevue x Tick). - Cela conduit à la relation (KMesuree = KPrevue + 1).
On en déduit le rapport (KPrevue/KMesuree = KPrevue / (KPrevue + 1)).
Le rapport (KPrevue/KMesuree) est proche de (1) pour (KPrevue) très grand.
Pour (KPrevue = 1) on a (KPrevue/KMesuree = 1/2 = 0.5).
Pour (KPrevue = 10) on a (KPrevue/KMesuree = 10/11 = 0.91).
Pour (KPrevue = 20) on a (KPrevue/KMesuree = 20/21 = 0.95).
Pour un (TPrevue) donné (KPrevue) augmente si le (Tick) diminue.
Donc, la précision du planificateur TTA est optimale lorsque le (Tick) est faible.


Opérations sur l'application (rdvTTA)



 Objectif de l'application (rdvTTA)


Sur l'objectif de l'application (rdvTTA) :

On souhaite générer un signal carré modulé sur une demi-période à partir du broche d'un microcontrôleur 8051.

Sur les contraintes de l'application (rdvTTA) :

On implémentera la structure logicielle de l'ordonnanceur TTA pour planifier les tâches de l'application.
On utilisera le timer T2 du microcontrôleur 8051 pour fixer l'horloge de synchronisation du planificateur TTA à (1 ms).
On fixera la période du signal carré à (1 s, 1000 ms).
On fixera la largeur de la modulation à (50 ms).

Schéma électrique de l'application (rdvTTA)


Sur le schéma électrique dans le simulateur Proteus :

On utilisera la broche (P2.7) du microcontrôleur 8051 pour afficher la forme d'onde de l'horloge de synchronisation du planificateur TTA (1, 2, TTA_TICK_MS).
On utilisera la broche (P1.7) du microcontrôleur 8051 pour afficher la forme d'onde du signal carré modulé (3, 4, SIGNAL).

image.png

Résultat de l'application (rdvTTA)


Sur le résultat dans le simulateur Proteus :

On affiche la forme d'onde de l'horloge de synchronisation du planificateur TTA sur le canal (A) de l'oscilloscope.
On affiche la forme d'onde du signal carré modulé sur le canal (A) de l'oscilloscope.

image.png


Opérations sur l'ordonnancement des tâches (rdvTTA)



Diagramme d'ordonnancement des tâches (rdvTTA)


Pour générer la forme d'onde signal carré modulé (SIGNAL) :

On utilise 3 tâches (task1, task2, task3).
On utilise les tâches (task1, task2) pour générer la forme d'onde du signal carré (WAVE).
On utilise la tâche (task3) pour générer la forme d'onde du signal modulé (MOD).
Puis on déduit la forme d'onde du signal carré modulé (SIGNAL = WAVE & MOD).

image.png

Dans la tâche (task1) :

On a le signal (WAVE = WAVE_ON).

Dans la tâche (task2) :

On a le signal (WAVE = WAVE_OFF).

Dans la tâche (task3) :

On a le signal (MOD = ! MOD).
Puis on a le signal (SIGNAL = WAVE & MOD).

Diagramme des délais de démarrage des tâches (rdvTTA)


Dans le planificateur des tâches (TTA) :

On démarre la tâche (task1) immédiatement (DTask1 = 0).
On démarre la tâche (task2) avec un retard (DTask2 = PWave / 2), où (PWave) est la période du signal carré (WAVE, 1 s, 1000 ms). On a (DTask2 = 500 ms).
On démarre la tâche (task3) immédiatement (DTask3 = 0).

image.png

Diagramme des périodes d'exécution des tâches (rdvTTA)


Dans le planificateur des tâches (TTA) :

On exécute la tâche (task1) selon la période (PTask1 = PWave), où (PWave) est la période du signal carré (WAVE, 1 s, 1000 ms). On a (PTask1 = 1000 ms).
On exécute la tâche (task2) selon la période (PTask2 = PWave), où (PWave) est la période du signal carré (WAVE, 1 s, 1000 ms). On a (PTask2 = 1000 ms).
On exécute la tâche (task3) selon la période (PTask3 = PMod), où (PMod) est la période du signal modulé (MOD, 100 ms). On a (PTask3 = 50 ms).

image.png

Diagramme du programme (rdvTTA)


Dans le programme (rdvTTA) :

On a une phase d'initialisation des tâches.
On a une boucle d'exécution des tâches.
On a une routine de mises à jour des tâches.

image.png


Opérations sur le programme (C)



Opérations sur le programme principale (main.c)



Opérations sur la fonction (main)


Dans la fonction (main) :

On exécute la fonction (tta_init) du module (TTA).
On exécute la fonction (signal_init) du module (signal).
On exécute la fonction (tta_add_task, signal_wave_on_update) du module (TTA).
On exécute la fonction (tta_add_task, signal_wave_off_update) du module (TTA).
On exécute la fonction (tta_add_task, signal_modulation_update) du module (TTA).
On exécute la fonction (tta_start) du module (TTA). - On rentre dans une boucle infinie.
Puis on exécute la fonction (tta_dispatch_tasks) du module (TTA).

...
void main()
{
    tta_init();
    signal_init();
    tta_add_task(signal_wave_on_update, 0, config_signal_wave_period);
    tta_add_task(signal_wave_off_update, config_signal_wave_on_period, 
    config_signal_wave_period);
    tta_add_task(signal_modulation_update, 0, 
    config_signal_modulation_on_period);
    tta_start();

    while (true)
    {
        tta_dispatch_tasks();
    }
}
...

Opérations sur le module (TTA)



Opérations sur la macro (TTA_PRELOAD_TIME_MS)


Dans la macro (TTA_PRELOAD_TIME_MS) :

On calcule la valeur de pré-chargement du timer T2 afin de réaliser un débordement suivi d'une interruption toutes les (x) millisecondes selon la valeur du paramètre (time_ms).

...
#define TTA_PRELOAD_TIME_MS(time_ms) \
    (65536 - ((config_osc_freq * time_ms) / (config_osc_per_inst * 1000)))
...

Opérations sur la structure (sTask)


Dans la structure (sTask) :

On déclare la variable (pTask) de type (pointeur de fonction) pour stocker une tâche.
On déclare la variable (delay) de type (uint, unsigned int) pour stocker le délai d'attente avant la première exécution de la tâche (en nombre de ticks).
On déclare la variable (period) de type (uint, unsigned int) pour stocker la période d'exécution de la tâche (en nombre de ticks).
On déclare la variable (run_me) de type (uchar, unsigned char) pour stocker le drapeau d'exécution de la tâche.

...
typedef struct _sTask
{
    void (*pTask)();
    uint delay;
    uint period;
    uchar run_me;
} sTask;
...

Dans la macro (TTA_TASK_MAX) :

On stocke le nombre maximal de tâches du module (TTA).

...
#define TTA_TASK_MAX (8)
...

Dans la variable (g_tta_task_queue) :

On stocke la liste des tâches de type (sTask).

...
static sTask g_tta_task_queue[TTA_TASK_MAX];
...

Opérations sur la fonction (tta_init)


Dans la fonction (tta_init) :

On exécute la macro (TTA_PRELOAD_TIME_MS) du module (TTA) pour retourner la variable (preload).
On parcourt la liste des tâches du module (TTA, TTA_TASK_MAX).
Puis on exécute la fonction (tta_delete_task) du module (TTA).
Ensuite, on recharge les registres du timer T2 afin de réaliser un débordement suivi d'une interruption toutes les (x) millisecondes selon la valeur du paramètre (config_tta_tick_ms).

...
void tta_init()
{
    uchar index;
    volatile uint preload = TTA_PRELOAD_TIME_MS(config_tta_tick_ms);

    for(index = 0; index < TTA_TASK_MAX; index++)
    {
        tta_delete_task(index);
    }
    
    T2CON = 0x00; 
    TH2 = preload >> 8; 
    RCAP2H = preload >> 8; 
    TL2 = preload; 
    RCAP2L = preload;
    ET2 = 1;
    TR2 = 1;
}
...

Opérations sur la fonction (tta_delete_task)


Dans la fonction (tta_delete_task) :

On initialise les paramètres de la variable (g_tta_task_queue, index) de type (sTask).

...
static void tta_delete_task(const uchar index)
{
    g_tta_task_queue[index].pTask 	= 0x0000;
    g_tta_task_queue[index].delay 	= 0;
    g_tta_task_queue[index].period 	= 0;
    g_tta_task_queue[index].run_me 	= 0;
}
...

Opérations sur la fonction (tta_add_task)


Dans la fonction (tta_add_task) :

On démarre une boucle afin de rechercher une place libre dans la liste des tâches (g_tta_task_queue).
On retourne une erreur d'index si aucune place n'est disponible dans la liste des tâches (g_tta_task_queue).
Sinon, on initialise la tâche (g_tta_task_queue, index) avec les paramètres (pTask, delay, period).
On retourne l'index de la nouvelle tâche (index).

...
uchar tta_add_task(void (*pTask)(), const uint delay, const uint period)
{
    uchar index = 0;
    while((g_tta_task_queue[index].pTask != 0) && (index < TTA_TASK_MAX)) 
    index++;
    if(index == TTA_TASK_MAX) return config_tta_index_error;
    g_tta_task_queue[index].pTask = pTask;
    g_tta_task_queue[index].delay = delay;
    g_tta_task_queue[index].period = period;
    g_tta_task_queue[index].run_me = 0;
    return index;
...

Opérations sur la fonction (tta_start)


Dans la fonction (tta_start) :

On initialise le registre (EA) à (true) pour activer toute les interruptions.

...
void tta_start()
{
    EA = 1;
}
...

Opérations sur la fonction (tta_dispatch_tasks)


Dans la fonction (tta_dispatch_tasks) :

On parcourt la liste des tâches du module (TTA, g_tta_task_queue).
Puis, on exécute la tâche (g_tta_task_queue, index, pTask) du module (TTA) si la variable (g_tta_task_queue, index, run_me) est supérieure à (0).
On décrémente la variable (g_tta_task_queue, index, run_me) après l'exécution de la tâche (g_tta_task_queue, index, pTask).
Puis, on exécute la fonction (tta_delete_task, index) du module (TTA) si la variable (g_tta_task_queue, index, period) est à (0).
Ensuite on exécute la fonction (tta_go_to_sleep) du module (TTA).

...
void tta_dispatch_tasks()
{
    uchar index;
        
    for(index = 0; index < TTA_TASK_MAX; index++)
    {
        if(g_tta_task_queue[index].run_me > 0)
        {
            (*g_tta_task_queue[index].pTask)();
            g_tta_task_queue[index].run_me -= 1;
            
            if(g_tta_task_queue[index].period == 0)
            {
                tta_delete_task(index);
            }
        }
    }
    tta_go_to_sleep();
}
...

Opérations sur la fonction (tta_go_to_sleep)


Dans la fonction (tta_go_to_sleep) :

On initialise le registre (PCON) à (0x01) pour basculer en mode économie d'énergie (en mode IDLE).

...
static void tta_go_to_sleep()
{
    PCON |= 0x01;
}
...

Opérations sur la fonction (on_tta_update_tasks)


Dans la fonction (on_tta_update_tasks) :

On parcourt la liste des tâches du module (TTA, g_tta_task_queue).
Puis, on incrémente la variable (g_tta_task_queue, index, run_me) du module (TTA) si la variable (g_tta_task_queue, index, delay) est à (0) et si la variable (g_tta_task_queue, index, pTask) est différente de (0).
Puis, on initialise la variable (g_tta_task_queue, index, delay) du module (TTA) avec la valeur de la variable (g_tta_task_queue, index, period) si la variable (g_tta_task_queue, index, period) est différente de (0), si la variable (g_tta_task_queue, index, delay) est à (0) et si la variable (g_tta_task_queue, index, pTask) est différente de (0).
Sinon, on décrémente la variable (g_tta_task_queue, index, delay) du module (TTA) si la variable (g_tta_task_queue, index, delay) est à (0) et si la variable (g_tta_task_queue, index, pTask) est différente de (0).

...
void on_tta_update_tasks() interrupt TTA_INTERRUPT_TIMER_T2 
{
    uchar index;
    TF2 = 0;

    for(index = 0; index < TTA_TASK_MAX; index++)
    {
        if(g_tta_task_queue[index].pTask != 0)
        {
            if(g_tta_task_queue[index].delay == 0)
            {
                g_tta_task_queue[index].run_me += 1;
                if(g_tta_task_queue[index].period != 0)
                {
                    g_tta_task_queue[index].delay = 
                    g_tta_task_queue[index].period;
                }
            }
            else
            {
                g_tta_task_queue[index].delay -= 1;
            }
        }
    }
    
    if(config_tta_tick_pin_on)
    {
        g_tta_tick_pin = !g_tta_tick_pin;
    }
}
...