avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [avr-gcc-list] custom signal prologue


From: Ben Mann
Subject: RE: [avr-gcc-list] custom signal prologue
Date: Wed, 24 Nov 2004 20:04:52 +0800

Hi Bernard,

The point is that "...do something..." is the calculating of the UDR value
and it takes quite a few instructions. So many in fact that another,
time-critical interrupt (very high speed, real-time etc) is botched and some
beautiful and highly optimised signal processing goes out the window. So, we
don't mind interrupting the UDR interrupt to process our much higher
priority interrupt.

So it is then obvious why we should disable UDRIE and do sei() before going
about our lengthy UDR calculation, as this takes only ~11 clock cycles -
less than the normal function prologue and allowing other interrupts to go
off quickly as required.

((btw, in my program, ...do something... actually is an inline function, as
I have to share it between both UARTs on the atmega64. The interrupt handler
is therefore carefully crafted to do the above preamble prior to most of the
"normal" prologue - which all has to be done in inline assembler. You can
see more discussion on this elsewhere in this thread.))

Furthermore, using TXC is inefficient - as the datasheet explains, TXC is
sent after the last bit of the transmission buffer is sent out - implying a
(possibly significant) delay while we respond to TXC and set the next UDR
byte. However, you are of course correct that TXC does not have the
limitation that UDR does and would be simpler to program.

Sadly this is what happens when we try and make this tiny processor do so
much :) The solutions aren't always easy! But it sure feels good to see it
jump through hoops...

Ben Mann



-----Original Message-----
From: Bernard Fouche [mailto:address@hidden 
Sent: Wednesday, 24 November 2004 6:42 PM
To: address@hidden; address@hidden
Subject: RE: [avr-gcc-list] custom signal prologue


If ...do something... is an inline function, you won't loose time
pushing/poping unneeded registers.

Now I wonder if, when just doing sei(), you're are not re-regenerating the
same interrupt. UDRE is cleared after processing the corresponding interrupt
handler or setting UDR. Did you try to set UDR asap in the interrupt handler
and then doing sei() ? That would allow your other time critical interrupt
to be processed. That would be:

SIGNAL(SIG_UART_DATA)
{
        UDR=..getting new data to send... or disabling UDRIE if nothing else
to send;
        sei();
}

Now the purpose of such a signal handler being to send new data if needed,
all the job is already done before sei()!

other solution: did you check using TXCIE instead of UDRIE ? It is written
in the datasheet that you can clear manually the TXC flag when you want. So
you clear it as you enter the signal handler and use sei(). This way another
interrupt can come and be processed really quickly and you won't regenerate
the same interrupt.

 Bernard

-----Message d'origine-----
De : address@hidden [mailto:address@hidden
la part de Ben Mann Envoye : mardi 23 novembre 2004 13:20 A :
address@hidden Objet : [avr-gcc-list] custom signal prologue


Hi all,

Is there any way to customise the prologue of an interrupt handler?

To explain...

I have a UDR interrupt handler in which I'd like to enable interrupts so
that another very time-critical interrupt can be handled promptly.

The usually accepted method does not work for UDR

 INTERRUPT(SIG_UART_DATA) {
     ...do something...
 }

because as soon as sei is enabled another UDR interrupt immediately triggers
and hangs the processor.

An inefficient but workable solution in C appears to be:

SIGNAL(SIG_UART_DATA) {
    //Disable UDRIE
    UCSRB &= _BV(UDRIE);
    sei();
    ...do something...
    UCSRB |= _BV(UDRIE);
}

The problem being that with complex replacements for "do something", the
prologue consists of pushing qutie a few registers. The trimmed .lst excerpt
below demonstrates the code the compiler generates for the first couple of
lines above in my application.

*********************
push __zero_reg__                               //UDRIE vector
push __tmp_reg__
in __tmp_reg__,__SREG__
push __tmp_reg__
clr __zero_reg__
push r18
push r19
push r20
push r21
push r22
push r23
push r24
push r25
push r26
push r27
push r30
push r31
/* prologue end (size=17) */
lds r24,154  /* disable UDRIE */
andi r24,lo8(-33)
sts 154,r24
sei   /* enable interrupts */
*********************

Is it possible to customise the prologue and somehow do the UDRIE disable
first, ie:

*********************
lds r24,154  /* disable UDRIE */        //UDRIE vector
andi r24,lo8(-33)
sts 154,r24
sei   /* enable interrupts */
push __zero_reg__
push __tmp_reg__
in __tmp_reg__,__SREG__
push __tmp_reg__
clr __zero_reg__
push r18
push r19
push r20
push r21
push r22
push r23
push r24
push r25
push r26
push r27
push r30
push r31
/* prologue end (size=21) */
*********************

For completeness I also looked at the promising and simple idea of:
SIGNAL(SIG_UART_DATA)
{
    //Disable UDRIE
    UCSRB &= _BV(UDRIE);
    sei();
    MyInterruptHandler();
}

Which I thought should require no prologue (MyInterruptHandler() pushing
what it needs) but the compiler still generates a similar looking prologue
for the interrupt handler - even with the interrupt and MyInterruptHandler()
in separate source files... (Which I found a little surprising)

Am I missing something obvious? Has anyone attempted to deal with this
before? (... sorry for the long post...I can't seem to keep it brief...)

Thanks

Ben Mann



_______________________________________________
avr-gcc-list mailing list
address@hidden http://www.avr1.org/mailman/listinfo/avr-gcc-list






reply via email to

[Prev in Thread] Current Thread [Next in Thread]