[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [avr-gcc-list] Atmega168: __vector_18 interruptible
From: |
Julius Luukko |
Subject: |
Re: [avr-gcc-list] Atmega168: __vector_18 interruptible |
Date: |
Thu, 27 Sep 2007 08:36:16 +0300 |
User-agent: |
KMail/1.9.7 |
On Wednesday 26 September 2007, Felipe Hernan wrote:
> __attribute__((interrupt)) allows to a vector to be interrupted
> re-enabling the global interrupt flag.
> ¿Why I need this?
>
> During __vector_18 (SIG_USART_RECV | USAR_RX_vect in libc) execution
> I need TIMER0_OVF_vect interruption.
>
> The reason
>
> My program implement a communication protocol for microcontrollers
> over RS232/485. The implementation should
> discard any frame (frame is in bytes) malformed or incomplete.
> Actually the way to detect incomplete frame is reading the last byte's
> timestamp and compare it against current, if that delta is
> greater than RX_TIMEOUT, then bytes isn't continuous, if delta isn't
> greater and frame is complete, an user callback is called.
> Additionally the protocol support an send option of Acknowledge that
> needly use TIMER0 and maybe a _send_
> is called from a user callback.
>
> Here a possible call stack
>
> __vector_18->rx_protocol->user_callback->send_frame
>
> Where send_frame has Acknowledge option.
>
> The project goal is a subsystem based in events, We dont want to add
> poll functions on main thead nor to add additional loop.
>
> The problem
>
> interrupt attribute not WORKS!. When a RX interrupt is done, the program
> dead.
>
> I use "naked" attribute in __vector_18 and I add a __asm__("sei" ::)
> as prologue, __asm__("reti ::") as epilogue and WORKS!
>
> #if defined(__AVR_ATmega168__)
> void USART_RX_vect(void) __attribute__((naked));
> void USART_RX_vect(void)
> #else
> void USART_RXC_vect(void) __attribute__((naked));
> void USART_RXC_vect(void)
> #endif
> {
> sei();
> #if defined(__AVR_ATmega168__)
> unsigned char c = UDR0;
> #else
> unsigned char c = UDR;
> #endif
> hal_rx_cb(c);
> asm("reti" ::);
> }
>
> output with -O3:
>
> 00000078 <__vector_18>:
> 78: 78 94 sei
> 7a: 80 91 c6 00 lds r24, 0x00C6
> 7e: e0 91 00 00 lds r30, 0x0000
> 82: f0 91 00 00 lds r31, 0x0000
> 86: 09 95 icall
> 88: 18 95 reti
>
> Why happens with __attribute__((interrupt))?!
>
Your approach only works since interrupts are enabled one clock cycle after
the sei instruction. The USART device's interrupt request is cleared after
you read UDR/UDR0. With __attribute__((interrupt)) the sei instruction
propably gets executed a few instructions before you read UDR and therefore
you will have an infinite loop of USART interrupts.
You can enable interrupts with a normal interrupt
ISR(your_vector_name)
{
c=UDR;
sei();
/* ISR continues with interrupts enabled */
}
Or did I miss something?
--
Julius