# 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.

### 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 -->