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

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

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

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

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

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

 

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

 

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

admiral,

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

 

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 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.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

кто как обеспечивает гарантию паузы 3,5T между пакетами?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

 

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

 

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

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

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что ж тут непонятного. Время на передачу байта фиксированное. Оно и используется в качестве таймера. А байт дальше драйвера 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:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ТОгда получим фронт в середине байта на 0,5Т.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проще надо быть с модбасом :)

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...