Перейти к содержанию

Ошибка переполнения приёмника (overrun)

Приёмник UART складывает принятые символы в маленький буфер. Если программа не успевает его освобождать, следующий символ приходит некуда — это ошибка переполнения, и как минимум один байт пропадает.

Обновлено Редакция GAW

Ошибка переполнения (overrun error) — ситуация, когда UART принял новый символ, а положить его некуда: предыдущие ещё не прочитаны программой. Приёмник выставляет флаг, и как минимум один символ теряется.

Флаги у разных UART

UARTРегистр и флагСколько символов помещается до переполнения
STM32F1USART_SR, OREрегистр данных + сдвиговый регистр
AVR (ATmega328P)UCSR0A, DOR0буфер из двух символов + сдвиговый регистр
UART 16550LSR, OEFIFO 16 символов + сдвиговый регистр

У ATmega328P флаг DOR0 взводится, когда буфер из двух символов полон, в сдвиговом регистре ждёт третий, а на линии уже начался следующий старт-бит. У STM32F1 по RM0008 символ в регистре данных сохраняется, а всё, что пришло в сдвиговый регистр во время переполнения, пропадает. UART 16550 в режиме FIFO сообщает о переполнении только тогда, когда заполнен весь FIFO.

Сколько времени у программы

Если нет FIFO и DMA, каждый символ надо забрать до прихода следующего. При 115 200 бит/с и формате 8N1 символ приходит каждые 10 / 115 200 ≈ 86,8 мкс (наш расчёт). Обработчик другого прерывания, который работает дольше, или долгий запрет прерываний — и байт потерян. На странице UART в STM32 показано, как сбрасывать флаг и принимать данные через DMA.

Как предотвратить

  1. Принимать по прерыванию в кольцевой буфер, а разбирать данные в основном цикле.
  2. Использовать DMA или UART с FIFO.
  3. Включить аппаратное управление потоком: приёмник снимает RTS, и передатчик останавливается. TI отмечает, что переполнения исключены, если обе стороны — TL16C550C с включённым автоматическим RTS/CTS и RTS каждой соединён с CTS другой.

Не путать с флагом переполнения V процессора — он относится к знаковой арифметике, см. флаг переполнения, — и с ошибкой кадра, когда символ принят, но на месте стоп-бита ноль.

Частые вопросы

Какой байт теряется при переполнении UART?

Зависит от микросхемы. У STM32F1 символ в регистре данных сохраняется, а всё, что приходит в сдвиговый регистр, пока флаг ORE стоит, пропадает. У ATmega328P в буфере остаются два символа, а теряется тот, что ждал в сдвиговом регистре. Флаг в любом случае означает, что потерян хотя бы один символ.

Почему при переполнении STM32 может зависнуть в прерывании?

Флаг ORE тоже вызывает прерывание приёма. Если обработчик проверяет только RXNE и не сбрасывает ORE последовательностью «прочитать USART_SR, затем USART_DR», флаг остаётся, прерывание повторяется бесконечно, а основной код не выполняется.

Как избавиться от ошибок переполнения?

Забирать байты быстрее, чем они приходят: принимать по прерыванию в кольцевой буфер или через DMA, не держать прерывания запрещёнными долго, взять UART с FIFO. Если приёмник всё равно может отстать, нужна аппаратная остановка передатчика — управление потоком RTS/CTS.

Источники

  1. STMicroelectronics. RM0008 Reference manual: STM32F101xx–STM32F107xx (Rev 21, February 2021) — разд. 27.3.3: переполнение — символ принят, когда RXNE ещё не сброшен; бит ORE; содержимое RDR не теряется, сдвиговый регистр перезаписывается, принятое во время переполнения теряется; прерывание при RXNEIE или EIE и DMAR; ORE сбрасывается чтением SR, затем DR; ORE = 1 означает потерю хотя бы одного символа
  2. Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B, 2020) — разд. 20.7.4: флаг DORn — потеря данных из-за заполненного буфера приёма (два символа), когда в сдвиговом регистре ждёт новый символ и обнаружен новый старт-бит; сбрасывается, когда принятый кадр успешно перенесён в буфер
  3. Texas Instruments. TL16C550C Asynchronous Communications Element with Autoflow Control (SLLS177I), 2021 — LSR, флаг OE: символ в RBR перезаписан следующим до чтения; в режиме FIFO переполнение — только когда FIFO полон и следующий символ полностью принят в сдвиговый регистр; переполнения исключаются, если обе стороны — TL16C550C с autoflow и RTS одной соединён с CTS другой

Нашли ошибку?