Перейти к содержимому

uart_dma — приём UART через DMA

Принимает символы с USART1 (тот же порт, куда идёт лог) через DMA в кольцевой буфер, собирает строки и выполняет команды: help, led on, led off, uptime. Любая другая строка печатается обратно с длиной.

Окно терминала
cmake --preset Release -DH723_RECIPES="uart_dma"

Терминал на USART1 115200 8N1: PB15 — вход платы (RX), PB14 — выход (TX). Через отладчик «Лобзик» это его виртуальный COM-порт; можно и любой USB-UART 3,3 В на J2 (13 — PB15, 14 — PB14).

Команды отправлены с ПК в терминал USART1:

uart_dma: started, type 'help' in USART1 terminal
uart_dma: commands: help, led on, led off, uptime
uart_dma: led on
uart_dma: uptime 15503 ms
uart_dma: rx 'hello board 123' (15 bytes)

При переполнении строка из 300 символов принимается и обрезается до 127 (длина буфера строки), восемь строк подряд по 42 байта принимаются целыми, хотя кольцевой буфер DMA (256 байт) за это время оборачивается несколько раз.

  • DMA в кольцевом режиме. DMA1 Stream3 по запросу USART1_RX пишет каждый принятый байт в буфер 256 байт и, дойдя до конца, начинает сначала. Процессор в приёме байтов не участвует.
  • Когда разбирать буфер. HAL_UARTEx_ReceiveToIdle_DMA вызывает колбэк в трёх случаях: буфер заполнен наполовину, заполнен целиком и линия замолчала (событие IDLE — пауза в один символ). Последнее важно: команда из 6 символов не заполнит буфер, но придёт сразу после паузы.
  • Новые данные — от прошлой позиции до текущей. Колбэк получает позицию DMA в буфере; байты между прошлой и новой позицией (с переходом через край) уходят в StreamBuffer FreeRTOS.
  • Прерывание короткое. В колбэке только копирование в StreamBuffer; строки собирает и команды выполняет обычная задача uartRx, которой можно печатать и ждать.
  • Память для DMA. Буфер — в RAM_D1 (pvPortMalloc), выровнен по 32 байта (строка кэша); RAM_D1 кэшируется, поэтому перед чтением — SCB_InvalidateDCache_by_Addr.
  • Шум на линии. Без подтяжки неподключённый вход ловит помехи и ошибки кадра; рецепт включает подтяжку PB15 к 3,3 В. После ошибки UART приём перезапускается в rxError.
  • Передача не тронута. Лог печатает через тот же huart1 (DMA1 Stream2); приём и передача у HAL независимы.
  • Свои команды — в handleLine.
  • Свой протокол (бинарный, Modbus, NMEA) — байты берутся из uartDmaRead() и разбираются своим кодом, без uartTask.
  • Другой UART: свободны USART2 (PA2/PA3), USART3 (PB10/PB11), UART4 (PA0/PA1) и другие — их нужно сначала включить (CubeMX или вручную: такты, выводы, HAL_UART_Init), затем поменять huart, DMA_REQUEST_... и, при занятом Stream3, номер потока DMA.

Исходники рецепта: recipes/uart_dma