Jump to content

    
Sign in to follow this  
admiral

Гарантия того, что по USART все данные ушли

Recommended Posts

А кто как борется с коллизиями?

RXE всегда включен - это ясно.

При отправке байта пишем его в переменную типа:

volatile uint8_t RS485_last_sent;
//...............................................
UDR = RS485_last_sent = *rx_ptr++;

Прерывание от RX не выключается никогда.

Но можно нарваться на момент, когда прерывание RX не успело подхватить RS485_last_sent и сравнить его. Поскольку UDR буферизирован, прочтем старое принятое значение - и кирдык. Ложная реакция обеспечена.

Share this post


Link to post
Share on other sites
А кто как борется с коллизиями?
Если один мастер и "Команда мастера - ответ слэйва", то и бороться не нужно. А, другого - и не использую.

Share this post


Link to post
Share on other sites
А кто как борется с коллизиями?

Если имеется в виду исключение одновременного выхода на линию нескольких мастеров, то

1. Все слушают всех и не выходят в передачу, когда линия занята

2. После освобождения линии у каждого девайса СВОЙ таймаут выхода в передачу (с повторной проверкой свободности линии)

3. Для большей надежности можно завести прерывание по старт-биту (на переход в 0 сигнала на линии), по нему - таймаут на передачу байта-полутора, и если в заданный промежуток перепадов больше не пришло - линия свободна. UART контроллер при этом не задействован, и проблемы с буферированием исчезают

Share this post


Link to post
Share on other sites
Да и "тяжелость" определяется ещё и скоростью передачи, особенно на очень высоких скоростях (тут уж - как не облегчай прерывания, а при некотором числе высокоприоритетных прерываний они всё равно превращаются в "тяжелое").

Да все так, только давайте посмотрим что может бегать по 485-му:

 

В Modbus RTU например, который бегает по 485-му, недопустимы какие-то непрогнозируемые паузы между символами. Пауза больше чем 1.5 символа по стандарту является поводом для отбраковки всего пакета!

Чтобы получить несвоевременный TXC, обработка UDRE должна опоздать аж на 2 символа! Т.е. межсимвольная пауза в системе где может случайно вылезти TXC посреди пакета - может достигать 2х символов. Как следствие этого - работа в Modbus RTU протоколе становится невозможной впринципе в такой системе.

 

Что делать? Отказаться от RTU? - нельзя, причины сами знаете.

 

Поэтому обработчики более выскоприоритетных прерываний строятся так, чтобы была гарантия отработки более низкоприоритетных во-время. Если не получается это сделать на одном AVR, тогда ставится еще один чип в помощь, либо берется другой МК, т.к. заранее известно, что система без этого захлебнется.

 

PS: С очень высокими скоростями по UART'у на AVRках не работаю - 115200 макс.

AVRки у меня всегда не ниже 11.059 тактируются, в основном 14.7456.

Share this post


Link to post
Share on other sites
admiral,

если "правильность" софта не пугает и это будет временной мерой, то достаточно будет перед засыпанием установить задержку в виде N*2 холостых циклов. где N - это к-во тактов необходимые для отправки одного байта по USART. а умножаем на 2, т к у USART'а двойная буферизация.

 

глупее не бывает, но вроде как временная мера сойдет

Я так и сделал - установил задержку 2мс перед засыпанием и стало все нормально.

Просто мучал меня этот вопрос т.к. нерационально получается - вдруг когда-то придется использовать USART не только для отладки. Да и думал может в документации ошибка закралась, т.к. не пойму почему не сделали сброс флага TXC при занесении данных в UDR.

Share this post


Link to post
Share on other sites
Я так и сделал - установил задержку 2мс перед засыпанием и стало все нормально.

Просто мучал меня этот вопрос т.к. нерационально получается - вдруг когда-то придется использовать USART не только для отладки. Да и думал может в документации ошибка закралась, т.к. не пойму почему не сделали сброс флага TXC при занесении данных в UDR.

Сбрасывать флаг прерывания должно только прерывание, иначе разрушится мир :) Затраты на сброс флага невелики - если прерывание разрешено, это время на 2 загрузки адреса + 1 такт на reti. Если же флаг сбрасывать при загрузке UDR, то вы не сможете отследить те самые разрывы между байтами, которые могут быть критичны.

 

Вам нужно вместо задержки 2 мс поставить ожидание флага TXC, его сброс (записью в TXC единицы!) и можно засыпать. Прерывание TXC должно быть запрещено (бит TXCIE =0), чтобы флаг TXC стоял не сбрасывался.

Share this post


Link to post
Share on other sites
Если же флаг сбрасывать при загрузке UDR, то вы не сможете отследить те самые разрывы между байтами, которые могут быть критичны.

А что мешает отслежить состояние флага перед записью в UDR?

Share this post


Link to post
Share on other sites
В Modbus RTU например, который бегает по 485-му, недопустимы какие-то непрогнозируемые паузы между символами. Пауза больше чем 1.5 символа по стандарту является поводом для отбраковки всего пакета!
Вы забыли упомянуть ещё о такой особенности таймаутов Modbus RTU:
#define MB_MIN_15T_TIMEOUT              MB_SEC_TO_TCNT_TIC( 0.000750f ) // 750 us    if bps>19200
#define MB_MIN_35T_TIMEOUT              MB_SEC_TO_TCNT_TIC( 0.001750f ) // 1.750 ms  if bps>19200

Я её использую.

Раз уж пошёл разговор про Modbus RTU, то хочу спросить кто как обеспечивает гарантию паузы 3,5T меду пакетами?

Я всегда отправляю преамбулу из 4 dummy байтов с отключенным передатчиком драйвера RS485.

Какие у Вас соображения на сей счёт? Может это лишняя паранойя, ведь я и так отлавливаю конец посылки по паузе?

Share this post


Link to post
Share on other sites
кто как обеспечивает гарантию паузы 3,5T между пакетами?

Никакая не паранойя - можно позволить УАРТУ за счет собственных средств не только разделять пакеты при передаче, но и обнаруживать паузу при приеме, отсылая также пустые фреймы.

Share this post


Link to post
Share on other sites

А я вот всё больше и больше склоняюсь к тому что это лишне.

Будь я slave или master, я ловлю конец посылки по паузе в 3,5Т ВСЕГДА - это ведь и есть гарантия разделения пакетов.

Так что слейв может отвечать немедленно без преамбулы сразу по факту получения пакета.

ИМХО. Я сейчас поэкспериментирую.

Share this post


Link to post
Share on other sites
Я всегда отправляю преамбулу из 4 dummy байтов с отключенным передатчиком драйвера RS485.

Такой подход имеет смысл применять тогда, когда мастер отправляет несколько broadcast сообщений (address 0x00 / 0xFF) подряд, не дожидаясь ни от кого ответа. Настройка системы, синхронизация времени, старт синхро-измерения и т.п.

Во всех остальных случаях - достаточно факта определения конца посылки по паузе в 3,5Т, и мастеру и слейвам.

 

Но на мой взгляд отправка 4х dummy байтов с отключенным передатчиком ломает всю "тупизну и прямолинейность" :) драйвера UART'a. Если без этого действует простейший алгоритм:

 

- включить передатчик

- отправить символ

- выключить передатчик если TXC.

 

то в случае с преамбулой будут варианты.

Share this post


Link to post
Share on other sites
Никакая не паранойя - можно позволить УАРТУ за счет собственных средств не только разделять пакеты при передаче, но и обнаруживать паузу при приеме, отсылая также пустые фреймы.
Поясните если не трудно про: "обнаруживать паузу при приеме, отсылая также пустые фреймы". Интересно...

Share this post


Link to post
Share on other sites

Что ж тут непонятного. Время на передачу байта фиксированное. Оно и используется в качестве таймера. А байт дальше драйвера 485 не уйдет.

На быcтрую руку примерно так:

По RxC: UDR = dummy; TimeOut = 0;

По TxC: if (++TimeOut <= N) {UDR = dummy;} else {DoOnTimeOut}

N, по моему, должен быть равен 4.

таким образом обнаруживается пауза > (4T...5T) (т.е. не факт, что пауза 4,5Т будет обнаружена)

 

P.S. Можно в качестве dummy-байта взять 0x0F. ТОгда получим фронт в середине байта на 0,5Т. И выход Tx завести на прерывание (по фронту). ТОгда можно будет обнаруживать паузы > (3,5Т...4,5Т). Но надо ли? :laughing:

Share this post


Link to post
Share on other sites
ТОгда получим фронт в середине байта на 0,5Т.

Вы ж не забывайте, что длительности в 1,5 и 3,5 Т выбирались исходя их соображений накрыть всех "опоздавших" и "неуспевающих" однозначным событием разделения данных. Имхо, если внутри распознается соответственно 2 и 4 Т, ничего страшного и "роняющего перфоманс" не происходит. Проще надо быть с модбасом :)

Share this post


Link to post
Share on other sites
Проще надо быть с модбасом :)

Товарищи! Возник у меня ещё один вопрос про modbus.

Хотелось бы узнать какие-нибудь элегантные способы решения проблемы поддержания функционирования стандартных функций чтения-записи регистров и коилов в контексте 8-ми битного little-endian MCU.

Я решаю сейчас данную закавыку через remap-таблицу во FLASH.

Она зараза большая становится, когда много данных нужно ремапить, да и нудно её редактировать (хоть всё уже и так через макросы зафигачено).

Я уже и так и сяк, но ничего другого выдумать не могу. Прошу ALL не стеснятся и высказывать любые здравые предложения! Спасибо!

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this