Subversion Repositories Bart

Rev

Blame | Last modification | View Log | RSS feed

  1. /* RCS revision control
  2.    $Header: c:/cvsroot/bart/rt_task.c,v 1.4 2004/03/09 22:09:10 mjames Exp $
  3.  */
  4.  
  5. /* RCS Log file
  6.  
  7.    $Log: rt_task.c,v $
  8.    Revision 1.4  2004/03/09 22:09:10  mjames
  9.    Hardware flow control implemented
  10.  
  11.    Revision 1.3  2004/03/09 00:45:20  mjames
  12.    Corrected mistakes, made task numbers visible
  13.  
  14.    Revision 1.2  2004/03/06 12:17:48  mjames
  15.    Moved headers around, made it clearer that there are no configurable
  16.    parts to the OS unless it is rebuilt
  17.  
  18.    Revision 1.1.1.1  2004/03/03 22:54:33  mjames
  19.    no message
  20.  
  21.  */
  22.  
  23.  
  24.  
  25. /*******************
  26. *  INCLUDE FILES   *
  27. ********************/
  28. #include "mcs51reg.h"
  29.  
  30. #include "rt_int.h"
  31. #include "rt_ext.h"
  32.  
  33.  
  34. /*******************
  35. * LOCAL MACROS     *
  36. ********************/
  37.  
  38.  
  39. /** compute timer rolling over for T0 */
  40. #define ROLLOVER_RATE (PRESCALE2/8192)
  41. /* this is 112.5 Hz */
  42.  
  43. #define INT_TASK_BIT(tasknum) (1<<(tasknum))
  44.  
  45. /* this code is for the main uart of the 8051 */
  46. /* timer registers used by T0 IRQ */
  47. /* 11.25Hz counter bank */
  48. volatile unsigned char T0ctr;
  49.  
  50. /* this 'register' is exported */
  51. volatile unsigned char T100ms;
  52.  
  53.  
  54. volatile unsigned char T10sec;
  55.  
  56. /*  first idata */
  57. STACK_TYPE  stack0[STACK0SIZE];
  58. STACK_TYPE  stack1[STACK1SIZE];
  59. #if TASKS >=3
  60. STACK_TYPE stack2[STACK2SIZE];
  61. #endif
  62. #if TASKS >=4
  63. STACK_TYPE stack3[STACK3SIZE];
  64. #endif
  65. volatile STACK_PTR_TYPE stack_save[TASKS];
  66. volatile SIGNAL_TYPE    task_signals[TASKS];
  67. volatile SIGNAL_TYPE    task_masks[TASKS];
  68. volatile TIMER_TYPE     task_timer[TASKS];
  69. volatile TASKID_TYPE    ready ;
  70. volatile TASKID_TYPE    run  ;
  71.  
  72.  
  73.  
  74. /* almost round robin with a modulo-4 task counter */
  75. #define RUN_TOG  0x10
  76. #define RUN_MASK 0x3F
  77.  
  78. /* 3 tasks including idle */
  79. #if TASKS == 3
  80. const STACK_PTR_TYPE  start_stack[]={
  81.   stack0,
  82.   stack1,
  83.   stack2};      
  84.  
  85.  
  86. #define VALID_TASK_NUM
  87. #endif
  88.  
  89. #if TASKS == 4
  90. const STACK_PTR_TYPE start_stack[]={
  91.   stack0,
  92.   stack1,
  93.   stack2,
  94.   stack3};      
  95.  
  96.  
  97. #define VALID_TASK_NUM
  98. #endif
  99.  
  100. #if !defined VALID_TASK_NUM
  101. #error Invalid TASK_NUM declaration
  102. #endif
  103.  
  104. /** This task table describes a round robin with priority :
  105.     there are 4 phases to the round robin
  106.     regardless of the number of tasks , so one task wins more often
  107.     with 3 tasks  tasks 1 and 2 are high priority,
  108.    task 3 runs when 1 and 2 are not running. If there are less than 4 tasks then
  109.    this table will still apply . */
  110. const char priotab[] =
  111.   {
  112.                 /** round 00 : leftmost task bit wins*/
  113.                 /*T3210 */
  114.      0,0,1,1,   /**< 0000,0001,0010,0011 */
  115.      2,2,2,2,   /**< 0100,0101,0110,0111 */
  116.      3,3,3,3,   /**< 1000,1001,1010,1011 */
  117.      3,3,3,3,   /**< 1100,1101,1110,1111 */
  118.                 /** round 01 : second task bit wins */
  119.                 /*T3210 */
  120.      0,0,1,0,   /**< 0000,0001,0010,0011 */
  121.      2,0,1,1,   /**< 0100,0101,0110,0111 */
  122.      3,0,1,1,   /**< 1000,1001,1010,1011 */
  123.      2,2,2,2,   /**< 1100,1101,1110,1111 */
  124.                 /** round 10 : third task bit wins */
  125.                 /*T3210 */
  126.      0,0,1,1,   /**< 0000,0001,0010,0011 */
  127.      2,2,2,0,   /**< 0100,0101,0110,0111 */
  128.      3,3,3,0,   /**< 1000,1001,1010,1011 */
  129.      3,0,1,1,   /**< 1100,1101,1110,1111 */
  130.                 /** round 11 : fourth or cycle again */
  131.                 /*T3210 */
  132.      0,0,1,0,   /**< 0000,0001,0010,0011 */
  133.      2,0,1,2,   /**< 0100,0101,0110,0111 */
  134.      3,0,1,3,   /**< 1000,1001,1010,1011 */
  135.      2,3,3,0,   /**< 1100,1101,1110,1111 */
  136.   };
  137.  
  138.  
  139.  
  140. /** Sets up the scheduler state variables to a clean initial state, but indicate a
  141.   task identified as MAIN_TASK_ID (the task under which main() will run)
  142.   is actually running and ready to run. Use with EA off !!*/
  143. void rt_tasks_init (void)
  144.   {
  145.   char i;
  146.   run   = MAIN_TASK_ID;
  147.   ready = TASK_BIT(MAIN_TASK_ID);
  148.  
  149.   for(i=0;i<TASKS;i++)
  150.     {
  151.     stack_save[i] = 0;
  152.     task_signals[i]=0;
  153.     task_masks[i]  =0;
  154.     task_timer[i]  =0;
  155.     }
  156.  
  157. }
  158.  
  159.  
  160.  
  161.  
  162.  
  163. /** the 100ms counter is one every 11.25 timeouts of the T0 counter    
  164.   * so we will count 12 timeouts when T100ms MOD 4 = 0 and 11 otherwise
  165.   * this means that 10 counts of T100ms are almost exactly 1 second     */
  166.  
  167. /** Timer interrupt running about once every 10ms */
  168. bit T0_interrupt_ea;
  169.  
  170. void T0Interrupt(void) interrupt T0_INTVEC using T0_INTERRUPT_BANK
  171.   {
  172. /*  TF0 = 0;  This Interrupt is cleared automatically by jumping down this vector */
  173.   T0ctr--;
  174.   if(T0ctr==0)
  175.     {
  176.     int i;
  177.     T100ms++;
  178.     if(T100ms & 3)
  179.       T0ctr= 11;/* 01,10,11  */
  180.     else
  181.       T0ctr= 12;/* 00 */
  182. /* and now decrement all of the 100 ms timers */
  183.     for (i=0;i<TASKS;i++)
  184.       {
  185.       if (task_timer[i] != 0)
  186.         {
  187.         task_timer[i]--;
  188.         if (task_timer[i] == 0)
  189.           {
  190.           task_signals[i] |= TIMER_SIG;
  191.           if(task_signals[i] & task_masks[i])
  192.             {
  193.             ready |= TASK_BIT(i); /* Mapping here */  
  194.             }
  195.           }
  196.         }
  197.       }    
  198. /* wrap T100ms around an integer number of seconds
  199.    The wrap value should be divisible by 4 because of
  200.    the fractional N counting */
  201.     if(T100ms>=MAXT100ms)
  202.       {
  203.       T10sec++;
  204.       T100ms=0;  
  205.       }
  206.     }
  207. /* use this interrupt to repetitively sample the flow
  208.    control lines for the primary UART */
  209. #if defined HARD_FLOW
  210.    /* if nCTS goes low and we are not watching it then retrigger TI */
  211.   if(!SIO1_CTS && !SIO1_TxBusy && SIO1_TxCount)
  212.       {
  213.       TI=1;
  214.       }
  215. #endif
  216.  
  217.  
  218.  
  219. #if !defined NO_IRQ_SCHEDULE
  220.  
  221.  _asm
  222. ; use assembler form of atomic operation for keeping ea
  223.   jbc ea,0001$  
  224.   clr _T0_interrupt_ea
  225.   sjmp 0002$
  226. 0001$:
  227.   setb _T0_interrupt_ea
  228. 0002$:
  229.  
  230.  
  231.  
  232. ; These are in bank 0
  233.   push  7
  234.   push  6
  235.   push  5
  236.   push  4
  237.   push  3
  238.   push  2
  239.   push  1
  240.   push  0
  241. ;
  242. ;
  243. ; Determine which task was running
  244. ; and save the task SP
  245. ;
  246.   mov a,_run
  247.   add a,#_stack_save
  248.   mov r0,a
  249.   mov a,sp
  250.   mov @r0,a
  251.  
  252. ; *********** SCHEDULE CODE HERE
  253. ;
  254. ; look at the task ready flags
  255.   mov  a,_ready
  256.   add  a,#RUN_TOG
  257.   anl  a,#RUN_MASK
  258.   mov  _ready,a
  259. ;
  260. ; get new running task ID
  261. ;
  262.   mov  dptr,#_priotab  
  263.   movc a,@a+dptr
  264. ;
  265.   mov _run,a
  266. ;  
  267.   add a,#_stack_save
  268.   mov r0,a
  269.   mov a,@r0
  270.   mov sp,a
  271. ;
  272.  
  273. ;
  274. ; Bank 0 registers in use here
  275. ;
  276.   pop  0
  277.   pop  1
  278.   pop  2
  279.   pop  3
  280.   pop  4
  281.   pop  5
  282.   pop  6
  283.   pop  7
  284. ;
  285. ; this is done in the ISR
  286. ;       pop     psw
  287. ;       pop     dph
  288. ;       pop     dpl
  289. ;       pop     b
  290. ;       pop     acc
  291. ;
  292. ;
  293. ;  
  294.   jnb _T0_interrupt_ea,0010$
  295.   setb ea
  296. 0010$:
  297.   _endasm;
  298.  
  299. #endif
  300.  
  301.   }
  302.  
  303. /********************************************************************************
  304. ** Name :               reschedule
  305.  This function determines which task to run, by using the ready variable as
  306. an index into the scheduler table. Each call to reschedule increments the upper
  307. 2 bits of the ready variable, so as to use a different part of the table on each call.
  308. This allows a round-robin with priority scheduling to take place.
  309. \break
  310. To set a bit in the ready variable, the task's signal (task_signal[task]) variable is
  311. masked with the task's mask (task_masks[task]) variable. If the result is non-zero then the
  312. bit corresponding to the tasks ID number is set in the ready variable.
  313. \break
  314. Task timers reaching zero from a non-zero value will assert the TIMER_SIG signal
  315. in the task's signal variable. If the mask in task's masks has TIMER_SIG set at that time
  316. then the task will have its bit set in the ready variable.
  317. \break
  318. A task will never run again if it has a zero task_masks variable and a zero task_timer
  319. variable, and its ready bit is zero. In all other cases the task will run again in the
  320. future
  321.  
  322.  
  323.  
  324. *********************************************************************************/
  325.  
  326.  
  327. bit reschedule_ea;
  328. void reschedule(void)
  329.   {
  330.   _asm
  331. ; use assembler form of atomic operation for keeping ea
  332.   jbc ea,0001$  
  333.   clr _reschedule_ea
  334.   sjmp 0002$
  335. 0001$:
  336.   setb _reschedule_ea
  337. 0002$:
  338.  
  339. ; this is done in any ISR
  340.         push    acc
  341.         push    b
  342.         push    dpl
  343.         push    dph
  344.         push    psw
  345.  
  346. ;
  347. ; These are in bank 0
  348. ;
  349.   push  7
  350.   push  6
  351.   push  5
  352.   push  4
  353.   push  3
  354.   push  2
  355.   push  1
  356.   push  0
  357. ;
  358. ;
  359. ;
  360. ; Determine which task was running
  361. ; and save the task SP
  362. ;
  363.   mov a,_run
  364.   add a,#_stack_save
  365.   mov r0,a
  366.   mov a,sp
  367.   mov @r0,a
  368.  
  369. ; *********** SCHEDULE CODE HERE
  370. ;
  371. ; look at the task ready flags
  372.   mov  a,_ready
  373.   add  a,#RUN_TOG
  374.   anl  a,#RUN_MASK
  375.   mov  _ready,a
  376. ;
  377. ; get new running task ID
  378. ;
  379.   mov  dptr,#_priotab  
  380.   movc a,@a+dptr
  381. ;
  382.   mov _run,a
  383. ;  
  384.   add a,#_stack_save
  385.   mov r0,a
  386.   mov a,@r0
  387.   mov sp,a
  388. ;
  389. ;
  390. ; Bank 0 registers in use here
  391. ;
  392.   pop  0
  393.   pop  1
  394.   pop  2
  395.   pop  3
  396.   pop  4
  397.   pop  5
  398.   pop  6
  399.   pop  7
  400.  
  401. ;
  402. ; this is done in the ISR
  403.         pop     psw
  404.         pop     dph
  405.         pop     dpl
  406.         pop     b
  407.         pop     acc
  408. ;
  409.   jnb _reschedule_ea,0010$
  410.   setb ea
  411. 0010$:
  412. ;
  413.   _endasm;
  414.  
  415.   }
  416.  
  417.  
  418. /********************************************************************************
  419. ** Name :               start_task
  420.  * the stack for the task is built and then its run flag is set  
  421.  * This uses the real task code for the task
  422. *********************************************************************************/
  423.  
  424. start_rc start_task(task_p f,char tasknum)
  425.   {
  426.   short fp;
  427.   STACK_PTR_TYPE csp;
  428.   USE_CRITICAL;
  429.   if (tasknum >= TASKS)
  430.     return FAILED;
  431.  
  432.   BEGIN_CRITICAL;
  433.   csp = start_stack[tasknum];
  434.   stack_save[tasknum] = (STACK_PTR_TYPE)csp+16 ;
  435. /* catch task return by pointing it at fallback termination function */
  436.   fp =  (int)&end_run_task;
  437.   *csp++     = (char)(fp & 0xff);
  438.   *csp++     = (char)(fp >> 8) ;
  439. /* and put a pointer to the return address which is function to call */  
  440.   fp = (int)f;    
  441.   *csp++     = (char)(fp &0xff);
  442.   *csp++     = (char)(fp >> 8) ;
  443.  
  444. /* then zero out the PSW image otherwise there will be a strange crash
  445.    as code tries to run in a random register bank  .... */
  446.   *csp++ = 0; /* csp[4]   = acc  could pass argument here */
  447.   *csp++ = 0; /* csp[5]   = b   */
  448.   *csp++ = 0; /*  csp[6] = dpl    */
  449.   *csp++ = 0; /*  csp[7] = dph    */
  450.   *csp++ = 0; /* psw VITAL */  
  451.   *csp++ = 0; /* csp [9] = r7 */
  452.   *csp++ = 0; /* csp [10] = r6 */
  453.   *csp++ = 0; /* csp [11] = r5 */
  454.   *csp++ = 0; /* csp [12] = r4 */
  455.   *csp++ = 0; /* csp [13] = r3 */
  456.   *csp++ = 0; /* csp [14] = r2 */
  457.   *csp++ = 0; /* csp [15] = r1 */
  458.   *csp   = 0; /* csp [16] = r0 */
  459.  
  460.  
  461. /* Set its task state as ready to run */
  462.   ready |= TASK_BIT(tasknum);
  463.   END_CRITICAL;
  464.   return STARTED;
  465.   }
  466.  
  467.  
  468. /********************************************************************************
  469. ** Name :               end_run_task
  470. *********************************************************************************/
  471. void end_run_task(void)
  472.   {
  473.   USE_CRITICAL;
  474.   /* whatever is running, stop it */    
  475.   BEGIN_CRITICAL;
  476.   ready &= ~TASK_BIT(run);
  477.   task_masks[run] = 0; /* Stop any further signals making task ready to run */
  478.   task_timer[run] = 0;  /* kill off pending task timeout */
  479.   END_CRITICAL;
  480.   reschedule();
  481. /* Should never get here as this task cannot be rescheduled  */
  482.   while(1);
  483.  
  484.   }
  485.  
  486.  
  487. /** schedules a sleep with early return on any signals. Need to include TIMER_SIG in
  488.     signal list  */
  489. char wait_timed(char signal,char ticks)
  490.   {
  491.   USE_CRITICAL;
  492.   BEGIN_CRITICAL;
  493.   ready             &= ~TASK_BIT(run); /* this task is going to sleep */
  494.   task_timer[run]    = ticks;
  495.   task_masks[run]    = signal;   /* accept these signals as a validto wait on */
  496.   END_CRITICAL;
  497.   reschedule();
  498.   return task_signals[run];
  499.   }
  500.  
  501. /** A sleep of 0 means a reschedule call */
  502. void sleep(char ticks)
  503.   {
  504.   USE_CRITICAL;
  505.  
  506.  
  507.   if (ticks)
  508.     {
  509.     BEGIN_CRITICAL;
  510.     ready             &= ~TASK_BIT(run); /* this task is going to sleep */
  511.     task_timer[run]    = ticks;
  512.     task_masks[run]    = TIMER_SIG;   /* accept this signal as a valid one to wait on */
  513.     task_signals[run] &=~TIMER_SIG;
  514. /* this is actually a virtual idle task here in the loop, allowing all tasks to sleep */
  515.     do {
  516.       END_CRITICAL;
  517.       reschedule();
  518.       BEGIN_CRITICAL;
  519.       }
  520.     while((task_signals[run] & TIMER_SIG) == 0);
  521.     task_signals[run] &= ~(TIMER_SIG);
  522.     task_masks[run]   &= ~TIMER_SIG;   /* accept this signal as a valid one to wait on */
  523.     END_CRITICAL;
  524.     }
  525.   else
  526.    {
  527.    reschedule();
  528.    }
  529.  
  530.   }
  531.  
  532. /** the current running task acknowledges the signal bits in the argument */
  533. void clear_signal(char pattern)
  534.   {
  535.   USE_CRITICAL;
  536.   BEGIN_CRITICAL;
  537.   task_signals[run] &= ~(pattern);
  538.   END_CRITICAL;
  539.   }
  540.  
  541. /** Sends a signal to the task referred to. Does not actually cause rescheduling
  542.   until either a T0 interrupt,  or a reschedule(), sleep() or wait_timed()
  543.    call made by this task */
  544. void signal(char task,char pattern)
  545.   {
  546.   USE_CRITICAL;
  547.   BEGIN_CRITICAL;
  548. /* this used in ISR context !! */
  549.   INT_SIGNAL(task,pattern);
  550.  
  551.   END_CRITICAL;
  552.   }
  553.  
  554.  
  555.  
  556. /*******************************************************************/
  557. /* System initialisation call */
  558.  
  559. void rt_system_init(void)
  560.   {
  561.  
  562.   AUXR  = M0 |XRS1 | XRS0  ;
  563.   CKCON = WdX2 | PcaX2 | SiX2 | T2X2 | T0X2 | X2; /* T1X2 bit is '0' to double UART speed */
  564.  
  565.   TMOD  = 0x20; /* timer1 mode2 timer0 mode0 */
  566.  
  567.   EA = 0;
  568.  
  569.  
  570.   }
  571.