Сергей Борщ 134 21 октября, 2021 Опубликовано 21 октября, 2021 · Жалоба 13 часов назад, Сергей Борщ сказал: Почему у Arlleex не получилось - я не знаю, завтра на работе постараюсь найти время проверить на F407. Не судьба - всех загнали на удаленку, дома F4 нет в наличии. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 21 октября, 2021 Опубликовано 21 октября, 2021 · Жалоба ... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 21 октября, 2021 Опубликовано 21 октября, 2021 · Жалоба 1 час назад, Arlleex сказал: Если поставить точку останова на u32 sr = USART1->SR, из консоли отправить 1 байт, затем сделать шаг - в sr будет виден установленный IDLE. Если же поставить точку останова на if(sr & USART_SR_IDLE), то при отправке из консоли одного байта в sr будет виден сброшенный IDLE. Типа не успел еще. Некорректный тест. Останов на брекпоинте - это уже другой режим функционирования процессора. Как там будет это обрабатываться UART-ом - одному ему известно, в мануале про это вроде нет инфы. Возможно что сам факт останова на бряке и ставит IDLE. Если нужно знать как будет работать в нормальном режиме работы - никаких бряков. Цитата т.е. этим я хочу узнать, кто же возникает первым - RXNE или IDLE. После запуска программы, отправляю с консоли 1 символ - светодиод переключился. Это, получается, соответствует описанию в RM: после заливки прошивки в МК, пока перешел в консоль, пока нажал кнопку - прошло много времени, и RX-path зафиксировал простой линии (все 1 в битах). Когда я нажал отправку символа - я залетел в прерывание и увидел, что IDLE установлен, а RXNE еще нет - т.е. IDLE действительно срабатывает только тогда, когда обнаружен простой линии + старт-бит следующего символа. Из теста не видно - когда у Вас установился IDLE. Может он установился сразу после инициализации порта и последующей паузы? Имхо - нужно сперва сделать паузу, заведомо очистить статусы, разрешить только RXNEIE, потом отправить символ (на малой скорости, с высоким приоритетом прерывания; чтобы точно IDLE не успел установиться после RXNE из-за задержки входа в ISR); и прочитать статусы - и посмотреть в SR один только RXNE стоит или RXNE+IDLE? т.е.: 1. инит порта; 2. пауза в несколько символов как минимум; 3. очистка SR; 4. разрешить RXNEIE; 5. отправить символ; 6. прочитать SR в ISR. 1 час назад, Сергей Борщ сказал: Не судьба - всех загнали на удаленку Везёт вам. Двигатель+стенд домой не унесёшь. Придётся теперь по выходным на работу выходить... Уроды, блин! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 21 октября, 2021 Опубликовано 21 октября, 2021 · Жалоба В общем, ща буду GPIO-шками мерять последовательность установки флагов, а то я уже сам запутался void USART1_IRQHandler(void) { u32 sr = USART1->SR; if(sr & USART_SR_IDLE) GPIOG->ODR ^= 1 << 13, (void)USART1->DR; if(sr & USART_SR_RXNE) GPIOG->ODR ^= 1 << 14, (void)USART1->DR; } Осциллом гляну. Итак, отправляю один символ. Судя по диаграмме, сначала взводится RXNE, затем IDLE. Скорость поставил 1200 бод. Самое забавное: если символ 0x00, то "расстояние" между фронтами ровно 1 символ (~83 мс). Если 0xFF - 1 бит (~1 мс). Отправляю несколько символов друг за другом - IDLE также устанавливается только после самого последнего. Только вот возникает стойкое ощущение, что тут может возникнуть гонка состояний, особенно при работе с DMA. Насколько я помню, доступа к DR со стороны CPU при работающем DMA на эту периферию быть не должно... А IDLE сбрасывается чтением DR. Почитал я еще мануалы на F4 и F0, и пришел к выводу, что документация там вообще на "высшем" уровне F0: Скрытый текст F4: Скрытый текст Да за такую документацию только руки поотрывать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 21 октября, 2021 Опубликовано 21 октября, 2021 · Жалоба 1 час назад, Arlleex сказал: Итак, отправляю один символ. Судя по диаграмме, сначала взводится RXNE, затем IDLE. Скорость поставил 1200 бод. Ну значит IDLE сигнализирует всё-таки о "таймауте отсутствия активности на линии". А не об "отсутствии активности сопровождаемой старт-битом". Цитата Самое забавное: если символ 0x00, то "расстояние" между фронтами ровно 1 символ (~83 мс). Если 0xFF - 1 бит (~1 мс). Это говорит о механизме отслеживания IDLE: Значит он отслеживается не от момента завершения стоп-бита последнего символа, а от момента последнего фронта 0->1 на линии. Т.е. - самым простейшим способом. PS: А эти тесты Вы делали при каком значении бита RWU? (про который я вчера писал). Влияет ли он на поведение IDLE? 1 час назад, Arlleex сказал: Да за такую документацию только руки поотрывать. Вы документацию Infineon не видели! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 21 октября, 2021 Опубликовано 21 октября, 2021 · Жалоба 17 минут назад, jcxz сказал: А эти тесты Вы делали при каком значении бита RWU? (про который я вчера писал). Влияет ли он на поведение IDLE? RWU = 0, при установке RWU и остальных прочих равных условиях поведение ровно такое же. RWU полезен, скорее всего, тогда, когда нужно прекратить слушать входной поток, но до начала следующего кадра (в системе, где кадры - это разделенные по времени посылки). Например, для безопасного "горячего" подключения в линию. Цитата Вы документацию Infineon не видели! Местами кривая тоже... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 21 октября, 2021 Опубликовано 21 октября, 2021 · Жалоба Вот как подобное описано в нормальной документации: (c) TI. Всё понятно - и когда и через сколько. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 24 октября, 2021 Опубликовано 24 октября, 2021 · Жалоба 19.10.2021 в 22:50, jcxz сказал: Переполнение буфера обнаруживается и обслуживается корректно (при необходимости запускаю DMA для очередного UART_RDMA_CHUNK не в основной буфер, а в отдельную "мусорку"). У Вас тот протокол поверх UART-а, я так полагаю, уже со всеми кадровыми разделителями и CRC? Иначе просто так перекинуть указатель снова на основной буфер с "мусорки" - маневр весьма опасный. У меня вот, например, протокол SLCAN, и там нет механизмов обеспечения проверки целостности кадров (да и сами "кадры" там условные). Для своей реализации, наверное, будет лишним обрабатывать переполнение (разве что вывести в отладочный порт сообщение, мол не хватает объема очереди/скорости парсинга и обработки). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 24 октября, 2021 Опубликовано 24 октября, 2021 · Жалоба 9 минут назад, Arlleex сказал: У Вас тот протокол поверх UART-а, я так полагаю, уже со всеми кадровыми разделителями и CRC? Иначе просто так перекинуть указатель снова на основной буфер с "мусорки" - маневр весьма опасный. Нет. Зачем? Это ведь UART - поток байт. Протокол (ходящий по нему) он у меня уже в задаче ОС обрабатывается. Разгребающей полученное от ISR/DMA из очереди. Точнее - протоколы, так как по разным UART-ам - разные протоколы, в то время как драйвер UART - единый. И ничего опасного: ISR, сделавший такое переключение, просто устанавливает "флаг переполнения". Разгребающая задача - обрабатывает этот флаг вместе с данными FIFO. Точно так же, как если бы она читала данные из аппаратного FIFO и обрабатывала их совместно с флагом переполнения в регистре статуса UART. Ведь у вас не возникает проблем с обработкой аппаратного FIFO? А здесь - его аналог, врукопашную на ISR/DMA. Цитата У меня вот, например, протокол SLCAN, и там нет механизмов обеспечения проверки целостности кадров (да и сами "кадры" там условные). Если он у Вас обрабатывается в задаче, то какая проблема точно так же обрабатывать в ней же и флаг переполнения? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 24 октября, 2021 Опубликовано 24 октября, 2021 · Жалоба Ну здесь, ИМХО, как-то заморочено будет R, W - указатели чтения и записи. Цветами обозначены конкретные сообщения: обрамления кадров нет (ASCII-формат), CRC тоже. Весь буфер разбит на одинаковые куски по 8 байт (просто для демонстрации). Запускаем DMA, и не читаем из буфера (чтобы было переполнение). Как только пришло прерывание Transfer Complete, перепрограммируем указатель на следующий кусок памяти, и так далее. При заполнении 2-го (счет с 0) буфера логика перекидывает указатель на "мусорку", потому что когда заполнится 3-й буфер, двигать уже что-то куда-то будет поздно (да и в этой точке можно считать 3-й буфер потенциально переполненным, т.к. если DMA запонит его 7-й элемент, двигать W будет уже некуда). Теперь все приходящие символы будут записываться в мусорку. Как только R переместится как минимум на 8 байтов, неактивный указатель DMA можно будет перекинуть на начало этого кусочка. Собственно, в мусорке часть красного сообщения была затерта новыми приходящими данными (фиолетовый цвет). По идее, надо как-то сообщить разгребающему потоку конкретное место, где возникло переполнение, чтобы он откинул как красное, так и (возможно битый) кусок того нового, которое будет помещено туда где сейчас зеленый. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 24 октября, 2021 Опубликовано 24 октября, 2021 · Жалоба 4 часа назад, Arlleex сказал: Запускаем DMA, и не читаем из буфера (чтобы было переполнение). Что Вы имеете в виду? Если запускаете DMA (DMA.RX), то это собственно запуск чтения. Или я не понял о чём речь.... 4 часа назад, Arlleex сказал: По идее, надо как-то сообщить разгребающему потоку конкретное место, где возникло переполнение Зачем "место" сообщать? Какой смысл? Принимающий процесс, вычитывая данные из FIFO.RX, собирает из них допустим кадр какого-то протокола (ну или на лету разбирает поток символов на элементарные лексемы). Когда выставляется флаг переполнения, то этот читающий поток просто переходит в состояние "не_синхронизирован". У меня это начальное состояние у всех приёмных потоков, в которое они переходят при старте работы или при возникновении ошибок (например переполнения). Переход из состояния "не_синхронизирован", в состояние "синхронизирован", происходит при обнаружении принимающим потоком границы кадра. Из "синхронизирован" уже можно переходить в состояние приёма кадра/лексемы. Например: для SLIP этой границей будет: SLIP_END (0xC0); для COBS = 0; для Modbus - пауза; для каких-то ASCII-ориентированных протоколов (например AT-командный протокол): '\r' или '\n' ... Обнаружили: переходим -> в состояние "синхронизирован", а при любой ошибке или после старта -> "не_синхронизирован". При переходе в "не_синхронизирован" из рабочих состояний приёмник сбрасывает все текущие накапливаемые переменные/буфера. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 24 октября, 2021 Опубликовано 24 октября, 2021 · Жалоба 13 часов назад, jcxz сказал: Что Вы имеете в виду? Если запускаете DMA (DMA.RX), то это собственно запуск чтения. Запустили DMA на прием символов из UART в буфер. В прерываниях TC соответствующим образом корректируем указатель на следующий кусочек этого буфера (DMA в режиме двойного буфера, конечно же). Чтобы "подыграть" переполнение FIFO, нужно всего лишь не читать из этого буфера из процесса чтения (т.е. не двигать указатель R на картинке). Цитата При переходе в "не_синхронизирован" из рабочих состояний приёмник сбрасывает все текущие накапливаемые переменные/буфера... Ведь потеряем же все накопленные в буфере данные. Смотрите, что я имею в виду: смоделируем ситуацию, когда в буфер прилетает поток байтов, а процесс вычитки из FIFO и обработки протокола тупит и вовремя не обрабатывает его. Зеленое сообщение поместилось в буфер полностью, красное - нет, поэтому W встал туда где он нарисован, а хвост красного сообщения улетел в "мусорку". Следом за красным прилетело еще одно сообщение, поток байтов которого обозначен синим цветом. Он также разместился в "мусорке" (потому что рабочий FIFO все еще полон) И вот читающий процесс все-таки раздуплился и начинает читать; для примера, пусть он вычитает и обработает зеленое сообщение. Как только в рабочем буфере FIFO стало достаточно места, чтобы передвинуть указатели с "мусорки" на него, принимаемые байты (для примера сообщения, помеченного фиолетовым цветом) будут размещаться уже в нем И вот засада: принимающий процесс видит, что в буфере есть байты, вычитывает их и синхронизируется с красным сообщением (распознает его начало). Только вот принимающий процесс не знает, что 2-байтовый обрубок конца красного сообщения валяется в "мусорке", а те 2 байта, что сейчас в качестве хвоста, это есть часть фиолетового сообщения. Грубо говоря, в последних байтах красного и фиолетового были эти самые '\r'. А в предпоследних - разные данные. Здесь спасла бы контрольная сумма, заложенная в протоколе поверх этого UART, например. А если делать глобальный флажок "FIFO переполнен", по которому приемный процесс должен сделать очистку этого FIFO, то мы таким образом потеряем все сообщения, в том числе те, которые разместились в буфере без проблем. А в SLCAN сообщения, как правило, коротенькие довольно - от единиц до пару десятков байтов. А буфер я хочу сделать в пару кБ хотя бы, а то и 8 Терять эти сообщения очень очень жалко. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 24 октября, 2021 Опубликовано 24 октября, 2021 · Жалоба 2 часа назад, Arlleex сказал: Здесь спасла бы контрольная сумма, заложенная в протоколе поверх этого UART, например. А если делать глобальный флажок "FIFO переполнен", по которому приемный процесс должен сделать очистку этого FIFO, то мы таким образом потеряем все сообщения, в том числе те, которые разместились в буфере без проблем. Ну и пусть потеряем. Ведь переполнение - это же нештатная ситуация. Которая не должна происходить в нормальном режиме работы программы. А может происходить только из-за каких-то нештатных режимов функционирования, например: останов под отладчиком в процессе отладки и т.п. Либо ещё какие-то особые ситуации. И корректная её обработка должна заключаться только в том, чтобы исключить разрушения памяти, выполнить корректную очистку, перевод всех автоматов состояний в исходную фазу и т.п. И чтобы после неё происходило корректное восстановление в штатный режим. Чтобы программа не повисла, грубо говоря. Если она у Вас происходит при обычной работе программы, то надо перепроектировать алгоритм работы так, чтобы этого не было. А не пытаться костылить. То что Вы предлагаете - это лечение симптомов болезни, а не самой болезни (исправление алгоритма). Да и не получится ничего из этого, потому как если уж переполнилось (не из-за того, что кривой код, а потому что не хватает производительности МК), то всякими контрольными суммами, их вычислениями, ситуацию только усугубите. PS: 8кБ - это даже если у Вас 1Мбод по CAN, всё равно нужно около 80мсек для полного заполнения. За это время можно воробья в поле загонять. Почему же времени не хватает на нормальную обработку? 2 часа назад, Arlleex сказал: процесс вычитки из FIFO и обработки протокола тупит и вовремя не обрабатывает его. Вот это и надо исправлять. А не костыли мастырить. PS: А вообще конечно можно не общий флаг переполнения использовать, а массив флагов, количеством равным количеству DMA-сегментов. Читающий процесс тогда должен считывать не по-символьно, а по-сегментно: сегмент данных с принадлежащим ему флагом/флагами. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 25 октября, 2021 Опубликовано 25 октября, 2021 · Жалоба 12 часов назад, jcxz сказал: А вообще конечно можно не общий флаг переполнения использовать, а массив флагов, количеством равным количеству DMA-сегментов... Вот мне такой механизм как-то больше по душе, думал над ним даже Я допускаю потерю пары-тройки уже принятых в буфер сообщений (это какие-то проценты от объема общего буфера) при нештатной ситуации. Можно развить идею с массивом флагов следующим образом. Функция чтения имеет прототип // buf - куда читать // len - сколько читать // return: сколько считалось u32 read(u8 buf[], u32 len); В чем замысел. Поток обработки периодически выполняет примерно следующие действия while(1) { ... static u8 buf[BUF_SIZE]; // промежуточный буфер парсера ... u32 fifoBsy = fifo.getBsy(); // считали, сколько занято в буфере if(fifoBsy > 0) { u32 len = fifoBsy <= BUF_SIZE ? fifoBsy : BUF_SIZE, br = fifo.read(buf, len); ... // тут, собственно, обработка } } Так пусть read() возвращает количество, запрошенное в len, но с учетом флага переполнения сегмента, из которого он будет читать. Т.е. драйвер установил флаг переполнения для сегмента 3, например. Мы запросили 32 байта, а нам read() выплюнул 8 всего лишь. По факту самого различия len и br можно судить о том, что поток в 32 байта, который сейчас в буфере - нифига не сплошной (т.е. нормальный ход заполнения буфера из UART был нарушен - к примеру, тем самым "сливом" в "мусорку"). Так что мы обрабатываем эти 8 байтов. Если среди них есть вполне законченные сообщения - ок. А если же парсер видит, что сообщение не закончено - переводим его автомат в состояние "несинхронизирован". Сообщение будет отброшено. Дальше по кругу снова вызывается ... read(). Даже если у следующего кусочка будет мусор в начале - несинхронизированный парсер не будет его воспринимать. Если прям вот хочется уметь считывать ровно столько сколько указали (если в буфере столько есть, конечно же), можно перегрузить read() или сделать этот метод с параметром. Ахринеть как круто я придумал Осталось написать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 25 октября, 2021 Опубликовано 25 октября, 2021 · Жалоба 26 минут назад, Arlleex сказал: Ахринеть как круто я придумал Осталось написать. Вы этим усложнением алгоритма и урезанием буфера (если кусочки по 8 байт, то на 8кБ наберётся 1кБ флагов!) ещё больше нагрузите парсер. И если он раньше терял, то так он будет ещё больше терять. Лучше этот 1кБ добавить к объёму очереди. И разобраться - почему у Вас парсер тормозит? И исправить это. Неужто Ваша задача чем-то занята целых 80мсек(!), что не успевает разобрать очередь? (или даже больше 80мс? ведь это я предположил худший случай ==1Мбод, но Вы скорость не указали). Когда такие долгие таймауты у задач, то имхо - нужно разбираться почему они такие долгие. Затем начнутся проблемы с порядком следования сообщений: хорошо если они совершенно независимые, но когда окажется, что одно сообщение зависит от другого, или важен порядок их следования - тут и выйдут боком все эти костыли с выборочным бракованием сообщений. Не надо бороться со следствием, надо причину исправить. имхо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться