2 – Prioridades, Stack e Boas Práticas na Criação de Tarefas
Ao criar tarefas no FreeRTOS, três decisões arquiteturais têm impacto direto na estabilidade e no determinismo do sistema: prioridade, tamanho da pilha (stack) e forma de alocação de memória. Erros nesses pontos são a principal causa de hard faults, travamentos intermitentes e comportamentos não determinísticos em sistemas embarcados com RTOS.
Prioridades de tarefas
O FreeRTOS utiliza um escalonador baseado em prioridade fixa. A regra é simples:
a tarefa pronta com maior prioridade sempre executa primeiro.
As prioridades são definidas no intervalo:
0 → prioridade mais baixa
configMAX_PRIORITIES - 1 → prioridade mais alta
Por padrão, configMAX_PRIORITIES costuma variar entre 5 e 10, dependendo da aplicação.
Exemplo típico de hierarquia de prioridades:
- Prioridade 4: tarefas de tempo crítico (controle, watchdog lógico)
- Prioridade 3: comunicação (UART, Ethernet, Wi-Fi)
- Prioridade 2: processamento de dados
- Prioridade 1: interface, LEDs, logging
- Prioridade 0: tarefas ociosas ou manutenção
Um erro comum é atribuir prioridade alta a tarefas que usam vTaskDelay() longos, o que não traz benefício algum. Prioridade alta deve ser reservada a tarefas que:
- reagem a eventos externos,
- acordam frequentemente,
- possuem requisitos temporais rígidos.
Stack de tarefas: como dimensionar corretamente
Cada tarefa no FreeRTOS possui sua própria pilha, usada para:
- variáveis locais,
- chamadas de função,
- salvamento de contexto durante context switch.
O parâmetro usStackDepth define o tamanho da pilha em palavras, não em bytes.
Exemplo:
usStackDepth = 128 // Em Cortex-M → 128 * 4 = 512 bytes
Como estimar o tamanho da stack
Uma regra prática inicial:
- Tarefa simples (GPIO, delays): 128 a 256 palavras
- Tarefa com printf / HAL / drivers: 256 a 512 palavras
- Tarefa com TCP/IP, JSON, TLS: 512 a 1024 palavras ou mais
Além disso, o FreeRTOS oferece ferramentas para validação:
uxTaskGetStackHighWaterMark(NULL);
Essa função retorna a menor quantidade de stack livre já observada, permitindo ajustar o valor com base em dados reais.
Stack overflow e mecanismos de proteção
O FreeRTOS pode detectar stack overflow em tempo de execução, dependendo da configuração:
#define configCHECK_FOR_STACK_OVERFLOW 2
E a implementação do hook:
void vApplicationStackOverflowHook(
TaskHandle_t xTask,
char *pcTaskName
)
{
taskDISABLE_INTERRUPTS();
for (;;);
}
Essa função é crítica em sistemas robustos, pois permite identificar falhas antes que causem corrupção de memória silenciosa.
Heap e criação dinâmica de tarefas
Quando xTaskCreate() é utilizado, o FreeRTOS aloca memória dinamicamente para:
- TCB (Task Control Block)
- Stack da tarefa
Isso depende diretamente do heap configurado (heap_1 a heap_5). Em aplicações modernas, heap_4 ou heap_5 são os mais recomendados por suportarem:
- liberação de memória,
- coalescência de blocos,
- menor fragmentação.
Se o heap não tiver espaço suficiente, xTaskCreate() falha silenciosamente, retornando pdFAIL.
Exemplo de verificação correta:
if (xTaskCreate(vTaskBlink, "Blink", 128, NULL, 1, NULL) != pdPASS)
{
/* Tratar erro de criação */
}
Boas práticas fundamentais
Algumas recomendações que evitam problemas clássicos:
- Nunca usar
while(1)com busy wait dentro da tarefa - Sempre usar
vTaskDelay()ou mecanismos de sincronização - Evitar
printfem tarefas de alta prioridade - Monitorar uso de stack durante o desenvolvimento
- Separar tarefas por responsabilidade (Single Responsibility Principle)
Uma arquitetura bem estruturada de tarefas torna o sistema mais previsível, escalável e fácil de manter, especialmente em projetos que envolvem comunicação, sensores e controle em tempo real.