Semaphores no FreeRTOS: Sincronização de Eventos e Contagem de Recursos
Os semaphores no FreeRTOS são mecanismos de sincronização, não de proteção de recursos. Essa distinção é sutil, porém fundamental para o correto desenho arquitetural de sistemas embarcados. Enquanto mutexes modelam posse exclusiva de um recurso, semáforos modelam ocorrência de eventos ou disponibilidade de múltiplas instâncias de um recurso.
O FreeRTOS implementa dois tipos principais de semáforos:
- Semáforo binário
- Semáforo de contagem
Ambos são baseados internamente em filas, mas com semântica própria.
Semáforo Binário
O semáforo binário pode assumir dois estados: disponível ou indisponível. É frequentemente usado para:
- Sincronizar uma task com uma ISR.
- Indicar que um evento ocorreu.
- Substituir busy wait por bloqueio eficiente.
Diferentemente do mutex, não existe herança de prioridade em semáforos binários.
Exemplo: ISR sinalizando uma Task
#include "FreeRTOS.h"
#include "semphr.h"
SemaphoreHandle_t xAdcSemaphore;
void vInit(void)
{
xAdcSemaphore = xSemaphoreCreateBinary();
}
void ADC_IRQHandler(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(xAdcSemaphore, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void vAdcTask(void *pvParameters)
{
for (;;)
{
if (xSemaphoreTake(xAdcSemaphore, portMAX_DELAY) == pdTRUE)
{
process_adc_data();
}
}
}
Semáforo de Contagem
O semáforo de contagem mantém um contador interno que representa quantas unidades de um recurso estão disponíveis ou quantos eventos ocorreram. É útil quando:
- Há múltiplos eventos gerados antes do processamento.
- Existe um pool de recursos idênticos.
- Eventos não podem ser perdidos.
Exemplo: Contagem de eventos
SemaphoreHandle_t xEventCounter;
void vInit(void)
{
xEventCounter = xSemaphoreCreateCounting(10, 0);
}
void vProducerTask(void *pvParameters)
{
xSemaphoreGive(xEventCounter);
}
void vConsumerTask(void *pvParameters)
{
if (xSemaphoreTake(xEventCounter, portMAX_DELAY) == pdTRUE)
{
handle_event();
}
}
Quando usar Semaphores
Use semáforos quando:
- Um evento precisa acordar uma ou mais tasks.
- Uma ISR precisa sinalizar uma task.
- É necessário contar ocorrências.
- A posse do recurso não é relevante.
Evite semáforos quando:
- O objetivo é proteger acesso exclusivo.
- Herança de prioridade é necessária.
- Comunicação de dados estruturados é exigida.
Vantagens Técnicas
- Simples e eficientes.
- Funcionam bem com ISRs.
- Flexíveis para contagem e sincronização.
- Reduzem latência por bloqueio eficiente.
Armadilhas comuns
- Usar semáforo binário como mutex.
- Perder eventos por má inicialização.
- Criar dependência implícita de ordem.
- Misturar semáforos e delays para sincronização.
Uma boa regra prática:
👉 Evento → Semáforo
👉 Recurso → Mutex
Na próxima seção, abordaremos as Message Queues, explicando transporte de dados entre tasks, desacoplamento de produtores e consumidores e impacto no uso de memória.