# FreeRTOS ## Liens utiles * L'environnement de développement : [SW4STM32](https://www.st.com/en/development-tools/sw4stm32.html) * Le cours et le code à télécharger : [OneDrive](https://1drv.ms/1j8UB71) / *[Ancien OneDrive](https://onedrive.live.com/?id=F4125FF038CFDEB1%216386)* * E-mail du prof : <tjoubert@theoris.fr> <!--* [OneDrive obsolète](https://1drv.ms/1yohhHOO)--> ## Introduction ```graphviz digraph ingenieurat { rankdir=LR moa -> CdC CdC -> Spec [label=" moe"] Spec -> conception conception -> code code -> tests } ``` CdC recevable : > Je dois être à Lyon demain matin. FreeRTOS est un choix de conception. Chronogramme : définir des activités. Sporadique. Scheduler. Multiplexage des appels. Coroutine : tâches synchrones. La fonction `vTaskStartScheduler`, qui démarre l'ordonnanceur FreeRTOS, est dans la fonction `main`, pas dans un thread. On déclare une tâche avec `TaskHandle_t`. FreeRTOS utilise la notation hongroise. > Polonaise, hongroise… De toute façon, ça vient de là-bas. Il faut fournir une callback pour `vTaskCode`. Main → Start boucle > `void`, c'est rien. `void*`, c'est tout. > Entre une boucle `while (1)` et une boucle `while delay 1 ms`, l'écart est **monstrueux** !! ## Sous Eclipse `File` > `New` > `C++ Project` Project type : `Executable` > `Ac6 STM32 MCU Project` Target Configuration : On coche `Show ST Discovery boards`, on sélectionne `STM32F7`, puis `STM32F746G-DISCO`. Project Firmware configuration On sélectionne `Hardware Abstraction Layer (Cube HAL)` et `Add low level drivers in the project` > `As sources in the application drivers`. Additional utilities : on coche `FreeRTOS`. L'IDE crée un contexte de projet. On a une bibliothèque de haut niveau simplifiée : `BSP_LED_Init`, etc. :::info On doit ajouter la variable de préprocesseur `USE_RTOS_SYSTICK` ! `File` > `Properties` > `C/C++ Build` > `MCU GCC Compiler` > `Preprocessor` > Ajouter un élément > `USE_RTOS_SYSTICK` ::: :::info Compilation et flash hors IDE : > make -C Debug all > st-flash write Debug/hello.bin 0x8000000 ::: ``` cpp #include "stm32f7xx.h" #include "stm32746g_discovery.h" #include "FreeRTOS.h" #include "task.h" // La fonction qu'on veut exécuter dans la tâche void TaskBlink(void* param) { for (;;) { BSP_LED_Toggle(LED1); vTaskDelay(1000); } } int main(void) { TaskHandle_t T1; // Valeur de retour (inutilisé dans cet exemple) BaseType_t ret; // On initialise sur la carte ce qu'on veut utiliser BSP_LED_Init(LED1); // D'abord, on crée une tâche ret = xTaskCreate(TaskBlink, "BLINK", 128, 0, 3, &T1); // Ensuite, on lance le planificateur de tâches vTaskStartScheduler(); for (;;); } ``` Le code ci-dessus ne marchera pas bien puisque `vTaskDelay` n'est pas pris en compte. On peut redéfinir `TaskBlink` comme suit : ```cpp void TaskBlink(void* param) { int lm; for (;;) { BSP_LED_Toggle(LED1); // Cette boucle ne sert qu’à s’assurer que // la boucle infinie est prise en compte for (int i = 1; i < 800000; i++) { lm += lm/i; } } } ``` On construit le projet avec `Project` > `Build project`. Manuel d'utilisation. `Utilities` > `STM32746G-Discovery` > `STM32746G-Discovery_BSP_User_Manual.chm` Derrière on peut virer la boucle avec lm etc... et remettre le vTaskDelay. ### Cas d'étude Qu'est-ce qui ne va pas dans ce code ? ```cpp= int main(void) { ADC3_Config(); BSP_LED_Init(LED1); for(;;) { ADC3_ReadValue(); BSP_LED_Toggle(LED1); vTaskDelay(uhADCxConvertedValue); } } ``` Dans ce mauvais code, on n'utilise pas de thread. Il manque `vTaskStartScheduler()`. En outre, aucune tâche n'a été créée. ![Arduino connectors](https://i.imgur.com/rw0ycSW.png) ### Misc Un ordonnanceur préemptif apporte 3 mécanismes : - une rotation des tâches (round robin) - timer logiciel - watchdog **Il faut faire attention aux inversions de priorité.** C'est une mauvaise pratique d'utiliser des délais plutôt que des timers ou des watchdogs (sauf pour le polling ?) => lorsqu'il réalise un audit de code temps réel, Thierry Joubert regarder le nombre d'appels à sleep ### Erratum slide `xQueueReceiveFromISR` à la place du premier `xQueueSendFromISR`. ### Envoi au prof Prendre les fichiers intéressants (main.c, main.h…) et le zipper dans une archive nommée <code>GI20\_1\_*NOM1*\_*NOM2*.zip</code> à <tjoubert@theoris.fr>. L'objet de l'e-mail est le nom du zip. Pour les prochains rendus, le préfixe sera GI20_2_, puis GI20_3_, etc. <!-- Ce commentaire doit rester la dernière ligne de la note -->