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:
#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
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.
```cstatic 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().
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".