No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Ciclo de vida de las tareas con FreeRTOS

16/30
Recursos

Aportes 8

Preguntas 3

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

La razón por la que los logs del ejemplo al final, no salen intercalados uno a uno de forma ideal, es porque en la práctica FreeRTOS le asigna un tiempo fijo a cada tarea, por lo que mientras la tarea siga dentro de su tiempo disponible, seguirá ejecutando los printf que le corresponden, hasta que FreeRTOS le de paso a la siguiente.

Es por eso que vemos varios “Task 1” juntos, luego varios “Task 2” juntos, y así sucesivamente.

Ahí os dejo mi código

#include <stdio.h>
#include "esp_chip_info.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

TaskHandle_t task1Handle = NULL;
TaskHandle_t task1Handle2 = NULL;


void task1(void *arg){
    unsigned int counter = 0;
    while(1){
        printf("Tarea 1, felicidades, count: %d\n", counter);
        counter++;
        if(counter == 5){
            printf("tarea 2 suspendida\n");
            vTaskSuspend(task1Handle2);
        }
        if (counter == 10){
            printf("tarea 2 reanudada\n");
            vTaskResume(task1Handle2);
        }
        if (counter == 15){
            printf("tarea 2 eliminada\n");
            vTaskDelete(task1Handle2);
        }
        if (counter == 15){
            printf("tarea 1 finalizada\n");
            vTaskDelete(NULL);
        }
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
}
void task2(void *arg){
    unsigned int counter = 0;
    while(1){
        printf("Tarea 2, felicidades, count: %d\n", counter);
        counter++;
        if (counter>15){
            printf("tarea 2 finalizada\n");
            vTaskDelete(NULL);
        }
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
}
void app_main(void)
{
    xTaskCreatePinnedToCore(task1, "task1", 4096, NULL, 10, &task1Handle, 0);
    xTaskCreatePinnedToCore(task2, "task2", 4096, NULL, 10, &task1Handle2, 1);
}

Le puse un pequeño delay de 100ms porque sin eso algunos printf no salían y parecía que en el tiempo en el que se montaba la tarea 2 en el segundo núcleo le daba tiempo la la tarea 1 de ejecutarse en su totalidad y los log salían muy raro.

Ciclo de vida de las tareas con FreeRTOS

Estoy probando con el LilyGo TTGO LoRa 32, y obtenía la salida:

I (313) app_start: Starting scheduler on CPU0
I (318) app_start: Starting scheduler on CPU1
I (318) main_task: Started on CPU0
I (328) main_task: Calling app_main()
Task 1 count: 1
Task 1 count: 2
Task 1 count: 3
Task 2 suspended
I (328) main_task: Returned from app_main()
Task 2 count: 1
Task 2 count: 2
Task 2 count: 3
Task 2 count: 4
Task 2 count: 5
Task 2 count: 6
Task 2 count: 7
Task 2 count: 8
Task 2 count: 9
Task 2 count: 10
Task 2 count: 11
Task 2 count: 12
Task 2 count: 13
Task 2 count: 14
Task 2 count: 15
Task 2 deleted

No se ve que la tarea 1 no controla la tarea. 2, ya que se la tarea 2 sigue ejecutándose después de que la tarea 1 la suspende, así que agregué al final del while de cada tarea un delay:

while (1)
    {
        ...
        vTaskDelay(pdMS_TO_TICKS(100));
    }

Y de esa forma ya funciona como debe:

I (313) app_start: Starting scheduler on CPU0
I (318) app_start: Starting scheduler on CPU1
I (318) main_task: Started on CPU0
I (328) main_task: Calling app_main()
Task 1 count: 1
I (328) main_task: Returned from app_main()
Task 2 count: 1
Task 1 count: 2
Task 2 count: 2
Task 1 count: 3
Task 2 suspended
Task 1 count: 4
Task 1 count: 5
Task 1 count: 6
Task 1 count: 7
Task 1 count: 8
Task 1 count: 9
Task 1 count: 10
Task 2 resumed
Task 2 count: 3
Task 1 count: 11
Task 2 count: 4
Task 1 count: 12
Task 2 deleted
Task 1 count: 13
Task 1 count: 14
Task 1 count: 15
Task 1 deleted

En mi vida soy el core 1 entrando en pánico ;’)

No logré que se ejecutaran en paralelo no lo sé \#include \<stdio.h>#include "freertos/FreeRTOS.h"#include "freertos/task.h" TaskHandle\_t taskHandle1 = NULL;TaskHandle\_t taskHandle2 = NULL; void task1(void \*args){    int count = 0;    while(1){        count++;        printf("Task #1; count: %d\n", count);        if(count == 3 && taskHandle2 != NULL){            vTaskSuspend(taskHandle2);            printf("Task #2 suspend\n");        }        if(count == 10 && taskHandle2 != NULL){            vTaskResume(taskHandle2);            printf("Task #2 resume\n");        }        if(count == 12 && taskHandle2 != NULL){            vTaskDelete(taskHandle2);            printf("Task #2 delete\n");        }        if(count >= 15){            printf("Task #1 Ok\n");            vTaskDelete(NULL);        }    }} void task2(void \*args){    int count = 0;    while(1){        count++;        printf("Task #2; count: %d\n", count);         if(count >= 15){            vTaskDelete(NULL);        }    }} void app\_main(void){    // Parametros:     //      función,     //      nombre de la tarea,     //      espacio reservado en memoria,    //      datos iniciales de la tarea,    //      prioridad de la tarea,    //      Almacenar la tarea para manipularla,    //      # de Core        xTaskCreate(task1, "task1", 4096, NULL, 10, \&taskHandle1); // Core 0 por defecto    xTaskCreatePinnedToCore(task2, "task2", 4096, NULL, 10, \&taskHandle2, 1);}
**eRTOS**  # **Manejo de Tareas en FreeRTOS con ESP32** En este documento, exploraremos cómo crear, pausar, reanudar y eliminar tareas en FreeRTOS utilizando un ESP32. También veremos cómo asignar tareas a diferentes núcleos del procesador y corregiremos errores comunes para evitar reinicios inesperados. ## **1. Creación de Tareas** Para iniciar, creamos una tarea simple que cuenta hasta 5 antes de eliminarse: \#include \<stdio.h> \#include "freertos/FreeRTOS.h" \#include "freertos/task.h" TaskHandle\_t taskHandle1 = NULL; void task1(void \*args) {     int count = 0;     while (1) {         count++;         printf("Task 1 count: %d\n", count);         if (count > 5) {             vTaskDelete(NULL);         }     } } void app\_main(void) {     xTaskCreate(task1, "task1", 4096, NULL, 10, \&taskHandle1); } Este código crea una tarea que se ejecuta en un bucle hasta que count supera 5, momento en el cual se elimina. ## **2. Creación de una Segunda Tarea** Para agregar una segunda tarea, modificamos el código para incluir task2: TaskHandle\_t taskHandle2 = NULL; void task2(void \*args) {     int count = 0;     while (1) {         count++;         printf("Task 2 count: %d\n", count);     } } void app\_main(void) {     xTaskCreate(task1, "task1", 4096, NULL, 10, \&taskHandle1);     xTaskCreate(task2, "task2", 4096, NULL, 10, \&taskHandle2); } Ahora, tenemos dos tareas ejecutándose en paralelo con la misma prioridad. ## **3. Asignación de Tareas a Diferentes Núcleos** Podemos ejecutar task2 en el segundo núcleo del ESP32 utilizando xTaskCreatePinnedToCore: void app\_main(void) {     xTaskCreate(task1, "task1", 4096, NULL, 10, \&taskHandle1);     xTaskCreatePinnedToCore(task2, "task2", 4096, NULL, 10, \&taskHandle2, 1); } De esta manera, task1 se ejecuta en el núcleo 0 y task2 en el núcleo 1. ## **4. Control de Ejecución de Tareas** Ahora, task1 controlará la ejecución de task2. La lógica es la siguiente: * Cuando task1 llega a 3, suspende task2. * Cuando task1 llega a 10, reanuda task2. * Cuando task1 llega a 12, elimina task2. * Cuando task1 llega a 15, se elimina a sí misma. Código actualizado: void task1(void \*args) {     int count = 0;     while (1) {         count++;         printf("Task 1 count: %d\n", count);         if (count == 3) {             vTaskSuspend(taskHandle2);             printf("Task 2 suspended\n");         }         if (count == 10) {             vTaskResume(taskHandle2);             printf("Task 2 resumed\n");         }         if (count == 12) {             vTaskDelete(taskHandle2);             printf("Task 2 deleted\n");         }         if (count == 15) {             printf("Task 1 deleted\n");             vTaskDelete(NULL);         }     } } Este código permite que task1 gestione task2 de manera controlada. ## **5. Compilación y Ejecución** Para compilar y subir el código al ESP32, ejecutamos en la terminal: idf.py build idf.py -p COM3 flash idf.py -p COM3 monitor Observaremos la ejecución en el monitor serie, donde task1 contará y suspenderá, reanudará y eliminará task2 en los momentos adecuados. ## **6. Consideraciones Finales** * **Evita el uso de >= en los condicionales** para evitar ejecuciones repetidas y errores de kernel. * **Las impresiones pueden no aparecer en orden exacto**, ya que FreeRTOS ejecuta tareas lo más rápido posible. * **Asignar tareas a núcleos específicos puede mejorar el rendimiento**, pero requiere planificación. Este ejercicio nos ayuda a comprender cómo FreeRTOS maneja tareas y cómo podemos controlarlas eficientemente.

Este es mi codigo utilizando vTaskDelay

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "time.h"

TaskHandle_t taskHandle_1;
TaskHandle_t taskHandle_2;

const TickType_t taskDelay_1 = 500 / portTICK_PERIOD_MS;
const TickType_t taskDelay_2 = 700 / portTICK_PERIOD_MS;

time_t elapsed_time_1;
time_t elapsed_time_2;

int counter_1 = 0;
int counter_2 = 0;

void task_1(void *args)
{
    while (true)
    {
        time(&elapsed_time_1);
        printf("Task 1 counter: %d seconds: %lld\n", counter_1, elapsed_time_1);
        counter_1++;
        vTaskDelay(taskDelay_1);

        switch (counter_1)
        {
            case 10:
                printf("Suspendiendo la tarea 2\n");
                vTaskSuspend(taskHandle_2);
                break;
            case 20:
                printf("Resumiendo la tarea 2\n");
                vTaskResume(taskHandle_2);
                break;
            case 30:
                printf("Eliminando la tarea 2\n");
                vTaskDelete(taskHandle_2);
                break;        
            case 50 ... 60:
                printf("Eliminando la tarea 1\n");
                vTaskDelete(taskHandle_1);
                break; 
            default:
                break;         
        };

    }
}

void task_2(void *args)
{
    while (true)
    {
        time(&elapsed_time_2);
        printf("Task 2 counter: %d seconds: %lld\n", counter_2, elapsed_time_2);
        counter_2++;
        vTaskDelay(taskDelay_2);

        if (counter_2 > 50)
        {
            printf("Finalizando la tarea 2\n");
            vTaskDelete(taskHandle_2);
        }

    }
}


void app_main(void)
{
    xTaskCreate(
        task_1,         //Nombre de la funcion que implementa la tarea
        "Tarea_1",      //Nombre descriptivo de la tarea con fines de debugging
        4096,           //El tamaño del task stack en bytes
        NULL,           //pointer a un parametro cuando la tarea esta siendo creada
        10,             //Prioridad de la tarea un numero
        &taskHandle_1   //apuntador para referenciar la tarea. 
    );
    
    //creamos la tarea asociandola al segundo core
    xTaskCreatePinnedToCore(
        task_2,         //Nombre de la funcion que implementa la tarea
        "Tarea_2",      //Nombre descriptivo de la tarea con fines de debugging
        4096,           //El tamaño del task stack en bytes
        NULL,           //pointer a un parametro cuando la tarea esta siendo creada
        10,             //Prioridad de la tarea un numero
        &taskHandle_2,  //apuntador para referenciar la tarea. 
        1               // core 0 y core 1
    );
}