Event Groups e flags binárias no FreeRTOS usando ESP32


{getToc} $title={Índice}


Event bits ou event flags são basicamente flags binárias, utilizados para indicar se um evento ocorreu ou não.

O presente artigo considera que a pessoa já tenha uma base de FreeRTOS. Caso seja iniciante, é recomendado que veja os dois artigos sobre FreeRTOS disponíveis aqui [1][2].

Um event group é um conjunto de event flags, e o número de bits pode variar de acordo com as configurações do seu sistema. O número a ser considerado neste artigo é 24 bits, que é a configuração padrão de um projeto gerado com o ESP-IDF, mas a quantidade para cada projeto específico pode ser vista no manual do FreeRTOS [3].

Para se criar um event group, pode-se usar a função xEventGroupCreate(), que aloca memória e retorna um ponteiro para o handle de um event group, conforme a seguir. [4]

```C
// Handle para o event group
EventGroupHandle_t event_group = NULL;
event_group = xEventGroupCreate();
```
Para setar o valor de um bit, pode-se utilizar a função xEventGroupSetBits. O primeiro argumento é o handle do event group, e o segundo é uma máscara de bits indicando quais os bits a serem setados. Por exemplo, caso deseje setar os bits 1 e 2, o valor deve ser 0x06 (00000110).

Caso se deseje travar uma task, e aguardar até que um ou mais bits sejam setados, pode-se usar a função xEventGroupWaitBits. O primeiro argumento é o handle do event group, o segundo é uma máscara dos bits a serem testados (este valor NÃO pode ser 0), o terceiro é um valor booleano que indica se as flags devem ser limpas após o retorno da função, o quarto é um valor booleano que, se for verdadeiro, indica que todos os bits deverão ser testados, e se for falso, apenas um bit setado já basta, e por fim o último argumento indica o timeout para a função (este valor pode ser setado para portMAX_DELAY, caso deseje travar a task até que a flag seja setada). Esta função retorna o valor do event group no momento em que os bits esperados foram setados, ou que o timeout aconteceu.
```C
xEventGroupWaitBits(event_group, /**< Handle do event group */
                    FLAGS_TO_WAIT, /**<  Máscara dos bits a serem testados */
                    CLEAR_ON_EXIT, /**< As flags devem ser limpas após o retorno? */
                    WAIT_ALL_BITS, /**< Todos os bits deverão ser testados? */
                    MAX_WAIT) /**< Tempo de espera máximo */
```

O exemplo a seguir utiliza 2 tasks, a task_a, que controla o valor da variável “counter”, e a task_b, que lê e mostra o valor desta mesma variável. Ele simula uma situação em que a task_b precisa aguardar a atualização de um valor na task_a, e utiliza do bit 0 como flag para verificar se a atualização foi feita. Depois de ler o event group, a flag referente a esse bit é limpa.

```C
/**
 * @file main.c
 * @author Matheus
 * @brief Event Group use example
 */

#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "esp_log.h"
#include "freertos/event_groups.h"
#include "freertos/portmacro.h"

#define COUNTER_EVENT_BIT BIT0
static int counter = 0;

EventGroupHandle_t event_group = NULL;

void task_a(void * pvParameters)
{
// atualiza o valor do counter a cada 1 segundo
    while(event_group != NULL) {
        counter++;
        xEventGroupSetBits(event_group, COUNTER_EVENT_BIT);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
    vTaskDelete(NULL);
}

void task_b(void * pvParameters)
{
    while (event_group != NULL) {
// aguarda a flag ser setada
// limpa a flag após a leitura e aguarda qualquer flags ser setada
        while(xEventGroupWaitBits(event_group, COUNTER_EVENT_BIT, true, false, portMAX_DELAY)) {
            ESP_LOGI("Event bit set", "New value: %d\n", counter);
        }
    }
    vTaskDelete(NULL);
}

void app_main(void)
{
    event_group = xEventGroupCreate();
    xTaskCreate(task_a, "task_a", 4096, NULL, 1, NULL);
    xTaskCreate(task_b, "task_b", 4096, NULL, 1, NULL);

    while (1)
    {
        vTaskDelay(portMAX_DELAY);
    }
}
```

Dessa forma, é garantido que a task_b só irá acessar o valor da variável counter após a task_a atualizar o valor da mesma. O resultado da execução do código acima pode ser vista a seguir:

```bash
...
I (261) app_start: Starting scheduler on CPU0
I (266) main_task: Started on CPU0
I (266) main_task: Calling app_main()
I (266) Event bit set: New value: 1
I (1266) Event bit set: New value: 2
I (2266) Event bit set: New value: 3
I (3266) Event bit set: New value: 4
I (4266) Event bit set: New value: 5
I (5266) Event bit set: New value: 6
I (6266) Event bit set: New value: 7
...
```

Postar um comentário

Deixe seu comentário ou sua sugestão!

Postagem Anterior Próxima Postagem

Formulário de contato