Debug Log · RP2040

CDC serial travando? O ISR de 8,2 kHz que estava sufocando a USB no RP2040

ELETROHEURO — Bastidores do CH3 (Analisador de Espectro)

Durante o desenvolvimento do firmware do CH3 — o canal de análise espectral do ELETROHEURO — cheguei num ponto em que a porta serial via USB (CDC) simplesmente parava de responder depois de alguns segundos rodando. Nenhum crash, nenhum reset, nenhuma mensagem de erro. O Serial Monitor do Arduino IDE ficava mudo, como se o Pico tivesse travado — mas o display continuava atualizando normalmente. Isso por si só já era uma pista importante.

O sintoma

O firmware do CH3 roda em dois núcleos: o Core 0 cuida da aquisição via ADC+DMA e do cálculo da FFT, enquanto o Core 1 atualiza o display ST7920 via U8g2 em HW SPI. A serial USB é usada só para debug — imprimir picos de frequência, tempos de execução, esse tipo de coisa.

O padrão era sempre o mesmo: nos primeiros segundos, tudo normal. Depois, silêncio total na serial. O programa continuava rodando — o display não travava — mas qualquer Serial.println() simplesmente sumia no vácuo.

Primeira hipótese (errada) Cheguei a suspeitar de buffer overflow na serial, já que eu estava imprimindo bastante coisa em loop. Reduzi o volume de prints — o problema continuou, só demorou mais pra aparecer.

Isolando a causa

O que me fez desconfiar da direção certa foi lembrar da taxa de amostragem do ADC: fs = 2000 Hz, com uma interrupção de hardware disparando a cada leitura. Só que a ISR não estava disparando a 2 kHz — ela estava configurada para rodar a 8,2 kHz, um valor de oversampling que eu tinha deixado da fase de testes do filtro anti-aliasing, e nunca tinha voltado pra ajustar.

Uma ISR rodando a essa frequência, mesmo que curta, consome uma fatia real de tempo de CPU no núcleo onde ela está registrada. E a pilha USB do RP2040 (a stack CDC do TinyUSB, usada por baixo dos panos pelo core do Earle Philhower) depende de ser "alimentada" com regularidade — se o processador fica tempo demais preso atendendo interrupções de alta prioridade, a stack USB não consegue processar os eventos dela a tempo, e o host (seu PC) simplesmente desiste da conexão CDC.

Causa raiz A ISR de amostragem a 8,2 kHz estava competindo por ciclos de CPU com o processamento da stack USB, que precisa de atenção frequente para manter a conexão CDC viva. Sob essa carga, a USB "morria" silenciosamente.

O caminho da correção

A correção teve duas frentes:

// Antes — taxa de oversampling esquecida da fase de testes
#define FS_HZ 8200

// Depois — taxa real de projeto, alinhada à banda de interesse
#define FS_HZ 2000  // N=1024, resolução ≈ 1,95 Hz/bin

Com a ISR voltando à taxa correta, a folga de CPU sobrando para o TinyUSB foi suficiente para a stack processar os eventos CDC em tempo hábil, e a serial parou de cair.

observação

O detalhe curioso é que esse tipo de bug é traiçoeiro justamente porque não trava nada visível. Se o display tivesse parado junto, a investigação teria sido óbvia. Como só a USB caía, a primeira tentação é sempre olhar para o próprio código da serial — e não para uma interrupção "inocente" rodando em segundo plano em outra frequência.

Fica a lição: qualquer ISR de alta frequência num projeto dual-core no RP2040 merece ser tratada como suspeita número um sempre que algo periférico — USB, I2C, o que for — começar a se comportar de forma intermitente sem motivo aparente.

Do blog para o artigo completo

Veja a arquitetura dual-core inteira do CH3

Sampling chain completa (fs=2000 Hz, N=1024, janela de Hamming), o filtro Sallen-Key anti-aliasing refinado e o firmware de aquisição + FFT + display no artigo técnico do Analisador de Espectro.

Ler artigo 3 →