|
AT90CAN128, Проблема с USART |
|
|
|
Sep 1 2007, 21:43
|
Группа: Новичок
Сообщений: 8
Регистрация: 1-09-07
Пользователь №: 30 221

|
Есть AT90CAN128, у которого используется USART1. При написании программы в CV AVR всё отлично пашет. Контроллер посылает данные в порт, гипертерминал их получает и выводит на экран. Т.е. железо в порядке. Но когда я попытался написать аналогичную программу в IAR, ком-порт работать перестал. При этом остальное не пострадало. Ниже приведены функции настройки и передачи данных. Код // Инициализация USART void USART_Init( void ) { // Включить приемник и передатчик UCSR1B = ( 1 << RXEN1 ) | ( 1 << TXEN1 ); // 8 data, no parity, 1 stop UCSR1C = ( 1 << UCSZ11 ) | ( 1 << UCSZ10 ); // 9600 bps при 16 MHz UBRR1 = 103; }
// Передача данных по USART void USART1_Transmit( unsigned char data ) { // Запись в буфер UDR1 = data; // Ожидание завершения передачи while ( ! ( UCSR1A & ( 1 << TXC1 ) ) ); } На ATmega8 данные функции работают после незначительной переделки ( только один USART, против двух у at90can128 ). В чем же дело?
|
|
|
|
|
Sep 2 2007, 16:03
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(--Ivan-- @ Sep 1 2007, 21:43)  Есть AT90CAN128, у которого используется USART1. При написании программы в CV AVR всё отлично пашет. Контроллер посылает данные в порт, гипертерминал их получает и выводит на экран. Т.е. железо в порядке. Но когда я попытался написать аналогичную программу в IAR, ком-порт работать перестал. При этом остальное не пострадало. Ниже приведены функции настройки и передачи данных.
На ATmega8 данные функции работают после незначительной переделки ( только один USART, против двух у at90can128 ). В чем же дело? Дело в том, что для AT90CAN128 адреса регистров компорта находятся в расширенной зоне адресов ввода-вывода (выше 0х60), а для ATmega8 - в обычной (ниже 0х60). Поменяйте файл с определениями регистров и будет вам щастье. И ещё, при инициализации лучше сначала инициализировать регистры порта, потом разрешать приёмник и передатчик, а не наоборот.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Sep 3 2007, 09:51
|
Группа: Новичок
Сообщений: 8
Регистрация: 1-09-07
Пользователь №: 30 221

|
Файл "iocan128.h", в котором определяются регистры, на первый взгляд без ошибок. Адреса связанных с компортом регистров специально сверил с документацией и не нашел отличий. Цитата(=GM= @ Sep 2 2007, 20:03)  И ещё, при инициализации лучше сначала инициализировать регистры порта, потом разрешать приёмник и передатчик, а не наоборот. Пробовал и так, и этак - никакой разницы.
|
|
|
|
|
Sep 3 2007, 16:26
|
Группа: Новичок
Сообщений: 8
Регистрация: 1-09-07
Пользователь №: 30 221

|
Цитата(=GM= @ Sep 3 2007, 15:59)  Попробуйте в режиме теста вывести данные не по прерыванию, а по ожиданию готовности TXC. Прерывания я не использовал. Код // Передача данных по USART void USART1_Transmit( unsigned char data ) { // Запись в буфер UDR1 = data; // Ожидание завершения передачи while ( ! ( UCSR1A & ( 1 << TXC1 ) ) ); } В основной программе просто циклично вызывается данная функция. Код void main( void ) { asm("cli"); PWM_Init(); USART_Init(); asm("sei");
int i=0, c=1; DDRC = 0xFF; PORTC = 0xFF; while (1) { USART1_Transmit( 'b' ); i += c; if ( i > 165 ) c = -1; if ( i < -165 ) c = 1; PWM_Set( i, i ); } } Судя по тому, что остальной код выполняется правильно, зацикливание из-за TXC1 не происходит. Вообще 90кан128 - довольно большой мк, может есть какие-нибудь хитрости именно с инициализацией. Цитата Так что вам мешает написать простенькую тестовую программу вывода в цикле буквы 'A' и сравнить листинги? Чудес ведь не бывает. Программка у меня примерно того же уровня сложности
|
|
|
|
|
Sep 3 2007, 20:50
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(--Ivan-- @ Sep 3 2007, 16:26)  Судя по тому, что остальной код выполняется правильно, зацикливание из-за TXC1 не происходит. Вообще 90кан128 - довольно большой мк, может есть какие-нибудь хитрости именно с инициализацией Ну, чудес не бывает, давайте посмотрим, что там яровский компилер натворил в асмовом коде.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Sep 4 2007, 18:55
|
Группа: Новичок
Сообщений: 8
Регистрация: 1-09-07
Пользователь №: 30 221

|
Цитата(=GM= @ Sep 4 2007, 00:50)  Ну, чудес не бывает, давайте посмотрим, что там яровский компилер натворил в асмовом коде. Знать бы ещё как этот код достать...
|
|
|
|
|
Sep 5 2007, 17:32
|
Группа: Новичок
Сообщений: 8
Регистрация: 1-09-07
Пользователь №: 30 221

|
Код \ In segment CODE, align 2, keep-with-next \ __nearfunc __version_3 void USART_Init() \ USART_Init: \ 00000000 E108 LDI R16, 24 \ 00000002 930000C9 STS 201, R16 \ 00000006 E006 LDI R16, 6 \ 00000008 930000CA STS 202, R16 \ 0000000C E607 LDI R16, 103 \ 0000000E E010 LDI R17, 0 \ 00000010 931000CD STS 205, R17 \ 00000014 930000CC STS 204, R16 \ 00000018 9508 RET \ 0000001A REQUIRE _A_UBRR1 \ 0000001A REQUIRE _A_UCSR1C \ 0000001A REQUIRE _A_UCSR1B
\ In segment CODE, align 2, keep-with-next \ __nearfunc __version_3 void USART1_Transmit(unsigned char) \ USART1_Transmit: \ 00000000 930000CE STS 206, R16 \ ??USART1_Transmit_0: \ 00000004 910000C8 LDS R16, 200 \ 00000008 FF06 SBRS R16, 6 \ 0000000A CFFC RJMP ??USART1_Transmit_0 \ 0000000C 9508 RET \ 0000000E REQUIRE _A_UDR1 \ 0000000E REQUIRE _A_UCSR1A
|
|
|
|
|
Sep 5 2007, 22:21
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(--Ivan-- @ Sep 5 2007, 17:32)  Код \ __nearfunc __version_3 void USART1_Transmit(unsigned char) \ USART1_Transmit: \ 00000000 930000CE STS 206, R16 \ ??USART1_Transmit_0: \ 00000004 910000C8 LDS R16, 200 \ 00000008 FF06 SBRS R16, 6 \ 0000000A CFFC RJMP ??USART1_Transmit_0 \ 0000000C 9508 RET \ 0000000E REQUIRE _A_UDR1 \ 0000000E REQUIRE _A_UCSR1A Здесь у вас логическая ошибка. После завершения передачи (после появления флага ТХС1=1), вам надо его очистить вручную, записав туда единицу. Флаг очищается автоматически только при обработке прерывания. См. с.195 документа 7682а. Если не очищать флаг, то произойдёт следующее. Вы запустили передачу, дождались ТХС, не сбросили его, проделали некоторые операции и вернулись к передаче символа, пустили символ на передачу, стали ждать окончания, но не дождались, поскольку ТХС не сброшен, быстренько сделали некоторые операции и перешли опять к передаче символа. Но передача предыдущего символа еще не закончилась, запись нового байта перебила передачу текущего, в итоге получилась каша. Как-то так.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Sep 6 2007, 04:33
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(--Ivan-- @ Sep 5 2007, 20:32)  Код \ In segment CODE, align 2, keep-with-next Отлично. А теперь, чтобы не ломать голову приведите листинг второй программы: Цитата(--Ivan-- @ Sep 2 2007, 00:43)  При написании программы в CV AVR всё отлично пашет. Контроллер посылает данные в порт, гипертерминал их получает и выводит на экран.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Sep 6 2007, 16:01
|
Группа: Новичок
Сообщений: 8
Регистрация: 1-09-07
Пользователь №: 30 221

|
Из-за кодвизарда в коде много лишнего. Выкладываю основное Код ; 280 // USART1 initialization ; 281 // Communication Parameters: 8 Data, 1 Stop, No Parity ; 282 // USART1 Receiver: On ; 283 // USART1 Transmitter: On ; 284 // USART1 Mode: Asynchronous ; 285 // USART1 Baud rate: 9600 ; 286 UCSR1A=0x00; STS 0xC8,R30 ; 287 UCSR1B=0xD8; LDI R30,LOW(216) STS 0xC9,R30 ; 288 UCSR1C=0x06; LDI R30,LOW(6) STS 0xCA,R30 ; 289 UBRR1H=0x00; LDI R30,LOW(0) STS 0xCD,R30 ; 290 UBRR1L=0x67; LDI R30,LOW(103) STS 0xCC,R30 Код ; 328 putchar1('a'); LDI R30,LOW(97) ST -Y,R30 RCALL _putchar1 Код ; 96 // USART1 Transmitter interrupt service routine ; 97 interrupt [USART1_TXC] void usart1_tx_isr(void) ; 98 {
.CSEG _usart1_tx_isr: ST -Y,R30 ST -Y,R31 IN R30,SREG ST -Y,R30 ; 99 if (tx_counter1) TST R7 BREQ _0xA ; 100 { ; 101 --tx_counter1; DEC R7 ; 102 UDR1=tx_buffer1[tx_rd_index1]; MOV R30,R6 LDI R31,0 SUBI R30,LOW(-_tx_buffer1) SBCI R31,HIGH(-_tx_buffer1) LD R30,Z STS 0xCE,R30 ; 103 if (++tx_rd_index1 == TX_BUFFER_SIZE1) tx_rd_index1=0; INC R6 LDI R30,LOW(8) CP R30,R6 BRNE _0xB CLR R6 ; 104 }; _0xB: _0xA: ; 105 } LD R30,Y+ OUT SREG,R30 LD R31,Y+ LD R30,Y+ RETI ; 106 ; 107 // Write a character to the USART1 Transmitter buffer ; 108 #pragma used+ ; 109 void putchar1(char c) ; 110 { _putchar1: ; 111 while (tx_counter1 == TX_BUFFER_SIZE1); _0xC: LDI R30,LOW(8) CP R30,R7 BREQ _0xC ; 112 #asm("cli") cli ; 113 if (tx_counter1 || ((UCSR1A & DATA_REGISTER_EMPTY)==0)) TST R7 BRNE _0x10 LDS R30,200 ANDI R30,LOW(0x20) BRNE _0xF _0x10: ; 114 { ; 115 tx_buffer1[tx_wr_index1]=c; MOV R30,R5 LDI R31,0 SUBI R30,LOW(-_tx_buffer1) SBCI R31,HIGH(-_tx_buffer1) LD R26,Y STD Z+0,R26 ; 116 if (++tx_wr_index1 == TX_BUFFER_SIZE1) tx_wr_index1=0; INC R5 LDI R30,LOW(8) CP R30,R5 BRNE _0x12 CLR R5 ; 117 ++tx_counter1; _0x12: INC R7 ; 118 } ; 119 else RJMP _0x13 _0xF: ; 120 UDR1=c; LD R30,Y STS 0xCE,R30 ; 121 #asm("sei") _0x13: sei ; 122 } ADIW R28,1 RET ; 123 #pragma used- ; 124
|
|
|
|
|
Sep 6 2007, 16:39
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(Сергей Борщ @ Sep 6 2007, 15:14)  Ну тогда бы сразу и сказали, кто из отвечавших должен сравнить эти листинги и найти в них отличия из-за которых не работает  Похоже, товарисч сам не знает, чего хочет. Привёл кусок программы с прерыванием, а ранее - кусок программы без прерывания, думайте мол сами. То --Ivan--. Я ж вам сказал, где у вас ошибка, чего проще, поставить сброс ТХС и проверить. А команда RETI сбрасывает ТХС! Что ж вы нас путаете?
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|