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

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

 Open Projects
 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.c
qtask-manual.txt
ex1.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
/vhost/mculabs/driver_db/qtask/files/ex1.c
    1 
    2 // define some task ID's
    3 #define TASKID_LEDBLINK       1
    4 #define TASKID_COUNT          2
    5 
    6 // define a pie (basically name of a state machine)
    7 qDefinePie pieBlinkLed;
    8 
    9 // how many uSeconds in a tick?
   10 // with this test, pic has 10mhz xtal with x4 PLL
   11 #define QTASK_TOCK   500
   12 
   13 #include "qtask.c"
   14 
   15 
   16 void slice_ledOn(void) {
   17   mPwrLed_on();
   18 }
   19 
   20 void slice_ledOff(void) {
   21   mPwrLed_off();
   22 }
   23 
   24 void task_blink_led(void)
   25 {
   26    // manage slices of the pie
   27    mqSliceManager(pieBlinkLed)
   28      {
   29      // define the order of the slices, (constant, function)
   30      mqOrderSlice(1,slice_ledOn());
   31      mqOrderSlice(2,slice_ledOff());
   32      }
   33    // we need to define what the last slice was (this resets slice counter)
   34    mqLastSlice(pieBlinkLed,2);
   35 }
   36 
   37 
   38 void task_count(void)
   39 {
   40   c++;
   41 }
   42 
   43 
   44 void main(void)
   45 {
   46 
   47 	// initialize the queued task system
   48 	qTaskInitialize();
   49 
   50 	// set task parameter ( task id, how many tics)
   51 	mqTaskSetTmr(TASKID_LEDBLINK, 1000000);
   52 	  mqTaskEnable(TASKID_LEDBLINK);
   53 	  mqTaskSetPri(TASKID_LEDBLINK, QTPRI_HIGHEST); // set highest priority
   54 
   55 	mqTaskSetTmr(TASKID_COUNT, 50000);
   56 	  mqTaskEnable(TASKID_COUNT);
   57 
   58 	mqTaskSchedulerEnable();	// turn on the task scheduler
   59 	enable_interrupts(GLOBAL);	// since scheduler runs on int, must enable global
   60 
   61 	// initialize the blink led pie (state machine)
   62 	mqPieIni(pieBlinkLed);
   63 
   64 	while(1)
   65 	  {
   66 	  // ** your main program here / or run all in task manager **
   67 
   68 	  // some tasks to manage
   69  	  mqTaskManager()
   70  	    {
   71 	    // tell it what function to execute per task id
   72  	    mqTaskFunction(TASKID_LEDBLINK, task_blink_led());
   73  	    mqTaskFunction(TASKID_COUNT, task_count());
   74 	    }
   75 	  }
   76 
   77 }

And here is the complete driver source file.
 qtask.c
/vhost/mculabs/driver_db/qtask/files/qtask.c
    1 /*
    2           file: qtask.c
    3        version: 1.02
    4    description: Queued Task Manager/Scheduler
    5            (C): (C) michael bradley
    6 
    7       Note: this driver currently is using timer1, so don't use it!
    8             you can change, and modify if you wish
    9 
   10    Changelog:
   11                12/12/2009  mqBeginSlice() removed, no longer needed
   12                12/07/2009  ISR is only called when needed vs ever x uSeconds
   13                            Code added to aid in creating state machines, called slices
   14                12/05/2009  Overall, faster code, smaller footprint
   15                            now working in ticks, instead of uSec
   16                            defined pri levels
   17                            changed flags internally
   18                            changed counter to count down
   19 */
   20 
   21 #define QTASK_DEBUG_PIN       PIN_C0 // i use this for monitoring timing
   22 
   23 #DEFINE QTPRI_HIGHEST      0
   24 #DEFINE QTPRI_HIGH         1
   25 #DEFINE QTPRI_NORMAL       2
   26 #DEFINE QTPRI_LOW          3
   27 #DEFINE QTPRI_LOWEST       4
   28 
   29 #define QTFLAG_RUNNING     0
   30 #define QTFLAG_ENABLED     1
   31 #define QTFLAG_QUED        2
   32 
   33 #define QTFLAG_MANAGETASK  0b00000010  // basically enabled bit only
   34 
   35 // a few macros
   36 #define mqTaskSetPri(id,n)    qTasks[id].priority = n;
   37 #define mqTaskSetTmr(id,t)    qTasks[id].threshold = t; qTasks[id].counter = t;
   38 #define mqTaskEnable(id)      bit_set(qTasks[id].flags,QTFLAG_ENABLED);
   39 #define mqTaskDisable(id)     bit_clear(qTasks[id].flags,QTFLAG_ENABLED);
   40 #define mqTSR(id)             bit_set(qTasks[id].flags,QTFLAG_RUNNING);
   41 #define mqTCR(id)             bit_clear(qTasks[id].flags,QTFLAG_RUNNING);
   42 #define mqTaskManager()       switch (qTaskGet())
   43 #define mqTaskFunction(id,fn) case id: { mqTSR(id); fn; mqTCR(id); break; }
   44 
   45 #define mqTaskSchedulerEnable()  enable_interrupts(INT_TIMER1);
   46 #define mqTaskSchedulerDisable() disable_interrupts(INT_TIMER1);
   47 #define mqTaskTimeOut()          set_timer1(65535-(tocks*10));
   48 #define mqTaskRest()             set_timer1(0);
   49 #define mqTaskTimerCur()         get_timer1();
   50 
   51 #define qDefinePie int8
   52 #define mqSliceManager(slice)    switch (slice)
   53 #define mqOrderSlice(sid,fn)     case sid: { fn; break; }
   54 #define mqPieIni(slice)          slice = 1;
   55 #define mqLastSlice(slice,num)   slice++; if (slice > num) { slice = 1; }
   56 
   57 // total tasks
   58 #ifndef TASKS_MAX             // define this on your own if you wish
   59    #define TASKS_MAX 16       // max number of tasks
   60    #endif
   61 
   62 #if TASKS_MAX > 32
   63    #error Too many tasks, must be <= 32
   64 #endif
   65 
   66 unsigned int8 qTaskFiFo[TASKS_MAX];
   67 unsigned int8 qTaskPointer;
   68 unsigned int16 qTaskTocDelta;
   69 
   70 
   71 struct stTaskItem
   72    {
   73    int8 flags;
   74    int8 priority;
   75    unsigned int16 threshold;
   76    unsigned int16 counter;
   77    } qTasks[TASKS_MAX];
   78 
   79 
   80 unsigned int8 qTaskGet(void)
   81 {
   82    unsigned int8 i,res;
   83 
   84    res = 0;
   85 
   86    if (qTaskPointer != 0)
   87      {
   88      res = qTaskFiFo[0];
   89      for (i=0; i<qTaskPointer; i++)
   90        {
   91        qTaskFiFo[i] = qTaskFiFo[i+1];
   92        }
   93      qTaskPointer--;
   94      bit_clear(qTasks[res].flags,QTFLAG_QUED);
   95      }
   96 
   97    return res;
   98 }
   99 
  100 void qTaskQue(unsigned int8 id)
  101 {
  102    int i,pa,pb;
  103    unsigned int8 tid;
  104    bit_set(qTasks[id].flags,QTFLAG_QUED);
  105    qTasks[id].counter = qTasks[id].threshold;
  106 
  107    qTaskFiFo[qTaskPointer] = id;
  108 
  109    for (i=qTaskPointer; i>1; i--)
  110      {
  111      if ( qTasks[qTaskFiFo[i]].priority < qTasks[qTaskFiFo[i-1]].priority )
  112        {
  113        tid = qTaskFiFo[i-1];
  114        qTaskFiFo[i-1] = qTaskFiFo[i];
  115        qTaskFiFo[i] = tid;
  116        }
  117      }
  118 
  119    qTaskPointer++;
  120    //if (qTaskPointer == TASKS_MAX) { qTaskPointer--; }
  121 }
  122 
  123 void qTaskInitialize()
  124 {
  125    unsigned int8 i;
  126    unsigned int16 tocks;
  127 
  128    // used to set qtask ticking
  129    setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
  130    tocks = QTASK_TOCK;
  131    qTaskTocDelta = 1;
  132    mqTaskTimeOut();
  133 
  134    qTaskPointer = 0;
  135    for (i=0; i<TASKS_MAX; i++)
  136      {
  137      qTaskFiFo[i] = 0;
  138      qTasks[i].flags = 0;
  139      qTasks[i].priority = QTPRI_NORMAL;
  140      }
  141 }
  142 
  143 // we use the timer 1 interrupt for scheduling
  144 // this should be high, not 1us!!!
  145 #int_TIMER1
  146 void  isr_scheduler(void)
  147 {
  148    unsigned int8 i;
  149    unsigned int16 tocks;
  150 
  151    //mqTaskRest();  // set timer to 0 so we can time how long we took in this isr
  152    tocks = qTaskTocDelta;
  153    #ifdef QTASK_DEBUG_PIN
  154       output_high(QTASK_DEBUG_PIN);
  155       #endif
  156    for (i=1; i<TASKS_MAX; i++)
  157      {
  158      // manage task if its enabled only, not running, not queued
  159      if ( qTasks[i].flags == QTFLAG_MANAGETASK )
  160        {
  161        qTasks[i].counter = qTasks[i].counter - tocks;
  162        if ( qTasks[i].counter == 0 )
  163          {
  164          qTaskQue(i);
  165          }
  166        else
  167          {
  168          if ( qTasks[i].counter < qTaskTocDelta ) { qTaskTocDelta = qTasks[i].counter; }
  169          }
  170        }
  171      }
  172 
  173    // adjust for tock resolution, and reduce by time spend in this isr
  174    // (at least try to reduce some, hey, were not an RTOS!)
  175    //tocks = (qTaskTocDelta * QTASK_TOCK) - mqTaskTimerCur();
  176    tocks = (qTaskTocDelta * QTASK_TOCK);
  177 
  178    #ifdef QTASK_DEBUG_PIN
  179       output_low(QTASK_DEBUG_PIN);
  180       #endif
  181    mqTaskTimeOut();     // set the next isr entry time
  182 }






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