|
|
  |
Одноразовый UART в AVR, Отправляет данные корректно только 1 раз.. |
|
|
|
Aug 2 2012, 18:17
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 4-03-09
Из: Богота, Колумбия
Пользователь №: 45 676

|
IAR 4.30, ATmega640. Структура. Надо её всю слить в UART. Беру указатель на начало и попёр. Вроде всё правильно. Но отправляется корректно она только первый раз, а потом идёт мусор. CODE #pragma pack(1) typedef struct { unsigned char Length; unsigned char Cmd; unsigned char ADC1[ADCBUFSISE]; // ADCBUFSISE == 18 unsigned char ADC2[ADCBUFSISE]; unsigned char ADC3[ADCBUFSISE]; unsigned char crc_h; unsigned char crc_l; } Response_str; #pragma pack() Response_str TransmisionFrame; unsigned char *pUart0_tx_pointer; void USART0_Transmit( unsigned char data ) { /* Wait for empty transmit buffer */ while ( !( UCSR0A & (1<<UDRE0)) ); /* Put data into buffer, sends the data */ UDR0 = data; } // инициирую отправку пакета раз в 2 секунды, пакет отправляется 2 мс, по этому период огромен void main( void ) { while(1) { pUart0_tx_pointer = &TransmisionFrame.Cmd; USART0_Transmit( TransmisionFrame.Length ); __delay_cycles(8000000*8); } } // прерывание // USART0 Transmitter interrupt service routine #pragma vector=(0x36*0x02) __interrupt void USART0_TXC_isr(void) { // if( pUart0_tx_pointer <= &TransmisionFrame.crc_l ) { UDR0 = *pUart0_tx_pointer++; } } Результат: Код 223A0000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000A55A - верный пакет 1A606908A5019746581A058A58A58199C65F1A606908A5019746581A058A58A58199C65F1A606908 A5019746581A058A58A58199C65F1A606908 - лажа 1A626910A52197C6581A078A64A5A19906601A626910A52197C6581A078A64A5A19906601A626910 A52197C6581A078A64A5A19906601A626910 - лажа Подумал, указатель сползает... Сделал так: Код while( 1 ) { pUart0_tx_pointer = &TransmisionFrame.Cmd; USART0_Transmit( TransmisionFrame.Length ); __delay_cycles(8000000*8); memset( &TransmisionFrame, 0xAA, sizeof(TransmisionFrame) ); } Получил: Код 223A0000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000A55A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Лага категорически не вижу
Сообщение отредактировал IgorKossak - Aug 2 2012, 18:23
Причина редактирования: [codebox] для длинного кода!!!
|
|
|
|
|
Aug 2 2012, 21:41
|
практикующий тех. волшебник
    
Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417

|
Цитата(Dikoy @ Aug 2 2012, 22:17)  ...инициирую отправку пакета раз в 2 секунды, пакет отправляется 2 мс... Код ..1A606908-A5019746581A058A58A58199C65F1A606908-A5019746581A058A58A58199C65F1A606908-A5019746581A058A58A58199C65F1A606908 - лажа 1A626910-A52197C6581A078A64A5A19906601A626910-A52197C6581A078A64A5A19906601A626910-A52197C6581A078A64A5A19906601A626910 - лажа ... 1) что то по времени не понятно. скорость какая порта? структура имеет 3*18+4=58 байт. за две милисекунды - дюже скорость не плохая... 2) у вас повтор идёт 18 байтовый в посылках которая лажа... 3) программа плохо написана. нигде не указано, что менять местами поля нельзя в структуре. особенно первые и последнии. не факт что кто то это будет знать через много дней. или вообще что такие поля будут существовать.
|
|
|
|
|
Aug 3 2012, 02:59
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 4-03-09
Из: Богота, Колумбия
Пользователь №: 45 676

|
Да, скорее всего стек... 18 байт, это размер массивов ADCх[ADCBUFSISE]; в структуре. У меня три порта USART в режиме SPI читают три АЦП и складывают байты в промежуточные буферы. Потом эти буферы быстренько перекладываются в данную структуру и она уходит на отправку через UART0. Приложил проект, если кому интересно. Сейчас полностью отключил эти SPI и их обработку, закомментировав adc_hardware_init();, и всё стало работать идеально. Значит прерывания дерутся. Расширить стек? 2kolobok0: скорость мегабит, через FT232R. При тупом поллинге работает прекрасно, это далеко не первый прибор такой, дело не в железе. Структура - стандартный протокол. Никто ничего менять и не будет Цитата(Сергей Борщ @ Aug 3 2012, 00:34)  Что-то (стек?) затирает содержимое структуры после первой передачи. Можно заполнять какое-либо поле структуры константой непосредственно перед передачей, чтобы подтвердить или опровергнуть это предположение. Ещё до отключения SPI провёл эксперимент. CODE do { pUart0_tx_pointer = &(TransmisionFrame.Length); TransmisionFrame.ADC1[0] = 0x01; TransmisionFrame.ADC2[0] = 0x02; TransmisionFrame.ADC3[0] = 0x03; UDR0 = *pUart0_tx_pointer++;
__delay_cycles(8000000*8); } while(1);
//***************************
223A01000000000000000000000000000000000002000000000000000000 0000000000000000030000000000000000000000000000000000A55A
5F1A016908A5119746581AD3895CA59199C65F1A026908A5119746581AD3 895CA59199C65F1A036908A5119746581AD3895CA59199C65F1A6169
5F1A016908A5119786581AEE8960A59199C65F1A026908A5119786581AEE 8960A59199C65F1A036908A5119786581AEE8960A59199C65F1A6069
Как видно, первый раз всё срабатывает, а потом кирдык. Размер стека по умолчанию, 32 бутеса...
|
|
|
|
|
Aug 3 2012, 08:44
|

Профессионал
    
Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409

|
Может организуйте fifo для отправки данных? CODE unsigned char Rx0Buf[UART_0_RXBUFSIZE];// the receiver buffer. unsigned char Rx0Head = 0;// the circular buffer index unsigned char Rx0Tail = 0; unsigned char Tx0Buf[UART_0_TXBUFSIZE];// the transmit buffer. unsigned int Tx0Head = 0;// the circular buffer index unsigned int Tx0Tail = 0;
signed int _getcharUART0() { __disable_interrupt(); signed int temp = -1; if (Rx0Tail != Rx0Head) { temp = Rx0Buf[Rx0Tail++]; if (Rx0Tail >= UART_0_RXBUFSIZE) Rx0Tail = 0; } __enable_interrupt(); return(temp); }
void _putcharUART0(signed char in_char) { __disable_interrupt(); if ((Tx0Head == Tx0Tail) && (UCSR0A & (1<<UDRE0))) { UDR0 = in_char; } else { Tx0Buf[Tx0Head++] = (unsigned char) in_char; if (Tx0Head >= UART_0_TXBUFSIZE) Tx0Head = 0; } __enable_interrupt(); }
#pragma vector=USART0_RX_vect __interrupt void USART0_RX_IRQ(void) { Rx0Buf[Rx0Head++] = UDR0; if (Rx0Head >= UART_0_RXBUFSIZE) Rx0Head = 0; }
#pragma vector = USART0_TX_vect __interrupt void USART0_TX_IRQ(void) { if (Tx0Tail != Tx0Head) { UDR0 = Tx0Buf[Tx0Tail++]; // send a byte of data if (Tx0Tail >= UART_0_TXBUFSIZE) Tx0Tail = 0;// check for wrap around. } }
Закидываете всю структуру сразу на передачу с помощью Код while(size--) { _putcharUART0(*pStruct++); } size - размер структуры pStruct - указатель на первый её элемент Подобное fifo 100% рабочее применялось во многих моих серийных проектах на AVR.
|
|
|
|
|
Aug 3 2012, 10:51
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Код while( 1 ) { pUart0_tx_pointer = &TransmisionFrame.Cmd; ... } Посмотрите, во что компилятор оптимизирует эту строчку. Есть волшебное слово volatile.
|
|
|
|
|
Aug 3 2012, 11:02
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(xemul @ Aug 3 2012, 13:51)  Код while( 1 ) { pUart0_tx_pointer = &TransmisionFrame.Cmd; ... } Посмотрите, во что компилятор оптимизирует эту строчку. Несоптимизировал компилятор строчку. Цитата(xemul @ Aug 3 2012, 13:51)  [code]while( 1 ) Есть волшебное слово volatile. Кого здесь volatile делать?
Сообщение отредактировал IgorKossak - Aug 3 2012, 11:27
|
|
|
|
|
Aug 3 2012, 11:56
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(_Артём_ @ Aug 3 2012, 15:02)  Несоптимизировал компилятор строчку. У меня нет иара, чтобы проверить, но, имхо, любой компилятор вынесет указанную строку в init() при любом отличном от 0 уровне оптимизации. Цитата Кого здесь volatile делать? Есть варианты?
|
|
|
|
|
Aug 3 2012, 12:18
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(xemul @ Aug 3 2012, 14:56)  У меня нет иара, чтобы проверить, но, имхо, любой компилятор вынесет указанную строку в init() при любом отличном от 0 уровне оптимизации. И что будет? Работать перестанет? Цитата(xemul @ Aug 3 2012, 14:56)  Есть варианты? Как минимум два.
|
|
|
|
|
Aug 3 2012, 12:25
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(_Артём_ @ Aug 3 2012, 16:18)  И что будет? Работать перестанет? Будет работать именно так, как написано - передавать по TransmisionFrame.Length байтов, начиная с pUart0_tx_pointer. Но pUart0_tx_pointer будет равен &TransmisionFrame.Cmd только единожды. Без оптимизации будет работать как задумано, кроме, вероятно, __delay_cycles(). Цитата Как минимум два. Да ну? "Огласите, пожалуйста, весь список", и с комментами, если можно.
|
|
|
|
|
Aug 3 2012, 12:43
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(xemul @ Aug 3 2012, 15:25)  Да ну? "Огласите, пожалуйста, весь список", и с комментами, если можно. Код volatile Response_str TransmisionFrame; unsigned char * volatile pUart0_tx_pointer; Строчка Код __delay_cycles(8000*8); вызывает варнинги Цитата Warning[Pe061]: integer operation result is out of range FirstChip\main.c 162 Warning[Pe068]: integer conversion resulted in a change of sign FirstChip\main.c 162 и программа дальше не идёт. Если так: Код __delay_cycles(8000UL*8); то идёт.
|
|
|
|
|
Aug 3 2012, 12:48
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(_Артём_ @ Aug 3 2012, 16:31)  Код volatile Response_str TransmisionFrame; Из приведённого ТС кода не следует, что TransmisionFrame имеет смысл объявлять volatile, но прокатит. Правда, потянет за собой оверхед при обращениях к TransmisionFrame. Цитата Код unsigned char * volatile pUart0_tx_pointer; Йес-с-с, Вы угадали. Это единственная переменная, модифицируемая в прерывании, и только в прерывании. Почти тот же эффект получится, если внутри while(1) {} pUart0_tx_pointer будет как-нибудь бесполезно изменяться, но так, чтобы компилятор не догадался, что оно бесполезно. __delay_xxx() не использую, но в комментах к подобным функциям обычно оговаривается уровень оптимизации, достаточный, чтобы они не выдавали цену на дрова.
|
|
|
|
|
Aug 3 2012, 13:07
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(xemul @ Aug 3 2012, 15:48)  Йес-с-с, Вы угадали. Это единственная переменная, модифицируемая в прерывании, и только в прерывании. Прыз в студию... Цитата(xemul @ Aug 3 2012, 15:48)  Почти тот же эффект получится, если внутри while(1) {} pUart0_tx_pointer будет как-нибудь бесполезно изменяться, но так, чтобы компилятор не догадался, что оно бесполезно. Обычно и без volatile работает. Хотя случаи могут быть разные. Цитата(xemul @ Aug 3 2012, 15:48)  __delay_xxx() не использую, но в комментах к подобным функциям обычно оговаривается уровень оптимизации, достаточный, чтобы они не выдавали цену на дрова. Там только про то говорится что параметр - константа. И всё.
|
|
|
|
|
Aug 3 2012, 13:19
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(_Артём_ @ Aug 3 2012, 17:07)  Обычно и без volatile работает. Хотя случаи могут быть разные. Вольному - воля. Цитата Там только про то говорится что параметр - константа. И всё. Тогда скорее всего в иар в либах живёт что-то вроде void __delay(unsigned long), а __delay_xxx() выполнены её обёртками. В gcc-avr, если склероз не врёт, подобное шло в сорцах и с оговорками.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|