Bueno, estoy intentando empezar a probar freeRTOS, despues de leer el excelente
post de reiniertl y varios documentos más, sobre freeRTOS, implementacion en STM32F4 y algo de CubeMX.
Como de entrada he encontrado problemas y soluciones decidí postear.
Primero, como IDE estoy usando System Workbench, que como ya hemos mostrado con planeta9999 en otros post, es el IDE gratuito de ST para sus micros y es donde estan poniendo la atención. Para generar el código uso el CubeMX integrado al STW.
Bien, primero, en el Cube MX elijo 3 pines (PA0, PA1 y PA4) como salidas y habilito el uso de freeRTOS:

Luego, en la pestaña de configuration vamos a freeRTOS (en el centro de la pantalla) para agregar las tareas que queramos.
En mi caso, como primer ejemplo voy a seguir un ejemplo que viene para la discovery, la cual voy a modificar para que corra en la Nucleo. La idea de las tareas es esta:
This application creates two threads with the same priority, which executes in
a periodic cycle of 15 seconds.
In the first 5 seconds, the thread 1 toggles LED3 each 200 ms and the
thread 2 toggles LED4 each 500 ms
In the second 5 seconds, the thread 1 suspend itself and the thread 2
continue toggling LED4
In the last 5 seconds, the thread 2 resume execution of thread 1 then
suspend itself, the thread 1 toggles the LED3 each 400 ms

En mi caso puse un led en PA0 y otro led en PA1:

Bien, ni bien trato de compilar sin agregar ningún código me encuentro con unos errores de unas instrucciones en assembler. Busco un poco y encuentro
esto en OpenSTM32:
Hi all,
try to change these project settings in the MCU Settings section:
Floating point hardware : fpv4-sp-d16
Floating-point ABI : hard
And make a Clean Project before rebuild.
Lo pruebo y funciona de 10! compila bien.
Bueno, ahora a escribir (copiar, pegar y modificar) el código de las tareas.
El código Original era este:
/**
* @brief Toggle LED3 and LED4 thread
* @param thread not used
* @retval None
*/
static void LED_Thread1(void const *argument)
{
uint32_t count = 0;
(void) argument;
for(;;)
{
count = osKernelSysTick() + 5000;
/* Toggle LED3 every 200 ms for 5 s */
while (count >= osKernelSysTick())
{
BSP_LED_Toggle(LED3);
osDelay(200);
}
/* Turn off LED3 */
BSP_LED_Off(LED3);
/* Suspend Thread 1 */
osThreadSuspend(NULL);
count = osKernelSysTick() + 5000;
/* Toggle LED3 every 400 ms for 5 s */
while (count >= osKernelSysTick())
{
BSP_LED_Toggle(LED3);
osDelay(400);
}
/* Resume Thread 2 */
osThreadResume(LEDThread2Handle);
}
}
/**
* @brief Toggle LED4 thread
* @param argument not used
* @retval None
*/
static void LED_Thread2(void const *argument)
{
uint32_t count;
(void) argument;
for(;;)
{
count = osKernelSysTick() + 10000;
/* Toggle LED4 every 500 ms for 10 s */
while (count >= osKernelSysTick())
{
BSP_LED_Toggle(LED4);
osDelay(500);
}
/* Turn off LED4 */
BSP_LED_Off(LED4);
/* Resume Thread 1 */
osThreadResume(LEDThread1Handle);
/* Suspend Thread 2 */
osThreadSuspend(NULL);
}
}
En mi caso, solo tengo que cambiar el nombre de las tareas y las funciones para hacer toggle y apagar los led, quedándome las tareas de este modo:
/* StartTask01 function */
void StartTask01(void const * argument)
{
/* USER CODE BEGIN StartTask01 */
uint32_t count = 0;
(void) argument;
/* Infinite loop */
for(;;)
{
count = osKernelSysTick() + 5000;
/* Toggle LED1 every 200 ms for 5 s */
while (count >= osKernelSysTick())
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0);
osDelay(200);
}
/* Turn off LED1 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
/* Suspend Thread 1 */
osThreadSuspend(NULL);
count = osKernelSysTick() + 5000;
/* Toggle LED1 every 400 ms for 5 s */
while (count >= osKernelSysTick())
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0);
osDelay(400);
}
/* Resume Thread 2 */
osThreadResume(taskTarea2Handle);
}
/* USER CODE END StartTask01 */
}
/* StartTask02 function */
void StartTask02(void const * argument)
{
/* USER CODE BEGIN StartTask02 */
uint32_t count;
(void) argument;
/* Infinite loop */
for(;;)
{
count = osKernelSysTick() + 10000;
/* Toggle LED2 every 500 ms for 10 s */
while (count >= osKernelSysTick())
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_1);
osDelay(500);
}
/* Turn off LED2 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
/* Resume Thread 1 */
osThreadResume(taskTarea1Handle);
/* Suspend Thread 2 */
osThreadSuspend(NULL);
}
/* USER CODE END StartTask02 */
}
De entrada podemos ver cosas muy distintas a las que contaba reiniertl en su post del RTOS de CCS, ya que son distintos RTOS.
En freeRTOS parece que no se preconfigura el tiempo de ejecucion de las tareas, sino ue se programan en su interior.
Con:
count = osKernelSysTick() + 5000;
/* Toggle LED1 every 200 ms for 5 s */
while (count >= osKernelSysTick())
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0);
osDelay(200);
}
lo que conseguimos es justamente el tiempo total de ejecucion, los 5000 mseg y con osDelay(200) damos el tiempo toggle del primer LED durante los primeros 5 seg.
Luego viene una instruccion que permite apagar el LED1 y suspendemos esta tarea.
Cuando la misma sea retomada (desde la tarea 2), comenzará desde aquí y no desde el principio.
En el siguiente bloque de la tarea 1 se configura para ue corra por 5 seg más haciendo toggle del led 1 cada 400mseg.
La tarea 2 es similar, solo que hay un solo ritmo de toggle por 10 segundos.
En el documento DM00105262 de ST, se explican algunas nociones sobre la implementacion de freeRTOS en los STM32 y se explica un poco este ejemplo, puntualmente en la página 17 tenemos:

Bien, finalmente compilamos, configuramos el debug y lo lanzamos y el resultado es este:
Veamos si puedo escribir los ejemplos de reiniertl...
Saludos!