Table of Contents
- Introdução geral
- Padrões Fundamentais de Estruturação de Tarefas
- Padrões de Comunicação e Sincronização em RTOS
- Padrões de Exclusão Mútua, Proteção de Recursos e Prevenção de Deadlock
- Padrões de Controle de Fluxo, Estados e Recuperação em RTOS
- Padrões de Arquitetura em Camadas, Drivers e Serviços em RTOS
- Padrões de Inicialização, Startup Sequencial e Monitoramento de Saúde
- Síntese Geral e Checklist Arquitetural de Padrões para FreeRTOS
Introdução geral
Em sistemas embarcados com RTOS, especialmente em aplicações industriais, automotivas e IoT crítico, o maior desafio não é apenas “fazer funcionar”, mas manter previsibilidade temporal, escalabilidade e manutenibilidade. É nesse ponto que os padrões de projeto aplicados a RTOS se tornam fundamentais.
Diferente de aplicações desktop, padrões em RTOS precisam respeitar restrições de tempo real, uso determinístico de memória, prioridades, latência de interrupções e sincronização segura entre contexto de ISR e tarefas. Muitos padrões clássicos de software são adaptados ou reinterpretados nesse contexto.
Neste artigo, começaremos pelos padrões estruturais básicos de tarefas, que formam a fundação de praticamente qualquer sistema com FreeRTOS.
Padrões Fundamentais de Estruturação de Tarefas
1.1 Superloop + Tasks (Incremental RTOS Adoption)
Problema resolvido:
Projetos legados em superloop (while(1)) tornam-se difíceis de manter à medida que crescem. Migrar tudo de uma vez para RTOS é arriscado.
Ideia do padrão:
Manter o superloop como uma tarefa principal, introduzindo gradualmente novas tarefas RTOS.
Quando usar:
- Migração de firmware bare-metal para FreeRTOS
- Sistemas simples que estão crescendo
- Prototipação controlada
Estrutura típica:
void LegacySuperloopTask(void *pvParameters)
{
for (;;)
{
ReadSensors();
ProcessData();
UpdateOutputs();
vTaskDelay(pdMS_TO_TICKS(10));
}
}
xTaskCreate(
LegacySuperloopTask,
"Legacy",
1024,
NULL,
tskIDLE_PRIORITY + 1,
NULL
);
Vantagens:
- Baixo risco na migração
- Preserva código validado
- Facilita testes incrementais
Risco comum:
Transformar essa tarefa em um “monstro” que ignora o espírito do RTOS. Este padrão deve ser transitório, não permanente.
1.2 One Task Per Responsibility (Uma tarefa por responsabilidade)
Problema resolvido:
Tarefas que fazem “de tudo” dificultam análise temporal, debugging e escalonamento.
Ideia do padrão:
Cada tarefa possui uma única responsabilidade funcional bem definida.
Exemplo típico em FreeRTOS:
- Task de aquisição
- Task de processamento
- Task de comunicação
void SensorTask(void *pvParameters)
{
for (;;)
{
ReadADC();
xTaskNotify(ProcessTaskHandle, 0, eNoAction);
vTaskDelay(pdMS_TO_TICKS(5));
}
}
void ProcessTask(void *pvParameters)
{
for (;;)
{
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
FilterData();
ComputeResults();
}
}
Vantagens:
- Facilita análise de prioridades
- Reduz acoplamento
- Favorece paralelismo real
Boas práticas:
- Nomear tarefas claramente
- Documentar WCET (Worst Case Execution Time)
- Evitar bloqueios longos
1.3 Cyclic Executive com RTOS
Problema resolvido:
Algumas aplicações precisam de periodicidade rígida, mesmo usando RTOS.
Ideia do padrão:
Uma tarefa de alta prioridade atua como orquestrador temporal, liberando outras tarefas de forma cíclica.
Estrutura conceitual:
- Task cíclica principal
- Subtarefas acionadas por notificações
void CyclicTask(void *pvParameters)
{
TickType_t xLastWakeTime = xTaskGetTickCount();
for (;;)
{
xTaskNotify(TaskAHandle, 0, eNoAction);
xTaskNotify(TaskBHandle, 0, eNoAction);
vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(10));
}
}
Vantagens:
- Controle temporal explícito
- Previsibilidade elevada
- Útil em controle e automação
Limitação:
Menos flexível que arquiteturas puramente orientadas a eventos.
1.4 Idle Task como Padrão Arquitetural
Problema resolvido:
Desperdício de CPU e energia quando o sistema está ocioso.
Ideia do padrão:
Usar a Idle Task como ponto central para:
- Economia de energia
- Limpeza de recursos
- Instrumentação
void vApplicationIdleHook(void)
{
EnterLowPowerMode();
}
Uso típico:
__WFI()em Cortex-M- Estatísticas de CPU
- Monitoramento de heap
Importante:
Nunca bloquear, nunca usar delays e nunca acessar recursos não protegidos.