atxmega32a4, przerwania USART i resetowanie uC...

Jun 05, 2011 10 Replies

Witam wszystkich i proszę o pomoc :-) Pytałem na avrfreaks, ale nie dostałem żadnej odpowiedzi...



Podłączyłem xmega32a4 do PCta i mogę wysyłać dane. Dodałem ISR do kodu, i przerwanie odpala się przy wysłaniu danych (TXC). To działa bez problemu. Teraz dodaję ISR dla RX i sprawdzam... i niestety, gdy wysyłam coś do uC to teoretycznie przerwanie się wykonuje... mówię teoretycznie, bo odebranie znaku resetuje się mikrokontroler! A gdy mikrokontroler się zresetuje i program wykonuje się od nowa, to wszystkie przerwania są wyłączone (i nawet TX już nie działa).



Ktoś wie co robię źle? :-(



Oto mój kod:


#define UART_GPS USARTE0



int main (void) { cli(); sei(); /* enable interrupts */



OSC.CTRL |= OSC_RC32MEN_bm; while(!(OSC_STATUS & OSC_RC32MRDY_bm)); CCP = CCP_IOREG_gc; CLK.CTRL = CLK_SCLKSEL_RC32M_gc;



UARTinit(&UART_GPS); // init serial port


while(1) { UARTputs(&UART_GPS, "test string\r\n"); _delay_ms(500); }



}

ISR(USARTE0_RXC_vect) { //UART receive interrupt PORTA.OUTTGL |= (1 <<PIN0); // PA0 is toggled }



ISR(USARTE0_TXC_vect) { //UART receive interrupt PORTA.OUTTGL |= (1 <<PIN1); // PA1 is toggled }


I moje funkcje:


//not finished yet, need to handle PORTE via arg void UARTinit(USART_t *port) { int bsel = 3325; int bscale = -3; // 4800 @ 32MHz


PORTE.OUTSET = PIN3_bm; PORTE.DIRSET = PIN3_bm; // PE3 (TXD0) as output PORTE.DIRCLR = PIN2_bm; // PE2 (RXD0) as input



PORTE.INTCTRL = 0x01; // set interrupt0 low level PORTE.INT0MASK = 0x04; // set pins 3 and 2 for as a source for interrupt



port->BAUDCTRLA = /*(uint8_t)*/ bsel; port->BAUDCTRLB = (bscale << 4) | (bsel >> 8);



PMIC.CTRL = PMIC_LOLVLEN_bm;



// Enable RX and TX low level interrupts port->CTRLA = USART_RXCINTLVL_LO_gc | USART_TXCINTLVL_LO_gc;



// Enable both RX and TX. port->CTRLB = USART_RXEN_bm | USART_TXEN_bm;



// Set USART to 8bit, no parity, 1 stop bit port->CTRLC = USART_CHSIZE_8BIT_gc | USART_PMODE_DISABLED_gc;



}


//send a string to UART uint8_t UARTputs(USART_t *port, const char *ptr) {



while(*ptr) { while(!(port->STATUS & USART_DREIF_bm)) // wait for output buffer to clear / send complete / ready to send _delay_us(1);



port->DATA = *ptr++; // send character }



return 1; }


Używam tego z MAX232 (wiem, że jest na 5V). Niestety nic innego na chwilę obecną pod ręką nie mam. TX z xmegi jest podłączony bezpośrednio, i to działa. RX jest podłączony przez dzielnik napięcia (Umax = 3V, zasilanie uC 3.3V).


Najprawdopodobniej musisz odczytać dane, które przyszły żeby wyzerować flagę przerwania. Doczytaj w pdfie lub sprawdź.

Miałem cichą nadzieję, że to to, ale jednak nie :/ W ogóle chyba nie trzeba czytać tych danych tak na dobrą sprawę, bo bufor może się bezkarnie przepełnić, ma nawet flagę przepełnienia bufora. Tak czy owak sprobowałem czytać USARTE0.DATA w procedurze ISR(), ale dalej to samo. W PDFie, którego przeczytałem już kilka razy dalej nic nowego nie znalazłem :/

Nie mam pojęcia o co chodzi :-( Jakieś pomysły?

Chyba trzeba będzie w konću wydać kasę na sprzętowy debugger...

m.

W atmegach flaga RXC jest zerowana dopiero po odczycie danej. Nie mam pdfa od xmegi, ale może być tak samo. Sprawdź jeszcze w kodzie wynikowym jak skompilowany jest odczyt - może być sytuacja, że kompilator zoptymalizował kod jeśli przypisana wartość nie jest później wykorzystana.

AVR1307:

"When a complete character is received in the shift register, it is copied to the buffer, and the shift register is ready to receive a second (or third) character. Note that, if three characters have been received, without reading the DATA register, a fourth character will cause loss of the character in the shift register, the third byte is lost. In this case the buffer overflow flag will be set (BUFOVF in USARTxn.STATUS)."

więc to potwierdza co mówiłem odnośnie czytania bufora.

A to odnośnie czytania z DATA: "The RXCIF flag is set when there are unread data in the receive buffer, and cleared when the receive buffer is empty. The RXCIF flag is cleared by reading the data, it is not required to clear the flag manually."

Zajrzę jeszcze do kodu asm. Ponoć reset może się pojawić przy skoku (jmp, rjmp) do niezdefiniowanego adresu (ponoć dzieje się tak gdy włączysz przerwanie a nie ma nigdzie procedury do jego obsługi -- wtedy wywołanie przerwania kończy się skokiem "niewiadomogdzie" i uC się resetuje). No nic, powalczę jeszcze...

Dzięki.

m.

W dniu 05.06.2011 21:28, Martin Lukasik pisze:

Nie, nie "niewiadomogdzie", ale właśnie pod reset (tam wskazują wszystkie niezdefiniowane przerwania) - możesz za pomocą jakiegoś objdump/gdb zobaczyć jak wygląda reset vector - czy jest jakaś funkcja przypisana.

Niestety nie ma nic pod tym wektorem. Rozumiem, że wektor resetu to 0. W asmie mam tylko wektory 58 i 60, co jest zgodne z założeniami i moim programem. Nie mam tam nigdzie skoku do wektora 0.

w .lss mam:

00000212 <__vector_58>: }

ISR(USARTE0_RXC_vect) { //UART receive interrupt 212: 1f 92 push r1 214: 0f 92 push r0 216: 0f b6 in r0, 0x3f ; 63 218: 0f 92 push r0 21a: 11 24 eor r1, r1 21c: 8f 93 push r24 21e: ef 93 push r30 220: ff 93 push r31 data = USARTE0.DATA; 222: 80 91 a0 0a lds r24, 0x0AA0 226: 80 93 00 20 sts 0x2000, r24 PORTA.OUTTGL |= (1 <<PIN0); // PA0 is toggled 22a: e0 e0 ldi r30, 0x00 ; 0 22c: f6 e0 ldi r31, 0x06 ; 6 22e: 87 81 ldd r24, Z+7 ; 0x07 230: 81 60 ori r24, 0x01 ; 1 232: 87 83 std Z+7, r24 ; 0x07

/* lcd_puts("INT triggered"); lcd_puts(UARTgetc(&USARTD0)); show_display();

*/ } 234: ff 91 pop r31 236: ef 91 pop r30 238: 8f 91 pop r24 23a: 0f 90 pop r0 23c: 0f be out 0x3f, r0 ; 63 23e: 0f 90 pop r0 240: 1f 90 pop r1 242: 18 95 reti

00000244 <__vector_60>:

ISR(USARTE0_TXC_vect) { //UART receive interrupt 244: 1f 92 push r1 246: 0f 92 push r0 248: 0f b6 in r0, 0x3f ; 63 24a: 0f 92 push r0 24c: 11 24 eor r1, r1 24e: 8f 93 push r24 250: ef 93 push r30 252: ff 93 push r31 PORTA.OUTTGL |= (1 <<PIN1); // PA1 is toggled 254: e0 e0 ldi r30, 0x00 ; 0 256: f6 e0 ldi r31, 0x06 ; 6 258: 87 81 ldd r24, Z+7 ; 0x07 25a: 82 60 ori r24, 0x02 ; 2 25c: 87 83 std Z+7, r24 ; 0x07 } 25e: ff 91 pop r31 260: ef 91 pop r30 262: 8f 91 pop r24 264: 0f 90 pop r0 266: 0f be out 0x3f, r0 ; 63 268: 0f 90 pop r0 26a: 1f 90 pop r1 26c: 18 95 reti

Wygląda ok... Przeoczyłem coś?

Dzieje się magia...

m.

U¿ytkownik "Martin Lukasik" snipped-for-privacy@milea.pl napisa³ w wiadomo¶ci news: snipped-for-privacy@u26g2000vby.googlegroups.com...

A niezdefiniowane wektory gdzie maj± skok? Zrób procedurê obs³ugi przerwania np. zapalaj±c± diodê na nieu¿ywanym porcie. I przekieruj na t± procedurê wszystkie wektory od nieu¿ywanych przerwañ. Je¶li stan diody siê zmieni, to znaczy, ¿e wywo³ujesz (masz niezamaskowane) jakie¶ przerwanie, którego obs³ugi nie przewidzia³e¶. Jak nie pomo¿e odepnij linie RX i TX od MAX232 i je po³±cz na krótko. To co nadasz znajdzie siê w buforze, zobacz czy procek wtedy te¿ siê resetuje, bo mo¿e to nie przerwania, tylko co¶ z napiêciami masz nie tak. Nastêpnie podaj na MAX232 sta³y sygna³ i zobacz jakie masz napiêcie na wyj¶ciu.

W dniu 2011-06-05 15:45, Martin Lukasik pisze:

[...]

A stos prawidłowo zainicjowany? K.

[...]

Z reguły kiedy z programem dzieje się magia, to winny jest temu stos. Przypatrz się dokładnie czy nie masz zbyt głębokich odwołań do funkcji, czy stos nie wchodzi na obszar danych albo nie wychodzi poza RAM, czy nie piszesz gdzieś poza obszarem zadeklarowanych zmiennych. Za każdym razem jak miałem do czynienia z "czarną magią" na uP, okazywało się że błąd był związany ze stosem.

pzdr. j.

Podpiąłem RX i TX na krótko, i problem był dalej.

Później zrobiłem tak jak piszesz -- wpakowałem diody na port, ustawiłem te 93 wektory, żeby zaświecały diody... :-) i doszedłem do problemu!!! Było to nieobsługiwane przerwanie! Jakie? External interrupt on PORTE.

Z UARTinit():

PORTE.INTCTRL = 0x01; // set interrupt0 low level PORTE.INT0MASK = 0x04; // set pins 3 and 2 for as a source for interrupt

Jako, że książek o xmega na oczy nie widziałem, to przenoszę się z mega przy pomocy tutorialów. I w jednym cudownym było właśnie powyższe, co durnie przepisałem, myśląc, że tak ma być.

Tylko ta linia jest za to odpowiedzialna:

port->CTRLA = USART_RXCINTLVL_LO_gc | USART_TXCINTLVL_LO_gc;

Działa teraz przecudownie, zmarnowałem na to 2 dni... ale hej, w sumie czegoś się nauczyłem!

WIELKIE DZIĘKI Marcin za podpowiedź i całej reszcie za pomoc!

Dobranoc, m.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required