Bonjour @le_viking,
Préambule : Le programme en #1 est issu de l'IA même si je l'ai modifié, il n'est pas le fruit de ma réflexion personnelle mais je le comprends facilement. Egalement, l'essentiel de ce qui suit ci-dessous est fourni par ChatGPT.
En faisant des recherches principalement sur l'IA, j'ai trouvé ça :
FreeRTOS est justement un système d'exploitation multitâche temps réel (RTOS = Real-Time Operating System).
Sa fonction première est de permettre l’exécution de plusieurs tâches concurrentes, chacune avec sa propre pile, son propre contexte, et gérée par un ordonnanceur (scheduler). Ce dernier décide à tout instant quelle tâche s’exécute en fonction de sa priorité et de son état (prête, bloquée, suspendue).
Le multitâche dans FreeRTOS ne dépend pas d’un multicœur : même avec un seul cœur, FreeRTOS exécute plusieurs tâches de manière fluide en faisant du changement de contexte (context switching).
Le multicœur sur ESP32 est un bonus possible, mais le multitâche FreeRTOS existe sans cela.
C’est justement ce que je démontre avec le programme en #1 : une tâche fait clignoter une LED, pendant qu’une autre effectue un traitement en parallèle (incrémentation, calcul, etc.). Le multitâche est bien visible et fonctionne sans intervention manuelle.
Si j'avais codé cela avec une simple boucle loop() comme en Arduino, il aurait fallu gérer tout à la main : états, délais, interruptions... Là, FreeRTOS me simplifie tout ce travail et offre une architecture propre, modulaire et réactive.
Le scheduler est l'outil de FreeRTOS qui gère les tâches donc il me semble que l'on peut dire clairement que FreeRTOS est dédié au multitâche. L'ordonnanceur ou sheduler est l'outil de FreeRTOS qui permet de le mettre en oeuvre :
Dans le code en #1, le scheduler est mis en oeuvre comme suit :
xTaskCreate(led_task, "LED Task", 2048, NULL, 1, NULL);
xTaskCreate(calc_task, "Calculation Task", 4096, NULL, 1, NULL);
Voici la signature complète de la fonction xTaskCreate :
xTaskCreate(
pvTaskCode,
pcName,
usStackDepth,
pvParameters,
uxPriority,
pxCreatedTask
);
où :
pvTaskCode : c'est la Fonction de la tâche à exécuter (pointeur vers une fonction de type void function(void *pvParameters) ) ;
pcName : c'est le Nom symbolique de la tâche (chaîne de caractères). Utilisé uniquement pour le débogage ou les logs.
usStackDepth : c'est la taille de la pile allouée à la tâche, exprimée en "mots" (words). Sur ESP32 : 1 word = 4 octets ; 2048 mots = 8192 octets de pile
pvParameters : Paramètre optionnel passé à la tâche (pointeur générique). Il Peut être NULL si on ne passe rien. Il est Utile si on veut partager des valeurs spécifiques à chaque instance de tâche.
uxPriority : C'est la Priorité de la tâche : Plus le chiffre est élevé, plus la tâche est prioritaire.
pxCreatedTask : c'est un Pointeur vers une variable de type TaskHandle_t qui permet de récupérer le handle de la tâche créée , pour : suspendre, reprendre, supprimer, etc.
J'ai demandé à l'IA de me générer une fiche sur vTaskDelay() :
Fiche mémo – vTaskDelay() et états des tâches dans FreeRTOS
vTaskDelay() – Temporisation dans FreeRTOS
La fonction :
vTaskDelay(TickType_t xTicksToDelay);
Met la tâche en pause (état “Bloqué”) pendant un certain temps, exprimé en “ticks d’horloge système”.
- Sur ESP32, 1 tick = 1 ms (en général).
- Pour écrire en millisecondes :
Utiliser vTaskDelay(ms / portTICK_PERIOD_MS);
Exemple :
vTaskDelay(1000 / portTICK_PERIOD_MS); // pause de 1000 ms = 1 seconde
Ce que fait vTaskDelay() :
- La tâche se met en “état bloqué”
- Le scheduler libère le CPU pour une autre tâche
- Quand le temps est écoulé, la tâche revient en “prête à s'exécuter”
Pourquoi utiliser vTaskDelay() ?
- Éviter les
while bloquants
- Laisser la main au scheduler
- Construire un vrai comportement multitâche fluide
- Respecter les contraintes temps réel sans bloquer les autres tâches
Les 4 états principaux d’une tâche dans FreeRTOS
| État |
Signification |
| Running |
La tâche est en cours d'exécution (elle a le CPU) |
| Ready |
La tâche est prête, mais attend son tour (selon priorité) |
| Blocked |
La tâche est temporairement en pause (par vTaskDelay, xQueueReceive, etc.) |
| Suspended |
La tâche est suspendue manuellement, elle ne peut pas être exécutée tant qu'on ne la reprend pas (vTaskSuspend) |
Cycle typique d'une tâche bien conçue :
while(1) {
// Action (ex : lecture capteur, traitement, affichage)
vTaskDelay(temps_ms / portTICK_PERIOD_MS);
}
Cela permet à FreeRTOS de faire tourner d'autres tâches entre-temps.
Très fluide, non-bloquant, modulaire.
Astuce :
Une tâche qui ne fait jamais vTaskDelay() bloque potentiellement le CPU (sauf si elle attend une queue, un sémaphore, etc.). C’est une erreur classique de débutant.
Fiche mémo – FreeRTOS : vTaskDelay() et états des tâches
vTaskDelay() – Temporisation dans FreeRTOS
Permet de mettre une tâche en pause (état "bloqué") pendant une durée exprimée en ticks (1 tick = 1 ms sur ESP32 en général).
Syntaxe :
vTaskDelay(duree_en_ticks);
Pour exprimer un délai en millisecondes :
vTaskDelay(ms / portTICK_PERIOD_MS);
Exemples :
vTaskDelay(1000 / portTICK_PERIOD_MS); // Pause de 1 seconde
vTaskDelay(200 / portTICK_PERIOD_MS); // Pause de 200 ms
Pendant ce temps, la tâche est bloquée et le scheduler donne la main à une autre tâche prête.
Pourquoi utiliser vTaskDelay ?
- Pour ne pas bloquer le processeur
- Pour permettre aux autres tâches de s’exécuter
- Pour construire des tâches cycliques sans monopoliser le CPU
États d’une tâche dans FreeRTOS :
| État |
Description |
| Running |
La tâche est en cours d’exécution (a le CPU) |
| Ready |
La tâche est prête, mais attend son tour |
| Blocked |
La tâche est en pause (par delay ou attente queue) |
| Suspended |
La tâche a été suspendue manuellement |
Cycle typique d’une tâche correcte :
while(1) {
// action
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
Cela garantit un fonctionnement multitâche fluide et non bloquant.
Astuce : Une tâche qui ne fait jamais vTaskDelay() ou attente sur queue/semaphore peut bloquer l’exécution des autres tâches. C’est une erreur fréquente chez les débutants.
Résumé : vTaskDelay() = clé du multitâche coopératif efficace. Il libère volontairement le CPU pour les autres tâches, gérées ensuite par le scheduler.
CONCLUSION :
Fiche mémo – Interaction entre xTaskCreate() et vTaskDelay() dans FreeRTOS
xTaskCreate() permet de créer une tâche, c’est-à-dire de définir une fonction indépendante qui s’exécutera sous le contrôle du système FreeRTOS.
Syntaxe :
xTaskCreate(fonctionTache, "Nom", pile, param, priorité, handle);
Chaque tâche créée devient active dès qu’elle est prête, et est gérée automatiquement par le scheduler.
vTaskDelay() permet à une tâche de se mettre volontairement en pause pendant un certain temps (en ticks). Elle entre alors en état “bloqué” et laisse le CPU disponible à une autre tâche.
Le scheduler (ordonnanceur) de FreeRTOS gère toutes les tâches créées par xTaskCreate(). Il sélectionne à chaque instant la tâche ayant la priorité la plus haute et qui est dans l’état “Ready”.
Lorsque vTaskDelay() est appelé dans une tâche :
la tâche passe en “Blocked”
le scheduler donne la main à une autre tâche prête
à l’issue du délai, la tâche revient en “Ready” et pourra à nouveau être exécutée
En résumé :
- xTaskCreate() lance une tâche
- vTaskDelay() libère le CPU temporairement
- le scheduler fait tourner les tâches selon priorité et disponibilité
C’est cette interaction entre la création des tâches (xTaskCreate) et la gestion du temps (vTaskDelay) qui rend FreeRTOS réellement multitâche, même sur un seul cœur.
Une bonne pratique est d’avoir dans chaque tâche un vTaskDelay() ou une attente non bloquante (queue, semaphore) afin de favoriser l’alternance fluide des tâches.
Bonne journée.
PS : Merci à ChatGPT
Mais au final c'est pas trop compliqué à comprendre ...