Code for multiprogram II

9 examples with code and digital analyzer images

digital pins

  • DI0 : high when dummy task is running

  • DI1 : high when task is running

  • DI2 : high when task2 is running (not all examples has a task2)

  • DI3: high when task is in critical region (not in alle examples)

  • DI4: high when task is in critical region (not in alle examples)

k01 - one periodic task

task runs in a loop:

  1. Eating 10 msec of CPU time

  2. Sleep for 30 ticks of 1 msec (set on k_init)

krnl/examples/demos-w-analyser/k01/k01.ino

demos-w-analyser/k01/k01.ino
demos-w-analyser/k02/k02.ino
demos-w-analyser/k03/k03.ino
demos-w-analyser/k04/k04.ino
demos-w-analyser/k05/k05.ino
demos-w-analyser/k06/k06.ino
demos-w-analyser/k07/k07.ino
demos-w-analyser/k08/k08.ino
demos-w-analyser/k09/k09.ino
demos-w-analyser/k10/k10.ino
demos-w-analyser/k11/k11.ino
k01myfirsttask/k01myfirsttask.ino
k02twotasks/k02twotasks.ino
k03asleep/k03asleep.ino
k03priorityequal/k03priorityequal.ino
k04periodic-clip/k04periodic-clip.ino
k04periodic/k04periodic.ino
k06syncsem/k06syncsem.ino
k07mutexsem-adv/k07mutexsem-adv.ino
k09msgq/k09msgq.ino
krnldebugled13/krnldebugled13.ino
krnlsimpledebugled/krnlsimpledebugled.ino

You can oberserve that

  1. task(DIO 1) is running approx every 40 msec andd eating 10 msec of time.

    1. high indicates running

  2. When task is not active then dummytask (DIO 0) takes over

alt text 

k02 Two tasks

In K02 both tasks (task(DIO 1) and task2( DIO 2) is

  1. both running an endless loop

  2. is active all time

  3. krnl has timer running at 1 msec (k_init)

  4. task and task2 has same priority so

    1. round robbing between them is every 1 msec

  5. and dummytask (DIO 0) will never run bq task and task2 will use all available time krnl/examples/demos-w-analyser/k02/k02.ino

  
/* k02
    One task printing own usage of stak
*/

#include 

#define STKSIZE 100

#define TASKPRIO 10

char stak[STKSIZE],stak2[STKSIZE];
struct k_t * pTask,*pTask2;

void task()
{
  int unusedStak;
  while (1) {
   // k_eat_msec(10);  // consume 10 millisec of CPU time
  //  k_sleep(30); // sleep 100 ticks - replacement for delay bq k_seelp releases CPU
  }
}


void task2()
{
  int unusedStak;
  while (1) {
  //  k_eat_msec(3);  // consume 10 millisec of CPU time
  //  k_sleep(20); // sleep 100 ticks - replacement for delay bq k_seelp releases CPU
  }
}


void setup() {
  // for debugging
  for (int i = 8; i < 14; i++)
    pinMode(i, OUTPUT);

  Serial.begin(9600);
  
  k_init(2, 0, 0); // 1 task, 0 semaphores, 0 messaegQueues */
  pTask = k_crt_task(task, TASKPRIO, stak, STKSIZE);
  pTask2 = k_crt_task(task2, TASKPRIO+1, stak2, STKSIZE);
  k_start(); /* start krnl timer speed 1 milliseconds*/

  Serial.println("If you see this then krnl didnt start :-( ");
}

void loop() {}

/***** DEBUGGING PART - LED ON 8-12**********/
/************************ DEBUG CALLBACK BREAKOUT PART ****************/
// must be extern C ! its not mandatory to supply with these  functions - only if you need

extern "C" {

  // called when a semphore is clipping - nr is id of semaphore and i os nr of times clip has occured
  unsigned char led13;
  void k_sem_clip(unsigned char nr, int i)
  {
    return;
    if (nr == 2)
      led13 |= 0x20;
  }

  void k_sem_unclip(unsigned char nr)
  {
    return;
    if (nr == 2)
      led13 = 0x00;
  }


  /* void k_send_Q_clip(unsigned char nr, int i) {} */

  // task numbering is in creation order: dummy: 0,  first of yours 1, next 2,...
  void k_breakout() // called every task shift from dispatcher
  {
    unsigned char c;
    PORTB  = (1 << pRun->nr); // arduino uno !! specific usage of PORTB
  }
  // for a MEGA you have to find another port :-)
  // port K (adc8-15) seems feasible
  // get inspired at http://kom.aau.dk/~jdn/edu/doc/arduino/ards.html
}




Observe

  1. dummytask(DIO 0) is never runnnig

  2. task and task2 (DIO 1 and DIO 2) is sharing CPU every 1 msec (round robbin)

alt text 

k03 Two tasks, same priority, eat and sleep

Two tasks: task(DIO 1) and task2 (DIO 2)

  1. Endless loop where they

    1. Eat 10/3 msec of CPU time

    2. Sleep 30/20 msec

  2. Utilization of CPU is approx 1040 + 3/23 = 0.38

  3. Leaving 72% of time to dummtask (DIO 0)

krnl/examples/demos-w-analyser/k03/k03.ino


/* k03
    two tasks multitasing same priority
*/

#include 

#define STKSIZE 100

#define TASKPRIO 10

char stak[STKSIZE], stak2[STKSIZE];
struct k_t * pTask, *pTask2;

void task()
{
  int unusedStak;
  while (1) {
    k_eat_time(10);  // consume 10 millisec of CPU time
    k_sleep(30); // sleep 100 ticks - replacement for delay bq k_seelp releases CPU
  }
}


void task2()
{
  int unusedStak;
  while (1) {
    k_eat_time(3);  // consume 10 millisec of CPU time
    k_sleep(20); // sleep 100 ticks - replacement for delay bq k_seelp releases CPU
  }
}


void setup() {
  // for debugging
  for (int i = 8; i < 14; i++)
    pinMode(i, OUTPUT);

  Serial.begin(9600);

  k_init(2, 0, 0); // 1 task, 0 semaphores, 0 messaegQueues */
  pTask = k_crt_task(task, TASKPRIO, stak, STKSIZE);
  pTask2 = k_crt_task(task2, TASKPRIO, stak2, STKSIZE);
  k_start(1); /* start krnl timer speed 1 milliseconds*/

  Serial.println("If you see this then krnl didnt start :-( ");
}

void loop() {}

/***** DEBUGGING PART - LED ON 8-12**********/
/************************ DEBUG CALLBACK BREAKOUT PART ****************/
// must be extern C ! its not mandatory to supply with these  functions - only if you need

extern "C" {

  // called when a semphore is clipping - nr is id of semaphore and i os nr of times clip has occured
  unsigned char led13;
  void k_sem_clip(unsigned char nr, int i)
  {
    return;
    if (nr == 2)
      led13 |= 0x20;
  }

  void k_sem_unclip(unsigned char nr)
  {
    return;
    if (nr == 2)
      led13 = 0x00;
  }


  /* void k_send_Q_clip(unsigned char nr, int i) {} */

  // task numbering is in creation order: dummy: 0,  first of yours 1, next 2,...
  void k_breakout() // called every task shift from dispatcher
  {
    unsigned char c;
    PORTB  = (1 << pRun->nr); // arduino uno !! specific usage of PORTB
  }
  // for a MEGA you have to find another port :-)
  // port K (adc8-15) seems feasible
  // get inspired at http://kom.aau.dk/~jdn/edu/doc/arduino/ards.html
}




You may observe

  1. Endless loop where they

    1. Eat 10/3 msec of CPU time

    2. Sleep 30/20 msec

  2. Utilization of CPU is approx 1040 + 3/23 = 0.38

  3. Leaving 72% of time to dummtask (DIO 0)

  4. when task and task2 both wnat to use CPU they will round robbin every 1 msec bq they have same priority

    1. See that at approx -33 smec to -27msec or so - at the arrow

  5. A rough estimation of worst case duration for eating time for the tasks will be

    1. task 10msec+3msec=13msec (approx the situation on the figure) bq task2 will max runs one time during task eating time

    2. task2 duration is 3 msec and round robbin with task will prolong task will those 3 msec, and prolong task2 with 3 msec as well in this situation

alt text 

k04 - as k03 but task has higher priority than task2

Two tasks: task(DIO 1) and task2 (DIO 2)

  1. Endless loop where they

    1. Eat 10/3 msec of CPU time

    2. Sleep 30/20 msec

  2. Utilization of CPU is approx 1040 + 3/23 = 0.38

  3. Leaving 72% of time to dummtask (DIO 0)

krnl/examples/demos-w-analyser/k04/k04.ino


/* k04
 *  as k03 but now task has higher priority so it can take cpu from task2 when needed :-)
*/

#include 

#define STKSIZE 100

#define TASKPRIO 10

char stak[STKSIZE], stak2[STKSIZE];
struct k_t * pTask, *pTask2;

void task()
{
  int unusedStak;
  while (1) {
    k_eat_msec(10);  // consume 10 millisec of CPU time
    k_sleep(30); // sleep 100 ticks - replacement for delay bq k_seelp releases CPU
  }
}


void task2()
{
  int unusedStak;
  while (1) {
    k_eat_msec(3);  // consume 10 millisec of CPU time
    k_sleep(20); // sleep 100 ticks - replacement for delay bq k_seelp releases CPU
  }
}


void setup() {
  // for debugging
  for (int i = 8; i < 14; i++)
    pinMode(i, OUTPUT);

  Serial.begin(9600);

  k_init(2, 0, 0); // 1 task, 0 semaphores, 0 messaegQueues */
  pTask = k_crt_task(task, TASKPRIO, stak, STKSIZE);
  pTask2 = k_crt_task(task2, TASKPRIO+1, stak2, STKSIZE); // +1 == lower priority
  k_start(); /* start krnl timer speed 1 milliseconds*/

  Serial.println("If you see this then krnl didnt start :-( ");
}

void loop() {}

/***** DEBUGGING PART - LED ON 8-12**********/
/************************ DEBUG CALLBACK BREAKOUT PART ****************/
// must be extern C ! its not mandatory to supply with these  functions - only if you need

extern "C" {

  // called when a semphore is clipping - nr is id of semaphore and i os nr of times clip has occured
  unsigned char led13;
  void k_sem_clip(unsigned char nr, int i)
  {
    return;
    if (nr == 2)
      led13 |= 0x20;
  }

  void k_sem_unclip(unsigned char nr)
  {
    return;
    if (nr == 2)
      led13 = 0x00;
  }


  /* void k_send_Q_clip(unsigned char nr, int i) {} */

  // task numbering is in creation order: dummy: 0,  first of yours 1, next 2,...
  void k_breakout() // called every task shift from dispatcher
  {
    unsigned char c;
    PORTB  = (1 << pRun->nr); // arduino uno !! specific usage of PORTB
  }
  // for a MEGA you have to find another port :-)
  // port K (adc8-15) seems feasible
  // get inspired at http://kom.aau.dk/~jdn/edu/doc/arduino/ards.html
}




You may observe

  1. Endless loop where they

    1. Eat 10/3 msec of CPU time

    2. Sleep 30/20 msec

  2. Utilization of CPU is approx 1040 + 3/23 = 0.38

  3. Leaving 72% of time to dummtask (DIO 0)

  4. when task and task2 both want to use CPU they will NOT do round robbin but task (DIO 1) will run to end bq task has higher priority than task2

  5. See at arrows where task becomes active and task2 is missing CPU and will get it after second arrow where task has eaten 10 msec of time

  6. So task will runs as alone in the world bq of highest priority in system and task2 will suffer and loosing CPU to task when requested even if task2 is active.

  7. So deadlines will vary for task2 but not for task.

  8. Worst case duration for task is teh duration for all loops and will be 3 msec

  9. Worstcase duration for task2 to execute 3 msec eating will be 3msec + 10msec. The 10 msec comning from waiting on CPU from task.

  10. A total different situation from k03.

alt text 

k05 Two tasks fighting for critical region

  1. Critical section implemented by a pair og k_wait and k_signal

  2. Pin 8 to 12 used for indication of who is running and which task is inside the region

    1. pin 8 (DIO 0) - Dummytask (task nr 0

    2. pin 9 (DIO 1) task (task nr 1)

    3. pin 10 (DIO 2) task2 (task nr 2)

    4. pin 11 (DIO 3) task inside region

    5. pin 12 (DIO 4) task2 inside region

  1. Some dirty code for fast pin togling. On Uno pin 8,9,10,.. is from PORTB bit 0,1,2,…

  2. If you are using a MEGA PORTA may be better. pin layout

Interrupt is disabled during PORTB manipulation to ensure it is carried out atomic.

Each task is eating time inside and outside the critical region krnl/examples/demos-w-analyser/k05/k05.ino


/* k05
    Critical region by semaphore
    task update data and task2 use them

*/

#include 

#define STKSIZE 100

#define TASKPRIO 10

char stak[STKSIZE], stak2[STKSIZE];
struct k_t * pTask, *pTask2, *sem1;

volatile char reg = 0;
 
void task()
{
  int res;
  while (1) {
    res = k_wait(sem1, 0); // knock knock at sem1. timeout = 0 means forever
    
    DI();  // just for setting bit for critical region for osc
    reg =  0x08;
    PORTB = (1 << pRun->nr) | reg;
    EI();

    k_eat_msec(10);  // consume 10 millisec of CPU time

    DI();
    reg = 0; // reset crit reg pin
    PORTB = (1 << pRun->nr) | reg;
    EI();

    k_signal(sem1);

    k_sleep(1);
    k_eat_msec(3);
    k_sleep(30); // sleep 100 ticks - replacement for delay bq k_seelp releases CPU
  }
}

void task2()
{
  int res;
  while (1) {
    res = k_wait(sem1, 0); // knock knock at sem1. timeout = 0 menans forever
    DI();  // just for setting bit for critical region for osc
    reg =  0x10;
    PORTB = (1 << pRun->nr) | reg;
    EI();

    k_eat_msec(3);  // consume 10 millisec of CPU time

    DI();
    reg = 0;
    PORTB = (1 << pRun->nr) | reg;
    EI();

    k_signal(sem1);
    k_sleep(1);
    k_eat_msec(1);

    k_sleep(20); // sleep 100 ticks - replacement for delay bq k_seelp releases CPU
  }
}


void setup() {
  // for debugging
  for (int i = 8; i < 14; i++)
    pinMode(i, OUTPUT);

  Serial.begin(9600);

  k_init(2, 2, 0); // 2 task, 1 semaphores, 0 messaegQueues */
  pTask = k_crt_task(task, TASKPRIO, stak, STKSIZE);
  pTask2 = k_crt_task(task2, TASKPRIO, stak2, STKSIZE); // +1 == lower priority

  sem1 = k_crt_sem(1, 10); // 1: start value, 10: max value (clipping)
  k_start(); /* start krnl timer speed 1 milliseconds*/

  Serial.println("If you see this then krnl didnt start :-( ");
}

void loop() {}

/***** DEBUGGING PART - LED ON 8-12**********/
/************************ DEBUG CALLBACK BREAKOUT PART ****************/
// must be extern C ! its not mandatory to supply with these  functions - only if you need

extern "C" {

  // called when a semphore is clipping - nr is id of semaphore and i os nr of times clip has occured
  unsigned char led13;
  ;
  void k_sem_clip(unsigned char nr, int i)
  {
    return;
    if (nr == 2)
      led13 |= 0x20;
  }

  void k_sem_unclip(unsigned char nr)
  {
    return;
    if (nr == 2)
      led13 = 0x00;
  }


  /* void k_send_Q_clip(unsigned char nr, int i) {} */

  // task numbering is in creation order: dummy: 0,  first of yours 1, next 2,...
  void k_breakout() // called every task shift from dispatcher
  {
    unsigned char c;
    PORTB  = (1 << pRun->nr) | reg; // arduino uno !! specific usage of PORTB
  }
  // for a MEGA you have to find another port :-)
  // port K (adc8-15) seems feasible
  // get inspired at http://kom.aau.dk/~jdn/edu/doc/arduino/ards.html
}




  1. pin 8 (DIO 0) - Dummytask (task nr 0

  2. pin 9 (DIO 1) task (task nr 1)

  3. pin 10 (DIO 2) task2 (task nr 2)

  4. pin 11 (DIO 3) task inside region

  5. pin 12 (DIO 4) task2 inside region

Each task is eating time inside and outside the critical region

Some observations for task2:

  1. At approx -12msec task2 is eating 3msec inside critical region

  2. At approx -9msec task2 is leaving critical region and sleep for 1 msec

  3. At approx -8 msec task2 is eating 1 msec

  4. At approx -7 msec task2 sleep for 20 msec

  5. At approx 23 msec task2 wake up loop to top of while and get critical region at once

  6. and repeat as above

What did happen at -40 msec ? Seems that

  1. before -40 msec is task inside critical region and task is waiting outside

  2. As soon as task release critical region task2 enter the region.

alt text 

k06 - as k05 but task2 has lower priority than task

Task has higher priority than task2

  1. task will take CPU when needed

    1. At approx 22 msec task take CPU after a 1msec sleep after critical region

    2. And the stay inside the region is prolonged for task2

krnl/examples/demos-w-analyser/k06/k06.ino

 
/* k06
    Critical region by semaphore
    task update data and task2 use them
    task has higher priority than task 2

*/

#include 

#define STKSIZE 100

#define TASKPRIO 10

char stak[STKSIZE], stak2[STKSIZE];
struct k_t * pTask, *pTask2, *sem1;

volatile char reg = 0;
 
void task()
{
  int res;
  while (1) {
    res = k_wait(sem1, 0); // knock knock at sem1. timeout = 0 means forever
    
    DI();  // just for setting bit for critical region for osc
    reg =  0x08;
    PORTB = (1 << pRun->nr) | reg;
    EI();

    k_eat_msec(10);  // consume 10 millisec of CPU time

    DI();
    reg = 0; // reset crit reg pin
    PORTB = (1 << pRun->nr) | reg;
    EI();

    k_signal(sem1);

    k_sleep(1);
    k_eat_msec(3);
    k_sleep(30); // sleep 100 ticks - replacement for delay bq k_seelp releases CPU
  }
}

void task2()  // lower prority than task above
{
  int res;
  while (1) {
    res = k_wait(sem1, 0); // knock knock at sem1. timeout = 0 menans forever
    DI();  // just for setting bit for critical region for osc
    reg =  0x10;
    PORTB = (1 << pRun->nr) | reg;
    EI();

    k_eat_msec(3);  // consume 10 millisec of CPU time

    DI();
    reg = 0;
    PORTB = (1 << pRun->nr) | reg;
    EI();

    k_signal(sem1);
    k_sleep(1);
    k_eat_msec(1);

    k_sleep(20); // sleep 100 ticks - replacement for delay bq k_seelp releases CPU
  }
}


void setup() {
  // for debugging
  for (int i = 8; i < 14; i++)
    pinMode(i, OUTPUT);

  Serial.begin(9600);

  k_init(2, 2, 0); // 2 task, 1 semaphores, 0 messaegQueues */
  pTask = k_crt_task(task, TASKPRIO, stak, STKSIZE);
  pTask2 = k_crt_task(task2, TASKPRIO+1, stak2, STKSIZE); // +1 == lower priority

  sem1 = k_crt_sem(1, 10); // 1: start value, 10: max value (clipping)
  k_start(); /* start krnl timer speed 1 milliseconds*/

  Serial.println("If you see this then krnl didnt start :-( ");
}

void loop() {}

/***** DEBUGGING PART - LED ON 8-12**********/
/************************ DEBUG CALLBACK BREAKOUT PART ****************/
// must be extern C ! its not mandatory to supply with these  functions - only if you need

extern "C" {

  // called when a semphore is clipping - nr is id of semaphore and i os nr of times clip has occured
  unsigned char led13;
  ;
  void k_sem_clip(unsigned char nr, int i)
  {
    return;
    if (nr == 2)
      led13 |= 0x20;
  }

  void k_sem_unclip(unsigned char nr)
  {
    return;
    if (nr == 2)
      led13 = 0x00;
  }


  /* void k_send_Q_clip(unsigned char nr, int i) {} */

  // task numbering is in creation order: dummy: 0,  first of yours 1, next 2,...
  void k_breakout() // called every task shift from dispatcher
  {
    unsigned char c;
    PORTB  = (1 << pRun->nr) | reg; // arduino uno !! specific usage of PORTB
  }
  // for a MEGA you have to find another port :-)
  // port K (adc8-15) seems feasible
  // get inspired at http://kom.aau.dk/~jdn/edu/doc/arduino/ards.html
}




  1. Observe at approx 22 msec that task taskes CPU bq task has higher priority than task2

  2. Which prolongs the stay of task inside the critical region (Seen on DIO 4) at 24msec

alt text 

k09 One task running fixed samplingsfrequency

A sempaphore get attached a krnl timer which signal to the semaphore every 10 tick * 1msec

The task do only wait by the semaphore and when the sempahore gets a krnl kick (signal) at regular intervals

  1. task is released form the semaphore

  2. eat 3 msec

  3. loop to top and wait again to next sample time

Can be used for control loops like

void task()
{
  int res;

  k_set_sem_timer(sem1, 10); // krnl signals every 10 msec

  while (1) {
    res = k_wait(sem1, 0); // knock knock at sem1. timeout = 0 means forever
    ADC(); // measure input
    controlAlg();
    DAC(); actuate output
  }
}

The code

krnl/examples/demos-w-analyser/k09/k09.ino


/* k09
     
     sampling with fixed frequency with timer on sempahore

*/

#include 

#define STKSIZE 100

#define TASKPRIO 10

char stak[STKSIZE], stak2[STKSIZE];
struct k_t * pTask, *pTask2, *sem1;

volatile char reg = 0;

void task()
{
  int res;

  k_set_sem_timer(sem1, 10); // krnl signals every 10 msec
  
  while (1) {
    res = k_wait(sem1, 0); // knock knock at sem1. timeout = 0 means forever
    k_eat_msec(3);
  }
}


void setup() {
  // for debugging
  for (int i = 8; i < 14; i++)
    pinMode(i, OUTPUT);

  Serial.begin(9600);

  k_init(1, 1, 0); // 2 task, 1 semaphores, 0 messaegQueues */
  pTask = k_crt_task(task, TASKPRIO, stak, STKSIZE);

  sem1 = k_crt_sem(0, 10); // 1: start value, 10: max value (clipping)
  k_start(); /* start krnl timer speed 1 milliseconds*/

  Serial.println("If you see this then krnl didnt start :-( ");
}

void loop() {}

/***** DEBUGGING PART - LED ON 8-12**********/
/************************ DEBUG CALLBACK BREAKOUT PART ****************/
// must be extern C ! its not mandatory to supply with these  functions - only if you need

extern "C" {

  // called when a semphore is clipping - nr is id of semaphore and i os nr of times clip has occured
  unsigned char led13;
  ;
  void k_sem_clip(unsigned char nr, int i)
  {
    return;
    if (nr == 2)
      led13 |= 0x20;
  }

  void k_sem_unclip(unsigned char nr)
  {
    return;
    if (nr == 2)
      led13 = 0x00;
  }


  /* void k_send_Q_clip(unsigned char nr, int i) {} */

  // task numbering is in creation order: dummy: 0,  first of yours 1, next 2,...
  void k_breakout() // called every task shift from dispatcher
  {
    unsigned char c;
    PORTB  = (1 << pRun->nr) | reg; // arduino uno !! specific usage of PORTB
  }
  // for a MEGA you have to find another port :-)
  // port K (adc8-15) seems feasible
  // get inspired at http://kom.aau.dk/~jdn/edu/doc/arduino/ards.html
}




  1. You can see that task is running very regular every 10 msec

alt text 

k10 two task sampling

Debugging on pins has been modified so

  1. DIO3 is high when task is eating CPU time after leaving k_wait

  2. DIO4 is high when task2 is eating CPU time after leaving k_wait

  3. task and task2 has same priority

  4. task is eating 4 msec every 15 msec

  5. task2 is eating 3 msec every 10 msec

a/k10/k10.ino


/* k10

     sampling with fixed frequency with timer on sempahore
     two tasks !
*/

#include 

#define STKSIZE 200

#define TASKPRIO 10

char stak[STKSIZE], stak2[STKSIZE];
struct k_t * pTask, *pTask2, *sem1, *sem2;

volatile char reg = 0;

void task()
{
  int res;

  k_set_sem_timer(sem1, 15); // krnl signals every 10 msec

  while (1) {
    res = k_wait(sem1, 0); // knock knock at sem1. timeout = 0 means forever
    if (res == 0) {
      DI();
      reg = reg | 0x08; // reset crit reg pin
      PORTB = (1 << pRun->nr) | reg;
      EI();

      k_eat_msec(4);

      DI();
      reg = reg & 0xf7; // reset crit reg pin
      PORTB = (1 << pRun->nr) | reg;
      EI();
    }
  }
}

void task2()
{
  int res;

  k_set_sem_timer(sem2, 10); // krnl signals every 10 msec

  while (1) {
    res = k_wait(sem2, 0); // knock knock at sem1. timeout = 0 means forever
    if (res == 0) {
      DI();  // just for setting bit for critical region for osc
      reg =  reg | 0x10;
      PORTB = (1 << pRun->nr) | reg;
      EI();

      k_eat_msec(3);

      DI();
      reg = reg & 0xef; // reset crit reg pin
      PORTB = (1 << pRun->nr) | reg;
      EI();
    }
  }
}


void setup() {
  // for debugging
  for (int i = 8; i < 14; i++)
    pinMode(i, OUTPUT);

  Serial.begin(9600);

  k_init(2, 2, 0); // 2 task, 1 semaphores, 0 messageQueues */
  pTask = k_crt_task(task, TASKPRIO, stak, STKSIZE);
  pTask2 = k_crt_task(task2, TASKPRIO, stak2, STKSIZE);
  sem1 = k_crt_sem(0, 0); // 1: start value, 10: max value (clipping)
  sem2 = k_crt_sem(0, 0); // 1: start value, 10: max value (clipping)k_start(); /* start krnl timer speed 1 milliseconds*/

  k_start();
  Serial.println("If you see this then krnl didnt start :-( ");
}

void loop() {}

/***** DEBUGGING PART - LED ON 8-12**********/
/************************ DEBUG CALLBACK BREAKOUT PART ****************/
// must be extern C ! its not mandatory to supply with these  functions - only if you need

extern "C" {

  // called when a semphore is clipping - nr is id of semaphore and i os nr of times clip has occured
  unsigned char led13;

  void k_sem_clip(unsigned char nr, int i)
  {
    return;
    if (nr == 2)
      led13 |= 0x20;
  }

  void k_sem_unclip(unsigned char nr)
  {
    return;
    if (nr == 2)
      led13 = 0x00;
  }


  /* void k_send_Q_clip(unsigned char nr, int i) {} */

  // task numbering is in creation order: dummy: 0,  first of yours 1, next 2,...
  void k_breakout() // called every task shift from dispatcher
  {
    unsigned char c;
    PORTB  = (1 << pRun->nr) | reg; // arduino uno !! specific usage of PORTB
  }
  // for a MEGA you have to find another port :-)
  // port K (adc8-15) seems feasible
  // get inspired at http://kom.aau.dk/~jdn/edu/doc/arduino/ards.html
}




Debugging on pins has been modified so

  1. DIO3 is high when task is eating CPU time after leaving k_wait

  2. DIO4 is high when task2 is eating CPU time after leaving k_wait

  3. task and task2 has same priority

  4. task is eating 4 msec every 15 msec

  5. task2 is eating 3 msec every 10 msec

So we can observe that due to round robbing and same priority eat time is prolonged from time to time for both tasks.

alt text 

k11 as k10 except task has higher priority taht task2

Now task has highest prority which means it will always get CPU

krnl/examples/demos-w-analyser/k11/k11.ino

  
/* k10

     sampling with fixed frequency with timer on sempahore
     two tasks !
*/

#include 

#define STKSIZE 200

#define TASKPRIO 10

char stak[STKSIZE], stak2[STKSIZE];
struct k_t * pTask, *pTask2, *sem1, *sem2;

volatile char reg = 0;

void task()
{
  int res;

  k_set_sem_timer(sem1, 15); // krnl signals every 10 msec

  while (1) {
    res = k_wait(sem1, 0); // knock knock at sem1. timeout = 0 means forever
    if (res == 0) {
      DI();
      reg = reg | 0x08; // reset crit reg pin
      PORTB = (1 << pRun->nr) | reg;
      EI();

      k_eat_msec(4);

      DI();
      reg = reg & 0xf7; // reset crit reg pin
      PORTB = (1 << pRun->nr) | reg;
      EI();
    }
  }
}

void task2()
{
  int res;

  k_set_sem_timer(sem2, 10); // krnl signals every 10 msec

  while (1) {
    res = k_wait(sem2, 0); // knock knock at sem1. timeout = 0 means forever
    if (res == 0) {
      DI();  // just for setting bit for critical region for osc
      reg =  reg | 0x10;
      PORTB = (1 << pRun->nr) | reg;
      EI();

      k_eat_msec(3);

      DI();
      reg = reg & 0xef; // reset crit reg pin
      PORTB = (1 << pRun->nr) | reg;
      EI();
    }
  }
}


void setup() {
  // for debugging
  for (int i = 8; i < 14; i++)
    pinMode(i, OUTPUT);

  Serial.begin(9600);

  k_init(2, 2, 0); // 2 task, 1 semaphores, 0 messageQueues */
  pTask = k_crt_task(task, TASKPRIO, stak, STKSIZE);
  pTask2 = k_crt_task(task2, TASKPRIO+1, stak2, STKSIZE);
  sem1 = k_crt_sem(0, 0); // 1: start value, 10: max value (clipping)
  sem2 = k_crt_sem(0, 0); // 1: start value, 10: max value (clipping)k_start(); /* start krnl timer speed 1 milliseconds*/

  k_start();
  Serial.println("If you see this then krnl didnt start :-( ");
}

void loop() {}

/***** DEBUGGING PART - LED ON 8-12**********/
/************************ DEBUG CALLBACK BREAKOUT PART ****************/
// must be extern C ! its not mandatory to supply with these  functions - only if you need

extern "C" {

  // called when a semphore is clipping - nr is id of semaphore and i os nr of times clip has occured
  unsigned char led13;

  void k_sem_clip(unsigned char nr, int i)
  {
    return;
    if (nr == 2)
      led13 |= 0x20;
  }

  void k_sem_unclip(unsigned char nr)
  {
    return;
    if (nr == 2)
      led13 = 0x00;
  }


  /* void k_send_Q_clip(unsigned char nr, int i) {} */

  // task numbering is in creation order: dummy: 0,  first of yours 1, next 2,...
  void k_breakout() // called every task shift from dispatcher
  {
    unsigned char c;
    PORTB  = (1 << pRun->nr) | reg; // arduino uno !! specific usage of PORTB
  }
  // for a MEGA you have to find another port :-)
  // port K (adc8-15) seems feasible
  // get inspired at http://kom.aau.dk/~jdn/edu/doc/arduino/ards.html
}




  1. DIO3 is high when task is eating CPU time after leaving k_wait

  2. DIO4 is high when task2 is eating CPU time after leaving k_wait

  3. task and task2 has same priority

  4. task is eating 4 msec every 15 msec

  5. task2 is eating 3 msec every 10 msec

Observe

  1. that DIO 4 might be high for longer that 3 msec

  2. that DIO 3 is always 4 msec bq task just takes CPU due to priority

  3. See at -13 msec for task2 we have 3 msec eat and the same at -8 msec.

  4. Might be that -13msec is delayed bq task is running from -17msec to -13msec

  5. I guess task2 would like to had CPU at -17msec but task takes it

  6. So we have jitter on task2

alt text 

CONCLUSION

Multitasking is very difficult to understand, estimate and debug