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:
Eating 10 msec of CPU time
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
task(DIO 1) is running approx every 40 msec andd eating 10 msec of time.
high indicates running
When task is not active then dummytask (DIO 0) takes over
k02 Two tasks
In K02 both tasks (task(DIO 1) and task2( DIO 2) is
both running an endless loop
is active all time
krnl has timer running at 1 msec (k_init)
task and task2 has same priority so
round robbing between them is every 1 msec
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
dummytask(DIO 0) is never runnnig
task and task2 (DIO 1 and DIO 2) is sharing CPU every 1 msec (round robbin)
k03 Two tasks, same priority, eat and sleep
Two tasks: task(DIO 1) and task2 (DIO 2)
Endless loop where they
Eat 10/3 msec of CPU time
Sleep 30/20 msec
Utilization of CPU is approx 1040 + 3/23 = 0.38
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
Endless loop where they
Eat 10/3 msec of CPU time
Sleep 30/20 msec
Utilization of CPU is approx 1040 + 3/23 = 0.38
Leaving 72% of time to dummtask (DIO 0)
when task and task2 both wnat to use CPU they will round robbin every 1 msec bq they have same priority
See that at approx -33 smec to -27msec or so - at the arrow
A rough estimation of worst case duration for eating time for the tasks will be
task 10msec+3msec=13msec (approx the situation on the figure) bq task2 will max runs one time during task eating time
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
k04 - as k03 but task has higher priority than task2
Two tasks: task(DIO 1) and task2 (DIO 2)
Endless loop where they
Eat 10/3 msec of CPU time
Sleep 30/20 msec
Utilization of CPU is approx 1040 + 3/23 = 0.38
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
Endless loop where they
Eat 10/3 msec of CPU time
Sleep 30/20 msec
Utilization of CPU is approx 1040 + 3/23 = 0.38
Leaving 72% of time to dummtask (DIO 0)
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
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
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.
So deadlines will vary for task2 but not for task.
Worst case duration for task is teh duration for all loops and will be 3 msec
Worstcase duration for task2 to execute 3 msec eating will be 3msec + 10msec. The 10 msec comning from waiting on CPU from task.
A total different situation from k03.
k05 Two tasks fighting for critical region
Critical section implemented by a pair og k_wait and k_signal
Pin 8 to 12 used for indication of who is running and which task is inside the region
pin 8 (DIO 0) - Dummytask (task nr 0
pin 9 (DIO 1) task (task nr 1)
pin 10 (DIO 2) task2 (task nr 2)
pin 11 (DIO 3) task inside region
pin 12 (DIO 4) task2 inside region
Some dirty code for fast pin togling. On Uno pin 8,9,10,.. is from PORTB bit 0,1,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
}
pin 8 (DIO 0) - Dummytask (task nr 0
pin 9 (DIO 1) task (task nr 1)
pin 10 (DIO 2) task2 (task nr 2)
pin 11 (DIO 3) task inside region
pin 12 (DIO 4) task2 inside region
Each task is eating time inside and outside the critical region
Some observations for task2:
At approx -12msec task2 is eating 3msec inside critical region
At approx -9msec task2 is leaving critical region and sleep for 1 msec
At approx -8 msec task2 is eating 1 msec
At approx -7 msec task2 sleep for 20 msec
At approx 23 msec task2 wake up loop to top of while and get critical region at once
and repeat as above
What did happen at -40 msec ?
Seems that
before -40 msec is task inside critical region and task is waiting outside
As soon as task release critical region task2 enter the region.
k06 - as k05 but task2 has lower priority than task
Task has higher priority than task2
task will take CPU when needed
At approx 22 msec task take CPU after a 1msec sleep after critical region
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
}
Observe at approx 22 msec that task taskes CPU bq task has higher priority than task2
Which prolongs the stay of task inside the critical region (Seen on DIO 4) at 24msec
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
task is released form the semaphore
eat 3 msec
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
}
You can see that task is running very regular every 10 msec
k10 two task sampling
Debugging on pins has been modified so
DIO3 is high when task is eating CPU time after leaving k_wait
DIO4 is high when task2 is eating CPU time after leaving k_wait
task and task2 has same priority
task is eating 4 msec every 15 msec
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
DIO3 is high when task is eating CPU time after leaving k_wait
DIO4 is high when task2 is eating CPU time after leaving k_wait
task and task2 has same priority
task is eating 4 msec every 15 msec
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.
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
}
DIO3 is high when task is eating CPU time after leaving k_wait
DIO4 is high when task2 is eating CPU time after leaving k_wait
task and task2 has same priority
task is eating 4 msec every 15 msec
task2 is eating 3 msec every 10 msec
Observe
that DIO 4 might be high for longer that 3 msec
that DIO 3 is always 4 msec bq task just takes CPU due to priority
See at -13 msec for task2 we have 3 msec eat and the same at -8 msec.
Might be that -13msec is delayed bq task is running from -17msec to -13msec
I guess task2 would like to had CPU at -17msec but task takes it
So we have jitter on task2
CONCLUSION
Multitasking is very difficult to understand, estimate and debug
|