Arlleex 178 25 октября, 2021 Опубликовано 25 октября, 2021 · Жалоба 32 минуты назад, jcxz сказал: Неужто Ваша задача чем-то занята целых 80мсек... Нет конечно, я предполагаю такой ситуации вообще никогда не возникнет. Сейчас все на бумаге, но нужно сразу закладываться на нештатные режимы (а вдруг что?). ТЗ на поведение при нештатных режимах - нет, полная свобода для творчества, но я хочу сделать максимально четко. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 30 декабря, 2021 Опубликовано 30 декабря, 2021 · Жалоба А кто как обрабатывает ошибки UART модуля при работе на прием через DMA? Т.е. при любой ошибке (framing error, например) что делаете? Сбрасываете весь FIFO? Грубо говоря, имея рабочий буфер в 8 кБ, помеха на линии технически заставит отбросить все уже имеющиеся корректные данные из этого буфера? Просто дело вот в чем: я же хотел попробовать поделить буфер на множество сегментов, и каждому сегменту отвести 1-битный флажок "валидности" данных. При возникновении ошибки текущий DMA-сегмент помечается как не валидный и при чтении данных из FIFO это будет учтено (просто нужно будет откинуть данные лишь одного сегмента, а не всего буфера). Только вот есть некая засада: нет средств аппаратного удержания номера активного DMA-буфера, в который прилетел "битый" символ. Программная реализация, ИМХО, надежно не реализуется, т.к. в любом случае пара прерываний TC от DMA и UART Errors образует гонки состояний, особенно при возникновении ошибок в конце текущего активного буфера и начале следующего заполняемого при сплошном высокоскоростном UART-потоке... Разве что помечать не валидными пару буферов (текущий и следующий) сразу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 30 декабря, 2021 Опубликовано 30 декабря, 2021 · Жалоба 1 час назад, Arlleex сказал: А кто как обрабатывает ошибки UART модуля при работе на прием через DMA? Т.е. при любой ошибке (framing error, например) что делаете? Сбрасываете весь FIFO? Всё зависит от назначения данного UART: с чем именно, в каких условиях работает и какой протокол обмена по нему ходит? 1. Например у меня, для UART-а, на котором сидит ESP8266, любое такое событие - абсолютно недопустимо, и при его возникновении: Останов драйвера ESP (со всеми вышележащими драйверами по иерархии) и реинит UART-а (с DMA). Так как такие события не могут происходить при нормальной работе (ESP8266 находится на той же плате где и МК, короткие линии связи); и потому что АТ-протокол обмена ESP8266 не устойчив к такого рода сбоям (правильное восстановление после такого сбоя в общем случае невозможно). 2. Если же на этом UART-е например RS-485, по которому к тому же ходит протокол, устойчивый к помехам на линии (кодонезависмый, с правильным фреймингом и контролем содержимого) и помехи на линии возможны исходя из самого характера работы системы: то можно и просто сбросить состояние ошибки, накопленные FIFO (все: аппаратные + программные), и сбросить машину состояний парсера протокола обмена. Но даже в случае с RS-485, если (исходя из характера работы системы) допустимо пойти 1-м вариантом, но лучше так и сделать. Так как проще и надёжнее. Идти 2-м путём имеет смысл если выполняются все условия (2-го варианта) и есть реальная необходимость: канал плотно загружен обменом, или по нему ходят реалтайм-данные и необходимо как можно более быстрое восстановление связи после помех и т.п. PS: Так что сначала нужно всё-таки определиться: реально оно нужно, или можно пойти по 1-му варианту? И если нужно, то зачем? Отсюда и танцевать. А смысла в универсальных конях в вакууме я не вижу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 30 декабря, 2021 Опубликовано 30 декабря, 2021 · Жалоба 1 час назад, jcxz сказал: Всё зависит от назначения данного UART: с чем именно, в каких условиях работает и какой протокол обмена по нему ходит? А разве реализация драйвера FIFO должна учитывать протокол, который будет ходить поверх? Я думаю, что это не совсем корректно. ИМХО, достаточно, читая статус очереди при вычитке данных из нее функцией read(), каким-то образом сообщить клиентскому коду, что с данными (запрошенными) все в порядке. Сделать это можно как раз по принципу, похожему на механизм виндовых функций ReadFile(). Т.е. запрашиваем сколько-нибудь данных, а она считывает столько, сколько было реально получено без каких-либо коллизий (но не более запрошенного количества). Выше примерный псевдокод я уже приводил. Ну либо отдельной переменной (ссылкой, по указателю - как угодно) передавать, а после проверять что там - если была лажа в потоке, сбрасываем автоматы протоколов выше. ИМХО, такое FIFO подойдёт и под ESP: просто увидев коллизию в очереди, вызываем функцию очистки ее и все. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 30 декабря, 2021 Опубликовано 30 декабря, 2021 · Жалоба 37 минут назад, Arlleex сказал: ИМХО, такое FIFO подойдёт и под ESP: просто увидев коллизию в очереди, вызываем функцию очистки ее и все. И что? А дальше как работать? Ну очистили вы FIFO, а как теперь данные получать из потока? Ещё раз: у ESP АТ-командный протокол не кодонезависимый! Поэтому если взять и просто выбросить кусок потока байт, то далее уже невозможно определить, что идёт после этого пропуска: часть команды или часть блока данных или ещё чего. Я имею в виду именно АТ-командный протокол работы ESP8266. То же самое касается и любых других некодонезависимых протоколов: не поможет там очистка FIFO, никак. PS: А если протокол кодонезависимый и очистка имеет смысл, то в ISR обработчика ошибок можно посмотреть текущий объём данных в приёмном FIFO, и послать сигнал RX-парсеру; парсер получив этот сигнал должен просто скипнуть указанный объём и всё. Это самый простой способ имхо. И тогда можно обойтись простой реализацией FIFO: с одним читателем одним писателем (без лищних блокировок на критических секциях). Никаких очисток в обработчике ошибок делать не надо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 18 февраля, 2022 Опубликовано 18 февраля, 2022 · Жалоба Заметил в связке DMA + UART (передача "память -> периферия") на довольно бодрых скоростях (921600 и выше до предельных возможностей UART-модуля), что устанавливается флаг ошибки FIFO DMA-потока. Хотя у меня выбран Direct Mode (DMDIS = 0). На маленьких скоростях UART-а не проверял (ибо отлаживался сразу на мегабите). DMDIS = 1 и любые вариации FIFO Level Treshold проблему не решают. При этом, собственно, данные все передаются верно (нет "перезаписанных" или вовсе отсутствующих байтов в потоке). Читая RM, пока что пришел к выводу, что (согласно описанию бита FIFO Error Interrupt Flag - FEIF) DMA не успевает "подгрузить" данные из памяти во внутренний FIFO и происходит т.н. Underrun Condition. Ведь DMA опирается на флаг TXE UART-модуля, который взводится практически сразу после записи в пустой DR (когда DR "сливается" в непосредственный сдвиговый регистр). Даже не понятно теперь, как обрабатывать FEIF, по-хорошему. Либо запретить вовсе это прерывание. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 18 февраля, 2022 Опубликовано 18 февраля, 2022 · Жалоба 5 часов назад, Arlleex сказал: Даже не понятно теперь, как обрабатывать FEIF, по-хорошему. Либо запретить вовсе это прерывание. Так он у вас возникает наверное из-за direct mode. А зачем UART-у direct mode? Если не секрет. Да и какая разница - есть этот FEIF или нет, если не используете Modbus или что-то подобное? UART - это ведь асинхронный интерфейс, а не синхронный. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 19 февраля, 2022 Опубликовано 19 февраля, 2022 · Жалоба 10 часов назад, jcxz сказал: Так он у вас возникает наверное из-за direct mode. А зачем UART-у direct mode? Если не секрет. На прием нужен Direct Mode. На передачу, собственно, тоже, т.к. FIFO Mode (DMDIS = 1) полезен, когда ширины шин памяти и периферии различны или когда используются Burst-транзакции. У меня же DMA-поток направляет массив байтов из ОЗУ в UART->DR, соответственно, MSIZE = PSIZE = 8 (бит), MBURST = PBURST = Single Transfers. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться