Author Topic: Fast task response to an interrupt  (Read 7110 times)

Offline jnewcomb

  • Newbie
  • *
  • Posts: 5
    • View Profile
Fast task response to an interrupt
« on: February 10, 2010, 08:12:03 PM »
Hi, been playing around with the demo application and like the way it can easily give us all the bells and whistles we need for our project - file system, webserver, usb, tcp, bootloader and so on.. all with a neat little scheduler that fits my preferred programming model of event based state machines.

As an aside, a table driven hierarchical state machine I have used in the past...
http://embedded.com/design/10700829

My past projects tend to run a pre-emptive RTOS - and for most of the 'executing time', they don’t need to. Agreed.
There is one case where I have relied on pre-emption to meet some tight real time constraints - and can't see an obvious solution using the uTasker scheduler. Really I'm looking for some tips/tricks/strategies on if/how I can solve these problems.

It concerns situations, for example,  when external devices give an interrupt to signal they need additional attention - and fairly quickly. A 'hypothetical example' is the SPI CAN driver chip MCP2515. It lets me know a message is waiting in the RX buffer - but I cant read the buffer from within the ISR (SPI comms within an ISR is not good practice!) .. If I leave it too late the buffer gets ovewritten.
So, what I do is have the ISR post an event to a task called 'ReadMCP2515_RxBuf'. The 'ReadMCP2515_RxBuf' task reads out the contents of the buffer over the SPI and places it in a FIFO in RAM for other tasks to consume as and when they can. (Assume CAN messages arrive in bursts)

Most of the time all tasks are waiting on a empty queue, so the real time requirement is met, but there will be conditions where this clashes with a periodic task, such as an ADC read - that in turn will start a flurry of message activity between tasks - status updates, LCD updates.. etc. all the time our 'ReadMCP2515_RxBuf' is not getting any service. (No one said event driven programming was easy!)
Ideally the current SPI operation finishes its chip select - (this could include an LCD update OR and an ADC read..) then the 'ReadMCP2515_RxBuf' should get started as soon as possible.

What are community members thoughts on tacking such an issues?
Multiple entries of 'ReadMCP2515_RxBuf' task in the table of tasks to be run?? That sort of thing??
Thanks,
Jon.

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3234
    • View Profile
    • uTasker
Re: Fast task response to an interrupt
« Reply #1 on: February 11, 2010, 11:48:46 PM »
Hi Jon

Generally (in my opinion and experience) a high percentage of embedded projects don't have any real advantage using a pre-emptive scheduler. A pre-emptive scheduler requires a certain amount of design skill, more resources and higher risk of 'hidden' errors (things that can go wrong only when a number of things take place in certain orders at certain timers and thus are often difficult to find).

Pre-emptive capabilities can however have important advantage in some projects and so are preferred for such projects - in some projects they may also be the only feasible solution.

Interrupts are very important in drivers in a non-pre-emptive design since they allow fast reaction to events such as data reception and then an 'offline' processing of the data content - it is assumed that the processing itself is not highly time-critical since it will take place once its handling task is next scheduled.

A single SPI based device shouldn't be a problem in an interrupt routine. The accesses are not that slow and only make a few us difference compared to an on-chip or parallel device. This shouldn't normally make any real difference and so received data can be copied to a driver input buffer, making the further processing less critical. When several devices are sharing an SPI it becomes more complicated due to the fact that disturbance of active SPI accesses need to be avoided - this required the interrupt to be blocked during accesses so that other interrupts can't take place which could try to use it (at least blocking between setting and clearing the CS line). This is however not a weakness of a non-pre-emptive solution but more general and so there shouldn't be any real disadvantages in this particular case. As long as interrupt handling is fast (the interrupt processing time itself doesn't cause other events in the system to be unacceptably delayed) things should be fine.

In a single case it is also quite simple to run longer interrupt handlers (eg. the reception and processing of data from an interrupt driven peripheral) in a low priority interrupt routine. This means that the interrupt occurs but the processors interrupts are allowed to continue arriving (either based on level or all) while the routine continues to handle the data. This will of course block other tasks from operating during this time but not other interrupts - these can continue being handled. In fact this shouldn't have any disadvantages over a pre-emptive solution which first detects the interrupt and then causes a high priority task to run - the high priority task will need to be switched to as fast as possible and then blocks any other tasks in the system to ensure it meets its speed requirements; simply staying in the interrupt (but unmasking where possible) results in the same effect but without the need to get from the start of the interrupt to the handling as fast as possible using task a context switch - the context switch becomes redundant since the handling can simply continue and so is also optimally fast.

Of course, when interrupt masking based on levels is used (the standard situation in uTasker project is that all interrupts are closed when handling any interrupt) there are other potential pitfalls and the design also gets a little more complicated, but it is still a powerful technique.

Generally I don't think that interrupt handling is something which the uTasker scheduling technique suffers from compared to a pre-emptive solution using context switching; a context switching will always introduce larger delays and more overhead generally. Generally using standard interrupt and interrupt nesting techniques allows most critical problems to be solved quite well. Where the pre-emptive solutions have main advantages is in cases where tasks need to perform a large amount of work (task run through time is high) and this work can not (easily) be "time -sliced" - an example is when calling library routines that have a high processing overhead (like encryption libraries) - in these cases there is a definite advantage - but at the end of the day choosing the best tools for a job is also the art of getting a job done the best. It must be able to do the job in hand but not be over-kill or too complicated...

Regards

Mark