|
|
  |
Гарантия того, что по USART все данные ушли |
|
|
|
Jan 14 2010, 13:57
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Цитата(Палыч @ Jan 14 2010, 16:48)  Значит, не один я так делаю. Почему же советы: "перед выдачей - сбросьте ТХС"? Думаю так делают все, кто работает с RS485. Я правда использую намного более низкие скорости 19200-38400, так что и по прерываниям все получается неплохо. Но и при 2-х мегабитах интервал передачи байта 80 тактов, так что если в критическую секцию обернуть и выдачу в UDR и сброс TXC, все должно работать нормально.
|
|
|
|
|
Jan 14 2010, 13:59
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(Палыч @ 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 в зависимости от того что надо. Если используем неблокирующие прерывания, приходится применять критическую секцию.  Если надо непрерывную передачу, контроль правильности/непрерывности можно сделать проверкой TXC перед передачей.
|
|
|
|
|
Jan 14 2010, 15:16
|

Профессионал
    
Группа: Свой
Сообщений: 1 940
Регистрация: 16-12-07
Из: Москва
Пользователь №: 33 339

|
Цитата(admiral @ Jan 14 2010, 15:57)  И вот вопрос: контроллеру нужно заснуть, как убедится, что все данные отосланы? Будет ли нормально, если я перед каждой посылкой байта (неважно последний он или нет) буду сбрасывать этот флаг? Не пойму почемуони не сделали, что бы, к примеру, при записи данных в UDR флаг TXC сбрасывался аппаратно? Если взглюнуть на структурную схему USART можно увидеть , что флаг TXC установиться при условии , что установлен флаг UDR и закончена передача байта , собственно он и сигнализирует о том , что сдвиговый регистр пуст и новых данных в буфере передачи нет . А , что Вы будете делать с ним дальше - значение не имеет , можете сбросить , записав единицу и уйти спать
--------------------
Закон Мерфи:
Чем тщательнее составлен проект, тем больше неразбериха, если что-то пошло не так
|
|
|
|
|
Jan 14 2010, 18:08
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(Палыч @ Jan 14 2010, 15:04)  Это-то - понятно. Интересует: как у Вас устроена программа, что по этому прерыванию Вы гарантировано знаете, что все байты переданы? Ваш изначальный вопрос касался 485-го. Так вот в контексте 485-го все держится на модели "запрос-ответ". Драйверу UARTа попросту не дается следующий __пакет__ до тех пор пока нас об этот не попросят, либо до тех пор пока нам не ответят, либо до тех пор пока не завершится таймаут. Из этого построение программы такое: Есть кольцевой буфер и есть put() который пишет в этот буфер. TXC прерывание разрешено постоянно и управляет направлением трансивера 485-го. (По TXC драйвер переключается на прием.) Флаг TXC руками не трогается никогда. В буфер помещается отправляемый пакет. Перед записью в UDR делается переключение трансивера 485 на передачу.. По UDRE - вычитка и отправка следующего байта из буфера. В системе нет настолько тяжелых обработчиков прерываний чтобы UDRE прерывание откладывалось настолько долго, что за это время могло возникнуть TXC прерывание, (суммарная латентность всех прерываний не превышает интервала одного символа UART'а). Поэтому все прекрасно работает.
|
|
|
|
|
Jan 14 2010, 18:53
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(defunct @ Jan 14 2010, 22:08)  Флаг TXC руками не трогается никогда.
В системе нет настолько тяжелых обработчиков прерываний чтобы UDRE прерывание откладывалось настолько долго, что за это время могло возникнуть TXC прерывание, (суммарная латентность всех прерываний не превышает интервала одного символа UART'а). Поэтому все прекрасно работает. Вот я - не понимаю: 1) откуда берется священная корова непрерывности данных в пакете, без тайм-аутов. 2) для чего TXC прерывание все время держать разрешенным. Объясните, пожалуйста
|
|
|
|
|
Jan 14 2010, 19:03
|
Местный
  
Группа: Участник
Сообщений: 246
Регистрация: 4-12-06
Пользователь №: 23 101

|
RS485, скорости до 115200. Делаю так же: формирую сообщение в буфере, переключаю на передачу, записываю первый байт в UDR. Дальше работают только прерывания: UDRE досыпает следующий байт, TXC переключает интерфейс на приём.
Как я узнаю, что все байты ушли? А как я знаю, сколько байтов передавать? По счётчику! Пока он больше 0 (или, если строка ASCIIZ байт данных не равен 0) работаем на передачу. Я успеваю это делать в прерывании UDRE. Если бы не успевал, проверил бы счётчик и в TXC, пока не переключил на приём.
Сообщение отредактировал Maik-vs - Jan 14 2010, 19:07
|
|
|
|
|
Jan 14 2010, 19:37
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(_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 }
|
|
|
|
|
Jan 14 2010, 20:58
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Цитата(defunct @ Jan 14 2010, 22:37)  А зачем его смыкать туда-сюда, код раздувать? Один раз при настройке уарта разрешили и забыли о нем вообще. Если есть возможность прогнозировать приход прерываний, то это работает. Если же нет, то RS485 идет в лес.  А ведь есть более приоритетные, нежели от 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 } А добавить туда еще проверку счетчика байт и проблема тоже решится. Не все передали - выходим из прерывания без переключения направления драйвера. ИМХО тоже вариант.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|