|
Какова "реальная" скорость UART? |
|
|
|
Jun 2 2008, 23:15
|
Местный
  
Группа: Свой
Сообщений: 222
Регистрация: 2-12-06
Из: г. Хабаровск
Пользователь №: 23 035

|
Здравствуйте! Стояла задача добиться максимальной скорости обмена по UART в Atmega128. Со стороны мк была написана небольшая програмка для измерения скорости обмена. Передача осуществляется в режиме прерывания. Код #define TX_BUFFER_SIZE 128 char tx_buffer[TX_BUFFER_SIZE];
#if TX_BUFFER_SIZE<256 unsigned char tx_wr_index,tx_rd_index,tx_counter; #else unsigned int tx_wr_index,tx_rd_index,tx_counter; #endif
// USART0 Transmitter interrupt service routine interrupt [USART0_TXC] void usart0_tx_isr(void) { if (tx_counter) { --tx_counter; UDR0 = tx_buffer[tx_rd_index]; if (++tx_rd_index == TX_BUFFER_SIZE) tx_rd_index=0; }; }
// Write a character to the USART0 Transmitter buffer #pragma used+ int COM_putchar(unsigned char c) { while (tx_counter == TX_BUFFER_SIZE); #asm("cli") if (tx_counter || ((UCSR0A & DATA_REGISTER_EMPTY)==0)) { tx_buffer[tx_wr_index]=c; if (++tx_wr_index == TX_BUFFER_SIZE) { tx_wr_index=0; } ++tx_counter; } else UDR0=c; #asm("sei") return 1;//<! }
в main:
unsigned long int tx_cnt; // счётчик переданных байт _включили_таймер if( ++tx_cnt < 65535 ) { COM_putchar(0x55); } _остановили_таймер В теории скорость передачи BAUD = 115200 бит/с. Передаём один старт-бит, 8 бит данных, один стоп-бит, итого 10 бит на передачу одного байта данных. На деле получаю: передано 65535 байт; время: 6,2с. Считаем BAUD: 65535*10/6,2 = 105702 бит/с. Не дотягивает передатчик до любой из стандартных скоростей, которую я выбирал. Может так и должно быть? Или стоит искать ошибки программы?
Сообщение отредактировал altlogic - Jun 2 2008, 23:17
--------------------
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 14)
|
Jun 3 2008, 01:12
|
Местный
  
Группа: Свой
Сообщений: 222
Регистрация: 2-12-06
Из: г. Хабаровск
Пользователь №: 23 035

|
Цитата(repairDV @ Jun 3 2008, 11:50)  Да, и это, скорее всего - потому, что у вас такая большая программа. Не понял если честно... Вы хотите сказать, что мой проц не успевает готовить данные для буфера передатчика? Цитата К тому же, если скорость обмена по uart в проце не будет совпадать со скоростью обмена по COM-порту в компьютере IBM, то как будет осуществляться связь между ними? опять не понял... Скорость обмена по протоколу uart и на компьютере и на мк выставлена 115200 бит/с. Вот я и хочу, чтобы мк при постоянной загрузке буфера передатчика передавал ровно 115200 бит за секунду, а не ~105000, как у меня сейчас. Ясно, что скорость обмена(115200) я менять не собираюсь.
Сообщение отредактировал altlogic - Jun 3 2008, 01:21
--------------------
|
|
|
|
|
Jun 3 2008, 02:58
|

Знающий
   
Группа: Свой
Сообщений: 578
Регистрация: 7-11-06
Из: Хабаровск
Пользователь №: 22 044

|
Цитата(altlogic @ Jun 3 2008, 12:12)  бит за секунду, а не ~105000, как у меня сейчас. Ясно, что скорость обмена(115200) я менять не собираюсь. Тут, вероятно, просто нужна настройка. Уже давно не общался с AVR, позабыл, как там настраивается uart. Скорее всего, у вас просто рассогласование по частоте. Нужно подбирать кварц, чтобы не было круглой цифры в мГц. Например, для 51серии стандартная частота кварца - 11,0592 мГц, а не 12 мГц - и только для обеспечения точного согласования для модуля uart. Поэтому, если вы предусматриваете использование асинхронного передатчика, то нужно подбирать кварцы, кратные этому значению - 11,0592. Скажем, 3,6864 мГц вместо 4 мгц, и т.п. Для большей точности лучше, конечно, подбирать частоту по осциллографу, перебирая те данные, которые вы записывете в таймер, если у вас uart работает от таймера.
--------------------
Маленький нанайца. А-а. А-а. Оморочком плыл. Маленький проточка. Осетра ловил.
|
|
|
|
|
Jun 3 2008, 03:14
|
Местный
  
Группа: Свой
Сообщений: 222
Регистрация: 2-12-06
Из: г. Хабаровск
Пользователь №: 23 035

|
Цитата(repairDV @ Jun 3 2008, 13:58)  Тут, вероятно, просто нужна настройка. Уже давно не общался с AVR, позабыл, как там настраивается uart. Скорее всего, у вас просто рассогласование по частоте. Нужно подбирать кварц, чтобы не было круглой цифры в мГц. Например, для 51серии стандартная частота кварца - 11,0592 мГц, а не 12 мГц - и только для обеспечения точного согласования для модуля uart. Поэтому, если вы предусматриваете использование асинхронного передатчика, то нужно подбирать кварцы, кратные этому значению - 11,0592. Скажем, 3,6864 мГц вместо 4 мгц, и т.п. Для большей точности лучше, конечно, подбирать частоту по осциллографу, перебирая те данные, которые вы записывете в таймер, если у вас uart работает от таймера. Вероятно это моя ощибка. Недостаточно чётко изложил свою проблему. Действительно я использую кварц 3,6864МГц, осцилографом не проверял, но сбоев при приёме/передаче за время отладки ни разу не наблюдал. Рассогласование по частоте здесь ни при чём. С уарта я просто пихаю данные "в никуда", то есть на приёмной стороне их никто не принимает(упростим задача, на самом деле конечно не так  Так вот я не могу добиться скорости выставления данных "в никуда" на 115200. Цитата(aaarrr @ Jun 3 2008, 14:03)  Используйте вместо прерывания по завершению передачи (TXC) прерывание по опустошению DATA-регистра (DRE). Так Вы убиваете даже ту мизерную буферизацию, что имеется в Меге. А вот это уже похоже на истину... Попробую проверить!
--------------------
|
|
|
|
|
Jun 3 2008, 04:04
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(altlogic @ Jun 3 2008, 03:15)  В теории скорость передачи BAUD = 115200 бит/с. Передаём один старт-бит, 8 бит данных, один стоп-бит, итого 10 бит на передачу одного байта данных. на самом деле 11. забыли бит четности. Если проверка на четность не включена, это ещё не значит, что бит не передаётся. Так что подкорректируем ваш результат: 105000*11/10=115500. Где-то так. Опять же, не забываем про погрешность деления частоты. Или у вас коэффициент целый получился?
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Jun 3 2008, 04:45
|
Местный
  
Группа: Свой
Сообщений: 222
Регистрация: 2-12-06
Из: г. Хабаровск
Пользователь №: 23 035

|
Цитата(MrYuran @ Jun 3 2008, 15:04)  на самом деле 11. забыли бит четности. Если проверка на четность не включена, это ещё не значит, что бит не передаётся. Так что подкорректируем ваш результат: 105000*11/10=115500. Где-то так.
Опять же, не забываем про погрешность деления частоты. Или у вас коэффициент целый получился? Если считать, что передано 11 бит, то скорость действительно сходится ( если учесть погрешность таймера). Коэффициент целый, частота делится без погрешности (3 686 400 / 115200 = 32). Бит чётности проверю на осцилографе  ДШ как-то невнятно пишет. А вот заставить работать мегу по прерыванию опустошения DATA-регистра у меня не получается. переписал свой обработчик прерывания с Код interrupt [ USART0_TXC] void usart0_TXC_isr(void) на Код interrupt [ USART0_DRE ] void usart0_UDRE_isr(void) вектора объявлены в стандартном хидере Код #define USART0_DRE 20 #define USART0_TXC 21 Результат: мк сбрасывается при передаче семи символов. Может надо было не только объявление прерывания поменять?..
Сообщение отредактировал altlogic - Jun 3 2008, 04:47
--------------------
|
|
|
|
|
Jun 3 2008, 04:54
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(MrYuran @ Jun 3 2008, 08:04)  на самом деле 11. забыли бит четности. Если проверка на четность не включена, это ещё не значит, что бит не передаётся. Это, ИМХО, из разряда гадания на кофейной гуще. Код инициализации мы не видели. Цитата(altlogic @ Jun 3 2008, 08:45)  мк сбрасывается при передаче семи символов. Может надо было не только объявление прерывания поменять?.. Разрешение TXC убрали? С точки зрения обработки разница только в том, что DRE активно еще до начала передачи.
|
|
|
|
|
Jun 3 2008, 06:00
|

Гуру
     
Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954

|
Цитата(altlogic @ Jun 3 2008, 02:15)  Стояла задача добиться максимальной скорости обмена по UART в Atmega128. ... Код ... #asm("cli") if (tx_counter || ((UCSR0A & DATA_REGISTER_EMPTY)==0)) { tx_buffer[tx_wr_index]=c; if (++tx_wr_index == TX_BUFFER_SIZE) { tx_wr_index=0; } ++tx_counter; } else UDR0=c; #asm("sei") return 1;//<! } ... C буфером передачи Вы, ИМХО, намудрили... По всей вероятности переменная tx_counter инициируется нулём, поэтому выражение в операторе if будет ложным всегда. (P.S. Тут я немного соврал, но правильность условия в первом if - очень сомнительна!) Использовать желательно прерывание UDE для добавления аппаратной буферизации. Цитата(altlogic @ Jun 3 2008, 07:45)  Результат: мк сбрасывается при передаче семи символов. Может надо было не только объявление прерывания поменять?.. Вероятно, добавили UDE, исправили прерывание, но не убрали разрешение прерывания по TXC, а обработчика прерывания уже - нет! Если разрешено какое-либо прерывание, а соответствующего обработчика нет, микроконтроллер попадает на адрес 0, и всё - заново.
|
|
|
|
|
Jun 3 2008, 07:15
|
Местный
  
Группа: Свой
Сообщений: 222
Регистрация: 2-12-06
Из: г. Хабаровск
Пользователь №: 23 035

|
Цитата(aaarrr @ Jun 3 2008, 15:54)  Код инициализации мы не видели. Код //#define _USART0_TXC_INTERRUPT_ void COM_init( unsigned int ubrr ) { UBRR0H = (unsigned char) (ubrr>>8); //Setting baudrate UBRR0L = (unsigned char) ubrr; //Setting baudrate #ifdef _USART0_TXC_INTERRUPT_ UCSR0B = ( 1 << RXEN0 ) | ( 1 << TXEN0 ); //Enable receiver and transmitter #else UCSR0B = ( 1 << RXEN0 ) ( 1 << TXEN0 ) | (1 << UDRIE0) |; //Enable receiver #endif UCSR0C = ( 1 << UCSZ01 ) | ( 1 << UCSZ00 ); //8N1...see Datasheet for more information UCSR0A=0x00; COM_rx_reset(); COM_tx_reset(); //Reset buffers etc. } void COM_rx_reset( void ) { COM_rx_off(); // Disable RX interrupt rx_i = rx_wr_i = 0; //Init variables rx_overflow = rx_ack = 0; //Zero overflow flag rx_buffer[ rx_wr_i ] = '\0'; //Buffer init. }
void COM_tx_reset( void ) { COM_tx_off(); // Disable RX interrupt tx_wr_index = 0; tx_rd_index = 0; tx_counter = 0; }
void COM_rx_on( void ) { UCSR0B |= ( 1 << RXCIE0 ); // Enable RX interrupt }
void COM_rx_off( void ) { UCSR0B &= ~( 1 << RXCIE0 ); // Disable RX interrupt }
void COM_tx_on( void ) { UCSR0B |= ( 1 << TXCIE0 ); // Enable TX interrupt }
void COM_tx_off( void ) { UCSR0B &= ~( 1 << TXCIE0 ); // Disable TX interrupt }
#ifdef _USART0_TXC_INTERRUPT_
//<! USART0_TXC - tx complete
interrupt [ USART0_TXC ] void usart0_TXC_isr(void) { if ( tx_counter ) { --tx_counter; UDR0 = tx_buffer[tx_rd_index]; if (++tx_rd_index == TX_BUFFER_SIZE) tx_rd_index=0; }; }
#else
//<! USART0_DRE - usart data register emptry
interrupt [ USART0_DRE ] void usart0_UDRE_isr(void) { if ( tx_counter ) { --tx_counter; UDR0 = tx_buffer[tx_rd_index]; if (++tx_rd_index == TX_BUFFER_SIZE) tx_rd_index=0; }; }
#endif
... void main(void) { ... //<! USART0 initialization (UBRR = 0x01 = 115200 @ 3.6864MHz) COM_init(0x01); ... } С объявленным _USART0_TXC_INTERRUPT_ передатчик работает в четыре раза быстрее. Цитата(Палыч @ Jun 3 2008, 17:00)  C буфером передачи Вы, ИМХО, намудрили... По всей вероятности переменная tx_counter инициируется нулём, поэтому выражение в операторе if будет ложным всегда. (P.S. Тут я немного соврал, но правильность условия в первом if - очень сомнительна!) Использовать желательно прерывание UDE для добавления аппаратной буферизации. Вероятно, добавили UDE, исправили прерывание, но не убрали разрешение прерывания по TXC, а обработчика прерывания уже - нет! Если разрешено какое-либо прерывание, а соответствующего обработчика нет, микроконтроллер попадает на адрес 0, и всё - заново. Про прерывания по TXC вы правильно заметили
--------------------
|
|
|
|
|
Jun 3 2008, 21:53
|
Местный
  
Группа: Свой
Сообщений: 222
Регистрация: 2-12-06
Из: г. Хабаровск
Пользователь №: 23 035

|
Всем участникам спасибо! Сегодня утром на свежую голову разобрался в вопросе, сделал НОРМАЛЬНО прерывания по пустому Data Register, и получил свои 115 200 на передатчике. Вот теперь встанет следующий вопрос - добиться 115 200 на приёмнике  У меня там тоже прерывания по окончанию приёма. Пока не проверял, но боюсь и там будет та же картина. Код interrupt [USART1_RXC] void usart1_rx_isr(void) { char status,data; status=UCSR1A; data=UDR1; if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0) { rx_buffer1[rx_wr_index1]=data; if (++rx_wr_index1 == RX1_BUFFER_SIZE) rx_wr_index1=0; if (++rx_counter1 == RX1_BUFFER_SIZE) { rx_counter1=0; rx_buffer_overflow1=1; }; }; }
--------------------
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|