Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Гарантия того, что по USART все данные ушли
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Страницы: 1, 2
admiral
Здравствуйте, не могли бы вы разъяснить такую ситуацию?
Перед входом в спящий режим мне нужно убедиться, что все данные ушли в линию. Для этого есть флаг ТХС. В даташите сказано:
Флаг устанавливается в 1 после передачи всех битов посылки из сдвигового регистра передатчика при условии, что в регистр данных UDR не было загружено новое значение. Флаг сбрасывается аппаратно при выполнении подпрограммы обработки прерывания или программно, записью в него лог. 1

Прерываний я не активировал, т.е. получается что после первой передачи, когда данные ушли, и в буфер я данных для отсылки не заносил, этот флаг установится в 1 и больше никогда не сбросится?
Если да, то получается, что после каждой передачи мне нужно программно сбрасывать этот бит?
Rst7
Цитата
Если да, то получается, что после каждой передачи мне нужно программно сбрасывать этот бит?


По науке - перед последней передачей. Если байты могут передаваться с задержкой между ними, то перед передачей последнего байта.
admiral
Цитата(Rst7 @ Jan 14 2010, 14:45) *
По науке - перед последней передачей. Если байты могут передаваться с задержкой между ними, то перед передачей последнего байта.

Спасибо, а если неизвестно последний это байт или нет? Тогда придется каждый раз сбрасывать этот бит перед посылкой очередного байта?
Rst7
Цитата
Спасибо, а если неизвестно последний это байт или нет?


Если неизвестно, то смысл тогда знания, что байт отправлен и можно спать?
Палыч
Цитата(Rst7 @ Jan 14 2010, 13:45) *
По науке - перед последней передачей. Если байты могут передаваться с задержкой между ними, то перед передачей последнего байта.
Можно словить "косяка", если между сбросом ТХС и загрузкой в UDR последнего байта закончилась передача байта из сдвигового регистра, а UDR был пуст... Выкручивался из этой ситуации сбросом TХC после загрузки последнего байта в UDR при закрытых прерываниях (между загрузкой и сбросом), при условии малой скорости передачи.

Цитата(admiral @ Jan 14 2010, 14:29) *
Спасибо, а если неизвестно последний это байт или нет? Тогда придется каждый раз сбрасывать этот бит перед посылкой очередного байта?
Вам, ведь, нужно убедиться, что все данные ушли в линию, значит - Вы знаете: последний байт или нет.
Rst7
Цитата
Выкручивался из этой ситуации сбросом TХC после загрузки последнего байта в UDR при закрытых прерываниях (между загрузкой и сбросом), при условии малой скорости передачи.


Безусловно, смысл в таком действии есть. Но уж лучше подходить с позиций изначально правильного проектирования софта, дабы на такие грабли не наступать smile.gif
Палыч
Цитата(Rst7 @ Jan 14 2010, 14:49) *
Но уж лучше подходить с позиций изначально правильного проектирования софта, дабы на такие грабли не наступать
Имхо, такие извращения - не результат неправильного проектирования софта, а результат неправильного проектирования аппаратуры USART: бит ТХС следовало бы, наверное, аппаратно сбрасывать при зазрузке байта в UDR.
Кстати, всегда интересовало: как другие разработчики определяют окончание передачи (это актуально при использовании RS-485: включение/отключение приёмника) при использовании прерываний и записи байта по освобождению UDR.
defunct
Цитата(Палыч @ Jan 14 2010, 14:07) *
Кстати, всегда интересовало: как другие разработчики определяют окончание передачи (это актуально при использовании RS-485: включение/отключение приёмника) при использовании прерываний и записи байта по освобождению UDR.

Не знаю как другие, но я - исключительно по прерыванию TXC от USART. Потому что:
Цитата
Флаг сбрасывается аппаратно при выполнении подпрограммы обработки прерывания

На кой ляд анализировать какой-то флаг, когда есть TXC event, который аппаратно управляет флагом.
V_G
На мой взгляд, как раз широкое использование прерываний и является одним из признаков грамотного проектирования софта.
В данном случае при передаче последнего символа в обработке прерывания DRE я запрещаю прерывание DRE и разрешаю TXC, а по приходу последнего окончательно завершаю передачу (иногда и запрещаю для перевода ноги в высокий импеданс)
Rst7
Цитата
На мой взгляд, как раз широкое использование прерываний и является одним из признаков грамотного проектирования софта.


Тут немного не в том дело. Если задумана непрерывная передача пакета, а, например, процессор может оказаться занят в интервале между передачей двух байт чем-то другим и не успеет записать в UDR, то зопа произойдет в любом случае, хоть прерывание, хоть poll. Вот что я имею в виду под неправильным проектированием.
admiral
Объясню ситуацию:
делаю устройство, т.к. питаться оно будет от батарей, то приходится экономить энергию вводя в спящий режим контроллер.
Для отладки использую usart, по нему контроллер передает в комп информацию что он в данный момент делает.
И вот была у меня беда - контроллер в ком-порт выдавал какой-то мусор вместо членораздельных фраз. Бился я бился над этим пока не попробовал отрубить вход в спяшщий режим.
В результате оказалось, что контроллер засыпал не успев отправить кусокпоследнего байта. Когда же он просыпался - то досылал оставшийся кусок и за ним новые данные.
Начал рыть документацию - оказывается, что флаг UDRE - указывает только на то, что контроллер готов принять новую порцию данных для отсылки, но не гарантирует, что данные уже отправлены.
Прерывания я не использую, поэтому флаг TXC сам не сбросится. Придется его сбрасывать программно.
И вот вопрос: контроллеру нужно заснуть, как убедится, что все данные отосланы? Будет ли нормально, если я перед каждой посылкой байта (неважно последний он или нет) буду сбрасывать этот флаг?
Не пойму почемуони не сделали, что бы, к примеру, при записи данных в UDR флаг TXC сбрасывался аппаратно?
Палыч
Цитата(defunct @ Jan 14 2010, 15:33) *
Не знаю как другие, но я - исключительно по прерыванию TXC от USART.
Это-то - понятно. Интересует: как у Вас устроена программа, что по этому прерыванию Вы гарантировано знаете, что все байты переданы? Поясню свой вопрос на примере "неправильного" софта (который такой гарантии не даёт, ну, или не во всех случаях):
1. Данные загружаются в UDR по прерыванию USART Data Register Empty
2. Перед загругкой последнего байта сбрасывается флаг TXC; последний байт загружается в UDR; разрешаются прерывания от USART Tx Complete
3. Наступает прерывание по TXC - считаем, что все байты переданы, что не всегда верно (см. выше - сообщение #5).

Цитата(admiral @ Jan 14 2010, 15:57) *
И вот вопрос: контроллеру нужно заснуть, как убедится, что все данные отосланы? Будет ли нормально, если я перед каждой посылкой байта (неважно последний он или нет) буду сбрасывать этот флаг?
Это - не повредит...
Цитата(admiral @ Jan 14 2010, 15:57) *
Не пойму почему они не сделали, что бы, к примеру, при записи данных в UDR флаг TXC сбрасывался аппаратно?
И я тоже этому в своё время был очень удивлён
V_G
Посмотрел на симуляторе - у меня флаг TXC сброшен ПОСТОЯННО. Возможно, потому, что передатчик запрещен постоянно и разрешается только, когда надо что-то передать. При разрешении передачи (и прерываний DRE, TXC) сразу возникает прерывание DRE, а TXC дергаться и не думает, и никогда в жизни я его программно не сбрасывал.

А передавать байты с большими паузами, что TXC успевает дернуться - это что за задача такая? Я формирую передающий буфер до начала передачи, в результате передача посылки идет непрерывно. И медленно в масштабе времени процессора, так что паузам просто неоткуда взяться!

Да, и еще признаки грамотно спроектированного сорта - минимальное прерывание проца внутри обработки прерываний и минимальная длительность участков запрещения прерываний. Вот тут уж паузам действительно неоткуда взяться, смело используйте TXC для фиксации окончания посылки.
Qwertty
Цитата(Палыч @ Jan 14 2010, 16:04) *
Поясню свой вопрос на примере "неправильного" софта (который такой гарантии не даёт, ну, или не во всех случаях):
1. Данные загружаются в UDR по прерыванию USART Data Register Empty
2. Перед загругкой последнего байта сбрасывается флаг TXC; последний байт загружается в UDR; разрешаются прерывания от USART Tx Complete
3. Наступает прерывание по TXC - считаем, что все байты переданы, что не всегда верно (см. выше - сообщение #5).

Поменяйте в пункте 2 "Перед загрузкой" на "сразу после загрузки" и получите свою гарантию.
Я не то что сбрасываю TXC, но и само это прерывание разрешаю именно внутри прерывания от UDRIE после загрузки последнего байта.
Палыч
Цитата(Rst7 @ Jan 14 2010, 15:48) *
Тут немного не в том дело. Если задумана непрерывная передача пакета, а, например, процессор может оказаться занят в интервале между передачей двух байт чем-то другим и не успеет записать в UDR, то зопа произойдет в любом случае, хоть прерывание, хоть poll. Вот что я имею в виду под неправильным проектированием.

Цитата(V_G @ Jan 14 2010, 16:31) *
А передавать байты с большими паузами, что TXC успевает дернуться - это что за задача такая? Я формирую передающий буфер до начала передачи, в результате передача посылки идет непрерывно. И медленно в масштабе времени процессора, так что паузам просто неоткуда взяться!
Да, и еще признаки грамотно спроектированного сорта - минимальное прерывание проца внутри обработки прерываний и минимальная длительность участков запрещения прерываний. Вот тут уж паузам действительно неоткуда взяться, смело используйте TXC для фиксации окончания посылки.
Задача, на которой у меня возникли такие проблемы - простая: передавать данные по RS-485 со скоростью 2Мбод (конечно, не только передавать, но и снимать информацию с датчиков, отрабатывать..). Даже с минимумом действий внутри обработчиков прерываний - не всегда можно успеть положить вовремя байт в UDR (прерывание по UDRE имеет невысокий приоритет, а механизма изменить приоритет в AVR - нет).
Как уже выше писал: решил проблему сбросом TXC после выдачи байта в UDR.

Цитата(Qwertty @ Jan 14 2010, 16:42) *
Поменяйте в пункте 2 "Перед загрузкой" на "сразу после загрузки" и получите свою гарантию. Я не то что сбрасываю TXC, но и само это прерывание разрешаю именно внутри прерывания от UDRIE после загрузки последнего байта.
Значит, не один я так делаю. Почему же советы: "перед выдачей - сбросьте ТХС"?
Qwertty
Цитата(Палыч @ Jan 14 2010, 16:48) *
Значит, не один я так делаю. Почему же советы: "перед выдачей - сбросьте ТХС"?

Думаю так делают все, кто работает с RS485. Я правда использую намного более низкие скорости 19200-38400, так что и по прерываниям все получается неплохо. Но и при 2-х мегабитах интервал передачи байта 80 тактов, так что если в критическую секцию обернуть и выдачу в UDR и сброс TXC, все должно работать нормально.
_Pasha
Цитата(Палыч @ Jan 14 2010, 17:04) *
1. Данные загружаются в UDR по прерыванию USART Data Register Empty
2. Перед загругкой последнего байта сбрасывается флаг TXC; последний байт загружается в UDR; разрешаются прерывания от USART Tx Complete
3. Наступает прерывание по TXC - считаем, что все байты переданы, что не всегда верно (см. выше - сообщение #5).


1. Иниц. указателя и счетчика байт
2. Разрешение UDRIE
Код
volatile uint8_t *tx_ptr;
volatile uint8_t tx_cnt;
void new_xmit(void *buff, uint8_t len)
{
  tx_ptr = buff;
  tx_cnt = len;
  UCSRB |= (1<<UDRIE);
}


3. Прерывание подхватывает поток: (GCC)
Код
// ATOMIC_BLOCK(ATOMIC_RESTORESTATE){
UDR= *tx_ptr++;
UCSRA &= ~(1<<TXC);
//}
if(--tx_cnt==0)
{
  UCSRB &= ~(1<<UDRIE);
  UCSRB |= (1<<TXCIE);
}


4. Программа смотрит, разрешено ли прерывание UDRE или TXC в зависимости от того что надо.

Если используем неблокирующие прерывания, приходится применять критическую секцию. laughing.gif

Если надо непрерывную передачу, контроль правильности/непрерывности можно сделать проверкой TXC перед передачей.
ILYAUL
Цитата(admiral @ Jan 14 2010, 15:57) *
И вот вопрос: контроллеру нужно заснуть, как убедится, что все данные отосланы? Будет ли нормально, если я перед каждой посылкой байта (неважно последний он или нет) буду сбрасывать этот флаг?
Не пойму почемуони не сделали, что бы, к примеру, при записи данных в UDR флаг TXC сбрасывался аппаратно?

Если взглюнуть на структурную схему USART можно увидеть , что флаг TXC установиться при условии , что установлен флаг UDR и закончена передача байта , собственно он и сигнализирует о том , что сдвиговый регистр пуст и новых данных в буфере передачи нет . А , что Вы будете делать с ним дальше - значение не имеет , можете сбросить , записав единицу и уйти спать
defunct
Цитата(admiral @ Jan 14 2010, 14:57) *
Прерывания я не использую, поэтому флаг TXC сам не сбросится. Придется его сбрасывать программно.

или придется начать использовать прерывания.
SysRq
Цитата(admiral @ Jan 14 2010, 15:57) *
Объясню ситуацию...
Сделайте отправку целиком по TXC, без UDRE. При отправке данных в цикле и по флагам, по-моему, ничуть не тормознее получится, и гарантированно отправите данные...
defunct
Цитата(Палыч @ Jan 14 2010, 15:04) *
Это-то - понятно. Интересует: как у Вас устроена программа, что по этому прерыванию Вы гарантировано знаете, что все байты переданы?

Ваш изначальный вопрос касался 485-го. Так вот в контексте 485-го все держится на модели "запрос-ответ". Драйверу UARTа попросту не дается следующий __пакет__ до тех пор пока нас об этот не попросят, либо до тех пор пока нам не ответят, либо до тех пор пока не завершится таймаут.

Из этого построение программы такое:
Есть кольцевой буфер и есть put() который пишет в этот буфер. TXC прерывание разрешено постоянно и управляет направлением трансивера 485-го. (По TXC драйвер переключается на прием.) Флаг TXC руками не трогается никогда.

В буфер помещается отправляемый пакет. Перед записью в UDR делается переключение трансивера 485 на передачу.. По UDRE - вычитка и отправка следующего байта из буфера.

В системе нет настолько тяжелых обработчиков прерываний чтобы UDRE прерывание откладывалось настолько долго, что за это время могло возникнуть TXC прерывание, (суммарная латентность всех прерываний не превышает интервала одного символа UART'а). Поэтому все прекрасно работает.
_Pasha
Цитата(defunct @ Jan 14 2010, 22:08) *
Флаг TXC руками не трогается никогда.

В системе нет настолько тяжелых обработчиков прерываний чтобы UDRE прерывание откладывалось настолько долго, что за это время могло возникнуть TXC прерывание, (суммарная латентность всех прерываний не превышает интервала одного символа UART'а). Поэтому все прекрасно работает.

Вот я - не понимаю:
1) откуда берется священная корова непрерывности данных в пакете, без тайм-аутов.
2) для чего TXC прерывание все время держать разрешенным.
Объясните, пожалуйста
Maik-vs
RS485, скорости до 115200. Делаю так же: формирую сообщение в буфере, переключаю на передачу, записываю первый байт в UDR. Дальше работают только прерывания: UDRE досыпает следующий байт, TXC переключает интерфейс на приём.

Как я узнаю, что все байты ушли? А как я знаю, сколько байтов передавать? По счётчику! Пока он больше 0 (или, если строка ASCIIZ байт данных не равен 0) работаем на передачу. Я успеваю это делать в прерывании UDRE. Если бы не успевал, проверил бы счётчик и в TXC, пока не переключил на приём.
defunct
Цитата(_Pasha @ Jan 14 2010, 20:53) *
1) откуда берется священная корова непрерывности данных в пакете, без тайм-аутов.

application драйверу его так передает. Я так строю программу и гарантирую эту непрерывность.

Цитата
2) для чего TXC прерывание все время держать разрешенным.

А зачем его смыкать туда-сюда, код раздувать? Один раз при настройке уарта разрешили и забыли о нем вообще.
Ведь все что оно делает, это:

__interrupt void uart_TxCompleteHandler(void)
{
#if (UART0_RS485)
// handle 485 driver direction
PortX &= ~(1 << RS485_REDE_Pin);
#endif
}
HALFer
admiral,
если "правильность" софта не пугает и это будет временной мерой, то достаточно будет перед засыпанием установить задержку в виде N*2 холостых циклов. где N - это к-во тактов необходимые для отправки одного байта по USART. а умножаем на 2, т к у USART'а двойная буферизация.

глупее не бывает, но вроде как временная мера сойдет
Qwertty
Цитата(defunct @ Jan 14 2010, 22:37) *
А зачем его смыкать туда-сюда, код раздувать? Один раз при настройке уарта разрешили и забыли о нем вообще.

Если есть возможность прогнозировать приход прерываний, то это работает. Если же нет, то RS485 идет в лес. sad.gif
А ведь есть более приоритетные, нежели от UDRE, прерывания - INTx, абсолютно асинхронные. Тут прогнозы не всегда работают.

Цитата(defunct @ Jan 14 2010, 22:37) *
Ведь все что оно делает, это:
__interrupt void uart_TxCompleteHandler(void)
{
#if (UART0_RS485)
// handle 485 driver direction
PortX &= ~(1 << RS485_REDE_Pin);
#endif
}

А добавить туда еще проверку счетчика байт и проблема тоже решится. Не все передали - выходим из прерывания без переключения направления драйвера. ИМХО тоже вариант.
SysRq
Цитата(_Pasha @ Jan 14 2010, 21:53) *
1) откуда берется священная корова непрерывности данных в пакете, без тайм-аутов.
Один из вариантов - канал RS-485 без растяжек (+ к питанию, - к земле). Если все абоненты молчат, то состояние линии не определено, и от помех появляется мусор, успешно принимающийся МК. Поэтому во время передачи пакета на приём переключаться нельзя до окончания передачи всего пакета ;(
Также, если более чем один мастер в канале...
_Pasha
Цитата(SysRq @ Jan 15 2010, 10:45) *
Если все абоненты молчат, то состояние линии не определено, и от помех появляется мусор, успешно принимающийся МК. Поэтому во время передачи пакета на приём переключаться нельзя до окончания передачи всего пакета ;(

Вы неверно представляете этот вариант. Или я smile.gif
Объясняю своими словами:
Если передающий встал на передачу, и между символами будет пауза, то эта пауза - не повод отключать TXE, если это все в пределах наперед заданного тайм-аута. Какого именно? Такого, чтобы в наихудшем случае программа успевала отослать данные. В этом случае мусор в линию не валится и на приемнике имеем красивый "1".
SysRq
Цитата(_Pasha @ Jan 15 2010, 10:48) *
Объясняю своими словами...
Ммм.. да, я под непрерывностью имел в виду именно это smile.gif
Палыч
Цитата(defunct @ Jan 14 2010, 21:08) *
В системе нет настолько тяжелых обработчиков прерываний чтобы UDRE прерывание откладывалось настолько долго, что за это время могло возникнуть TXC прерывание, (суммарная латентность всех прерываний не превышает интервала одного символа UART'а). Поэтому все прекрасно работает.
Это - хорошо, когда нет тяжелых прерываний... "Тяжесть" - штука относительная. Число "лёгких" прерываний с приоритетом выше чем у USART может быть достаточно для того, чтобы в сумме они составили "одно тяжелое". Да и "тяжелость" отпределяет ещё и скоростью передачи, особенно на очень высоких скоростях (тут уж - как не облегчай прерывания, а при некотором числе высокоприоритетных прерываний они всё равно превращаются в "тяжелое").
_Pasha
А кто как борется с коллизиями?
RXE всегда включен - это ясно.
При отправке байта пишем его в переменную типа:
Код
volatile uint8_t RS485_last_sent;
//...............................................
UDR = RS485_last_sent = *rx_ptr++;

Прерывание от RX не выключается никогда.
Но можно нарваться на момент, когда прерывание RX не успело подхватить RS485_last_sent и сравнить его. Поскольку UDR буферизирован, прочтем старое принятое значение - и кирдык. Ложная реакция обеспечена.
Палыч
Цитата(_Pasha @ Jan 15 2010, 12:23) *
А кто как борется с коллизиями?
Если один мастер и "Команда мастера - ответ слэйва", то и бороться не нужно. А, другого - и не использую.
V_G
Цитата(_Pasha @ Jan 15 2010, 19:23) *
А кто как борется с коллизиями?

Если имеется в виду исключение одновременного выхода на линию нескольких мастеров, то
1. Все слушают всех и не выходят в передачу, когда линия занята
2. После освобождения линии у каждого девайса СВОЙ таймаут выхода в передачу (с повторной проверкой свободности линии)
3. Для большей надежности можно завести прерывание по старт-биту (на переход в 0 сигнала на линии), по нему - таймаут на передачу байта-полутора, и если в заданный промежуток перепадов больше не пришло - линия свободна. UART контроллер при этом не задействован, и проблемы с буферированием исчезают
defunct
Цитата(Палыч @ Jan 15 2010, 10:12) *
Да и "тяжелость" определяется ещё и скоростью передачи, особенно на очень высоких скоростях (тут уж - как не облегчай прерывания, а при некотором числе высокоприоритетных прерываний они всё равно превращаются в "тяжелое").

Да все так, только давайте посмотрим что может бегать по 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
Цитата(HALFer @ Jan 15 2010, 00:35) *
admiral,
если "правильность" софта не пугает и это будет временной мерой, то достаточно будет перед засыпанием установить задержку в виде N*2 холостых циклов. где N - это к-во тактов необходимые для отправки одного байта по USART. а умножаем на 2, т к у USART'а двойная буферизация.

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

Я так и сделал - установил задержку 2мс перед засыпанием и стало все нормально.
Просто мучал меня этот вопрос т.к. нерационально получается - вдруг когда-то придется использовать USART не только для отладки. Да и думал может в документации ошибка закралась, т.к. не пойму почему не сделали сброс флага TXC при занесении данных в UDR.
Maik-vs
Цитата(admiral @ Jan 18 2010, 10:31) *
Я так и сделал - установил задержку 2мс перед засыпанием и стало все нормально.
Просто мучал меня этот вопрос т.к. нерационально получается - вдруг когда-то придется использовать USART не только для отладки. Да и думал может в документации ошибка закралась, т.к. не пойму почему не сделали сброс флага TXC при занесении данных в UDR.

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

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

А что мешает отслежить состояние флага перед записью в UDR?
demiurg_spb
Цитата(defunct @ Jan 15 2010, 14:54) *
В 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.
Какие у Вас соображения на сей счёт? Может это лишняя паранойя, ведь я и так отлавливаю конец посылки по паузе?
_Pasha
Цитата(demiurg_spb @ Jan 21 2010, 15:10) *
кто как обеспечивает гарантию паузы 3,5T между пакетами?

Никакая не паранойя - можно позволить УАРТУ за счет собственных средств не только разделять пакеты при передаче, но и обнаруживать паузу при приеме, отсылая также пустые фреймы.
demiurg_spb
А я вот всё больше и больше склоняюсь к тому что это лишне.
Будь я slave или master, я ловлю конец посылки по паузе в 3,5Т ВСЕГДА - это ведь и есть гарантия разделения пакетов.
Так что слейв может отвечать немедленно без преамбулы сразу по факту получения пакета.
ИМХО. Я сейчас поэкспериментирую.
defunct
Цитата(demiurg_spb @ Jan 21 2010, 13:10) *
Я всегда отправляю преамбулу из 4 dummy байтов с отключенным передатчиком драйвера RS485.

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

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

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

то в случае с преамбулой будут варианты.
demiurg_spb
Цитата(_Pasha @ Jan 21 2010, 14:32) *
Никакая не паранойя - можно позволить УАРТУ за счет собственных средств не только разделять пакеты при передаче, но и обнаруживать паузу при приеме, отсылая также пустые фреймы.
Поясните если не трудно про: "обнаруживать паузу при приеме, отсылая также пустые фреймы". Интересно...
Александр Куличок
Что ж тут непонятного. Время на передачу байта фиксированное. Оно и используется в качестве таймера. А байт дальше драйвера 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.gif
_Pasha
Цитата(Александр Куличок @ Jan 23 2010, 00:18) *
ТОгда получим фронт в середине байта на 0,5Т.

Вы ж не забывайте, что длительности в 1,5 и 3,5 Т выбирались исходя их соображений накрыть всех "опоздавших" и "неуспевающих" однозначным событием разделения данных. Имхо, если внутри распознается соответственно 2 и 4 Т, ничего страшного и "роняющего перфоманс" не происходит. Проще надо быть с модбасом smile.gif
demiurg_spb
Цитата(_Pasha @ Jan 23 2010, 08:02) *
Проще надо быть с модбасом smile.gif

Товарищи! Возник у меня ещё один вопрос про modbus.
Хотелось бы узнать какие-нибудь элегантные способы решения проблемы поддержания функционирования стандартных функций чтения-записи регистров и коилов в контексте 8-ми битного little-endian MCU.
Я решаю сейчас данную закавыку через remap-таблицу во FLASH.
Она зараза большая становится, когда много данных нужно ремапить, да и нудно её редактировать (хоть всё уже и так через макросы зафигачено).
Я уже и так и сяк, но ничего другого выдумать не могу. Прошу ALL не стеснятся и высказывать любые здравые предложения! Спасибо!
_Pasha
Цитата(demiurg_spb @ Jan 29 2010, 21:26) *
Она зараза большая становится, когда много данных нужно ремапить, да и нудно её редактировать (хоть всё уже и так через макросы зафигачено).

1. Написать приблуду и работать с Ёкселем в формате *.csv
2. Проблема, кстати, сходная с созданием таблицы редактирования/доступа к параметрам: зоопарк валидаторов, read-only/write-only/rw, источник или приемник данных (функция/ОЗУ/eeprom/flash), clear after use...

Код
typedef struct
{
// неявное задание правил доступа RO WO RW - метод == NULL
size_t (*read)(void *src, size_t size);//если результат != заданному size, то ашипко
size_t (*write)(void *dst, void *src, size_t size);
} data_src_stream_t;

typedef struct
{
uint16_t log_addr;
void      *phy_addr;
void *validator; // там же хранится инфа о размере
void *stream;
} remap_tbl_t;
//........................................
struct Valid32_cnt //пример
{
  uint8_t size;// всегда первым байтом пойдет как тэг
  uint32_t low;
  uint32_t high;
} pause_tmr={4,120000,240000};

Про coil_read() или coil_write()
Иногда проще все уложить в switch(), но лучше imho избавляться от двухбайтового оверхеда.
Если нехватка флеша на таблицу - приходится все паковать в битовые поля.
Код
typedef struct
{
uint16_t log_addr;
void      *phy_addr;

uint8_t mate;// многоцелевой индекс - все, что не отображается в полях, потом делается через switch(remap.mate)

unsigned size:2;// elem size
unsigned pool:4;// register pool
unsigned perm_rd:1;
unsigned perm_wr:1;
} remap_t;


Вот видите - у меня тот же бардак smile.gif
demiurg_spb
Цитата(_Pasha @ Jan 30 2010, 06:05) *
1. Написать приблуду и работать с Ёкселем в формате *.csv
Тоже об этом думал, но пока что-то останавливает.
Цитата
2. Проблема, кстати, сходная с созданием таблицы редактирования/доступа к параметрам: зоопарк валидаторов, read-only/write-only/rw, источник или приемник данных (функция/ОЗУ/eeprom/flash), clear after use...
Схожая да не совсем. К параметрам меню не обращаются как к "raw big-endian 16-bit data", и не пытаются читать потоком данные например float или DWORD или BYTE или BIT. И "самое страшное" что могут обратится лишь к младшему или старшему полуслову float или DWORD, а про массивы я вообще молчу:-) И про то, что есть 5 отдельных адресных пространств SRAM, FLASH, EEPROM, DATAFLASH, RTC. Мама помоги!!!! Пока я это всё делал чуть не тронулся умом;-) А всё из-за этого &%@# modbus (нехорошего в общем и целом).
С меню у меня всё достаточно красиво получилось (писал на Си в "стиле С++", некое наследование путём включения базового типа menu_item_t во всех потомков, ну и таки да, реализация методов доступа через switch (item_type) - так компактнее получилось, структуры практически без callback'ов). Написал макросы для ассигнования этих типов и всё получилось читабельно и вменяемо (хоть работы проделано немало).
Цитата
Вот видите - у меня тот же бардак smile.gif
Ага, нормально:-)
_Pasha
Цитата(demiurg_spb @ Jan 30 2010, 13:46) *
И про то, что есть 5 отдельных адресных пространств ... Мама помоги!!!!

Поток ввода/вывода - это мама? или папа? smile.gif
demiurg_spb
Цитата(_Pasha @ Jan 31 2010, 08:24) *
Поток ввода/вывода - это мама? или папа? smile.gif
Они родимые:-)
Maik-vs
Цитата(Александр Куличок @ Jan 21 2010, 01:47) *
А что мешает отслежить состояние флага перед записью в UDR?

Если паузы между байтами недопустимы, прерывание UDRE используется для загрузки следующего байта, пока текущий передаётся. Если паузы допустимы - UDRE пофиг и не используется. Смысл читать его ПЕРЕД записью?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.