avr-chat
[Top][All Lists]
Advanced

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

[avr-chat] xmega interrupt structure/nesting/priority (GCC)


From: larry barello
Subject: [avr-chat] xmega interrupt structure/nesting/priority (GCC)
Date: Mon, 26 Jan 2009 15:04:09 -0800

The Xmega has three priority levels for interrupts.  Interrupts within a
priority level cannot nest.  I.e. if I am in the middle of a long and
tedious process within my USART RxC interrupt, I cannot receive (or
transmit) any more characters.

Yeah, I know this is a bad idea, but I wrote this really cool event driven
scheduler that essentially runs everything as a nested interrupt (ISR) and
it works sweet on a mega128.   While processing a buffer the Rx stream
continues because I re-enable interrupts while running the task.  In my
actual project I have four serial streams and a timer system going on at
once.  Each can cause a system event that leads to potentially extensive
processing before returning to the previous code.  E.g. timer calls switch
input which might cause a 1/4 second period of re-painting the LCD
display...

This scheme works on the mega128 because if a task is busy, additional new
events just queue up waiting for the task to return and fetch the next event
to process.  When a task has one or more queued events, it is put onto a run
queue, or if the task is higher priority than the interrupted one, it is
called.  Eventually things unwind, the various queues are processed, and
events handled by their associated tasks in a defined priority fashion.

This model breaks on the xmega because I cannot receive any more characters
in *any* stream until I return from the ISR that generates an event that
causes lengthy processing (e.g. fires a task).  If the task involves
anything lengthy (fprintf of float data..., navigational computations,
screen updates) the other streams are blocked.

One possible solution is to assign various i/o ports to various interrupt
levels.  But I have many channels, and only three levels to work with.
Besides, it doesn't really work because, for example, the processing of GPS
input data is triggered by the last character received (RxC) and is now busy
updating the LCD display...  According to the XMEGA A manual, the only way
to clear an in-progress interrupt is by executing a 'reti' instruction.  

So, I got tricky: I defined a function to "reset" the PMIC and allow further
interrupts:

__attribute__((naked, noinline)) void _reti(void) 
{
        asm volatile ("sei");
        asm volatile ("reti");
}

And I call _reti()  to "(re)enable" interrupts within my scheduler before
passing control to the task code.  Note, I use cli/sei as a global control
when munging queues, and the reti does't actually update the I bit any more
- it just pops a level off the PMIC...  

Seems to work. The code (~60kb) which is stable on the mega128 (just using
sei/cli to manage interrupts) is unstable on the xmega during screen
updates, so my "hack" isn't quite the same...  

Am I playing with fire here?  Anyone doing things like this?  Is this
documented anywhere other than page 123 of the XMEGA A manual?  Anyone else
port their little scheduler to the xmega and deal with these issues?

Any hints to what I am missing are welcome.







reply via email to

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