Autor Tema: Intentando freeRTOS en STM32F411 Nucleo Board  (Leído 1731 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado elgarbe

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 2174
Intentando freeRTOS en STM32F411 Nucleo Board
« en: 24 de Mayo de 2015, 15:41:09 »
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:
Código: [Seleccionar]
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:

Código: [Seleccionar]
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:

Código: [Seleccionar]
/**
  * @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:

Código: [Seleccionar]
/* 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:
Código: [Seleccionar]
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!
« Última modificación: 25 de Mayo de 2015, 17:02:07 por elgarbe »
-
Leonardo Garberoglio

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 6949
Re: Intentando freeRTOS en STM32F411 Nucleo Board
« Respuesta #1 en: 24 de Mayo de 2015, 15:51:33 »
Yo recuerdo que intente copiar uno de un ejemplo de TI con la placa de evaluacion y no me funciono.

Luego decidi crear un proyecto por mi mismo y logre hacer funcionar el freeRTOS sin nigun problema, lo unico que tuve que agregarle fue el port, que imagino que sera parecido a todos los demas cortex, es el que tiene las fucniones de interrupcion para los vectores asi manejan los ticks (creo que uno eran el PendSV, SVCall y Systick).

Una ves realizado el proyecto quisiera ver como es para hacer que el mismo FreeRTOS te envie las "estadisticas" de cada proceso,

Desconectado elgarbe

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 2174
Re: Intentando freeRTOS en STM32F411 Nucleo Board
« Respuesta #2 en: 25 de Mayo de 2015, 13:44:06 »
En el caso de ST, el cubeMX ya trae los port para cada micro, solo que la integracion de MX con STM WorkBench es recientey estan mejorándolo.

Bien, voy a ir poninedo algunas notas que me serviran (y quizá a alguno de ustedes tmb).
En primer lugar estoy leyendo este post ya que el de reiniertl es para el RTOS de CCS y por lo ue estoy viendo hay muchas diferencias con freeRTOS.

Una de las primeras cosas que estoy viendo es que la funcion osDelay(xx) no es un delay que bloquea con tiempo muerto a la tarea. Sino que dicha funcion lo que hace es poner la tarea en estado BLOQUEADA por el tiempo puesto como parámetro. De este modo, entre 2 toggle de led 1 el CPU no está perdiendo tiempo haciendo nada, sino que el scheduler puede revisar la lista de tareas para ver si hay alguna a ejecutar.
Entonces este código:
Código: [Seleccionar]
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 hace es primero obtener el conteo actual de los Ticks del sistema, sumarle 5000 (cada tick esta configurado como 1mseg) y almacenarlo en count.
Luego con el while, lo que hacemos es que la tarea haga "algo" por 5 seg.
Ese algo, en este caso es hacer un toggle de un led. El tema acá sería como hacer para que el toggle sea cada 200mseg? Bueno, puedo poner un gran delay_ms(200) el cual hará que la tarea se quede ejecutando código o bien, mucho mejor, pasar la tarea a BLOQUEADO por 200mseg. Y es eso lo que hace osDelay. Cuando terminen los 200mseg, automáticamente la tarea pasará a READY y cuando el scheduler la vea le asignará el uC (siempre y cuando no haya otra tarea de mayor prioridad esperando).

Hay una forma de pasar a estado SUSPENDIDA a una tarea determinada. Es usando osThreadSuspend(xxxx), donde xxxx puede ser NULL para SUSPENDER la tarea actual o el nombre de la tarea a blouear. Para continuar una tarea usamos osThreadResume(xxxx).

bien, esta primera parte, sobre tareas básicas esta bastante asimilado.
Seguiré avanzando a ver que sale.
La primer duda que tengo en mente para resolver es que pasa con un proceso que es netamente ejecutado en una ISR? Por ejemplo, que pasa si tengo un GPS enviando datos al uC por una uart. Actualmente yo tengo puesto en el llamado a una funcion de parseo de caracter x caracter dentro de la ISR, pero como se resuelve eso en el entorno de un RTOS?.... ya lo averiguaré...

Saludos!
-
Leonardo Garberoglio

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 6949
Re: Intentando freeRTOS en STM32F411 Nucleo Board
« Respuesta #3 en: 25 de Mayo de 2015, 18:22:25 »
Citar
La primer duda que tengo en mente para resolver es que pasa con un proceso que es netamente ejecutado en una ISR? Por ejemplo, que pasa si tengo un GPS enviando datos al uC por una uart. Actualmente yo tengo puesto en el llamado a una funcion de parseo de caracter x caracter dentro de la ISR, pero como se resuelve eso en el entorno de un RTOS?.... ya lo averiguaré...

Creo que no existe ningun proceso asi. lo que si conozco es que uan ves entrado al vector se habilita un semaforo para que un proceso con alta prioridad se ejecute y este vuelve a devolver el semaforo el semaforo. Si no mal recuerdo era algo asi :).
Es decir solo el ISR habilita a un proceso. Mientras el otro proceso se encuentra bloqueado.

Desconectado elgarbe

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 2174
Re: Intentando freeRTOS en STM32F411 Nucleo Board
« Respuesta #4 en: 25 de Mayo de 2015, 18:29:03 »
Citar
La primer duda que tengo en mente para resolver es que pasa con un proceso que es netamente ejecutado en una ISR? Por ejemplo, que pasa si tengo un GPS enviando datos al uC por una uart. Actualmente yo tengo puesto en el llamado a una funcion de parseo de caracter x caracter dentro de la ISR, pero como se resuelve eso en el entorno de un RTOS?.... ya lo averiguaré...

Creo que no existe ningun proceso asi. lo que si conozco es que uan ves entrado al vector se habilita un semaforo para que un proceso con alta prioridad se ejecute y este vuelve a devolver el semaforo el semaforo. Si no mal recuerdo era algo asi :).
Es decir solo el ISR habilita a un proceso. Mientras el otro proceso se encuentra bloqueado.

Acabo de terminar el tutorial y es como decís, se utilizan semáforos... bueno ahora estoy tratando de armar el proyecto en el IDE de ST para empezar con estas pruebas. Ya tengo parte del código que esta funcionando en proyectos separados, ahora tengo que tratar de pasar todo  un solo proyecto, haciendo uso de las tareas... veremos que sale.

sds.
-
Leonardo Garberoglio