AVR Раздел по микроконтроллерам компании Atmel - AVR / ATtiny / ATmega / ATMega128 / ATxmega, вопросы по программированию в AVR studio и все, относящееся к AVR... |
11.09.2019, 22:20
|
|
Супер-модератор
Регистрация: 13.03.2004
Адрес: Minsk
Сообщений: 2,378
Сказал спасибо: 1,948
Сказали Спасибо 1,327 раз(а) в 578 сообщении(ях)
|
Re: Странный баг управления драйвером RS-485
Сообщение от bdn62
|
Но контроль последнего отправленного бита выполняется в строке
while(!( UCSR0A & (1 ‹‹ TXC0)));//
|
Если верить даташиту, то TXC сбрасывается либо при записи туда 1, либо при обработке соотв. прерывания. В вашем примере я не увидел ни того, ни того. Так что он взводится после окончания передачи ПЕРВОГО байта и не очищается никогда.
А буферизация у меги есть. Так что опережение на два байта вполне закономерно. Один в регистре сдвига - передается, второй в буфере.
__________________
[ жизнь приятна и красива, если выпить литр пива ]
Последний раз редактировалось nml; 11.09.2019 в 22:50.
|
|
|
|
11.09.2019, 23:41
|
|
Частый гость
Регистрация: 19.05.2010
Сообщений: 27
Сказал спасибо: 76
Сказали Спасибо 8 раз(а) в 2 сообщении(ях)
|
Re: Странный баг управления драйвером RS-485
Еще раз спасибо за внимание!
Но:
while(!( UCSR0A & (1 ‹‹ TXC0)));//
UCSR0A |= (1 ‹‹ TXC0);
т е сначала жду установки TXC0, затем его обнуляю
А вот про буферизацию это интересно. Хотя как обрабатывать этот редчайший, но после "заскока" ежесекундно повторяющийся "глюк" пока не понимаю.
|
|
|
|
12.09.2019, 01:09
|
|
Гражданин KAZUS.RU
Регистрация: 17.06.2008
Адрес: Украина
Сообщений: 676
Сказал спасибо: 360
Сказали Спасибо 753 раз(а) в 358 сообщении(ях)
|
Re: Странный баг управления драйвером RS-485
Странно; функция RS485_U0_send в посте #1 написана один-в-один по даташиту с учетом буферизации и ожиданием окончания передачи последнего бита. Все как бы должно работать. Эррата молчит.
А прерывания запрещать на время передачи ( вдруг кто-то портит порт в прерываниях ) тогда уж так:
Код:
|
void RS485_U0_send(unsigned char *buff, unsigned char len)
{
int cnt;
unsigned char tmp;
tmp = SREG;
__asm__ ("cli");
PORTB |= (1 ‹‹ PB4);//and set high level
cnt = 0;
while(cnt ‹ len)
{
while(!( UCSR0A & (1 ‹‹ UDRE0)));
UDR0 = buff[cnt ++];
}
while(!( UCSR0A & (1 ‹‹ TXC0)));//
UCSR0A |= (1 ‹‹ TXC0);
PORTB &= ~(1 ‹‹ PB4);//set R/W low level
SREG = tmp;
inc_tranzaction_MB1();
} |
Можно (на всякий случай ) еще бит прерывания этого передатчика почистить.
|
|
|
Сказали "Спасибо" j-Roger
|
|
|
12.09.2019, 07:35
|
|
Гуру портала
Регистрация: 06.05.2005
Адрес: Краснодар, возле укротворного моря.
Сообщений: 18,841
Сказал спасибо: 2,531
Сказали Спасибо 11,764 раз(а) в 5,895 сообщении(ях)
|
Re: Странный баг управления драйвером RS-485
Сообщение от j-Roger
|
прерывания запрещать на время передачи ( вдруг кто-то портит порт в прерываниях )
|
Интересное предложение. Вообще-то, прерывания служат для того, чтобы выполнить что-то "именно здесь и сейчас". А если выполнение этого можно отложить на неопределенное время (миллисекунды!), как в данном предложении, то нахрена тогда использовать прерывания?!
Сообщение от nml
|
опережение на два байта вполне закономерно. Один в регистре сдвига - передается, второй в буфере.
|
Очень уж должны сойтись звезды... Но тут поможет запрет переключения на прием при непустом регистре данных передачи.
Сообщение от bdn62
|
Проверил поисковиком редактора все файлы проекта - нигде больше нет обращения к биту PORTB.PB4
|
Нужно проверить ВСЕ обращения к порту. Бит может быть изменен не только обращением к одному биту, групповуха тоже возможна.
Еще возможно формирование буфера на два байта короче (не записана контрольная сумма), потому как в самой функции передачи буфера, вроде бы, все в порядке.
А еще возможно пересечение стека и области переменных. Уже говорил. В этом случае возможны зависания, нарушения в алгоритме и вообще ХЗЧ.
__________________
Не бейте больно, ежели чо, ну не удержался... А вааще,
"Мы за все хорошее, против всей х..., По лугам некошеным чтобы шли ступни,
Чтобы миром правила правда, а не ложь, Мы за все хорошее, нас не на...!
..." (Ленинград)
Я не несу ответственности за свои действия в Вашей голове.
|
|
|
|
12.09.2019, 09:20
|
|
Почётный гражданин KAZUS.RU
Регистрация: 12.02.2013
Сообщений: 1,015
Сказал спасибо: 43
Сказали Спасибо 273 раз(а) в 214 сообщении(ях)
|
Re: Странный баг управления драйвером RS-485
Код программы написан в дурном стиле. Если в посылке несколько (десяток) байт - то тогда код сойдёт. Такие вещи "по взрослому" надо делать на DMA.
А от дурного программирования до дурного поведения программы один шаг.
|
|
|
Сказали "Спасибо" dgrishin
|
|
|
12.09.2019, 10:07
|
|
Почётный гражданин KAZUS.RU
Регистрация: 13.03.2010
Сообщений: 2,901
Сказал спасибо: 499
Сказали Спасибо 3,061 раз(а) в 1,425 сообщении(ях)
|
Re: Странный баг управления драйвером RS-485
Сообщение от dgrishin
|
Такие вещи "по взрослому" надо делать на DMA.
|
Ну вот и самые внимательные подтянулись))) ДМА в меге...
|
|
|
Сказали "Спасибо" AR_Favorit
|
|
|
12.09.2019, 10:24
|
|
Прописка
Регистрация: 29.10.2008
Сообщений: 272
Сказал спасибо: 0
Сказали Спасибо 102 раз(а) в 95 сообщении(ях)
|
Re: Странный баг управления драйвером RS-485
Сообщение от bdn62
|
Но именно иногда происходит зависание, иллюстрируемое осциллограммой 1, которая и вызывает у меня оторопь. Причем в этом зависании устройство сидит "вечно", до аппаратной инициализации МК.
|
Про зависание... это тоже не понятно, самое главное что видно по осциллограмме - это потеря 2х байтов...
Допустим что ТС описал нам все так как происходит и с регистром UCSR0A, в момент работы макроса RS485_U0_send, никто ни чего не делает, то такой баг (пропуск контроля выдачи 2х байт) может возникать только тогда, когда бит TXC0 равен единице на момент его проверки процедурой while(!( UCSR0A & (1 ‹‹ TXC0)));. Почему? пока не понятно... Сам, многократно контролировал выдачу выдачу подобным образом, никогда проблем не было...
Согласно ДШ такого не должно быть - бит TXC0 устанавливается в 1 только тогда, когда из сдвигового регистра (TRANSMIT SHIFT REGISTER) все выдано (вплоть до стопового бита) и в буферном регистре UDR0 (UDR (Transmit)) тоже ничего нет. Что в общем-то противоречит тому что мы видим. Но, оно есть...
Если бы в макросе RS485_U0_send была ошибка, то он бы стабильно работал неправильно, смущает то, что периодически выдача идет правильно (если верить ТС).
Есть одно замечание по макросу RS485_U0_send. Насколько я знаю, - сброс ФЛАГОВ програмным путем регистров АВР должен делаться не через UCSR0A |= (1 ‹‹ TXC0); (чтение-модификация-запись), а через UCSR0A = (1 ‹‹ TXC0); - просто запись в регистр (именно так изменится один бит)...Но, настаивать не буду - это ТС легко проверит в железе... Достаточно установить в UCSR0A|=(1‹‹ U2X0); двойную скорость... если выполнение команды UCSR0A = (1 ‹‹ TXC0); очистит регистр - восстановит скорость до нормальной (смотреть осциллографом), то сброс бита нужно делать через UCSR0A |= (1 ‹‹ TXC0);
Далее...ТС попробуй следующее...
Для такой реализации макроса RS485_U0_send, я бы его переписал следующим образом
PHP код:
|
void RS485_U0_send(unsigned char *buff, unsigned char len) { int cnt; PORTB |= (1 ‹‹ PB4);//and set high level
cnt = 0; while(cnt ‹ len) { UDR0 = buff[cnt ++]; // при первом запуске макроса регистр пустой... while(!( UCSR0A & (1 ‹‹ UDRE0))); // переставили контроль буфера...!!!!!!!!!
} UCSR0A = (1 ‹‹ TXC0); // сбросим перед проверкой, мы точно знаем что один байт еще не выдан.... while(!( UCSR0A & (1 ‹‹ TXC0)));//
UCSR0A = (1 ‹‹ TXC0); PORTB &= ~(1 ‹‹ PB4);//set R/W low level inc_tranzaction_MB1(); }
|
Такая реализаци даст возможность контролировать только один - последний байт. И если будет потеря, то только одного байта, тогда будем думать еще...
Сброс UCSR0A = (1 ‹‹ TXC0); перед while - на всякий случай. Нужно проверить с ним и без....
согласно ДШ сам он сбрасывается только через прерывание (прерываний нет, значит сброс программно...)
bdn62 , попробуй... и отпишись...
Последний раз редактировалось mimuh64; 12.09.2019 в 11:08.
|
|
|
|
12.09.2019, 11:53
|
|
Прописка
Регистрация: 30.08.2010
Сообщений: 143
Сказал спасибо: 237
Сказали Спасибо 35 раз(а) в 28 сообщении(ях)
|
Re: Странный баг управления драйвером RS-485
Если в момент передачи произойдет долгое прерывание( дольше передачи 1 или 2 байта), то TXC0 будет взведен( и сам уже не сброситься)!
Для начала можно попробовать такой велосипед:
Код:
|
while(cnt ‹ len)
{
while(!( UCSR0A & (1 ‹‹ UDRE0)));
__asm__ ("cli");
UDR0 = buff[cnt ++];
UCSR0A |= (1 ‹‹ TXC0);
__asm__ ("sei");
}
while(!( UCSR0A & (1 ‹‹ TXC0)));// |
|
|
|
|
12.09.2019, 13:09
|
|
Частый гость
Регистрация: 19.05.2010
Сообщений: 27
Сказал спасибо: 76
Сказали Спасибо 8 раз(а) в 2 сообщении(ях)
|
Re: Странный баг управления драйвером RS-485
Велосипед
__asm__ ("cli");
UDR0 = buff[cnt ++];
UCSR0A |= (1 ‹‹ TXC0);
__asm__ ("sei");
пока работает, буду ждать...
|
|
|
|
12.09.2019, 13:26
|
|
Гуру портала
Регистрация: 06.05.2005
Адрес: Краснодар, возле укротворного моря.
Сообщений: 18,841
Сказал спасибо: 2,531
Сказали Спасибо 11,764 раз(а) в 5,895 сообщении(ях)
|
Re: Странный баг управления драйвером RS-485
Сообщение от pt200
|
Если в момент передачи произойдет долгое прерывание( дольше передачи 1 или 2 байта), то
|
такого программера надо лупить розгами до просветления и осознания.
И вообще - организация передачи сообщения так, как сделано у ТС (циклом), заслуживает общественного осуждения и порицания. Нормально - с использованием прерываний, раз уж ПДП нету.
__________________
Не бейте больно, ежели чо, ну не удержался... А вааще,
"Мы за все хорошее, против всей х..., По лугам некошеным чтобы шли ступни,
Чтобы миром правила правда, а не ложь, Мы за все хорошее, нас не на...!
..." (Ленинград)
Я не несу ответственности за свои действия в Вашей голове.
Последний раз редактировалось akegor; 12.09.2019 в 13:30.
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 03:28.
|
|