• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

ESP не контролирует поток UART

Алексей.

Active member
Всё равно функция передачи является не блокирующей и не неблокирующей
Да как же не блокирующаяся, сначала выполняется ожидание свободного места в фифо
while((USS(uart->uart_nr) >> USTXC) >= 0x7f);
на 9600 время выхода одного байта очень большое, если не проверять свободное место в фифо, а просто записать байт в регистр USF(uart->uart_nr) = c, контроллер просто его проигнорирует.
до вызова Serial.write можно просто получить доступное количество байтов для записи Serial.availableForWrite и после вызова Serial.write запросив Serial.availableForWrite должны получить на единицу меньше.
Пока счет micros() не достиг времени вывода символа не вызываете ничего.
Можно и время фиксировать, но зачем не понятно, если после вызова Serial.write первый Serial.availableForWrite вернул 100, второй и третий тоже 100 а четвертый вернул 101, значит какой то байт (самый первый) вышел из фифо
сигнал направления передачи для полудуплексной шины
Можно по подробнее, это не rs485 по двум проводам?
 

mcmega

Member
У меня скорость выставлена 115200, поэтому в любом случае нужно что то придумывать для запуска контроля потока. Как получится реализовать, скину исходники, думаю многим будет интересно иметь WiFi программатор.
Я кстати и хочу полудуплекс делать, отослал байт, прочитал что на входе, и т. д.
 

mcmega

Member
Дык не заходите в mcuProg() пока не вышло время от micros() после последней передачи + 20000000/baud. А при опросе наличия принятых символов проверяйте время от micros() после последней передачи + (10*(кол-во переданных символов > 128? 128 : кол-во переданных символов) *1000000 + 10000000 + время ожидания ответа от устройства)/baud и выходите из mcuProg() пока время не вышло и принятых символов нет.
Ранее, с имеющимися функциями работы с UART нет необходимости что-то предпринимать и Loop() пусть занимается другими задачами.
Я всегда буду передавать по 1 символу в цикле. А откуда эти расчеты и что это за значения?
 

pvvx

Активный участник сообщества
Да как же не блокирующаяся, сначала выполняется ожидание свободного места в фифо
while((USS(uart->uart_nr) >> USTXC) >= 0x7f);
на 9600 время выхода одного байта очень большое, если не проверять свободное место в фифо, а просто записать байт в регистр USF(uart->uart_nr) = c, контроллер просто его проигнорирует.
до вызова Serial.write можно просто получить доступное количество байтов для записи Serial.availableForWrite и после вызова Serial.write запросив Serial.availableForWrite должны получить на единицу меньше.
Блокирующая должна отдать управление после передачи последнего стоп бита последнего байта. Неблокирующая - положить байт в буфер передачи и отдать управление (для анализа переполнения буфера она отдает кол-во обработанных байт в запросе). При работе с неблокирущими функциями существуют калбаки, такие как - передача осуществлена.
Со времен DOS, для приема с UART, назначается тайм-аут до приема первого символа, максимальный меж-символьный и макс. время на запрос. Время иногда выражается в символьной скорости. Лучше когда в битовой (но это реже).
Можно по подробнее, это не rs485 по двум проводам?
Не обязательно. Не только RS-485 использует драйвер с переключением направления, а так-же и многие софт протоколы, например описываемый у топикастера... :) Т.е. практически всегда требуется при полу-дуплексе (запросно-ответной системе).
Вы собрались переписать API и драйвер UART для Arduino?
Для поддержки описанных вещей у всех аппаратных реализаций UART с FIFO и/или DMA существует встроенный программируемый таймер тишины на линии RX выраженный в символьной скорости или битрейте, дающий прерывание с соответствующим флагом. ESP не исключение, но у неё данный счетчик считает в своих единицах и имеет полу-асинхронный сброс по активному уровню на RX, что не позволяет точно работать именно с символьной скоростью. Но это мелочи - хоть такой.
Это реализовано только у Cesanta и в TCP2UART + Modbus TCP/RTU RS-485 свалке ещё несколько лет назад. Лет через десять может и Adrduino IDE подтянется :)
 
Последнее редактирование:

Алексей.

Active member
Со времен DOS, для приема с UART, назначается тайм-аут до приема первого символа
таймауты это немножко более верхний уровень, вспомните, у старых 8250 без фифо прерывание дергалось на каждый байт, только успевай регистр данных вычитывать ;-) доводилось для ДОС-а .sys драйвер делать, из голосового модема zyxel (были такие в прошлом веке) и пк речевой авто-информатор делать, сейчас смешно вспоминать :)
С есп у ардуины действительно ни два ни полтора, и не кэширует сама если байт в фифо не лезет, а если лезет то вроде как неблокирующий вызов, Вы правы.
Вы собрались переписать API и драйвер UART для Arduino?
Нет совсем не так, ардуина тут ни причем, есть контроллер на арм-е с линуксом, ядро 3.4 собираем без всяких излишеств, сбор данных по rs485 подключенного к usb-rs485 выполняет приложение 3-их разработчиков. Вот я и хотел выкинуть провода и использовать tcp2uart и по этому искал готовое решение, пока не нашел, но всё в наших руках.
Не обязательно. Не только RS-485 использует драйвер с переключением направления
Не вижу, пока сам не кодил, пока ограничений, если нам известен полу-дуплексный протокол взаимодействий, что нам мешает при выполнении передачи, включаем направление "передача", отправляем байты в фифо не допуская переполнения и контролируем опустошение фифо, когда фифо пустое и нам передавать больше нечего, включаем направление "прием". Разве не так?
 

pvvx

Активный участник сообщества
Не вижу, пока сам не кодил, пока ограничений, если нам известен полу-дуплексный протокол взаимодействий, что нам мешает при выполнении передачи, включаем направление "передача", отправляем байты в фифо не допуская переполнения и контролируем опустошение фифо, когда фифо пустое и нам передавать больше нечего, включаем направление "прием". Разве не так?
Нет - не так. Пустое FIFO не говорит о том, что символ выведен на шину TX. Во первых там ещё передается эн-ное кол-во stop бит, а во вторых из FIFO байт попадает в регистр передатчика и начинает выводиться, а FIFO или DMA уже пусто.
Проблемы с определением момента полного вывода символа на TX есть у всех простых MCU, даже если есть аппаратный флаг работы передатчика по занятости выводом - там обычно не входит время вывода stop бита. На ESP, при полудуплексе и работе на одну линию, решается зарядкой счетчика тайм-аута приема и переключением UART в режим Loopback при передаче. В данном режиме счетчик паузы на RX работает синхронно и выдает прерывание (и ставит флаг) после передачи последнего символа и указанной паузы в счетчике тишины на линии RX, который у ESP имеет единицы измерения "в попугаях", но достаточно быстрых - не менее 8 тиков на символ. Диапазон программирования счета счетчика тишины где-то от 2 -х до 128 точно, если не более (давно это было). Т.е. программируется на тишину менее одного символа и до пары десятков. У стандартных UART 16550 - счет выбирается в 1..8 символов тишины...
 
Последнее редактирование:

Алексей.

Active member
Нет - не так. Пустое FIFO не говорит о том, что символ выведен на шину TX. Во первых там ещё передается эн-ное кол-во stop бит, а во вторых из FIFO байт попадает в регистр передатчика и начинает выводиться, а FIFO или DMA уже пусто.
Да, но ведь нам известны правила, отсчитываем 1,5 байтных интервала и переключаемся на прием.
 

pvvx

Активный участник сообщества
Да, но ведь нам известны правила, отсчитываем 1,5 байтных интервала и переключаемся на прием.
Вперед это сделать на 3 мегабита и более. Ниже ныне никому не надо. На ESP в Modbus-TCP свалке корректно отрабатывает паузы и переключения до 1 мегабита.
У народа, работающего с MCU, проблемы как задать QSPI более 400MHz, а вы вcё в том веке? :)
На дворе USB3.1 - 10 Гбит/c, бытовой комп заливает на одиночный m.2 винчестер 2Гегабайта в сек, позволяя принимать десяток каналов с внешних MCU.
Даже если ограничиваться устаревшим WiFi с HT20 на ESP - то это 1 мегабайт в сек и ниже внешний интерфейс ему уже не интересен. Но из-за отсутствия DMA у ESP предел работы WiFi-UART на уровне 3 мегабита (а надо не ниже десятки для соответвия). Это пиковые, но если для них всё проработано, тогда всё что ниже потянет всегда и с нормальным качеством. Arduino на это не рассчитана - у неё предел "мигание светодиодом" и реализовывать на ней в "скече" уровень HAL, обходя глюки и фичи Arduino IDE писак никто не будет, т.к. это извращение. Надо было изначально писать правильные дрова на неё, но ... программисты вывелись, а остались только ... :) В итоге "дети" приучаются к пожиранию г...на и это распространяется на всё дальнейшее.
 
Последнее редактирование:

Алексей.

Active member
Вперед это сделать на 3 мегабита и более. Ниже ныне никому не надо. На ESP в Modbus-TCP свалке корректно отрабатывает паузы и переключения до 1 мегабита.
Не совсем ясна цель, если просто по ловить таймауты запретив прерывания, но надо четко представлять чем мы рискуем запретив прерывания, может просто высоко скоростной драйвер взять (если бюджет позволяет) который сам переключается.

Аналогия полу дуплекса с высокоскоростным QSPI понятна, надо ухитрится на низко производительном MCU успевать переключать SS
А такое вообще возможно?
 

pvvx

Активный участник сообщества
Не совсем ясна цель, если просто по ловить таймауты запретив прерывания, но надо четко представлять чем мы рискуем запретив прерывания, может просто высоко скоростной драйвер взять (если бюджет позволяет) который сам переключается.

Аналогия полу дуплекса с высокоскоростным QSPI понятна, надо ухитрится на низко производительном MCU успевать переключать SS
А такое вообще возможно?
Сказано же - работает в Modbus TCP / RTU RS-485 + WEB server уже давно...
Для нерадивых Modbus RS-485 устройств приходиться вставлять доп. задержки (тоже вписано в меню web). К нерадивым относится Owen и прочие китай-перепродавцы...
 

mcmega

Member
Бурные обсуждения, позновательно!)
Так скажите, с чего начать, какой подход, хоть теоретически, использовать?
А то обсуждать можно много, но хотелось бы что то попробовать и посмотреть как в железе будет.
 

Алексей.

Active member
Нет исходных данных.
В каких случаях avr посылает 0x13? Сколько еще байтов он может после этого принять?
Если хекс-формат текстовая строка из цифро-букв которую avr должен принять полностью и обработать, то после приема одной строки шлет ли avr 0х13 (подожди мол, мне нужно прошить данные) и после обработки шлет ли 0x11 (всё, я прошил, давай следующий)?
 

mcmega

Member
Обновил шапку и добавил исходные данные по работе с загрузчиком.
 

Алексей.

Active member
Ответ в правильно поставленном вопросе :)
Дожидаетесь XOn, отправляете только 128 байт, ведь только после заполнения буфера должны получить XOff, ожидайте XOff затем ожидайте Xon и снова отправляйте 128 байт.
Если длина записи не фиксированная, например hex строка заканчивается символами возврат каретки перевод строки, ожидайте XOff и XOn после отправки конца строки.
 

mcmega

Member
Ответ в правильно поставленном вопросе :)
Дожидаетесь XOn, отправляете только 128 байт, ведь только после заполнения буфера должны получить XOff, ожидайте XOff затем ожидайте Xon и снова отправляйте 128 байт.
Если длина записи не фиксированная, например hex строка заканчивается символами возврат каретки перевод строки, ожидайте XOff и XOn после отправки конца строки.
В том то и дело, принцип управления потоком будет единый, но количество передаваемых байт разное. Поэтому нужно отслеживать не после пачки 128Байт, а после каждого отосланного символа. Ответ MCU практически мгновенный при заполнении буфера. Я в перспективе хочу передавать bin файл, а не hex (он размером в 3 раза меньше). На все про все места не более 128К. Поэтому остается вариант отслеживания каждого отосланного байта и получение/неполучение ответа.
Поэтому я склоняюсь к использованию каких то механизмов определения переданности Байта и использования расчетных задержек с небольшим запасом.
 

Алексей.

Active member
В том то и дело, принцип управления потоком будет единый, но количество передаваемых байт разное. Поэтому нужно отслеживать не после пачки 128Байт, а после каждого отосланного символа. Ответ MCU практически мгновенный при заполнении буфера. Я в перспективе хочу передавать bin файл, а не hex (он размером в 3 раза меньше). На все про все места не более 128К. Поэтому остается вариант отслеживания каждого отосланного байта и получение/неполучение ответа.
Если после отправки XOff сам MCU не может принять ни одного байта, остается контролировать выход каждого байта, зная точный размер фифо (после инициализации уарта, пока ещё не отправили ни одного байта, запрашиваем Serial.availableForWrite, должен вернуть 128), после отправки очередного байта ожидаем пока Serial.availableForWrite опять не вернет максимальное значение (128 байт), затем отсчитываем 2 с небольшим байтных интервала, один на доставку нашего байта, один доставку XOff и ещё чуть чуть на принятие решения на MCU. Ваша задержка в 3ms именно это и делает, а Вы не хотите
тупить в цикле целых 3мс
 

mcmega

Member
Если после отправки XOff сам MCU не может принять ни одного байта, остается контролировать выход каждого байта, зная точный размер фифо (после инициализации уарта, пока ещё не отправили ни одного байта, запрашиваем Serial.availableForWrite, должен вернуть 128), после отправки очередного байта ожидаем пока Serial.availableForWrite опять не вернет максимальное значение (128 байт), затем отсчитываем 2 с небольшим байтных интервала, один на доставку нашего байта, один доставку XOff и ещё чуть чуть на принятие решения на MCU. Ваша задержка в 3ms именно это и делает, а Вы не хотите
Использование delay непозволительно в асинхронном сервере, нужно работать по флагам и состояниям. Глюки выплывают из-за этого.
 

Алексей.

Active member
Вас не устраивает ардуиновский delay, но это же Ваш выбор :)
Поясните пожалуйста - асинхроннй сервер в wifi программаторе это что?
 

mcmega

Member
Вас не устраивает ардуиновский delay, но это же Ваш выбор :)
Поясните пожалуйста - асинхроннй сервер в wifi программаторе это что?
На ESP помимо программатора работает Web сервер. Через него можно управлять устройством на MCU, обновлять прошивки, искать и подключаться к разным точкам доступа... Программатор - это часть проекта, но при желании его можно вынести как отдельное устройства.
 
Сверху Снизу