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 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.
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.
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.
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.
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 →