SE4Binome2026-8

De projets-se.plil.fr
Révision datée du 10 septembre 2026 à 13:52 par Cdescamp (discussion | contributions) (→‎Ordonnanceur)
(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)
Aller à la navigation Aller à la recherche

Présentation

Lien du : Dépôt git

Date limite pour impression de toutes les cartes : 23 octobre 2026

Ordonnanceur

Présentation et objectif :

Vous n'avez pas besoin d'avoir conçu et réalisé des cartes électroniques pour commencer à écrire le système d'exploitation du pico-ordinateur et en particulier l'ordonnanceur sous-jacent.

Le principe est d'utiliser un minuteur du microcontrôleur pour lancer périodiquement une fonction d'interruption que vous allez transformer en ordonnanceur.

Dans un premier temps vous testerez votre ordonnanceur en créant deux tâches statiques pour faire clignoter, avec des périodes différentes, deux LED du bouclier fourni.

Par la suite vous allez complexifier votre ordonnanceur en ajoutant :

  • une tâche de lecture de caractère par le port série (stocké en mémoire partagé) ;
  • une tâche d'écriture sur le port série (du caractère lu sur le port série) ;
  • [optionnel] une tâche d'écriture sur la matrice (du caractère lu sur le port série) ;
  • [optionnel] une tâche d'écriture sur l'afficheur 7 segments (du caractère lu sur le port série).

Les deux dernières tâches sont plus compliquées à réaliser dans la mesure où elles utilisent une ressource commune. Cela dit si vous lancez plusieurs tâches de lecture série ou d'écriture série vous tombez sur la même difficulté.

Jusqu'en 2024/2025 les tâches de l'ordonnanceur étaient définies dans un tableau statique de tâches.

A partir de 2025/2026 ce tableau devient dynamique avec la gestion de l'arrêt des tâches et la possibilité d'en lancer de nouvelles. Pour l'arrêt il faut implanter une fonction exit qui retire proprement la tâche courante de la liste des tâches à ordonnancer. Pour le lancement, la fonction exec doit installer la fonction passée en paramètre comme une nouvelle tâche à ordonnancer. Une gestion automatique des piles d'exécution devient nécessaire.

A partir de 2026/2027 vous devez aussi pouvoir charger le code des tâches à partir de la mémoire de masse. Il vous faut écrire une fonction load prenant en paramètre le nom du fichier exécutable. Cette fonction copie le code exécutable (compilé comme relogeable) dans une partie non utilisée de la mémoire flash du microcontrôleur. Vous pouvez ensuite utiliser la fonction exec.

Spécification technique :

Pour réaliser votre ordonnanceur commencez par programmer le minuteur 1 de l'ATmega328p (ou de l'ATmega32u4) de sorte à ce qu'il génère une interruption toutes les 20ms. L'interruption va déclencher une fonction de gestion d'interruption (ISR pour Interrupt Service Routine). Vous utiliserez une ISR nue pour éviter les interférences du compilateur sur la pile d'exécution :

ISR(TIMER1_COMPA_vect,ISR_NAKED) { /* Sauvegarde du contexte de la tâche interrompue */ ... /* Appel à l'ordonnanceur */ scheduler(); /* Récupération du contexte de la tâche ré-activée */ ... asm volatile ( "reti" ); } Vous constatez qu'il vous reste à écrire, dans l'ISR, le code pour sauvegarder et récupérer le contexte d'exécution d'une tâche. Pour cela réfléchissez aux éléments d'un microcontrôleur qui sont nécessaires pour l'exécution d'un programme puis réfléchissez à une méthode pour sauver l'état de ces éléments. Attention, il est impératif de sauver directement le contexte dans l'ISR, tout code C préalable à la sauvegarde pourrait modifier l'état des registres.

Au moins dans un premier temps, les tâches seront définies de façon statique. Toutes les tâches doivent être définies dans un tableau global, seront lancées dès le démarrage du microcontrôleur et ne se termineront que lorsque le microcontrôleur sera arrêté ou relancé. Vous devez implanter une table des tâches en utilisant une structure dont un des champs doit être la fonction réalisant la tâche. A vous de définir les autres champs.

Avant de démarrer l'ordonnanceur, il faut prendre soin à ce que la récupération du contexte dans l'ISR fonctionne alors que les tâches n'auront pas encore été lancées. Il faut donc une fonction permettant d'initialiser le contexte pour chaque tâche. Pour poser l'adresse d'une fonction sur la pile vous pouvez utiliser le code ci-dessous. uint16_t adresse=(uint16_t)fonction; asm volatile("push %0" : : "r" (adresse & 0x00ff) ); asm volatile("push %0" : : "r" ((adresse & 0xff00)>>8) ); Comme première amélioration de votre ordonnanceur, il vous est suggéré de mettre en place un état endormi pour vos processus. Vous pourriez ainsi endormir vos processus pour un certain temps, l'ISR se chargeant de mettre à jour les minuteurs des processus et les réveillant à l'expiration du délai.

Comme seconde amélioration, le tableau des tâches doit être géré de façon plus dynamique. Il n'est pas demandé de pouvoir changer la taille du tableau qui aura toujours une taille maximale définie par une constante. Par contre une tâche doit pouvoir être ajoutée à la liste des tâches sur présentation de la seule fonction à exécuter. Il faut donc calculer les adresses des piles de façon automatique. Pour simplifier, partez de l'adresse de la pile initiale 0x0800 et soustrayiez une constante qui deviendra la taille maximale des piles des tâches. L'initialisation de la pile de la nouvelle tâche devra se faire au vol. Enlever une tâche de la liste des tâches n'est pas particulièrement complexe, vous pouvez même laisser la tâche dans un état "terminé", son emplacement dans le tableau pouvant alors être récupéré par toute nouvelle tâche. Il est cependant demandé de gérer correctement la libération des piles des tâches. Cela signifie que l'adresse de la pile d'une nouvelle tâche n'est calculé en fonction de la plus basse des adresses de pile utilisées que s'il n'existe pas de bloc non utilisé en mémoire plus haute.

Pour un chargement, au vol, de code exécutable dans la mémoire flash vous allez devoir utiliser les fonctions d'écriture dans cette mémoire disponibles dans la bibliothèque C du compilateur avr-gcc. Le procédé n'est pas trivial : [1].

Des informations complémentaires sont disponibles dans le document Multitasking on an AVR

Ressources : EC Système de fichier