Programando com FreeRTOS pt.2

 

{getToc} $title={Índice}


Introdução

O presente artigo tem como finalidade apresentar os recursos de manipulação de tarefas Suspend e Resume do sistema operacional FreeRTOS.

É recomendado que se leia a parte 1 da série sobre FreeRTOS.

Exemplos de implementação no esp32

Para os exemplos de demonstração foi utilizado o microcontrolador ESP32, com a versão de IDF v4.4.2, e como base será utilizado o seguinte código:

```c
#include <stdlib.h>
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_err.h"


#define TASK_1_NAME "task 1"
#define TASK_1_STACK_SIZE (configMINIMAL_STACK_SIZE * 4)
#define TASK_1_PRIORITY (tskIDLE_PRIORITY + 1)


#define TASK_2_NAME "task 2"
#define TASK_2_STACK_SIZE (configMINIMAL_STACK_SIZE * 4)
#define TASK_2_PRIORITY (tskIDLE_PRIORITY + 2)


//declaração das funções
static void task_1(void* arg);
static void task_2(void* arg);


//declaração dos handles
static TaskHandle_t xtask_handle_1 = NULL;
static TaskHandle_t xtask_handle_2 = NULL;


void app_main(void)
{
    BaseType_t xReturn = pdPASS;

    xReturn = xTaskCreate(&task_1,
                        TASK_1_NAME,
                        TASK_1_STACK_SIZE,
                        NULL,
                        TASK_1_PRIORITY,
                        &xtask_handle_1);

    if(xReturn != pdPASS || xtask_handle_1 == NULL)
    {
        printf("Erro ao criar a task 1\n");
    }

    xReturn = xTaskCreate(&task_2,
                        TASK_2_NAME,
                        TASK_2_STACK_SIZE,
                        NULL,
                        TASK_2_PRIORITY,
                        &xtask_handle_2);

    if(xReturn != pdPASS || xtask_handle_2 == NULL)
    {
        printf("Erro ao criar a task 2\n");
    }

    while (1)
    {
        vTaskDelay(pdMS_TO_TICKS(10000));
    }
}

static void task_1(void* arg)
{
    while(true)
    {
        ESP_LOGW("main", "%s tick : %d", __func__, xTaskGetTickCount());
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

static void task_2(void* arg)
{
    for(;;)
    {
        ESP_LOGI("main", "%s tick : %d", __func__, xTaskGetTickCount());
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}
```

vTaskSuspend

O método VtaskSuspend é utilizado para suspender tarefas, Quando suspensa, uma tarefa nunca terá tempo de processamento do microcontrolador, não importa qual seja sua prioridade. Como argumento temos os seguintes cenários:

  • A tarefa se suspende
```c
static void task_1(void* arg)
{
    uint8_t count = 0;
    while(true)
    {
        if(count > 4)
        {
            vTaskSuspend(NULL);
        }    
        count++;
        ESP_LOGW("main", "%s tick : %d", __func__, xTaskGetTickCount());
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}
```

Nesse caso como argumento de vTaskSuspend é passado o valor NULL, presente na linha 8. Na saída do log, repare que o print em amarelo (execultado pela task_1) para de ocorrer após a tarefa ser suspensa.

```terminal
<pre><font color="#4E9A06">I (311) cpu_start: Starting scheduler on PRO CPU.</font>
<font color="#4E9A06">I (0) cpu_start: Starting scheduler on APP CPU.</font>
<font color="#C4A000">W (0) main: task_1 tick : 0</font>
<font color="#4E9A06">I (0) main: task_2 tick : 0</font>
<font color="#4E9A06">I (1336) main: task_2 tick : 51</font>
<font color="#C4A000">W (1336) main: task_1 tick : 51</font>
<font color="#4E9A06">I (1836) main: task_2 tick : 101</font>
<font color="#C4A000">W (1836) main: task_1 tick : 101</font>
<font color="#4E9A06">I (2336) main: task_2 tick : 151</font>
<font color="#C4A000">W (2336) main: task_1 tick : 151</font>
<font color="#4E9A06">I (2836) main: task_2 tick : 201</font>
<font color="#C4A000">W (2836) main: task_1 tick : 201</font>
<font color="#4E9A06">I (3336) main: task_2 tick : 251</font>
<font color="#4E9A06">I (3836) main: task_2 tick : 301</font>
<font color="#4E9A06">I (4336) main: task_2 tick : 351</font>
</pre>
```
  • A tarefa suspende outra

Nesse cenario é passado para o método o handle da task que deseja suspender.

```c
static void task_1(void* arg)
{
    uint8_t count = 0;
    while(true)
    {
        if(count > 4)
        {
            vTaskSuspend(xtask_handle_2);
        }
        count++;
        ESP_LOGW("main", "%s tick : %d", __func__, xTaskGetTickCount());
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}
```

Note que a agora o log da task_1 continua ativo, enquanto o da task2 para de ocorrer após a tarefa ser suspensa.

```terminal
<pre><font color="#4E9A06">I (311) cpu_start: Starting scheduler on PRO CPU.</font>
<font color="#4E9A06">I (0) cpu_start: Starting scheduler on APP CPU.</font>
<font color="#C4A000">W (0) main: task_1 tick : 0</font>
<font color="#4E9A06">I (0) main: task_2 tick : 0</font>
<font color="#4E9A06">I (1336) main: task_2 tick : 51</font>
<font color="#C4A000">W (1336) main: task_1 tick : 51</font>
<font color="#4E9A06">I (1836) main: task_2 tick : 101</font>
<font color="#C4A000">W (1836) main: task_1 tick : 101</font>
<font color="#4E9A06">I (2336) main: task_2 tick : 151</font>
<font color="#C4A000">W (2336) main: task_1 tick : 151</font>
<font color="#4E9A06">I (2836) main: task_2 tick : 201</font>
<font color="#C4A000">W (2836) main: task_1 tick : 201</font>
<font color="#4E9A06">I (3336) main: task_2 tick : 251</font>
<font color="#C4A000">W (3336) main: task_1 tick : 251</font>
<font color="#C4A000">W (3836) main: task_1 tick : 301</font>
<font color="#C4A000">W (4336) main: task_1 tick : 351</font>
</pre>
```

vTaskResume

Uma tarefa que foi suspensa por uma ou mais chamadas para vTaskSuspend() será disponibilizada para execução novamente por uma única chamada para vTaskResume().

```c
static void task_1(void* arg)
{
    uint8_t count = 0;
    while(true)
    {
        if(count == 2)
        {
            vTaskSuspend(xtask_handle_2);
        }
        if(count > 4)
        {
            vTaskResume(xtask_handle_2);
        }
        count++;
        ESP_LOGW("main", "%s tick : %d", __func__, xTaskGetTickCount());
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}
```

A linha 12 utiliza o método de resume, nele é passado o handle da task que está suspensa, o log a seguir apresenta o resultado do teste.

```terminal
<pre><font color="#4E9A06">I (311) cpu_start: Starting scheduler on PRO CPU.</font>
<font color="#4E9A06">I (0) cpu_start: Starting scheduler on APP CPU.</font>
<font color="#C4A000">W (0) main: task_1 tick : 0</font>
<font color="#4E9A06">I (0) main: task_2 tick : 0</font>
<font color="#4E9A06">I (1336) main: task_2 tick : 51</font>
<font color="#C4A000">W (1336) main: task_1 tick : 51</font>
<font color="#4E9A06">I (1836) main: task_2 tick : 101</font>
<font color="#C4A000">W (1836) main: task_1 tick : 101</font>
<font color="#C4A000">W (2336) main: task_1 tick : 151</font>
<font color="#C4A000">W (2836) main: task_1 tick : 201</font>
<font color="#4E9A06">I (3336) main: task_2 tick : 251</font>
<font color="#C4A000">W (3336) main: task_1 tick : 251</font>
<font color="#4E9A06">I (3836) main: task_2 tick : 301</font>
<font color="#C4A000">W (3836) main: task_1 tick : 301</font>
</pre>
```

No próximo artigo da séria, será abordado o conteúdo "notificações de tarefas".

Referências

Bruno Lima

Engenheiro de computação atuando em desenvolvimento de sistemas embarcados (Firmware) com microcontroladores e processadores (Linux Embarcado). Contribuidor de projetos públicos e fóruns de c/c++. linkedin github

Postar um comentário

Deixe seu comentário ou sua sugestão!

Postagem Anterior Próxima Postagem

Formulário de contato