MCU & FPGA UART (Serial) UART não é Porta Serial: Como Projetar Protocolos Robustos em Sistemas Embarcados

UART não é Porta Serial: Como Projetar Protocolos Robustos em Sistemas Embarcados


Bufferização não é opcional: é o primeiro contrato com a realidade

O momento exato em que um firmware começa a falhar em campo quase sempre coincide com a ausência de uma decisão clara sobre bufferização. UART não entrega mensagens; ela entrega bytes no tempo. Ignorar isso é assumir, implicitamente, que produtor e consumidor sempre operam na mesma cadência — o que raramente é verdade fora de laboratório.

Quando um byte chega pela UART, ele chega independente do estado interno do firmware. Pode chegar enquanto outra interrupção está sendo atendida, enquanto uma tarefa de maior prioridade executa, ou no meio de uma operação crítica. Se esse byte não for capturado imediatamente e armazenado, ele simplesmente se perde. Não há “voltar atrás”.

O erro clássico: processar dados no contexto da interrupção

Um antipadrão extremamente comum é tentar interpretar comandos diretamente dentro da ISR (Interrupt Service Routine):

// ❌ ISR fazendo parsing e lógica de aplicação
void USART_IRQHandler(void) {
    char c = USART_ReadByte();

    if (c == 'O') {
        char next = USART_ReadByte();
        if (next == 'N') {
            led_on();
        }
    }
}

Esse código é frágil por múltiplas razões:

  • Assume que os bytes chegam agrupados
  • Assume timing perfeito entre caracteres
  • Mistura transporte, protocolo e aplicação
  • Executa lógica potencialmente lenta dentro da ISR
  • Não lida com perda, repetição ou ruído
  • Não escala para comandos maiores

Em sistemas reais, ISR não é lugar de decisão, é lugar de captura determinística.

A abordagem correta: ISR mínima + buffer explícito

A primeira decisão arquitetural correta é:

A interrupção só coleta dados. Quem entende os dados roda fora dela.

Um ring buffer (buffer circular) simples já muda completamente o jogo:

// ✅ Captura determinística, sem interpretação
#define RX_BUF_SIZE 256

static uint8_t rx_buf[RX_BUF_SIZE];
static volatile uint16_t rx_wr = 0;
static volatile uint16_t rx_rd = 0;

void USART_IRQHandler(void) {
    uint8_t byte = USART_ReadByte();
    uint16_t next = (rx_wr + 1) % RX_BUF_SIZE;

    if (next != rx_rd) {  // evita overwrite
        rx_buf[rx_wr] = byte;
        rx_wr = next;
    }
}

Agora temos propriedades importantes:

  • Nenhum byte válido se perde (enquanto houver espaço)
  • ISR é curta e previsível
  • O sistema pode atrasar a interpretação sem perder dados
  • O comportamento sob carga é controlável

Esse buffer cria uma fronteira clara entre o mundo físico (UART) e o mundo lógico (protocolo).

Consumir bytes é diferente de interpretar mensagens

Com o buffer, a aplicação pode processar os dados no seu próprio ritmo:

bool uart_get_byte(uint8_t *out) {
    if (rx_rd == rx_wr) {
        return false; // buffer vazio
    }

    *out = rx_buf[rx_rd];
    rx_rd = (rx_rd + 1) % RX_BUF_SIZE;
    return true;
}

Nesse ponto, ainda não existe comando, não existe pacote, não existe semântica. Existe apenas um fluxo confiável de bytes.

Essa separação é crucial: sistemas que misturam “leitura de byte” com “interpretação de comando” acabam presos a hacks, flags ocultas e comportamentos implícitos impossíveis de manter.

Bufferização como base para escalabilidade

A partir desse momento, decisões mais avançadas se tornam possíveis:

  • Vários produtores (DMA, UART, rádio) alimentando buffers
  • Vários consumidores (parser, logger, monitor)
  • Mudança de baudrate sem quebrar o protocolo
  • Simulação e teste com streams artificiais
  • Recuperação após erro sem reset

Sem buffer, nada disso é viável.

Um critério simples de maturidade

Um firmware sério consegue responder claramente a estas perguntas:

  • Qual é o tamanho máximo do burst de dados?
  • O que acontece quando o buffer enche?
  • Existe backpressure ou descarte controlado?
  • O sistema se recupera após bytes inválidos?
  • É possível reiniciar o parser sem reset do MCU?

Se essas respostas não existem no projeto, a UART está sendo usada como “fio de texto”, não como canal de transporte.



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