[TUT][C][Code] Simple Task Switcher

Go To Last Post
15 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi guys!

Well I always wondered how to make things simple and easy to use.
So one day I came up with this multi-tasking code, which I hope will
help atleast beginners.
(I want to specify that I havent copied this and I dont care if something
similar is found somewhere in this universe.)

I'm presenting a simple (partialy) preemtive task switching system which
combines little asm code with C based code.

Also if one should feel that it can improve the code, be my guest.
(I have to admit the code can be optimised in many areas.)
If someone finds any errors feel free to mention them.

What are the good parts:
1. If you want time divisons as low as 1ms, well you can atleast
try it out
2. 1 thread uses 36bytes of stack + Xbytes for the thread itself; where X can be set by user
3. Very easy to set the number of tasks.
4. Also it is 99% C code, it works with S3 and SO optimisations.
(Havent tryed S0, S1, S2 but it should work)

What are the bad parts of the system:
1. Two or more tasks should not use simultaneous same peripheral
or use data that cant be identified by the task.
2. The switching is done at the loss of ~233cycles/S3, so one should
consider using optimal ussefull cycles vs the switching cycles.
3. SRAM is used proportional with the number of tasks
4. Code space

Short briefing:
The system uses Timer0(but it can use any timer) to create the
switching-between-tasks mechanism.

First time the program starts, it is initializing the existing threads and
after it starts to work normally.

How to start the work:
1. Declare the thread functions;
2. id_thread represents the actual running thread;(do not ever modify this)
3. threads_init_ok specifies that threads were initilised ok;
4. int main() contains the the initialization of Timer0 and the
thread first-time-initilisation process;
5. The threads-body structure;
6. The ISR code for the switching process

Good luck!

//
//	Thread Switching Code (Partialy Preemptive)
//	(c)Banciu Alexandru 2012. Free for any use.
//	Code built for ATmega128 @ 7.3728Mhz
//
//	Easy to understand and to configure
//	

void thread0(); 
void thread1(); 
void thread2(); 
volatile uint8_t id_thread=0;
volatile uint8_t threads_init_ok=0;
volatile uint8_t thread0_init_ok=0, thread1_init_ok=0, thread2_init_ok=0;
volatile uint8_t t0_PCH, t0_PCL, t0_register0;
volatile uint8_t regs[3][2]; //v[id_thread][PCx]; X=0=>L; X=1=>H

int main()
{ 
//void* alloca (size_t __size);
//timer0_init();
do{

//Thread0 initialization
sei();{}while(thread0_init_ok==0);cli();
if(threads_init_ok==0){goto exit_thread0;}
thread0();
exit_thread0:

//Thread1 initialization
sei();{}while(thread1_init_ok==0);cli();
if(threads_init_ok==0){goto exit_thread1;}
thread1();	
exit_thread1:

//Thread2 initialization
//Last thread initilization body structure
sei();do{}while(thread2_init_ok==0);cli();
thread2();

}while(1);
return 0;
}

void thread0()
{
sei();
do{
//CODE
}while(1);
}

void thread1()
{
sei();
do{
//CODE
}while(1);
}

void thread2()
{
sei();
do{
//CODE
}while(1);
}

ISR(TIMER0_COMP_vect, ISR_NAKED)
{
asm volatile ("sts t0_register0, r0");
asm volatile ("pop r0");//PCH
asm volatile ("sts t0_PCH, r0");//save PCH
asm volatile ("pop r0");//PCL
asm volatile ("sts t0_PCL, r0");//save PCL
asm volatile ("push r0");//restore PCL
asm volatile ("lds r0, t0_PCH");
asm volatile ("push r0");//restore PCH
asm volatile ("lds r0, t0_register0");
asm volatile ("push r0"); 
asm volatile ("push r1"); 
asm volatile ("push r2"); 
asm volatile ("push r3"); 
asm volatile ("push r4"); 
asm volatile ("push r5"); 
asm volatile ("push r6"); 
asm volatile ("push r7"); 
asm volatile ("push r8"); 
asm volatile ("push r9"); 
asm volatile ("push r10"); 
asm volatile ("push r11"); 
asm volatile ("push r12"); 
asm volatile ("push r13"); 
asm volatile ("push r14"); 
asm volatile ("push r15"); 
asm volatile ("push r16"); 
asm volatile ("push r17"); 
asm volatile ("push r18"); 
asm volatile ("push r19"); 
asm volatile ("push r20"); 
asm volatile ("push r21"); 
asm volatile ("push r22"); 
asm volatile ("push r23"); 
asm volatile ("push r24"); 
asm volatile ("push r25"); 
asm volatile ("push r26"); 
asm volatile ("push r27"); 
asm volatile ("push r28"); 
asm volatile ("push r29"); 
asm volatile ("push r30"); 
asm volatile ("push r31"); 
asm volatile ("in r0, 0x3B");//RAMPZ
asm volatile ("push r0");
asm volatile ("in r0, 0x3F");//SREG
asm volatile ("push r0"); 
regs[id_thread][0]=SPL;
regs[id_thread][1]=SPH;

//set the initialized thread flag and
//reserve a custom thread stack size
switch(id_thread)
{
case 0: thread0_init_ok=1; SP=SP-32; break;
case 1: thread1_init_ok=1; SP=SP-16; break;
case 2: thread2_init_ok=1; break;
default: break;
//add case according to nr. of threads
}

if(id_thread>=2){id_thread=0; threads_init_ok=1;} //3 Active Threads
else{id_thread++;}

if(threads_init_ok)
{
SPL=regs[id_thread][0];
SPH=regs[id_thread][1];
asm volatile ("pop r0");
asm volatile ("out 0x3F, r0");//SREG
asm volatile ("pop r0");
asm volatile ("out 0x3B, r0");//RAMPZ
asm volatile ("pop r31");
asm volatile ("pop r30");
asm volatile ("pop r29");
asm volatile ("pop r28");
asm volatile ("pop r27");
asm volatile ("pop r26");
asm volatile ("pop r25");
asm volatile ("pop r24");
asm volatile ("pop r23");
asm volatile ("pop r22");
asm volatile ("pop r21");
asm volatile ("pop r20");
asm volatile ("pop r19");
asm volatile ("pop r18");
asm volatile ("pop r17");
asm volatile ("pop r16");
asm volatile ("pop r15");
asm volatile ("pop r14");
asm volatile ("pop r13");
asm volatile ("pop r12");
asm volatile ("pop r11");
asm volatile ("pop r10");
asm volatile ("pop r9");
asm volatile ("pop r8");
asm volatile ("pop r7");
asm volatile ("pop r6");
asm volatile ("pop r5");
asm volatile ("pop r4");
asm volatile ("pop r3");
asm volatile ("pop r2");
asm volatile ("pop r1");
asm volatile ("pop r0");
}
else
{
asm volatile ("lds r0, t0_PCL");//load PCL
asm volatile ("push r0");//restore PCL
asm volatile ("lds r0, t0_PCH");//load PCH
asm volatile ("push r0");//restore PCH
}
asm volatile ("reti");
}
Last Edited: Sat. Aug 25, 2012 - 02:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I'm presenting a simple (partialy) preemtive task switching system which
combines little asm code with C based code.
I appreciate that you want to contribute to the community by making your code public.
But I am sorry, I don't think that that code should be "advertised" here as tutorial. It is the most inefficient "simple" task switcher I have seen so far. And it has a huge design flaw, it is preemptive but the threads don't have their own stacks. Therefore the threads are very restricted, e.g. you can't call a function within a thread.

Quote:
Also if one should feel that it can improve the code, be my guest.
(I have to admit the code can be optimised in many areas.)
If someone finds any errors feel free to mention them.
Wouldn't that be only a waste of time? The result would be something very similar to the dozens already existing task switchers.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the reply sternst.
In order with your observations, I have added stacks for each thread and also optimized the code.
I've tested "call a function within a thread" and works well with the new code as long as it stays in the predefined(by user) thread stack.

Also I dont mean this code to be a tutorial if it has no good usage for anyone.
Also any ideea is wellcomed.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Also I dont mean this code to be a tutorial

Why did you post in the tutorial forum then?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tutorials should undergo a vetting process before being posted in the tutorial forum. If not that, then at least delete them after complaints about correctness and usefulness.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well I'm tempted to just cut this loose in AVR Forum for peer review but I'd like to hear from the OP first. Either he thinks this is a tutorial or he doesn't (latter seems more likely).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

I couldn't help but notice this post. Which is code to achieve multi-tasking.

I will share for any newbie the most powerful method in embedded programming that even some experienced programmers are not aware of. It will enable you to make simple or complex, scalable, understandable and reliable embedded applications.

I am talking about the 'state-machine'

Important Tip 1:

1. Separate your tasks into 'state machines';

Code each task with a function that is called rapidly and repeatedly by the main function.

For example:


void sampling_task()
{
   switch(state)
   {
      case startSample:
            start something
            or do something
            state = nextstate
      break;
      
      case nextstate:
       
           if ready for state3
              state = state3

      etc
      etc

   }
}

etc.
this may seem convoluted at first.
But it is truly beautiful and elegant.
the most important thing about these state machines is that they contain no delays, and they return quickly.

Important tip 2:

Time delays,
Never do a time delay with a loop of nops.
Instead setup one global counter called 'tick'.

unsigned uint32 tick

Every 10mSec this tick is incremented in a timer interrupt.

this single tick value can be used to implement any number of simultaneous time delays in any of your tasks:

eg:

if ((unsigned int32)(tick - mytimer1) > 50)
{
    // do this every 500mSec
    //

     mytimer1 = tick ;
}

Finally:

Your main function will look like this:


main()
{

    // set things up (start the tick timer)

    
   // endless loop
   //
   for(;;)
    {

        sampling_task();
        another_task();
        and_another_task();
        and_anther_task();
      
    }



   
}


Summary:

This is called 'cooperative multitasking'
Tasks are not 'preempted'
You can use global variables across tasks.
You don't need an operating system.
It is easy to debug.
It is fast and efficient.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Penguin,

I presume you didn't see this then:

http://www.avrfreaks.net/index.p...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wave that flag Cliff!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh,
No I didn't see that.
It does have the extra level of a task-switching framework, which is a bit bulkier.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You'd have to be counting every last byte to consider it 'bulky'. Check to see how many bytes it actually does cost you.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Will Part 2 be on the new site Russell? We have to have something to entice us over to the other side. :lol:

Ross McKenzie ValuSoft Melbourne Australia

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

RickB wrote:
Tutorials should undergo a vetting process before being posted in the tutorial forum. If not that, then at least delete them after complaints about correctness and usefulness.

I think this would be a good idea. It seems crazy that anyone can write a "tutorial" and post it.

Quebracho seems to be the hardest wood.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Again, I argue for a voting mechanism so that e.g. a tutorials forum becomes a meritocracy of sorts.

I think censoring tutorials should be done with great care and very rarely.

"He used to carry his guitar in a gunny sack, or sit beneath the tree by the railroad track. Oh the engineers would see him sitting in the shade, Strumming with the rhythm that the drivers made. People passing by, they would stop and say, "Oh, my, what that little country boy could play!" [Chuck Berry]

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Johan:

 

Tutorials should undergo a vetting process before being posted in the tutorial forum. If not that, then at least delete them after complaints about correctness and usefulness.

Nothing I said constitutes advocating censorship, this is a technical educational forum promoting best practices and technical excellence to aid beginners in achieving their goals. It is  not a political discussion. Period.