16а. RS-485: линия, терминаторы, смещение и направление передачи
В разделе 16.8 ведомый Modbus RTU уже отвечает по RS-485: вывод DE на PA1
поднимается перед ответом и снимается по флагу TC. Раздел 89.4 добавил
правило «скорость × длина ≈ 10⁸», два терминатора по 120 Ом и смещение
390 Ом при 3,3 В. Здесь — сама линия и всё, что вокруг вывода DE: как
строить шину и где ставить терминаторы, как считать смещение при одном и
двух терминаторах и с допусками, почему TXE обрезает ответ, как DE
ведёт сам USART у G4 и на сколько линия замолкает между запросом и ответом.
Опоры: справочные руководства RM0008 (F1: флаги TXE и TC) и RM0440
(G4: DE, DEAT, DEDT, таймаут приёма), даташит DS12288 (вывод
USART2_RTS_DE), заголовки CMSIS семи семейств из паков Keil, привязки
Zephyr для USART STM32 и Modbus. Смещение, доли бита и время обмена
посчитаны моделью на ПК; код собран armclang для F103 и G474, а код F103
прогнан на компьютере против модели USART по RM0008.
Как это называется в документации
Оригинал Перевод differential pair (A, B) дифференциальная пара: провода A и B half-duplex полудуплекс termination resistor терминатор: резистор на конце линии fail-safe biasing смещение линии в покое stub отвод от магистрали к прибору unit load единица нагрузки driver enable (DE) включение передатчика RS-485 receiver enable (/RE) включение приёмника, активный низкий transmission complete ( TC)передача завершена driver enable assertion / deassertion time ( DEAT,DEDT)задержка DE до старт-бита и после стоп-бита driver enable polarity ( DEP)полярность DE receiver timeout ( RTOEN,RTOR)таймаут приёма: тишина на RX в битах
16а.1 Линия и один обмен по ней
RS-485 — это пара проводов A и B. Приёмник смотрит только на разность
A − B: наводка, одинаковая на обоих проводах, вычитается. Передатчик
в один момент один — линия полудуплексная: пока ведущий говорит,
все остальные слушают, потом наоборот. Направление каждый прибор
переключает сам выводами приёмопередатчика: DE включает передатчик
(активный высокий), /RE — приёмник (активный низкий), так их описывает
привязка Zephyr zephyr,modbus-serial. Если DE и /RE сидят на одном выводе,
единица на нём одновременно включает передатчик и выключает приёмник.
Третий провод — общий. Разность A − B приёмник видит, только пока оба провода не уходят слишком далеко от его земли, а допустимое синфазное напряжение — в даташите приёмопередатчика. У приборов в разных шкафах земли разные (раздел 54.1), и без общего провода или изоляции линия работает до первой разницы потенциалов.
Один обмен Modbus на 9600 бод выглядит так:
Из рисунка видно всё, о чём раздел: кто держит линию в паузе (16а.3), когда снимать DE (16а.4 и 16а.5) и сколько длится обмен (16а.6).
16а.2 Топология: шина, отводы, терминаторы
Приборы вешают на одну магистраль цепочкой: кабель заходит в прибор и выходит к следующему. У такой линии два конца, и терминаторы стоят ровно там — по одному на каждом физическом конце (раздел 89.4). Звезда из нескольких лучей даёт столько концов, сколько лучей, и согласовать её двумя резисторами нельзя.
Отвод — кусок провода от магистрали до приёмопередатчика — сам по себе несогласованная линия. По правилу раздела 160.1 он незаметен, пока его задержка меньше примерно шестой части фронта передатчика. Фронт — в даташите приёмопередатчика: у микросхем с ограниченной скоростью нарастания он длиннее, и отводы они терпят длиннее. Отвод держат коротким, а клеммы ставят прямо у приёмопередатчика.
Терминатор в каждом приборе — частая ошибка сборки: десять резисторов по 120 Ом параллельно дают 12 Ом. Смещение 390 Ом при 3,3 В на такой нагрузке даёт 50 мВ — вчетверо ниже порога, и линия в паузе снова ловит шум. Поэтому перемычку терминатора в приборе включают только на двух крайних.
Нагрузку от входов приёмников стандарт считает в единицах нагрузки. Сколько единиц (или какую долю единицы) занимает приёмопередатчик и сколько приборов можно повесить на линию, пишут в его даташите. Чисел здесь нет: текста стандарта на диске нет, а у разных микросхем они разные — берите их из даташита своей.
16а.3 Смещение: расчёт под порог при одном и двух терминаторах
Смещение — резистор Rb от питания к A и такой же от B к земле. В покое через них и терминаторы течёт ток, и между A и B получается
VAB = Vcc × Rt / (2 × Rb + Rt),
где Rt — терминаторы параллельно: 120 Ом, если он один, и 60 Ом, если их два. A выше B — приёмник выдаёт единицу, то есть тот самый покой UART. Порог приёмника берём 200 мВ — это граница из раздела 89.4: от неё и выше приёмник обязан выдать единицу; свой порог — в даташите. Входы приёмников модель не учитывает: с ними VAB ещё немного меньше.
Номинал мало: резисторы и питание гуляют. Модель на ПК ищет Rb так, чтобы 200 мВ набиралось и в худшем случае — питание на 5 % ниже, Rb на 1 % больше, Rt на 1 % меньше, — и берёт ближайший меньший номинал ряда E12:
| Питание | Терминаторов | Rb не больше | С допусками | Ряд E12 | VAB | Худший случай | Ток |
|---|---|---|---|---|---|---|---|
| 5 В | 1 | 1440 Ом | 1338 Ом | 1200 Ом | 238 мВ | 222 мВ | 1,98 мА |
| 5 В | 2 | 720 Ом | 669 Ом | 560 Ом | 254 мВ | 237 мВ | 4,24 мА |
| 3,3 В | 1 | 930 Ом | 863 Ом | 820 Ом | 225 мВ | 210 мВ | 1,88 мА |
| 3,3 В | 2 | 465 Ом | 432 Ом | 390 Ом | 236 мВ | 220 мВ | 3,93 мА |
Что из таблицы следует:
- Считать под два терминатора. Смещение, рассчитанное под один (820 Ом при 3,3 В), на линии с двумя даёт 116 мВ — ниже порога. Второй терминатор появляется, когда линию дотягивают до последнего прибора, и связь, работавшая на столе, в шкафу ломается.
- 680 Ом при 5 В — на грани. Номинал 211 мВ, но в худшем случае 197 мВ. Раздел 89.4 называет 560–680 Ом; с допусками остаётся 560.
- Один комплект на линию. Если смещение включено в каждом приборе, комплекты складываются параллельно:
| Комплектов 390 Ом при 3,3 В | VAB | Ток | Нагрузка передатчика |
|---|---|---|---|
| 1 | 236 мВ | 3,93 мА | 55,7 Ом |
| 2 | 440 мВ | 7,33 мА | 52,0 Ом |
| 4 | 776 мВ | 12,94 мА | 45,9 Ом |
Запас по порогу растёт, но растёт и ток, и нагрузка передатчика: по сигналу питание — та же земля, и каждый комплект висит на линии как 2 × Rb. В бюджете изолированного порта из раздела 54.4 на подтяжки линии заложено 10 мА: один комплект туда помещается, четыре — уже нет. Какую нагрузку выдерживает передатчик, пишет его даташит.
У многих новых приёмопередатчиков порог сдвинут так, что тишина читается единицей и без смещения (раздел 89.4). Это видно в даташите по порогу приёмника; тогда резисторы смещения не нужны.
16а.4 DE вручную на F103: по TC, а не по TXE
У USART F1 и F407 аппаратного DE нет (16а.5), и вывод DE — обычный
выход. В разделе 16.8 его снимают опросом TC в цикле. Для ведущего,
которому некогда ждать, — то же на прерываниях. RM0008 (27.3.2) о
флагах: TXE взводится, когда байт переложен из регистра данных в
сдвиговый, то есть в момент, когда он только начал уходить в линию;
TC — когда кадр ушёл целиком и новых данных нет. Отсюда модель на ПК:
у запроса из 8 байт на 9600 бод TXE последнего байта приходит на
8021 мкс, TC — на 9167 мкс; DE, снятый по TXE, обрезает 1146 мкс —
последний байт, старший байт CRC. У посылки из одного байта хуже: пока
передатчик свободен, запись в DR сразу уходит в сдвиговый регистр, и
TXE остаётся взведённым — DE падает раньше, чем байт начался.
Вторая ловушка — сброс: USART_SR после сброса равен 0x00C0, то есть
TC уже взведён. Сбрасывает его пара «чтение SR — запись DR».
Разрешите TCIE до первого байта — и первое же прерывание придёт по
старому TC. Поэтому TCIE включают только после записи последнего
байта:
void rs485_send(const uint8_t *p, uint32_t n)
{
if (n == 0)
return;
while (tx_busy) {
}
tx_p = p;
tx_n = n;
tx_busy = 1;
USART2->CR1 &= ~USART_CR1_RE; /* своё эхо не принимать */
GPIOA->BSRR = 1u << 1; /* DE = 1: передатчик на линии */
USART2->CR1 |= USART_CR1_TXEIE; /* байты кладёт прерывание; TCIE пока нельзя: TC = 1 с самого сброса */
}
void USART2_IRQHandler(void)
{
uint32_t sr = USART2->SR;
uint32_t cr1 = USART2->CR1;
if ((cr1 & USART_CR1_TXEIE) && (sr & USART_SR_TXE)) {
USART2->DR = *tx_p++; /* чтение SR, затем запись DR сбрасывают TC */
if (--tx_n == 0) /* последний байт только начал уходить: ждать TC, а не TXE */
USART2->CR1 = (uint16_t)((cr1 & ~USART_CR1_TXEIE) | USART_CR1_TCIE);
} else if ((cr1 & USART_CR1_TCIE) && (sr & USART_SR_TC)) {
GPIOA->BSRR = 1u << (1 + 16); /* стоп-бит последнего байта в линии: DE = 0 */
USART2->CR1 = (uint16_t)((cr1 & ~USART_CR1_TCIE) | USART_CR1_RE);
tx_busy = 0;
}
if (sr & USART_SR_RXNE)
rs485_rx_byte((uint8_t)USART2->DR);
}
Приёмник USART (RE) на время передачи выключен: так своё эхо не
попадёт в приём, как бы ни был подключён /RE — вместе с DE или на
землю. RX подтянут к питанию: если выход приёмника при выключении
отпускает линию (у многих микросхем так, смотрите даташит), без
подтяжки вывод плавал бы.
Этот же файл собран на компьютере вместе с моделью USART по RM0008 —
время в битах, TXE и TC ведут себя как в описании выше:
| Вариант | Байт | Бит в линию | Бит при DE = 0 |
|---|---|---|---|
по TC — код выше |
8 | 88 | 0 |
по TC — код выше |
1 | 11 | 0 |
по TXE последнего байта |
8 | 88 | 11 |
по TXE последнего байта |
1 | 11 | 11 |
TCIE сразу, обработчик смотрит TC первым |
8 | 88 | 88 |
По TC DE падает ровно на границе последнего стоп-бита. Между подъёмом
DE и старт-битом — только вход в прерывание. Если приёмопередатчику нужно
время на включение (оно в даташите), выдержите его до первой записи в
DR — на G4 это делает поле DEAT.
16а.5 Аппаратный DE: G474 и какие семейства это умеют
У нового USART вывод DE ведёт сам блок. RM0440 (37.5.20): бит DEM
в USART_CR3 выводит сигнал DE на ножку RTS; DEP выбирает полярность
(0 — активный высокий); DEAT в USART_CR1 — время от подъёма DE до
начала старт-бита, DEDT — от конца последнего стоп-бита до снятия DE.
Оба поля по 5 бит и считаются в долях бита: 1/16 при OVER8 = 0 и 1/8
при OVER8 = 1. Писать их можно только при UE = 0. Привязка Zephyr
st,stm32-uart называет их de-assert-time и de-deassert-time —
«в шестнадцатых долях бита, от 0 до 31», в HAL то же делает
HAL_RS485Ex_Init.
Какие семейства это умеют — по заголовкам CMSIS из паков Keil:
| Семейство | Заголовок | DEM, DEP |
DEAT, DEDT |
RTOEN |
|---|---|---|---|---|
| F0 | stm32f072xb.h | есть | есть | есть |
| F1 | stm32f10x.h | нет | нет | нет |
| F3 | stm32f303xc.h | есть | есть | есть |
| F4 | stm32f407xx.h | нет | нет | нет |
| F7 | stm32f767xx.h | есть | есть | есть |
| G4 | stm32g474xx.h | есть | есть | есть |
| L4 | stm32l476xx.h | есть | есть | есть |
Сколько это во времени:
| Скорость | Доля при OVER8 = 0 |
Наибольшее, 31 доля | То же при OVER8 = 1 |
|---|---|---|---|
| 9600 бод | 6,5104 мкс | 201,82 мкс | 403,65 мкс |
| 115 200 бод | 0,5425 мкс | 16,82 мкс | 33,64 мкс |
| 1 Мбит/с | 0,0625 мкс | 1,94 мкс | 3,88 мкс |
31 доля — это 1,9375 бита при OVER8 = 0 и 3,875 бита при OVER8 = 1.
DEAT берут так: время включения передатчика из даташита × скорость × 16,
округлить вверх. Допустим, приёмопередатчику нужно 3 мкс: на 115 200 бод
это DEAT = 6, а на 1 Мбит/с нужно 48 долей — поле столько не вмещает,
и остаётся OVER8 = 1 (24 доли по 1/8).
Код для G474 — USART2 на тех же PA1, PA2 и PA3, что у F103 в разделе 16.8; по даташиту DS12288 PA1 — это USART2_RTS_DE на AF7, рядом TX и RX на том же AF7:
#define DE_TIME 16u /* DEAT и DEDT: 16 долей по 1/16 бита = 1 бит (OVER8 = 0) */
#define RTO_BITS 39u /* 3,5 символа по 11 бит = 38,5 бита -> 39 */
#define CR1_RS485 ((DE_TIME << USART_CR1_DEAT_Pos) | (DE_TIME << USART_CR1_DEDT_Pos) | \
USART_CR1_M0 | USART_CR1_PCE | USART_CR1_RTOIE | USART_CR1_TE | USART_CR1_RE)
void rs485_g4_init(void)
{
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN;
RCC->APB1ENR1 |= RCC_APB1ENR1_USART2EN;
GPIOA->AFR[0] = (GPIOA->AFR[0] & ~0xFFF0u) | 0x7770u; /* PA1, PA2, PA3 — AF7 */
GPIOA->MODER = (GPIOA->MODER & ~0xFCu) | 0xA8u; /* все три — альтернативная функция */
USART2->BRR = 17708u;
USART2->RTOR = RTO_BITS;
USART2->CR2 = USART_CR2_RTOEN;
USART2->CR3 = USART_CR3_DEM; /* DEP = 0: DE активен высоким уровнем */
USART2->CR1 = CR1_RS485; /* DEAT, DEDT и формат пишут при UE = 0 */
USART2->CR1 = CR1_RS485 | USART_CR1_UE;
}
BRR = 170 МГц / 9600 = 17708: скорость 9600,18 бод, ошибка +0,0019 %.
DEAT = DEDT = 16 — один бит, на 9600 бод 104,2 мкс. Статические
утверждения в файле держат номера битов по RM0440: DEM и DEP — биты
14 и 15 CR3, DEAT — 25:21, DEDT — 20:16 CR1. armclang сводит
настройку USART2 (адрес 0x4000 4400) к шести записям: BRR = 0x452C,
RTOR = 0x27, CR2 = 0x800000, CR3 = 0x4000, CR1 = 0x0610140C
и затем 0x0610140D — тот же CR1 с UE. Передача после этого —
просто запись в TDR: DE поднимется за DEAT до старт-бита и упадёт
через DEDT после стоп-бита без участия прошивки.
Цена: DE выходит на ножку RTS, так что аппаратное управление потоком RTS на этом USART уже не занять.
16а.6 Время кадра, оборот линии и 3,5 символа
Символ Modbus RTU — 11 бит (раздел 16.8). Запрос «прочитать 10 регистров» — 8 байт, ответ на него — 25: адрес, функция, счётчик, 20 байт данных и CRC. Между кадрами линия молчит не меньше 3,5 символа, выше 19 200 бод — постоянные 1750 мкс (раздел 198в.3). Сколько занимает один обмен без времени на обработку в ведомом:
| Скорость | Символ | Запрос | Пауза | Ответ | Обмен | Обменов в секунду, не больше |
|---|---|---|---|---|---|---|
| 9600 бод | 1145,8 мкс | 9167 мкс | 4011 мкс | 28 646 мкс | 45 834 мкс | 21,8 |
| 19 200 бод | 572,9 мкс | 4583 мкс | 2006 мкс | 14 323 мкс | 22 918 мкс | 43,6 |
| 115 200 бод | 95,5 мкс | 764 мкс | 1750 мкс | 2387 мкс | 6651 мкс | 150,4 |
На 115 200 бод две паузы по 1750 мкс — больше половины обмена: поднимать скорость дальше почти бесполезно, а длину линии она сокращает по правилу 89.4.
Оборот линии — момент, когда ведущий отпускает её, а ведомый
захватывает. Ведомый начинает отвечать не раньше, чем кончится тишина
3,5 символа: так он узнаёт конец запроса. Значит, у ведущего на снятие
DE — 4011 мкс на 9600 бод. DEDT = 16 занимает 104,2 мкс, вход в
прерывание на F103 — единицы микросекунд: запас огромный. Опасен не
Modbus, а свои протоколы, где ведомый отвечает сразу: тогда задержка
снятия DE у ведущего должна быть меньше самой короткой задержки ответа.
Конец кадра на G4 без таймера. В разделах 16.8 и 198в тишину считает
таймер. У нового USART для этого есть таймаут приёма: RTOEN в CR2 и
число бит тишины в RTOR; RTOF взводится, если пауза длиннее значения
плюс 2 доли бита (RM0440). 3,5 символа — это 38,5 бита:
RTO |
RTOF после |
Нужно не меньше | Итог |
|---|---|---|---|
| 38 | 38,125 бита | 38,5 бита | рано: кадр режется |
| 39 | 39,125 бита | 38,5 бита | годится |
Отсюда RTO_BITS = 39 в коде выше. Разрыв внутри кадра до 1,5 символа
(16,5 бита) протокол разрешает — он счётчик не доведёт. RM0440 в разделе
про Modbus берёт для примера 2 символа, 22 бита; протоколу нужно 3,5.
Постоянные 1750 мкс для скоростей выше 19 200 бод на 115 200 бод — это
202 бита.
Изоляция и защита. Если приборы питаются от разных земель — цифровой изолятор и изолированный преобразователь (разделы 54.4 и 54.6). Всё, что выходит на клеммы, получает ограничитель у разъёма (разделы 62.9 и 203.4), от синфазной помехи на кабеле — синфазный дроссель (раздел 168).
16а.7 Грабли
Связь есть на столе и пропадает в шкафу. Смещение считали под один терминатор, а на объекте их два: 820 Ом при 3,3 В дают 116 мВ вместо нужных 200. Считать под два — 390 Ом.
Шум в паузах, ложные старт-биты. Терминатор включён в каждом приборе: десять по 120 Ом — это 12 Ом, и смещение даёт 50 мВ. Терминаторы — только на двух концах.
Работает, но чуть что — сбои. 680 Ом при 5 В: номинал 211 мВ, но с допусками питания и резисторов 197 мВ. Брать 560.
Ведущий видит тайм-аут, хотя ответ ушёл. DE сняли по TXE: последний
байт CRC обрезан. У посылки из одного байта не уходит вообще ничего.
DE падает, не успев подняться. TCIE разрешили до первого байта, а
TC взведён ещё со сброса (USART_SR = 0x00C0).
Своё эхо в приёме. /RE на земле, приёмник слушает собственную
передачу. Выключать RE в CR1 на время передачи — или выбрасывать эхо.
На G4 DEAT и DEDT не меняются. Поля пишут только при UE = 0 —
сначала CR1 без UE, потом с ним.
Таймаут приёма режет кадр. RTO = 38: RTOF приходит после
38,125 бита, раньше 3,5 символа. Нужно 39.
Звезда вместо цепочки. У звезды больше двух концов — два терминатора её не согласуют. Магистраль — цепочкой, отводы короткие.
16а.8 Итоги
- RS-485 — пара A и B, полудуплекс и общий провод; DE включает передатчик высоким уровнем, /RE — приёмник низким.
- Шина — цепочкой с двумя концами; терминатор 120 Ом только на них, отводы короткие. Десять терминаторов — 12 Ом и 50 мВ смещения.
- Смещение: VAB = Vcc × Rt / (2Rb + Rt). С допусками под два терминатора: 390 Ом при 3,3 В (худший случай 220 мВ), 560 Ом при 5 В (237 мВ). Под один — 820 Ом и 1200 Ом, но на двух терминаторах 820 Ом даёт 116 мВ.
- DE на F1 и F4 снимают по
TC: поTXEтеряется последний байт, 11 бит;TCIEвключают только после последнего байта. - F0, F3, F7, G4, L4 ведут DE сами:
DEM,DEPвCR3,DEATиDEDTвCR1— до 31 доли бита (1,9375 бита приOVER8= 0). - Один обмен «10 регистров» на 9600 бод — 45 834 мкс, не больше 21,8 в секунду; на 115 200 бод — 6651 мкс, и паузы там больше половины.
- Конец кадра Modbus на G4 — таймаут приёма,
RTO= 39 бит.
Полные исходники
rs485_f103.c — RS-485 на STM32F103: передача по прерываниям, DE снимается по флагу TC.
/* 16а: RS-485 на STM32F103 — передача по прерываниям, вывод DE снимается по флагу TC.
USART2: PA2 — TX, PA3 — RX, PA1 — DE и /RE приёмопередатчика (как в разделе 16.8), 9600 8E1.
Собирается armclang: -DSTM32F10X_MD -include stm32f10x.h. */
#include <stddef.h>
#include <stdint.h>
#ifdef USART_CR3_DEM
#error "у USART F1 аппаратного DE нет: такого бита в заголовке быть не должно"
#endif
_Static_assert(USART_SR_TXE == 0x80 && USART_SR_TC == 0x40, "TXE и TC — биты 7 и 6 USART_SR (RM0008)");
_Static_assert(USART_CR1_TXEIE == 0x80 && USART_CR1_TCIE == 0x40, "их прерывания — те же биты в CR1");
_Static_assert(36000000u / 9600u == 3750u && 36000000u % 9600u == 0u, "9600 бод от APB1 36 МГц без погрешности");
extern void rs485_rx_byte(uint8_t b); /* приём кадра — раздел 16.8 */
static const uint8_t *tx_p;
static volatile uint32_t tx_n;
static volatile uint8_t tx_busy;
void rs485_init(void)
{
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
GPIOA->BSRR = (1u << (1 + 16)) | (1u << 3); /* DE = 0 — слушаем; подтяжка RX вверх */
GPIOA->CRL = (GPIOA->CRL & ~0xFFF0u)
| (0x2u << 4) /* PA1: выход 2 МГц — DE и /RE */
| (0xAu << 8) /* PA2: альтернативная функция — TX */
| (0x8u << 12); /* PA3: вход с подтяжкой — RX */
USART2->BRR = 3750u;
USART2->CR1 = USART_CR1_UE | USART_CR1_M | USART_CR1_PCE | USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
NVIC_EnableIRQ(USART2_IRQn);
}
void rs485_send(const uint8_t *p, uint32_t n)
{
if (n == 0)
return;
while (tx_busy) {
}
tx_p = p;
tx_n = n;
tx_busy = 1;
USART2->CR1 &= ~USART_CR1_RE; /* своё эхо не принимать */
GPIOA->BSRR = 1u << 1; /* DE = 1: передатчик на линии */
USART2->CR1 |= USART_CR1_TXEIE; /* байты кладёт прерывание; TCIE пока нельзя: TC = 1 с самого сброса */
}
void USART2_IRQHandler(void)
{
uint32_t sr = USART2->SR;
uint32_t cr1 = USART2->CR1;
if ((cr1 & USART_CR1_TXEIE) && (sr & USART_SR_TXE)) {
USART2->DR = *tx_p++; /* чтение SR, затем запись DR сбрасывают TC */
if (--tx_n == 0) /* последний байт только начал уходить: ждать TC, а не TXE */
USART2->CR1 = (uint16_t)((cr1 & ~USART_CR1_TXEIE) | USART_CR1_TCIE);
} else if ((cr1 & USART_CR1_TCIE) && (sr & USART_SR_TC)) {
GPIOA->BSRR = 1u << (1 + 16); /* стоп-бит последнего байта в линии: DE = 0 */
USART2->CR1 = (uint16_t)((cr1 & ~USART_CR1_TCIE) | USART_CR1_RE);
tx_busy = 0;
}
if (sr & USART_SR_RXNE)
rs485_rx_byte((uint8_t)USART2->DR);
}
rs485_g474.c — RS-485 на STM32G474: DE ведёт сам USART, конец кадра ловит таймаут приёма.
/* 16а: RS-485 на STM32G474 — вывод DE ведёт сам USART2 (DEM), конец кадра Modbus ловит таймаут приёма.
USART2: PA1 — DE (USART2_RTS_DE), PA2 — TX, PA3 — RX, все AF7; 9600 8E1 от PCLK1 170 МГц.
Собирается armclang: -DSTM32G474xx -include stm32g4xx.h. */
#include <stdint.h>
#define DE_TIME 16u /* DEAT и DEDT: 16 долей по 1/16 бита = 1 бит (OVER8 = 0) */
#define RTO_BITS 39u /* 3,5 символа по 11 бит = 38,5 бита -> 39 */
#define CR1_RS485 ((DE_TIME << USART_CR1_DEAT_Pos) | (DE_TIME << USART_CR1_DEDT_Pos) | \
USART_CR1_M0 | USART_CR1_PCE | USART_CR1_RTOIE | USART_CR1_TE | USART_CR1_RE)
_Static_assert(USART_CR3_DEM == (1u << 14) && USART_CR3_DEP == (1u << 15), "DEM и DEP — биты 14 и 15 USART_CR3 (RM0440)");
_Static_assert(USART_CR1_DEAT_Pos == 21 && USART_CR1_DEAT_Msk == 0x03E00000u, "DEAT[4:0] — биты 25:21 CR1");
_Static_assert(USART_CR1_DEDT_Pos == 16 && USART_CR1_DEDT_Msk == 0x001F0000u, "DEDT[4:0] — биты 20:16 CR1");
_Static_assert(DE_TIME <= 31u && RTO_BITS <= USART_RTOR_RTO_Msk, "поля DEAT, DEDT — 5 бит, RTO — 24 бита");
_Static_assert(CR1_RS485 == 0x0610140Cu, "CR1: DEAT = DEDT = 16, 8E1, RTOIE, TE, RE");
_Static_assert((170000000u + 4800u) / 9600u == 17708u, "BRR для 9600 бод от 170 МГц");
void rs485_g4_init(void)
{
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN;
RCC->APB1ENR1 |= RCC_APB1ENR1_USART2EN;
GPIOA->AFR[0] = (GPIOA->AFR[0] & ~0xFFF0u) | 0x7770u; /* PA1, PA2, PA3 — AF7 */
GPIOA->MODER = (GPIOA->MODER & ~0xFCu) | 0xA8u; /* все три — альтернативная функция */
USART2->BRR = 17708u;
USART2->RTOR = RTO_BITS;
USART2->CR2 = USART_CR2_RTOEN;
USART2->CR3 = USART_CR3_DEM; /* DEP = 0: DE активен высоким уровнем */
USART2->CR1 = CR1_RS485; /* DEAT, DEDT и формат пишут при UE = 0 */
USART2->CR1 = CR1_RS485 | USART_CR1_UE;
}
/* Передача: DE поднимется за DEAT до старт-бита и упадёт через DEDT после стоп-бита сам */
void rs485_g4_send(const uint8_t *p, uint32_t n)
{
while (n--) {
while (!(USART2->ISR & USART_ISR_TXE)) {
}
USART2->TDR = *p++;
}
}
Дальше: раздел 16б «Приём UART без потерь: DMA в кольцо, IDLE и половина буфера» — кольцевой DMA, позиция по NDTR, разбор кадров без копирования и размер кольца от скорости и задержки.