2 — Interrupções no Zephyr
O papel correto das ISRs em pipelines de eventos robustos
Em sistemas embarcados de produção, interrupções (Interrupt Service Routines – ISRs) não são lugares para lógica. Elas são pontos de fronteira entre o mundo físico assíncrono e o sistema operacional. No Zephyr, isso é ainda mais explícito: a ISR deve capturar o evento e sair o mais rápido possível, delegando todo o processamento para mecanismos seguros do kernel.
2.1 O erro clássico: ISR como “mini-thread”
Em firmware imaturo, é comum ver interrupções fazendo:
- Leitura de sensores complexos
- Parsing de protocolos
- Logs extensivos
- Alocação de memória
- Chamadas bloqueantes
- Uso indevido de delays
Isso cria três problemas graves:
- Latência imprevisível (outras ISRs ficam bloqueadas).
- Deadlocks sutis (uso indevido de APIs não seguras em ISR).
- Sistema frágil (qualquer mudança quebra temporização).
No Zephyr, a regra é clara:
ISR só sinaliza. Threads processam.
2.2 O que uma ISR pode fazer no Zephyr
Dentro de uma interrupção, você deve se limitar a:
- Capturar estado mínimo (timestamp, flag, contador).
- Notificar o sistema por:
k_sem_give()k_msgq_put(..., K_NO_WAIT)k_work_submit()k_timer_start()(em casos específicos)
- Limpar a fonte da interrupção.
Nada além disso.
2.3 Exemplo 1 — Interrupção de GPIO bem projetada
Vamos partir de um caso real:
um sensor industrial que gera um pulso em GPIO quando um evento ocorre (ex.: encoder, sensor óptico, alarme externo).
Configuração do callback de interrupção
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
/* Semáforo para sinalizar evento */
K_SEM_DEFINE(event_sem, 0, 1);
/* Callback da interrupção */
static void gpio_event_isr(const struct device *dev,
struct gpio_callback *cb,
uint32_t pins)
{
/* ISR mínima: apenas sinaliza */
k_sem_give(&event_sem);
}
static struct gpio_callback gpio_cb;
Inicialização do GPIO
static int gpio_init(void)
{
const struct device *gpio_dev =
DEVICE_DT_GET(DT_NODELABEL(gpio0));
gpio_pin_configure(gpio_dev, 5,
GPIO_INPUT | GPIO_PULL_UP);
gpio_pin_interrupt_configure(
gpio_dev, 5, GPIO_INT_EDGE_TO_ACTIVE);
gpio_init_callback(&gpio_cb,
gpio_event_isr, BIT(5));
gpio_add_callback(gpio_dev, &gpio_cb);
return 0;
}
📌 Observações importantes:
- Nenhum processamento ocorre na ISR.
- Nenhuma lógica de negócio.
- Nenhuma temporização.
- Apenas sinalização.
2.4 A thread consumidora do evento
Agora o processamento acontece em contexto de thread, onde tudo é seguro:
void event_thread(void)
{
while (1) {
/* Bloqueia até evento */
k_sem_take(&event_sem, K_FOREVER);
/* Aqui começa o pipeline real */
process_event();
}
}
Esse padrão já separa claramente:
- Detecção (ISR)
- Reação (thread)
Mas ainda há um problema:
👉 E se o evento gerar múltiplas etapas ou exigir temporização?
É aqui que entram Soft Timers e Workqueues — que não substituem a ISR, mas completam o pipeline.
2.5 Regra de ouro para ISRs em firmware industrial
Guarde este checklist mental:
✔ ISR deve ser curta e previsível
✔ ISR não conhece regras de negócio
✔ ISR não faz retry
✔ ISR não faz timeout
✔ ISR apenas empurra o evento para o pipeline
Tudo que cresce, escala ou muda não pertence à interrupção.