MCU & FPGA RTOS ISR + RTOS na Prática com FreeRTOS

ISR + RTOS na Prática com FreeRTOS

Prioridades de interrupção no Cortex-M e regras do FreeRTOS

Grande parte dos problemas graves em sistemas FreeRTOS com Cortex-M não está no código das tasks, mas sim em uma configuração incorreta das prioridades de interrupção. Esses erros são difíceis de depurar, muitas vezes não geram faults explícitos e se manifestam como travamentos aleatórios, perda de eventos ou comportamento não determinístico.

Para evitar isso, é essencial compreender como o NVIC do Cortex-M funciona e como o FreeRTOS impõe regras sobre ele.


5.1 Como o NVIC trata prioridades de interrupção

Nos microcontroladores Cortex-M, as prioridades de interrupção:

  • São representadas por números menores = maior prioridade
  • Nem todos os bits do campo de prioridade são implementados
  • O número de bits válidos é definido por __NVIC_PRIO_BITS

Exemplo típico:

  • STM32F4: 4 bits de prioridade (0 a 15)
  • STM32F1: 4 bits
  • STM32H7: 4 bits (com subprioridades opcionais)

Ou seja:

PrioridadeNível
0mais alt
15mais baixa

O NVIC permite que:

  • Uma interrupção de prioridade maior interrompa outra de prioridade menor
  • ISRs de prioridade muito alta nunca sejam interrompidas pelo kernel

5.2 O papel de configMAX_SYSCALL_INTERRUPT_PRIORITY

O FreeRTOS não permite que qualquer ISR chame suas APIs. Apenas interrupções com prioridade igual ou inferior (numericamente maior) a um determinado limite podem interagir com o kernel.

Esse limite é definido pela macro:

#define configMAX_SYSCALL_INTERRUPT_PRIORITY

Ela define a maior prioridade de interrupção (menor número) que ainda pode chamar APIs FromISR.

Exemplo prático em um STM32 com 4 bits de prioridade:

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
#define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - __NVIC_PRIO_BITS))

Isso significa:

  • ISRs com prioridade 0 a 4 → NÃO podem chamar FreeRTOS
  • ISRs com prioridade 5 a 15 → PODEM chamar APIs FromISR

Essa distinção é obrigatória e não opcional.


5.3 Erro clássico: “funciona até parar de funcionar”

Um erro muito comum é configurar uma interrupção com prioridade máxima (0) e, dentro dela, chamar:

xQueueSendFromISR(...)

O código compila.
O sistema inicializa.
Às vezes funciona.

Mas o comportamento é indefinido.

Por quê?

Porque:

  • O FreeRTOS desabilita interrupções até configMAX_SYSCALL_INTERRUPT_PRIORITY
  • Uma ISR com prioridade mais alta ignora esse bloqueio
  • O kernel pode ser acessado em estado inconsistente

Resultado:

  • Corrupção de estruturas internas
  • Deadlocks silenciosos
  • HardFaults intermitentes

5.4 Regra de ouro para Cortex-M + FreeRTOS

Se uma interrupção chama qualquer API do FreeRTOS, ela NÃO pode ter prioridade maior do que configMAX_SYSCALL_INTERRUPT_PRIORITY.

Ou, dito de forma prática:

  • ISRs de tempo crítico absoluto (ex: controle PWM, safety)
    → prioridade alta, não usam FreeRTOS
  • ISRs que sinalizam tasks
    → prioridade mais baixa, usam APIs FromISR

5.5 Configuração correta no código

Exemplo de configuração segura:

HAL_NVIC_SetPriority(USART1_IRQn, 6, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);

E no FreeRTOSConfig.h:

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

Nesse cenário:

  • USART1 pode chamar xQueueSendFromISR
  • Timer de controle crítico pode rodar em prioridade 2 sem interferência

5.6 Por que o FreeRTOS faz isso?

Essa regra existe para garantir:

  • Determinismo temporal
  • Escalonamento previsível
  • Integridade das estruturas internas
  • Portabilidade entre arquiteturas

Sem esse modelo, o kernel teria que:

  • Suportar preempção total dentro de ISRs
  • Aumentar drasticamente a complexidade
  • Perder desempenho e previsibilidade

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