Padrões de Inicialização, Startup Sequencial e Monitoramento de Saúde
Em sistemas com FreeRTOS, o boot é o momento mais frágil do sistema. Muitos firmwares falham não durante a operação normal, mas durante inicialização parcial, falhas de periféricos, ordem incorreta de dependências ou estados indefinidos.
Os padrões desta seção tornam o startup determinístico, auditável e recuperável.
6.1 Startup Task (Task de Inicialização)
Problema resolvido:
Inicialização espalhada entre main(), ISRs e tarefas diversas.
Ideia do padrão:
Criar uma tarefa exclusiva de startup, responsável por inicializar tudo em ordem controlada, antes do sistema entrar em operação normal.
Estrutura típica
int main(void)
{
HardwareInit();
xTaskCreate(StartupTask, "Startup", 1024, NULL, tskIDLE_PRIORITY + 3, NULL);
vTaskStartScheduler();
}
void StartupTask(void *pvParameters)
{
InitDrivers();
InitServices();
InitApplication();
xTaskCreate(AppTask, "App", 1024, NULL, tskIDLE_PRIORITY + 1, NULL);
vTaskDelete(NULL);
}
Vantagens:
- Ordem explícita
- Inicialização rastreável
- Elimina “efeitos colaterais” no
main()
Boa prática:
Startup task deve se autodestruir após cumprir sua função.
6.2 Init Sequencing (Sequenciamento de Inicialização)
Problema resolvido:
Tarefas começam a rodar antes de suas dependências estarem prontas.
Ideia do padrão:
Inicialização ocorre em fases bem definidas, com sincronização explícita.
Exemplo com Event Groups
#define EVT_DRIVERS_READY (1 << 0)
#define EVT_SERVICES_READY (1 << 1)
void StartupTask(void *pvParameters)
{
InitDrivers();
xEventGroupSetBits(systemEvents, EVT_DRIVERS_READY);
InitServices();
xEventGroupSetBits(systemEvents, EVT_SERVICES_READY);
vTaskDelete(NULL);
}
void AppTask(void *pvParameters)
{
xEventGroupWaitBits(
systemEvents,
EVT_DRIVERS_READY | EVT_SERVICES_READY,
pdFALSE,
pdTRUE,
portMAX_DELAY
);
RunApplication();
}
Vantagem:
Dependências explícitas → menos bugs “fantasma”.
6.3 Dependency Ordering Pattern
Problema resolvido:
Serviços que dependem implicitamente uns dos outros.
Ideia do padrão:
Cada serviço declara o que precisa antes de operar.
Exemplo conceitual
bool Network_IsReady(void);
bool Storage_IsReady(void);
void TelemetryTask(void *pvParameters)
{
while (!Network_IsReady() || !Storage_IsReady())
{
vTaskDelay(pdMS_TO_TICKS(100));
}
StartTelemetry();
}
Melhoria recomendada:
Substituir polling por eventos ou notificações.
6.4 Health Monitoring Pattern (Monitoramento de Saúde)
Problema resolvido:
Tarefas travam silenciosamente.
Ideia do padrão:
Cada tarefa reporta periodicamente seu estado para um supervisor central.
Estrutura básica
typedef struct {
uint32_t taskId;
TickType_t lastAlive;
} TaskHealth;
void HealthReport(uint32_t id)
{
healthTable[id].lastAlive = xTaskGetTickCount();
}
void SupervisorTask(void *pvParameters)
{
for (;;)
{
if (TaskTimeoutDetected())
EnterRecoveryMode();
vTaskDelay(pdMS_TO_TICKS(500));
}
}
Vantagens:
- Detecção precoce de falhas
- Integração natural com watchdog
- Essencial em sistemas remotos
6.5 Fail-Safe State Pattern
Problema resolvido:
Sistema entra em estado indefinido após falha grave.
Ideia do padrão:
Definir explicitamente um estado seguro, conhecido e controlado.
void EnterSafeState(void)
{
DisableOutputs();
StopMotors();
SignalErrorLED();
}
Importante:
Fail-safe não é reset. É sobrevivência controlada.
6.6 Warm Restart vs Cold Restart
Problema resolvido:
Reset total desnecessário causa perda de estado e latência.
Ideia do padrão:
Diferenciar:
- Cold restart → reboot completo
- Warm restart → reinicialização parcial de serviços
if (RecoverableFault())
RestartServices();
else
SystemReset();