MCU & FPGA RTOS Interrupções e Soft Timers no Zephyr OS

Interrupções e Soft Timers no Zephyr OS


Interrupções e Soft Timers no Zephyr OS: Guia Completo para Firmware em RTOS

Frase-chave foco

1 – Introdução: o papel de Interrupções e Soft Timers em um RTOS moderno

Em sistemas embarcados modernos, especialmente aqueles baseados em um RTOS (Real-Time Operating System) como o Zephyr OS, a forma como lidamos com eventos assíncronos define diretamente a robustez, a previsibilidade temporal e a escalabilidade do firmware. Dois mecanismos são absolutamente centrais nesse contexto: interrupções de hardware e soft timers. Embora ambos sejam usados para reagir a eventos no tempo ou no mundo físico, eles possuem naturezas, custos e implicações arquiteturais bastante distintas.

As interrupções permitem que o hardware “interrompa” a execução normal da CPU para tratar eventos críticos e de baixa latência, como mudanças em GPIOs, chegada de dados em periféricos ou estouros de contadores. Já os soft timers do Zephyr são abstrações de alto nível baseadas no kernel, que permitem executar callbacks temporizados sem recorrer a timers de hardware dedicados ou lógica de polling. Essa separação clara entre o que é tempo crítico e o que é tempo gerenciado pelo kernel é uma das grandes virtudes do Zephyr.

Um erro comum de quem vem de arquiteturas bare-metal ou de RTOS mais simples é tentar resolver tudo com interrupções. No Zephyr, isso é um anti-padrão arquitetural. O sistema foi projetado para que interrupções sejam curtas, determinísticas e não bloqueantes, delegando o processamento mais pesado para threads, workqueues ou timers. Entender essa filosofia é essencial para escrever firmware escalável e seguro.

Ao longo deste artigo, vamos explorar:

  • Como o Zephyr trata interrupções de forma portável e segura
  • Como configurar e usar ISRs (Interrupt Service Routines) corretamente
  • Como funcionam os Soft Timers (k_timer)
  • Quando usar interrupção, timer ou thread
  • Padrões e armadilhas comuns em projetos reais

Sempre com exemplos em C, comentados e aplicáveis a placas reais como STM32, nRF e RP2040.


2 – Modelo de Interrupções no Zephyr: conceitos fundamentais

Antes de escrever qualquer ISR no Zephyr, é fundamental entender que o sistema adota um modelo de interrupções abstraído, desacoplado do hardware específico, mas ainda permitindo acesso direto quando necessário. O Zephyr se apoia em três pilares principais:

  1. Árvore de dispositivos (Devicetree)
  2. API genérica de IRQ do kernel
  3. Separação rígida entre contexto de interrupção e contexto de thread

No Zephyr, interrupções não são configuradas diretamente em registradores no código da aplicação (como em bare-metal). Em vez disso, elas são declaradas e conectadas por meio do Devicetree, que descreve o hardware de forma declarativa. Isso permite que o mesmo código rode, sem modificações, em arquiteturas distintas.

O que é uma ISR no Zephyr?

Uma ISR (Interrupt Service Routine) no Zephyr é uma função C comum, mas com restrições severas:

  • Não pode bloquear
  • Não pode usar k_sleep()
  • Não pode alocar memória dinâmica
  • Não pode chamar APIs que dependem do escalonador

Ela deve apenas:

  • Reconhecer o evento
  • Capturar dados mínimos
  • Sinalizar uma thread, timer ou workqueue

Esse modelo força uma arquitetura mais limpa e previsível.


3 – Conectando uma interrupção no Zephyr (exemplo com GPIO)

Vamos começar com um exemplo clássico: interrupção por mudança de nível em um pino GPIO, algo extremamente comum em botões, sensores e sinais externos.

Passo 1 – Definição no Devicetree (conceito)

O Zephyr já fornece nós de GPIO prontos no Devicetree. Em geral, você não precisa criar nada manualmente, apenas referenciar o pino correto.

Exemplo conceitual (simplificado):

button0: button_0 {
    gpios = <&gpioa 0 GPIO_ACTIVE_LOW>;
};

Passo 2 – Estrutura de callback de GPIO

No Zephyr, interrupções de GPIO usam a estrutura gpio_callback.

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>

/* Callback associado à interrupção */
static struct gpio_callback button_cb_data;

Passo 3 – Implementação da ISR

A função de callback será executada em contexto de interrupção:

void button_pressed_isr(const struct device *dev,
                        struct gpio_callback *cb,
                        uint32_t pins)
{
    ARG_UNUSED(dev);
    ARG_UNUSED(cb);
    ARG_UNUSED(pins);

    /* ISR deve ser curta e não bloqueante */
    printk("Botão pressionado!\n");
}

⚠️ Observação importante:
Mesmo o printk() não é ideal dentro de ISR em sistemas críticos. Ele é usado aqui apenas para fins didáticos. Em projetos reais, o correto é sinalizar uma thread.


Passo 4 – Configuração do GPIO e da interrupção

const struct device *button_dev;

button_dev = DEVICE_DT_GET(DT_NODELABEL(gpioa));

gpio_pin_configure(button_dev, 0, GPIO_INPUT | GPIO_PULL_UP);

gpio_pin_interrupt_configure(button_dev,
                              0,
                              GPIO_INT_EDGE_FALLING);

gpio_init_callback(&button_cb_data,
                   button_pressed_isr,
                   BIT(0));

gpio_add_callback(button_dev, &button_cb_data);

Neste ponto:

  • O hardware gera a interrupção
  • O driver de GPIO chama a ISR
  • O kernel garante isolamento e segurança

4 – Arquitetura correta: ISR + sinalização de thread

A forma correta de usar interrupções no Zephyr é acordar ou sinalizar uma thread, e não executar lógica pesada na ISR.

Exemplo usando semaforos:

K_SEM_DEFINE(button_sem, 0, 1);

void button_pressed_isr(const struct device *dev,
                        struct gpio_callback *cb,
                        uint32_t pins)
{
    k_sem_give(&button_sem);
}

Thread associada:

void button_thread(void)
{
    while (1) {
        k_sem_take(&button_sem, K_FOREVER);
        printk("Evento tratado em thread\n");
    }
}

Essa arquitetura:

  • Mantém ISRs determinísticas
  • Evita jitter
  • Escala melhor com múltiplos eventos

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