UART и USART в STM32: настройка, скорость, приём по DMA
Последовательный порт STM32 по справочным руководствам: из чего складывается скорость и регистр BRR, сколько ошибки частоты выдерживает приёмник и почему внутренний RC-генератор для UART рискован, как работают флаги и прерывания, как принимать пакеты неизвестной длины через DMA и линию IDLE, полудуплекс по одному проводу и RS-485.
Обновлено Редакция GAW
USART (Universal Synchronous/Asynchronous Receiver-Transmitter) — последовательный порт STM32. В обычном асинхронном режиме это UART: линия передачи TX, линия приёма RX, кадр из старт-бита, 8 или 9 бит данных и стоп-битов. Тот же блок умеет синхронный режим с тактовым выходом CK, аппаратное управление потоком RTS/CTS, полудуплекс по одному проводу, LIN, IrDA и протокол смарт-карт ISO 7816-3 (RM0008, раздел 27.2). Блоки без синхронного режима называются UART — например, UART4 и UART5.
Общие сведения об интерфейсе — уровни, форматы кадра, RS-232 — в статье об интерфейсе UART. Здесь — то, что относится к STM32F1 и STM32F4: скорость и регистр BRR, допуск по частоте, флаги, прерывания и DMA. Все биты регистров разобраны на страницах USART STM32F1 и STM32F4, а значение BRR для любой частоты считает калькулятор скорости UART.
Коротко
- Порты: у STM32F103x8/B — USART1–USART3; у STM32F405/407 — USART1, USART2, USART3, USART6, UART4 и UART5.
- Скорость: fCK/(16 · USARTDIV), у STM32F4 при OVER8 = 1 — fCK/(8 · USARTDIV); USARTDIV — 12 бит целой части и 4 бита дроби в BRR.
- Предел: 4,5 Мбит/с у USART1 STM32F103, 10,5 Мбит/с у USART1 и USART6 STM32F407 (с OVER8).
- Допуск приёмника: 3,33–4,375 % суммарной ошибки частоты при передискретизации 16.
- Флаги RXNE, ORE, IDLE, NE, FE и PE сбрасываются чтением SR, затем DR; TXE — записью в DR.
- Пакеты неизвестной длины удобно принимать через DMA в кольцевой буфер и прерывание IDLE.
Порты и выводы
| Порт | STM32F103x8/B | STM32F405/407 | Шина | Наибольшая скорость |
|---|---|---|---|---|
| USART1 | есть | есть | APB2 | 4,5 Мбит/с у F103; 5,25 и 10,5 Мбит/с у F407 |
| USART2, USART3 | есть | есть | APB1 | 2,25 Мбит/с у F103; 2,62 и 5,25 Мбит/с у F407 |
| UART4, UART5 | нет | есть, без CK, RTS и CTS | APB1 | 2,62 и 5,25 Мбит/с |
| USART6 | нет | есть | APB2 | 5,25 и 10,5 Мбит/с |
Скорости — из DS5319 (раздел 2.3.17) и DS8626 (таблица 5): у STM32F407 первое число — при передискретизации 16, второе — при 8. У старших STM32F1 есть ещё UART4 и UART5, у STM32F42x/43x — UART7 и UART8. Выводы по умолчанию для USART1 — PA9 (TX) и PA10 (RX). У STM32F1 их можно перенести на PB6 и PB7 битом USART1_REMAP, у STM32F4 нужные выводы выбирают в таблице альтернативных функций: USART1–USART3 — AF7, UART4, UART5 и USART6 — AF8. Режимы выводов: TX — альтернативная функция с двухтактным выходом, RX — вход без подтяжки или с подтяжкой вверх (RM0008, таблица 24). Подробнее — в статье о GPIO STM32.
Скорость и регистр BRR
Скорость передачи и приёма задаёт один делитель (RM0008, раздел 27.3.4; RM0090, раздел 30.3.4):
У STM32F1 бита OVER8 нет, и формула сводится к fCK/(16 · USARTDIV). f_CK — частота шины: PCLK2 для USART1 (и USART6 у F4), PCLK1 для остальных портов. USARTDIV — дробное число в регистре BRR: биты 15–4 — целая часть DIV_Mantissa, биты 3–0 — дробь DIV_Fraction в шестнадцатых. При OVER8 = 1 дробь занимает 3 бита, а бит 3 должен оставаться нулём.
Примеры из RM0008: BRR = 0x1BC — это USARTDIV = 27 + 12/16 = 27,75. Чтобы получить USARTDIV = 25,62, дробь округляют до ближайших шестнадцатых — 0,62 · 16 = 9,92 → 10, BRR = 0x19A, фактически 25,625. Если при округлении дробь доходит до 16, её переносят в целую часть: 50,99 превращается в BRR = 0x330, то есть ровно 51.
| Скорость | USART1 STM32F103, 72 МГц | Ошибка | USART2 STM32F407, 42 МГц | Ошибка |
|---|---|---|---|---|
| 9600 | 468,75 (0x1D4C) | 0 % | 273,4375 (0x1117) | 0 % |
| 115 200 | 39,0625 (0x271) | 0 % | 22,8125 (0x16D) | −0,11 % |
| 921 600 | 4,875 (0x4E) | 0,16 % | 2,875 (0x2E) | −0,93 % |
Значения для STM32F103 — из таблицы 192 RM0008, для STM32F407 посчитаны по той же формуле с округлением дроби до шестнадцатых. Наибольшая скорость получается при USARTDIV = 1: fCK/16 — 4,5 Мбит/с при 72 МГц. С OVER8 = 1 у STM32F4 предел вдвое выше, но приёмник хуже переносит ошибку частоты, и RM0090 рекомендует OVER8 = 0 там, где важна устойчивость. Записывать BRR во время обмена нельзя: счётчики делителя перезагружаются сразу после записи.
Допуск приёмника и выбор генератора
Приёмник ловит спад старт-бита и дальше берёт отсчёты в середине каждого бита. При передискретизации 16 он проверяет старт-бит отсчётами 3, 5, 7 и 8, 9, 10, а уровень бита данных решает большинство из отсчётов 8, 9 и 10; если они не совпали, ставится флаг шума NE (RM0008, раздел 27.3.3, таблица 191). Поэтому ошибка частоты накапливается к концу кадра: к последнему стоп-биту отсчёт не должен уйти за его границу.
RM0008 (раздел 27.3.5) складывает ошибку из четырёх частей: отклонение частоты передатчика, округление делителя приёмника, отклонение генератора приёмника и искажения в линии. Их сумма должна быть меньше допуска приёмника:
| Длина кадра | Дробь BRR = 0 | Дробь BRR ≠ 0 | Дробь 0, один отсчёт | Дробь ≠ 0, один отсчёт |
|---|---|---|---|---|
| 8 бит данных (M = 0) | 3,75 % | 3,33 % | 4,375 % | 3,88 % |
| 9 бит данных (M = 1) | 3,41 % | 3,03 % | 3,97 % | 3,53 % |
Это допуски при передискретизации 16 (RM0008, таблицы 193 и 194; RM0090, таблицы 144 и 145). «Один отсчёт» — режим ONEBIT = 1 у STM32F4, когда уровень бита определяет единственный отсчёт в середине; у STM32F1 те же числа соответствуют случаю, когда флаг шума NE не считается ошибкой. При OVER8 = 1 допуск у STM32F4 ниже: 2,5 % и 2 % с тремя отсчётами, 3,75 % и 3 % с одним (для M = 0).
Отсюда практический вывод о генераторе. Частота внутреннего RC-генератора HSI с заводской калибровкой у STM32F103 отклоняется на −2…+2,5 % в диапазоне −40…105 °C (DS5319, таблица 24), у STM32F407 — на −8…+4,5 % (DS8626, таблица 34; при 25 °C — ±1 %). Если вторая сторона работает от кварца, STM32F103 на HSI ещё укладывается в допуск 3,33–3,75 % при комнатной температуре, но с запасом в доли процента, а STM32F407 на холоде может из него выйти. Для надёжной связи UART тактируют от кварца HSE через PLL — частоты шин для своей схемы тактирования можно проверить в калькуляторе тактирования.
Передача: TXE и TC
Регистр DR при записи попадает в буфер передачи TDR, откуда данные переходят в сдвиговый регистр. Флаг TXE означает, что TDR свободен и можно писать следующий байт: он сбрасывается записью в DR. Флаг TC ставится, когда закончен кадр, включая стоп-бит, и в TDR нет нового байта (RM0008, раздел 27.3.2). Отсюда два правила:
- для потока данных ждут TXE — следующий байт успевает лечь в буфер, пока передаётся текущий, и между кадрами нет пауз;
- перед выключением USART, уходом в режим пониженного потребления и переключением направления драйвера RS-485 обязательно ждут TC = 1, иначе последний байт обрежется.
TC сбрасывается чтением SR и последующей записью в DR или записью нуля в бит TC. Бит SBK отправляет символ BREAK — кадр из нулей длиной 10 или 11 бит, — который используется, например, в LIN.
Приём и ошибки
Флаг RXNE ставится, когда принятый байт перешёл в DR. Чтение DR сбрасывает его. Вместе с байтом могут появиться флаги ошибок:
| Флаг | Что случилось |
|---|---|
| ORE | переполнение: пришёл новый байт, а предыдущий ещё не прочитан. Байт в DR сохраняется, принятые следом теряются |
| NE | шум: отсчёты внутри бита не совпали |
| FE | ошибка кадра: стоп-бит не найден там, где ожидался, — несовпадение скоростей или BREAK на линии |
| PE | ошибка чётности, если включён контроль (бит PCE) |
| IDLE | после приёма линия молчит целый кадр — конец пакета |
ORE, NE, FE, PE и IDLE сбрасываются последовательностью «чтение SR, затем чтение DR» (RM0008, 27.6.1). Прерывание по RXNE (бит RXNEIE) вызывается и при ORE: обработчик, который читает DR только при RXNE, но не проверяет ORE, рискует зациклиться, если флаг ORE остался стоять без RXNE. Флаг IDLE после сброса не поднимется снова, пока не будет принят хотя бы один байт.
Простой обработчик приёма в кольцевой буфер:
void USART1_IRQHandler(void)
{
uint32_t sr = USART1->SR;
if (sr & (USART_SR_RXNE | USART_SR_ORE)) {
uint8_t b = (uint8_t)USART1->DR; /* the SR then DR read also clears ORE, NE, FE */
if (!(sr & (USART_SR_FE | USART_SR_PE)))
ring_put(b);
}
}
Приём через DMA и линию IDLE
На высоких скоростях прерывание на каждый байт отнимает много времени, и надёжнее отдать приём DMA. Бит DMAR регистра CR3 заставляет USART запрашивать DMA на каждый принятый байт, DMAT — на каждый TXE (RM0008, раздел 27.3.13). Запросы закреплены за каналами DMA:
| Порт | STM32F1, DMA1: RX / TX | STM32F4: RX / TX |
|---|---|---|
| USART1 | канал 5 / канал 4 | DMA2, канал 4: поток 2 или 5 / поток 7 |
| USART2 | канал 6 / канал 7 | DMA1, канал 4: поток 5 / поток 6 |
| USART3 | канал 3 / канал 2 | DMA1, канал 4: поток 1 / поток 3; TX ещё поток 4, канал 7 |
| USART6 | — | DMA2, канал 5: поток 1 или 2 / поток 6 или 7 |
Таблица — по RM0008 (таблица 78) и RM0090 (таблицы 43 и 44). Для пакетов неизвестной длины — команд, NMEA, Modbus — удобна связка DMA в кольцевом режиме и прерывания IDLE. DMA непрерывно пишет байты в кольцевой буфер, а флаг IDLE поднимается, когда передатчик замолчал хотя бы на длительность кадра. В обработчике IDLE позицию записи узнают по счётчику DMA, который уменьшается с каждым байтом и в кольцевом режиме перезагружается.
Пример для USART2 STM32F407 (DMA1, поток 5, канал 4):
#include "stm32f4xx.h"
#define RX_SIZE 256U
static uint8_t rx_buf[RX_SIZE];
static uint32_t rx_tail; /* next byte the application has not read yet */
void usart2_init(void) /* PCLK1 = 42 MHz, 115200 baud, PA2 = TX, PA3 = RX */
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_DMA1EN;
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER2 | GPIO_MODER_MODER3))
| GPIO_MODER_MODER2_1 | GPIO_MODER_MODER3_1;
GPIOA->AFR[0] = (GPIOA->AFR[0] & ~(GPIO_AFRL_AFSEL2 | GPIO_AFRL_AFSEL3))
| (7U << GPIO_AFRL_AFSEL2_Pos) | (7U << GPIO_AFRL_AFSEL3_Pos);
DMA1_Stream5->CR = 0;
while (DMA1_Stream5->CR & DMA_SxCR_EN) {}
DMA1_Stream5->PAR = (uint32_t)&USART2->DR;
DMA1_Stream5->M0AR = (uint32_t)rx_buf;
DMA1_Stream5->NDTR = RX_SIZE;
DMA1_Stream5->CR = (4U << DMA_SxCR_CHSEL_Pos) /* channel 4: USART2_RX */
| DMA_SxCR_MINC | DMA_SxCR_CIRC /* peripheral to memory, ring buffer */
| DMA_SxCR_EN;
USART2->BRR = (22U << 4) | 13U; /* USARTDIV 22.8125: 115068 baud */
USART2->CR3 = USART_CR3_DMAR;
USART2->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | USART_CR1_IDLEIE;
NVIC_EnableIRQ(USART2_IRQn);
}
void USART2_IRQHandler(void)
{
if (USART2->SR & USART_SR_IDLE) {
(void)USART2->DR; /* SR then DR read clears IDLE */
uint32_t head = RX_SIZE - DMA1_Stream5->NDTR;
while (rx_tail != head) {
packet_byte(rx_buf[rx_tail]);
rx_tail = (rx_tail + 1U) % RX_SIZE;
}
packet_end();
}
}
У STM32F1 то же делает канал DMA: для USART1 — DMA1_Channel5 с регистрами CPAR, CMAR, CNDTR и битами MINC и CIRC в CCR. Если пакет может оказаться длиннее буфера, включают ещё прерывания DMA по половине и концу буфера и забирают данные в них.
Полудуплекс и RS-485
Бит HDSEL регистра CR3 соединяет TX и RX внутри: обмен идёт по одному проводу через вывод TX (RM0008, раздел 27.3.10). Пока USART ничего не передаёт, он отпускает линию, поэтому вывод TX настраивают как выход с открытым стоком в единице и подтягивают линию резистором. Конфликты на линии аппаратура не разрешает: передача начинается сразу после записи в DR, и очередь передатчиков должна соблюдать программа. В этом режиме биты LINEN, CLKEN, SCEN и IREN должны быть сброшены.
Для RS-485 нужен внешний драйвер — например, MAX485 — и вывод, который переключает его на передачу. В списке возможностей USART STM32F1 и STM32F4 (RM0008, 27.2; RM0090, 30.2) аппаратного управления драйвером нет, поэтому направление переключают выводом GPIO: включают передатчик перед записью первого байта и выключают по флагу TC после последнего. Как устроена сама линия — в статье о RS-485.
Аппаратное управление потоком включают битами RTSE и CTSE регистра CR3: RTS остаётся низким, пока приёмник готов принять байт, а передатчик ждёт низкого уровня на CTS перед каждым кадром (RM0008, раздел 27.3.14).
Пример: USART1 STM32F103
Передача и приём на 115 200 бит/с при PCLK2 = 72 МГц, выводы PA9 и PA10:
#include "stm32f1xx.h"
void usart1_init(void)
{
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN;
/* PA9 = TX: alternate function push-pull, 10 MHz (MODE9 = 01, CNF9 = 10);
PA10 = RX stays a floating input after reset */
GPIOA->CRH = (GPIOA->CRH & ~(GPIO_CRH_MODE9 | GPIO_CRH_CNF9))
| GPIO_CRH_MODE9_0 | GPIO_CRH_CNF9_1;
USART1->BRR = 0x271; /* USARTDIV = 39.0625: 115200 baud at 72 MHz */
USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
NVIC_EnableIRQ(USART1_IRQn);
}
void usart1_putc(char c)
{
while (!(USART1->SR & USART_SR_TXE)) {}
USART1->DR = (uint8_t)c;
}
void usart1_flush(void) /* before sleep, disabling or turning an RS-485 driver */
{
while (!(USART1->SR & USART_SR_TC)) {}
}
Частые ошибки
- Неверная частота шины в расчёте BRR — USART1 и USART6 тактируются от PCLK2, остальные от PCLK1. У STM32F103 на 72 МГц это 72 и 36 МГц, у STM32F407 на 168 МГц — 84 и 42 МГц.
- Выключение USART сразу после записи последнего байта — байт обрезается. Ждите TC.
- Ожидание TC вместо TXE в цикле передачи — между байтами появляются паузы, и скорость падает.
- Не сброшен ORE — после переполнения прерывание может срабатывать снова и снова. Читайте SR, затем DR.
- UART на HSI у STM32F407 — при изменении температуры частота уходит за допуск приёмника.
- TX в режиме входа — без режима альтернативной функции на выводе нет сигнала, а у STM32F4 ещё нужен правильный номер AF.
- DMA включён после USART — первые байты приходят раньше, чем канал готов, и теряются; сначала настраивают DMA, затем ставят DMAR и включают приём.
Частые вопросы
Какое значение BRR нужно для 115 200 бит/с?
BRR хранит делитель USARTDIV = f_CK / (16 · скорость) в формате 12 бит целой части и 4 бита дроби. Для USART1 STM32F103 на 72 МГц USARTDIV = 39,0625, то есть BRR = 39 · 16 + 1 = 0x271, ошибка 0 % (RM0008, таблица 192). Для USART2 STM32F407 при PCLK1 = 42 МГц USARTDIV = 22,786: целая часть 22, дробь 0,786 · 16 ≈ 13, BRR = 0x16D, ошибка −0,11 %.
Какую ошибку скорости выдерживает UART STM32?
Приём остаётся правильным, пока суммарное отклонение — ошибка передатчика, округление делителя приёмника, отклонение его генератора и искажения линии — меньше допуска приёмника. При 8 битах данных, передискретизации 16 и дробном делителе это 3,33 %, при целом делителе — 3,75 %, а с выборкой одним отсчётом (ONEBIT у STM32F4) — 3,88 % и 4,375 % (RM0008, таблицы 193–194; RM0090, таблицы 144–145). С передискретизацией 8 допуск меньше: 2–3,75 %.
Можно ли тактировать UART от внутреннего генератора HSI?
Только при небольшом диапазоне температур и при точной частоте второй стороны. У STM32F103 частота HSI с заводской калибровкой отклоняется на −2…+2,5 % от −40 до 105 °C (DS5319, таблица 24), у STM32F407 — на −8…+4,5 % (DS8626, таблица 34). Это сравнимо с допуском приёмника 3,3–3,75 % или больше него, поэтому для надёжной связи нужен кварц.
Как принимать по UART пакеты неизвестной длины?
Через DMA в кольцевом режиме и прерывание IDLE. DMA складывает каждый принятый байт в буфер, а флаг IDLE поднимается, когда после приёма линия молчит целый кадр. В прерывании IDLE текущую позицию записи вычисляют по счётчику DMA: длина буфера минус NDTR (CNDTR у STM32F1). Флаг IDLE сбрасывают чтением SR, затем DR.
Почему пропадают байты при приёме по прерыванию?
Если следующий байт пришёл раньше, чем программа прочитала предыдущий, ставится флаг переполнения ORE: байт в DR сохраняется, а новые теряются. ORE вызывает то же прерывание, что RXNE, и сбрасывается только чтением SR, затем DR. Обработчик должен быть коротким и иметь достаточный приоритет; на высоких скоростях надёжнее DMA.
Источники
- STMicroelectronics. RM0008 Rev 21. Reference manual: STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx — 27.2 — возможности USART; 27.3.2 — передатчик, TXE и TC; 27.3.3 — приёмник: обнаружение старт-бита, отсчёты шума (таблица 191), ORE, FE; 27.3.4 — дробный делитель, примеры BRR, таблица 192 — ошибки скорости при 36 и 72 МГц; 27.3.5 — допуск приёмника (таблицы 193 и 194); 27.3.10 — полудуплекс; 27.3.13 — DMA; 27.3.14 — RTS и CTS; 27.6 — регистры; 13.3.7, таблица 78 — каналы DMA1
- STMicroelectronics. RM0090 Rev 22. Reference manual: STM32F405/415, STM32F407/417, STM32F427/437 and STM32F429/439 — 30.3.4 — скорость с OVER8 (уравнения 1 и 2), ONEBIT; 30.3.5 — допуск приёмника с OVER8 и ONEBIT (таблицы 144 и 145); 10.3.3, таблицы 43 и 44 — потоки и каналы DMA для USART
- STMicroelectronics. DS5319 Rev 20. STM32F103x8, STM32F103xB datasheet — 2.3.17 — USART1 до 4,5 Мбит/с, остальные до 2,25 Мбит/с; таблица 24 — точность HSI
- STMicroelectronics. DS8626 Rev 12. STM32F405xx, STM32F407xx datasheet — таблица 5 — USART1–USART6, UART4, UART5: шины, наибольшие скорости при передискретизации 16 и 8; таблица 34 — точность HSI
- STMicroelectronics. CMSIS Device F1 и F4: stm32f103xb.h, stm32f407xx.h — имена битов и векторов прерываний для примеров
Нашли ошибку?
Смотрите также
- UARTКадр 8N1, скорость и допуск, TX и RX, уровни, USB–UART, AVR и STM32
- Скорость UARTUBRR, BRR, TH1 и ошибка скорости
- Кадр UART по битамБиты кадра, чётность, время символа, разбор и расхождение скоростей
- RS-485Уровни, длина линии, терминаторы, смещение, MAX485, Modbus RTU
- GPIO STM32Режимы выводов, регистры F1 и F4, BSRR, AF, скорость, токи, 5 В, код
- Таймеры STM32Тактирование, PSC/ARR, ШИМ, мёртвое время, захват, энкодер, OPM, синхронизация
- Тактирование STM32PLL под нужную частоту, шины, флеш-память, регистры RCC и код