:: Home :: Code Snippets :: Drivers :: Projects :: About ::
 Main Menu
  Home
  Code Snippets
  About

 Open Drivers
 EA-DOGM - LCD Display Driver
 PIC32 mcompat - PIC32 mcompat
 qTask - Queued Task Manager
 _build - Embedded build information

 Open Projects
 fplCore - Self contained controller
 uProfiler - uController uProfiller
 oLogic - Oscilloscope Logic Viewer
 oLogic 1.4 - NEW Logic Viewer
 SSX32 - Serial Servo Driver



 Sources
Prototyping
  PicStuff
  Sparkfun

Equipment
  Saelig
  Tequipment

Supply House
  Jameco
  Mouser
  Digikey
  Allied Electronics
  Clearwater Technologies

Miscellaneous
  BCM
  N34D Blog

qTask, a Queued Task Manager

This is a super simple Queued Task Manager, aka qTask.

Note, This is not an RTOS, most people throw that around loosely, in fact, this is not even remotely crudely an RTOS! An RTOS is a Real Time Operating System. qTask is not real time, and its definitely not an operating system!

qTask is simply a queued task manager, that is, it queues tasks for execution. These tasks have periods (time) that they need to be executed.

This is where the Non-Real Time comes in. Tasks are scheduled during an interrupt, with priorities, thus, if a task is already queued to be run, and a higher priority task comes up, then it will be executed first, causing a bit of a delay for the other task.

Using this technique, I am able to get around the round robin style of executing tasks, instead, just executing tasks that need to be run.

Just added, some code to aid in creating a state machine. I call it slices, basically slices of a pie :) This slices are to help break up the size of a large task. Thus when a task is executed, it can just execute a portion of the pie.

Another note: This is a work in progress for me, so I don't have it hashed out 100%, but it is functional, and I am using it in a retail product at the moment.

 Driver Specs
version: 1.02
mcu: 12,16,18
compiler: CCS C

 Files
qtask-manual.txt
ex1.c
qtask.c

qtask.zip - All files


Here is a video with several tasks as well as bar graph task sliced up.

A simple view of how to use it
This will turn on an LED every .5 second, then turn it off .5 second later (note, xtal = 10mhz, x4 pll is on, timer1 is used for the task manager)
 Example Usage
// define some task ID's
#define TASKID_LEDBLINK       1
#define TASKID_COUNT          2

// define a pie (basically name of a state machine)
qDefinePie pieBlinkLed;

// how many uSeconds in a tick?
// with this test, pic has 10mhz xtal with x4 PLL
#define QTASK_TOCK   500

#include "qtask.c"


void slice_ledOn(void) {
  mPwrLed_on();
}

void slice_ledOff(void) {
  mPwrLed_off();
}

void task_blink_led(void)
{
   // manage slices of the pie
   mqSliceManager(pieBlinkLed)
     {
     // define the order of the slices, (constant, function)
     mqOrderSlice(1,slice_ledOn());
     mqOrderSlice(2,slice_ledOff());
     }
   // we need to define what the last slice was (this resets slice counter)
   mqLastSlice(pieBlinkLed,2);
}


void task_count(void)
{
  c++;
}


void main(void)
{

	// initialize the queued task system
	qTaskInitialize();

	// set task parameter ( task id, how many tics)
	mqTaskSetTmr(TASKID_LEDBLINK, 1000000);
	  mqTaskEnable(TASKID_LEDBLINK);
	  mqTaskSetPri(TASKID_LEDBLINK, QTPRI_HIGHEST); // set highest priority

	mqTaskSetTmr(TASKID_COUNT, 50000);
	  mqTaskEnable(TASKID_COUNT);

	mqTaskSchedulerEnable();	// turn on the task scheduler
	enable_interrupts(GLOBAL);	// since scheduler runs on int, must enable global

	// initialize the blink led pie (state machine)
	mqPieIni(pieBlinkLed);

	while(1)
	  {
	  // ** your main program here / or run all in task manager **

	  // some tasks to manage
 	  mqTaskManager()
 	    {
	    // tell it what function to execute per task id
 	    mqTaskFunction(TASKID_LEDBLINK, task_blink_led());
 	    mqTaskFunction(TASKID_COUNT, task_count());
	    }
	  }

}

And here is the complete driver source file.
 qtask.c
/*
          file: qtask.c
       version: 1.02
   description: Queued Task Manager/Scheduler
           (C): (C) michael bradley

      Note: this driver currently is using timer1, so don't use it!
            you can change, and modify if you wish

   Changelog:
               12/12/2009  mqBeginSlice() removed, no longer needed
               12/07/2009  ISR is only called when needed vs ever x uSeconds
                           Code added to aid in creating state machines, called slices
               12/05/2009  Overall, faster code, smaller footprint
                           now working in ticks, instead of uSec
                           defined pri levels
                           changed flags internally
                           changed counter to count down
*/

#define QTASK_DEBUG_PIN       PIN_C0 // i use this for monitoring timing

#DEFINE QTPRI_HIGHEST      0
#DEFINE QTPRI_HIGH         1
#DEFINE QTPRI_NORMAL       2
#DEFINE QTPRI_LOW          3
#DEFINE QTPRI_LOWEST       4

#define QTFLAG_RUNNING     0
#define QTFLAG_ENABLED     1
#define QTFLAG_QUED        2

#define QTFLAG_MANAGETASK  0b00000010  // basically enabled bit only

// a few macros
#define mqTaskSetPri(id,n)    qTasks[id].priority = n;
#define mqTaskSetTmr(id,t)    qTasks[id].threshold = t; qTasks[id].counter = t;
#define mqTaskEnable(id)      bit_set(qTasks[id].flags,QTFLAG_ENABLED);
#define mqTaskDisable(id)     bit_clear(qTasks[id].flags,QTFLAG_ENABLED);
#define mqTSR(id)             bit_set(qTasks[id].flags,QTFLAG_RUNNING);
#define mqTCR(id)             bit_clear(qTasks[id].flags,QTFLAG_RUNNING);
#define mqTaskManager()       switch (qTaskGet())
#define mqTaskFunction(id,fn) case id: { mqTSR(id); fn; mqTCR(id); break; }

#define mqTaskSchedulerEnable()  enable_interrupts(INT_TIMER1);
#define mqTaskSchedulerDisable() disable_interrupts(INT_TIMER1);
#define mqTaskTimeOut()          set_timer1(65535-(tocks*10));
#define mqTaskRest()             set_timer1(0);
#define mqTaskTimerCur()         get_timer1();

#define qDefinePie int8
#define mqSliceManager(slice)    switch (slice)
#define mqOrderSlice(sid,fn)     case sid: { fn; break; }
#define mqPieIni(slice)          slice = 1;
#define mqLastSlice(slice,num)   slice++; if (slice > num) { slice = 1; }

// total tasks
#ifndef TASKS_MAX             // define this on your own if you wish
   #define TASKS_MAX 16       // max number of tasks
   #endif

#if TASKS_MAX > 32
   #error Too many tasks, must be <= 32
#endif

unsigned int8 qTaskFiFo[TASKS_MAX];
unsigned int8 qTaskPointer;
unsigned int16 qTaskTocDelta;


struct stTaskItem
   {
   int8 flags;
   int8 priority;
   unsigned int16 threshold;
   unsigned int16 counter;
   } qTasks[TASKS_MAX];


unsigned int8 qTaskGet(void)
{
   unsigned int8 i,res;

   res = 0;

   if (qTaskPointer != 0)
     {
     res = qTaskFiFo[0];
     for (i=0; i<qTaskPointer; i++)
       {
       qTaskFiFo[i] = qTaskFiFo[i+1];
       }
     qTaskPointer--;
     bit_clear(qTasks[res].flags,QTFLAG_QUED);
     }

   return res;
}

void qTaskQue(unsigned int8 id)
{
   int i,pa,pb;
   unsigned int8 tid;
   bit_set(qTasks[id].flags,QTFLAG_QUED);
   qTasks[id].counter = qTasks[id].threshold;

   qTaskFiFo[qTaskPointer] = id;

   for (i=qTaskPointer; i>1; i--)
     {
     if ( qTasks[qTaskFiFo[i]].priority < qTasks[qTaskFiFo[i-1]].priority )
       {
       tid = qTaskFiFo[i-1];
       qTaskFiFo[i-1] = qTaskFiFo[i];
       qTaskFiFo[i] = tid;
       }
     }

   qTaskPointer++;
   //if (qTaskPointer == TASKS_MAX) { qTaskPointer--; }
}

void qTaskInitialize()
{
   unsigned int8 i;
   unsigned int16 tocks;

   // used to set qtask ticking
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
   tocks = QTASK_TOCK;
   qTaskTocDelta = 1;
   mqTaskTimeOut();

   qTaskPointer = 0;
   for (i=0; i<TASKS_MAX; i++)
     {
     qTaskFiFo[i] = 0;
     qTasks[i].flags = 0;
     qTasks[i].priority = QTPRI_NORMAL;
     }
}

// we use the timer 1 interrupt for scheduling
// this should be high, not 1us!!!
#int_TIMER1
void  isr_scheduler(void)
{
   unsigned int8 i;
   unsigned int16 tocks;

   //mqTaskRest();  // set timer to 0 so we can time how long we took in this isr
   tocks = qTaskTocDelta;
   #ifdef QTASK_DEBUG_PIN
      output_high(QTASK_DEBUG_PIN);
      #endif
   for (i=1; i<TASKS_MAX; i++)
     {
     // manage task if its enabled only, not running, not queued
     if ( qTasks[i].flags == QTFLAG_MANAGETASK )
       {
       qTasks[i].counter = qTasks[i].counter - tocks;
       if ( qTasks[i].counter == 0 )
         {
         qTaskQue(i);
         }
       else
         {
         if ( qTasks[i].counter < qTaskTocDelta ) { qTaskTocDelta = qTasks[i].counter; }
         }
       }
     }

   // adjust for tock resolution, and reduce by time spend in this isr
   // (at least try to reduce some, hey, were not an RTOS!)
   //tocks = (qTaskTocDelta * QTASK_TOCK) - mqTaskTimerCur();
   tocks = (qTaskTocDelta * QTASK_TOCK);

   #ifdef QTASK_DEBUG_PIN
      output_low(QTASK_DEBUG_PIN);
      #endif
   mqTaskTimeOut();     // set the next isr entry time
}






:: Home :: Resources :: PIC Microcontrollers ::
:: 10F :: 12F :: 16F :: 18F :: 24F :: 24H :: 30F :: 33F ::
(C) Copyright 2009 mculabs.com - contact: info@mculabs.com
0.0036869049072266