MCU & FPGA RTOS FreeRTOS na Prática: Threads, Semáforos, Filas, Mutexes, Timers e Boas Práticas em Sistemas Embarcados

FreeRTOS na Prática: Threads, Semáforos, Filas, Mutexes, Timers e Boas Práticas em Sistemas Embarcados

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.


0 0 votos
Classificação do artigo
Inscrever-se
Notificar de
guest
0 Comentários
mais antigos
mais recentes Mais votado
Feedbacks embutidos
Ver todos os comentários

Related Post

0
Adoraria saber sua opinião, comente.x