Pages: 1 2 [3]   Go Down
Author Topic: Can Arduino Multitask?  (Read 3025 times)
0 Members and 1 Guest are viewing this topic.
the land of sun+snow
Offline Offline
Faraday Member
**
Karma: 149
Posts: 2790
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Nick Gammon wrote:
Quote
Quote from: jfhaugh on Today at 05:11:08 PM
Cool!  So, in my ISR I save the flags and PC in a task state structure, the load the previous saved flags from a different task state structure, stack the PC, and RETI?

Just remind me of how you are going to handle stack-based variables.

Point of information ... wouldn't all those context switch areas and stacks for multiple tasks eat up a
lot of the lowly 2KB RAM space of the mega328?

FWIW and JFTHOI, last year I wrote a rather largish program to test the idea of using the state-machine
scheme I outlined above to handle multiple program levels and multiple tasks. (it was on a 40-MHZ PIC24
and not Arduino, however).

The nice thing is you don't have context switch areas or RAM usage explosion, and by coding the
state-machines well, you still can get pretty good, though not perfect, time-scheduling. I did use
interrupts for the time-critical stuff.

The state-machines can be used for both timed-coded and non-time-coded tasks. If the task is
time-coded [as the OP's original loops], then the overhead is near zero when the task timeout
does not occur. Jump in, check time, return. I'd guess it's much much less than the
context-switching overhead in a preemptive multitasker.

If the task is non-time-coded and takes a fair amount of processing to complete, then the onus is on
the coder to limit the amount of processing done on each entry into the task. One can have many
successive states in the task and do a limited amount of processing on each entry into the task.

All in all, I was amazed at how well the idea worked, and how much simpler it was than implementing
a preemptive context-switching multitasker might have been.

Comments?









Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think the state machine idea is more reasonable on a 2Kb RAM machine than trying to implement some sort of Unix.

Preemptive multitasking has overheads, and you will have issues like race conditions for variables and IO ports. The processor doesn't support semaphores which I think would likely to be required. Plus to multitask you would need each task to have their own stack, and quite probably, heap. You will run out of RAM.

Since the chips are worth around $5 you are probably better off doing what some others have done and just set up a multi-processor system and communicate via I2C or SPI.
Logged

West Des Moines, Iowa USA
Offline Offline
Sr. Member
****
Karma: 2
Posts: 428
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Comments?

I agree, and decided that for what I'm doing I'd prefer to (kinda) hide the fact that it's a state machine - and was mildly surprised how little code was needed to implement a basic capability. Here's the whole body of code needed for a single chain of states:

Code:
void (*runCode)() = (void(*)())0;
unsigned long runTime = ~0ul >> 1;

void idle(void)
{  if (runCode && millis() >= runTime) runCode();
}

void schd(unsigned long when,void(*what)())
{  runCode = what;
   runTime = when;
   idle();
}

void aftr(unsigned long delay,void(*what)())
{  schd(millis()+delay,what);
}

which I expanded to handle more than just a single scheduled event. The idle() function is used to give any "ripe" scheduled task an opportunity to run, and control returns after that/those have run. It's working fairly well.
Logged

There's always a better way!

the land of sun+snow
Offline Offline
Faraday Member
**
Karma: 149
Posts: 2790
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Since the chips are worth around $5 you are probably better off doing what some others have done and just set up a multi-processor system and communicate via I2C or SPI.

Yes, a good suggestion that no one else has made IIRC. On my robot tank, I am actually using stacked
Arduino boards [#2 mounted 1" above #1, so the lower headers are accessible], and using #1 for most
of the background I/O and #2 as the brains of the outfit. Using RS232 for comms.
Logged

the land of sun+snow
Offline Offline
Faraday Member
**
Karma: 149
Posts: 2790
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The processor doesn't support semaphores which I think would likely to be required

I forgot to mention, with the state-machine approach, you don't need actual semaphores, rather
regular flags will do, since there is no pre-emption and no race conditions, etc.
Logged

the land of sun+snow
Offline Offline
Faraday Member
**
Karma: 149
Posts: 2790
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

@Morris
Quote
void (*runCode)() = (void(*)())0;

You have some nice ideas, along with the (*execute)() buiness mentioned previously.
Worth looking into. Thanks.
Logged

West Des Moines, Iowa USA
Offline Offline
Sr. Member
****
Karma: 2
Posts: 428
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you. I have my share of ideas that don't pan out so well that I try not to let anyone see, but it's fun to share those that do work.  smiley-mr-green
Logged

There's always a better way!

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 176
Posts: 12283
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Just what the doctor ordered...
http://arduino.cc/forum/index.php?topic=51210.0
http://arduino.cc/playground/Code/QP
Logged

Finland
Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes it can by time sharing CPU's duties.


http://arduino.cc/forum/index.php/topic,66062.msg694047.html#msg694047
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I want to put a RGB led in an arcade style button, I have some code to make it fade between colors. I want to run this (looping) while also reading the button and doing other stuff from the resulting state of the button. How do any of you suggest going about this?

use attachInterrupt() triggered by the arcade button, be sure to debounce it properly
Logged

Austin, TX
Offline Offline
Full Member
***
Karma: 0
Posts: 134
I make my own electricity.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Cool!  So, in my ISR I save the flags and PC in a task state structure, the load the previous saved flags from a different task state structure, stack the PC, and RETI?

Just remind me of how you are going to handle stack-based variables.

One stack per thread.

When the scheduler timer expires, I save all the state needed for the RETI to land back where it came from.  I then pick another thread, load whatever registers are required to resume from exactly where the previous scheduler expiry interrupt was, load the flags, stack the PC, RETI.

This is a walk in the park.  A long and pointless walk in the park, but nothing technically difficult.
Logged

Pages: 1 2 [3]   Go Up
Jump to: