In C language

/*

********************************************************************************************************

*        CRTOS_V2.c                   RTOS KERNEL SOURCE CODE

*

* Co-Operative RTOS written in C based on PaulOS by Ing. Paul P. Debono :

* ———————————————————————–

*

* For use with the 8051 family of microcontrollers

*

* Notes:

*

* Timer to use for the RTOS ticks is user selectable, Timer 0, 1 or 2

* Naturally, Timer 2 can only be used with an 8032 CPU.

*

* Assign the correct values to ‘TICK_TIMER’, ‘CPU’, ‘MAINSTACK’ and ‘NOOFTASKS’ in CRTOS_V2.h

*

* If it is noticed that timing parameters are not being met well – the system’s TICKTIME

* can be modified by changing the value ‘TICKTIME’ in CRTOS_V2.h – please adhere to the

* conditions mentioned in CRTOS_V2.h

*

* File     : CRTOS_V2.c

* Revision : 7C

* Date     : FEBRUARY 2005

* By    : John Blaut, Paul P. Debono

*

*                 B. Eng. (Hons.) Elec. Course Final Year Project

*                 University Of Malta

*

********************************************************************************************************

*/

/*

********************************************************************************************************

*                                              INCLUDES

********************************************************************************************************

*/

 

#include <reg52.h>         /* 8052 Special Function Registers 8052  */

#include “CRTOS_V2.h”      /* CRTOS system calls definitions (IN PROJECT DIRECTORY) */

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*                                         GLOBAL VARIABLES

********************************************************************************************************

*/

 

uchar data  * data ReadyQTop;                  // Address of last ready task

uchar data  Running;                           // Number of current task

bit   bdata IntFlag;                           // Flag indicating a task waiting for an interrupt was found

bit   bdata TinQFlag;                          // Flag indicating that a task timed out

bit   bdata Priority;                          // Flag indicating whether priority is enabled or disabled

uchar data  ReadyQ[NOOFTASKS + 2];       // Queue stack for tasks ready to run

 

#if (CPU == 8032)

uchar idata SPTs[NOOFTASKS + 1];         // SP for each task and one for the idle (main) task

uchar idata TaskFlags[NOOFTASKS + 1];    // Bytes storing flags for each task and idle (main) task

 

#elif (CPU == 8051)

uchar xdata SPTs[NOOFTASKS + 1];         // SP for each task and one for the idle (main) task

uchar xdata TaskFlags[NOOFTASKS + 1];    // Bytes storing flags for each task and idle (main) task

// stored in external RAM since internal RAM is only 128 bytes

#endif

 

ulong xdata TTs[NOOFTASKS];                    // Array storing remaining timeout time for each task

ulong xdata IntvalCnt[NOOFTASKS];        // Array storing remaining periodic interval time for each task

ulong xdata IntvalRld[NOOFTASKS];              // Array storing the periodic interval time value for each task

uchar xdata Ext_Stack[(NOOFTASKS + 1) * STACKSIZE]; // Area in external RAM reserved for saving the

// stack of each task including the idle (main) task

#if (STACK_CHECK)

uchar xdata MaxSPTs[NOOFTASKS + 1] = { MAINSTACK – 1 };    // Bytes storing maximum value attained by SP of each task in order

#endif                                                                            // to calculate each task’s maximum stack size in case STACK_CHECK

// is defined in CRTOS.h

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*                                         FUNCTION DEFINITIONS

********************************************************************************************************

*/

 

/*

********************************************************************************************************

*

* Function name : INIT_RTOS

*

* Function type : Initialisation System call

*

* Description   : This system call initialises the RTOS variables, task SPs and enables any required

*                        interrupts

*

* Arguments     : iemask     Represents the interrupt enable mask which is used to set up the IE special

*                                        function register. Its value determines which interrupts will be enabled

*                                        during the execution of the user’s application.

*

* Returns       : None

*

********************************************************************************************************

*/

void INIT_RTOS(uchar iemask)

{

uint idata i;

#if (TICK_TIMER == 0)

IE = (iemask & 0x7f) | 0x02;      /* Set up 8051 IE register, using timer 0 */

IP = 0x02;                          /* Assign scheduler interrupt high priority */

#elif (TICK_TIMER == 1)

IE = (iemask & 0x7f) | 0x08;      /* Set up 8051 IE register, using timer 1 */

IP = 0x08;                          /* Assign scheduler interrupt high priority */

#elif (TICK_TIMER == 2)

IE = (iemask & 0x7f) | 0x20;          /* Set up 8051 IE register, using timer 2 */

IP = 0x20;                           /* Assign scheduler interrupt high priority */

#endif

 

for (i = 0; i < ((NOOFTASKS + 1) * STACKSIZE); i++)

Ext_Stack[i] = 0;

Running = IDLE_TASK;    /* Set idle task as the running task */

 

for (i = 0; i < NOOFTASKS; i++)

{

TTs[i] = NOT_TIMING;        /* Initialise task timeouts,  */

IntvalCnt[i] = NOT_TIMING;  /* periodic interval count    */

IntvalRld[i] = NOT_TIMING;  /* and reload variables.    */

ReadyQ[i] = IDLE_TASK;      /* Fill the READY queue with  */

}                                         /* with the idle task         */

 

ReadyQ[NOOFTASKS] = IDLE_TASK;

ReadyQ[NOOFTASKS + 1] = IDLE_TASK;

 

ReadyQTop = ReadyQ;       /* Pointer to last task made to point to */

/* base of the queue.                    */

 

for (i = 0; i < NOOFTASKS + 1; i++)

{

SPTs[i] = MAINSTACK + 2; /* Initialise task SP values    */

TaskFlags[i] = 0;      /* Initialise task status bytes */

}

}

 

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*

* Function name : CREATE

*

* Function type : Initialisation System call

*

* Description   : This system call is used in the main program for each task to be created for use in

*                        the application.

*

* Arguments     : task       Represents the task number (1st task is numbered as 0).

*

*                 taskadd    Represents the task’s start address, which in the C environment, would

*                                        simply be the name of the procedure

*

* Returns       : None

*

********************************************************************************************************

*/

 

void CREATE(uchar task, uint taskadd)

{

ReadyQTop++;            /* Task is added to next available */

*ReadyQTop = task;      /* position in the READY queue.    */

 

Ext_Stack[STACKSIZE * task] = taskadd % 256;

Ext_Stack[(STACKSIZE * task) + 1] = taskadd / 256;

}

 

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*

* Function name : RTOSGO

*

* Function type : Initialisation System call

*

* Description   : This system calls is used to start the RTOS going such that it supervises the

*                        application processes.

*

* Arguments     : prior            Determines whether tasks ready to be executed are sorted prior to processing

*                                        or not. If prior = 0 a FIFO queue function is implied, if prior = 1 the

*                                        queue is sorted by task number in ascending order, as a higher priority is

*                                        associated with smaller task number (task 0 would have the highest

*                                        priority), such that the first task in the queue, which would eventually

*                                        run, would be the one with the smallest task number having highest priority.

*

* Returns       : None

*

********************************************************************************************************

*/

 

void RTOSGO(uchar prior)

{

if (prior == 1)         /* Checks if tasks priorities       */

Priority = 1;     /* are to be enabled             */

else

Priority = 0;

#if (TICK_TIMER == 0)

TH0 = BASIC_TICK / 256;       /* Configure Timer 0 in 16-bit      */

TL0 = BASIC_TICK % 256;           /* timer mode for the 8051     */

TMOD &= 0xF0;       /* Clear T0 mode control, leaving T1 untouched */

TMOD |= 0x01;           /* Set T0 mode control */

TR0 = 1;            /* Start timer 0 */

TF0 = 1;                /* Cause first interrupt immediately */

 

#elif (TICK_TIMER == 1)

TH1 = BASIC_TICK / 256;       /* Configure Timer 1 in 16-bit      */

TL1 = BASIC_TICK % 256;           /* timer mode for the 8051     */

TMOD &= 0x0F;       /* Clear T1 mode control, leaving T0 untouched */

TMOD |= 0x10;           /* Set T1 mode control */

TR1 = 1;            /* Start timer 1 */

TF1 = 1;                /* Cause first interrupt immediately */

 

#elif (TICK_TIMER == 2)

RCAP2H = BASIC_TICK / 256;    /* Configures Timer 2 in 16-bit     */

RCAP2L = BASIC_TICK % 256;    /* auto-reload mode for the 8032    */

T2CON = 0x84;   /* TR2 = TF2 = 1 */

#endif

 

TinQFlag = 1; /* Signals scheduler that tasks have been         */

/* added to the queue.                           */

EA = 1;           /* Interrupts are enabled, starting the RTOS    */

}

 

 

/*

********************************************************************************************************

*/

 

/*

********************************************************************************************************

*

* Function name : RUNNING_TASK_ID

*

* Function type : Inter-task Communication System call

*

* Description   : This system call is used to check to get the number of the

*                        current task.

*

* Arguments     : None

*

* Returns       : Number of currently running task from which it must be called

*

********************************************************************************************************

*/

uchar RUNNING_TASK_ID(void)

{

return (Running);

}

 

 

 

/*

********************************************************************************************************

*

* Function name : SCHECK

*

* Function type : Inter-task Communication System call

*

* Description   : This system call is used to check if the current task has its signal set. It tetsts

*                        whether there was any signal sent to it by some other task.

*

* Arguments     : None

*

* Returns       : 1 if its signal bit is set, 0 if not set

*

********************************************************************************************************

*/

 

uchar SCHECK(void)

{

EA = 0;

Check_Task_Max_SP();

 

if ((TaskFlags[Running] & SIGS) == SIGS) /* If a signal is      */

{                                                    /* present it’s cleared */

TaskFlags[Running] &= ~SIGS;       /* and 1 is returned.   */

EA = 1;

return 1;

}

else              /* If a signal is not present, 0 is returned */

{

EA = 1;

return 0;

}

}

 

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*

* Function name : SIGNL

*

* Function type : Inter-task Communication System call

*

* Description   : This system call is used to send a signal to another task.

*

* Arguments     : task       Represents the task to which a signal is required to be sent.

*

* Returns       : None

*

********************************************************************************************************

*/

 

void SIGNL(uchar task)

{

EA = 0;

Check_Task_Max_SP();

 

if ((TaskFlags[task] & SIGW) == SIGW)

{

TaskFlags[task] &= ~SIGS;     /* If a task has been waiting  */

TaskFlags[task] &= ~SIGW;   /* for a signal, the task no   */

TTs[task] = NOT_TIMING;     /* longer as to wait and is    */

ReadyQTop++;                      /* added to the READY queue.   */

*ReadyQTop = task;

TinQFlag = 1;

EA = 1;

}

else                                  /* If it was not waiting, its */

TaskFlags[task] |= SIGS;      /* signal sent bit is set       */

EA = 1;

}

 

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*

* Function name : WAITS

*

* Function type : Event-Waiting System call

*

* Description   : This system call causes a task to wait for a signal to arrive within a given number of

*                        RTOS ticks. If the signal is already present, the task continues to execute.

*

* Arguments     : ticks            Represents the number of ticks for which the task will wait for a signal to

*                                        arrive. Valid range for this argument is 0 to 4294967295. A value of 0 means

*                                        waiting forever for a signal to arrive.

*

* Returns       : None

*

********************************************************************************************************

*/

 

void WAITS (ulong ticks)

{

EA = 0;

Check_Task_Max_SP();

if ((TaskFlags[Running] & SIGS) == SIGS) /* If signal already   */

{                                                    /* sent it clears the  */

TaskFlags[Running] &= ~SIGS;       /* signal and the task */

EA = 1;                                     /* continues to run.   */

}

else

{                                          /* If signal is not present  */

TaskFlags[Running] |= SIGW;  /* the task is sent in the   */

TTs[Running] = ticks;        /* waiting state, by causing */

QShift();                        /* a task switch.            */

}

}

 

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*

* Function name : WAITT

*

* Function type : Event-Waiting System call

*

* Description   : This system call causes a task to go in the waiting state for a timeout period given

*                        by a defined number of RTOS ticks.

*

* Arguments     : ticks            Represents the number of ticks for which the task will wait. Valid range for

*                                        this parameter is 1 to 4294967295. A zero waiting time parameter is set to 1

*                                        by the RTOS itself, since a zero effectively kills the task, making it wait

*                                        forever.

*

* Returns       : None

*

********************************************************************************************************

*/

 

void WAITT (ulong ticks)

{

EA = 0;

Check_Task_Max_SP();

 

if (ticks == 0)

ticks = 1;               /* Task’s timeout variable is updated */

TTs[Running] = ticks;      /* and the task then enters the       */

QShift();                      /* waiting state.                           */

}

 

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*

* Function name : WAITV

*

* Function type : Event-Waiting System call

*

* Description   : This system call is used by a task to wait for the end of its periodic interval. If

*                        the interval has already passed, the task continues to execute.

*

* Arguments     : None

*

* Returns       : None

*

********************************************************************************************************

*/

 

void WAITV(void)

{

EA = 0;

Check_Task_Max_SP();

 

if ((TaskFlags[Running] & SIGV) == SIGV) /* If the periodic    */

{                                                    /* interval time has  */

TaskFlags[Running] &= ~SIGV;         /* has elapsed, the   */

EA = 1;                                        /* task continues to  */

}                                                    /* execute.           */

else

{                                                    /* Else the task      */

TaskFlags[Running] |= SIGV;            /* enters the waiting */

QShift();                                  /* state.               */

}

}

 

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*

* Function name : PERIODIC

*

* Function type : Event-Waiting System call

*

* Description   : This system call causes a task to repeat its function every given number of RTOS ticks.

*

* Arguments     : ticks            Represents the length of the periodic interval in terms of RTOS ticks, after

*                                        which the task repeats itself. Valid range for this parameter is 1 to

*                                        4294967295.

*

* Returns       : None

*

********************************************************************************************************

*/

 

void PERIODIC (ulong ticks)

{

EA = 0;

Check_Task_Max_SP();

 

if (ticks == 0)

ticks = 1;

IntvalRld[Running] = ticks;   /* Task’s periodic interval count */

IntvalCnt[Running] = ticks;   /* and reload variables are       */

EA = 1;                               /* initialised.                     */

}

 

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*

* Function name : WAITI

*

* Function type : Event-Waiting System call

*

* Description   : This system call causes a task to wait for a given event (interrupt). It identifies

*                        for which interrupt the task has to wait. Once identified – the task’s appropriate

*                        flag is set and the task is set in the waiting state by causing a task swap – the task

*                        would wait indefinitely for the interrupt as its timeout variable would be set to 0

*                        (NOT_TIMING) either during initialisation of the RTOS or after expiry of its timeout

*                        period due to other prior invocations of wait-inducing system calls.

*

* Arguments     : intnum    Represents the interrupt number associated with the given interrupt for

*                           which the calling task intends to wait

*

* Returns       : None

*

********************************************************************************************************

*/

 

void WAITI(uchar intnum)

{

EA = 0;

Check_Task_Max_SP();

switch (intnum)

{

case 0:                         /* Interrupt number 0    */

TaskFlags[Running] |= EXT0W;  /* Task made to wait for */

QShift();                             /* external interrupt 0  */

break;

#if (TICK_TIMER != 0)

case 1:                         /* Interrupt number 1    */

TaskFlags[Running] |= TIM0W;    /* Task made to wait for */

QShift();                             /* timer 0 interrupt     */

break;

#endif

 

case 2:                         /* Interrupt number 2    */

TaskFlags[Running] |= EXT1W; /* Task made to wait for */

QShift();                             /* external interrupt 1  */

break;

 

#if (TICK_TIMER != 2)

case 3:                         /* Interrupt number 3    */

TaskFlags[Running] |= TIM1W; /* Task made to wait for */

QShift();                             /* timer 1 interrupt     */

break;

#endif

 

case 4:                         /* Interrupt number 4    */

TaskFlags[Running] |= SER0W; /* Task made to wait for */

QShift();                             /* serial port interrupt */

break;

 

#if (TICK_TIMER != 2)

case 5:                         /* Interrupt number 3    */

TaskFlags[Running] |= TIM2W; /* Task made to wait for */

QShift();                             /* timer 1 interrupt     */

break;

#endif

 

default:

EA = 1;

break;

}

}

 

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*

* Function name : DEFER

*

* Function type : Task Suspention System call

*

* Description   : This system call is used to stop the current task in order for the next task in the

*                        queue to execute. In the meantime the current task is placed at the end of the queue.

*

* Arguments     : None

*

* Returns       : None

*

********************************************************************************************************

*/

 

void DEFER(void)

{

EA = 0;

Check_Task_Max_SP();

 

TTs[Running] = NOT_TIMING;

ReadyQTop++;                    /* Task added to the end of the */

*ReadyQTop = Running;     /* ready queue prior to causing */

QShift();                     /* a task switch.                   */

}

 

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*

* Function name : KILL

*

* Function type : Task Suspention  System call

*

* Description   : This system call kills the current task, by putting it permanently waiting, such that

*                        it never executes again. It also clears any set waiting signals which the task might

*                        have.

*

* Arguments     : None

*

* Returns       : None

*

********************************************************************************************************

*/

 

void KILL(void)

{

EA = 0;

Check_Task_Max_SP();

 

TaskFlags[Running] = 0;      /* Task is killed by clearing it    */

TTs[Running] = NOT_TIMING;   /* flags, setting it to wait forver */

QShift();                        /* and then cause a task switch.    */

}

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*

* Function name : QShift

*

* Function type : Context Switcher (Internal function)

*

* Description   : This function is used to perform a context switch i.e. task swapping

*

* Arguments     : None

*

* Returns       : None

*

********************************************************************************************************

*/

 

void QShift (void) using 1

{

uchar data i, temp;

uint  data offset;

uchar idata * idata internal;

uchar data  * idata qtask;

uchar data  * idata pair;

 

Check_Task_Max_SP();

 

TinQFlag = 0;

 

SPTs[Running] = SP;                 /* Current task’s SP is saved    */

 

internal = MAINSTACK;

offset = STACKSIZE * Running;

/* Current task’s stack is saved */

 

for (i = 0; i < STACKSIZE; i++)

Ext_Stack[offset + i] = *(internal + i);

qtask = ReadyQ;                     /* READY queue is shifted ahead */

while (qtask <= ReadyQTop)      /* by one position                  */

{

*qtask = *(qtask + 1);

qtask++;

}

ReadyQTop–;      /* Pointer to last task in queue is decremented */

 

if (ReadyQTop < ReadyQ) /* Ensure that this pointer is never  */

ReadyQTop = ReadyQ;     /* below the start of the READY queue */

if (Priority == 1)              /* If task priorities are enabled */

{                                 /* the queue is sorted such that  */

pair = ReadyQTop;     /* the highest priority task        */

while (pair > ReadyQ) /* becomes the running task, i.e. */

{                           /* the one having the smallest    */

/* task number.                         */

/* Just one scan through the list */

pair–;

if (*pair > *(pair + 1))

{

temp = *pair;

*pair = *(pair + 1);

*(pair + 1) = temp;

}

}

}

/* The first task in the READY queue */

Running = ReadyQ[0];            /* becomes the new running task      */

offset = STACKSIZE * Running;

/* The new running task’s stack   */

/* area is copied to internal RAM */

for (i = 0; i < STACKSIZE; i++)

*(internal + i) = Ext_Stack[offset + i];

SP = SPTs[Running];     /* The new running task’s SP is restored */

/* such that the new task will execute.  */

EA = 1;

}

 

 

/*

********************************************************************************************************

*/

 

/*

********************************************************************************************************

*

* Function name : Xtra_Int_0

*

* Function type : Interrupt Service Routine

*

* Description   : This is the external 0 interrupt ISR whose associated interrupt number is 0.

*

* Arguments     : None

*

* Returns       : None

*

********************************************************************************************************

*/

 

void Xtra_Int_0 (void) interrupt 0 using 1

{

EA = 0;

Check_Task_Max_SP();

Xtra_Int(EXT0W);     /* Passes EXT0W for identification purposes */

}

 

 

/*

********************************************************************************************************

*

* Function name : RTOS_Timer_Int

*

* Function type : Scheduler Interrupt Service Routine

*

* Description   : This is the RTOS scheduler ISR. It generates system ticks and calculates any remaining

*                        waiting and periodic interval time for each task.

*

* Arguments     : None

*

* Returns       : None

*

********************************************************************************************************

*/

 

#if (TICK_TIMER == 0)  /* If Timer 0 is used for the scheduler */

void RTOS_Timer_Int (void) interrupt 1 using 1

{

uchar data k;                 /* For the 8051, Timer 0 is used */

uchar data * idata q;     /* for scheduling.                   */

bit   data On_Q;

 

TH0 = BASIC_TICK / 256;      /* Timer registers reloaded     */

TL0 = BASIC_TICK % 256;

 

#elif (TICK_TIMER == 1)      /* If Timer 1 is used for the scheduler */

void RTOS_Timer_Int (void) interrupt 3 using 1

{

uchar data k;                 /* For the 8051, Timer 0 is used */

uchar data * idata q;     /* for scheduling.                   */

bit   data On_Q;

 

TH1 = BASIC_TICK / 256;      /* Timer registers reloaded     */

TL1 = BASIC_TICK % 256;

 

 

#elif (TICK_TIMER == 2)      /* If Timer 2 is used for the scheduler */

void RTOS_Timer_Int (void) interrupt 5 using 1

{

uchar data k;                  /* For the 8032, Timer 2 is used */

uchar data * idata q;     /* for scheduling.                   */

bit   data On_Q;

TF2 = 0;                     /* Timer 2 interrupt flag is cleared */

#endif

 

Check_Task_Max_SP();

for (k = 0; k < NOOFTASKS; k++)

{

if (IntvalCnt[k] != NOT_TIMING) /* Updates the tasks’  */

{                                       /* periodic intervals. */

IntvalCnt[k]–;

if (IntvalCnt[k] == NOT_TIMING)

{         IntvalCnt[k] = IntvalRld[k];

if ((TaskFlags[k] & SIGV) == SIGV)

{

/* If periodic interval    */

/* has elapsed and the     */      TaskFlags[k] &= ~SIGV;

/* task has been waiting   */      q = ReadyQ;

/* for this to occur, the  */      On_Q = 0;

/* task is placed in the   */      while (q <= ReadyQTop)

/* READY queue, if it is   */   {

/* verified that the task  */            if (k == *q)

/* does not already reside */       {

/* in the queue, as now    */                     On_Q = 1;

/* the task no longer      */                   break;

/* requires to wait.       */            }

q++;

}

if (On_Q == 0)

{

ReadyQTop++;

*ReadyQTop = k;

TinQFlag = 1;

}

}

/* If however the task  */

/* was not waiting for  */

/* this event, the task */

/* is not place in the  */

/* the ready queue.     */

 

else

TaskFlags[k] |= SIGV;

}

}

if (TTs[k] != NOT_TIMING)

{                             /* Updates the tasks’ */

TTs[k]–;                       /* timeout variables. */

if (TTs[k] == NOT_TIMING)

{

ReadyQTop++;           /* If a waiting task’s */

*ReadyQTop = k;        /* timeout elapses     */

TinQFlag = 1;            /* the task is placed  */

TaskFlags[k] &= ~SIGW; /* in the ready queue. */

}

}

/* If the idle task is running, when tasks are  */

/* known to reside in the queue, a task switch  */

/* is purposely induced so these tasks can run. */

}

 

if ((TinQFlag == 1) && (Running == IDLE_TASK))

QShift();

}

 

/*

********************************************************************************************************

*/

 

 

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*

* Function name : Xtra_Int_1

*

* Function type : Interrupt Service Routine

*

* Description   : This is the Timer 0 ISR whose associated interrupt number is 1. It is only enabled in

*                        case an 8032 microcontroller is being used in combination with an EEPROM. The reason

*                        being is that without an EEPROM Timer 0 is not available on the 8032 and in case of

*                        the 8051 Timer 0 is already being used as the RTOS scheduler.

*                 It is also available if using the version 2 monitor ROM.

*

* Arguments     : None

*

* Returns       : None

*

********************************************************************************************************

*/

 

#if (TICK_TIMER != 0)

/* Timer 0 interrupt used for RTOS on 8051 */

/* For the 8032, it can only be used with the modified monitor eprom or user eprom */

/* it is used for the single step in the old version monitor eprom */

 

void Xtra_Int_1 (void) interrupt 1 using 1

{

EA = 0;

Check_Task_Max_SP();

Xtra_Int(TIM0W);     /* Passes TIM0W for identification purposes */

}

 

#endif

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*

* Function name : Xtra_Int_2

*

* Function type : Interrupt Service Routine

*

* Description   : This is the external 1 interrupt ISR whose associated interrupt number is 2.

*

* Arguments     : None

*

* Returns       : None

*

********************************************************************************************************

*/

 

void Xtra_Int_2 (void) interrupt 2 using 1

{

EA = 0;

Check_Task_Max_SP();

Xtra_Int(EXT1W);     /* Passes EXT1W for identification purposes */

}

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*

* Function name : Xtra_Int_3

*

* Function type : Interrupt Service Routine

*

* Description   : This is the Timer 1 ISR whose associated interrupt number is 3.

*

* Arguments     : None

*

* Returns       : None

*

********************************************************************************************************

*/

#if (TICK_TIMER != 1)

 

void Xtra_Int_3 (void) interrupt 3 using 1

{

EA = 0;

Check_Task_Max_SP();

Xtra_Int(TIM1W);     /* Passes TIM1W for identification purposes */

}

 

#endif

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*

* Function name : Xtra_Int_4

*

* Function type : Interrupt Service Routine

*

* Description   : This is the serial port ISR whose associated interrupt number is 4.

*

* Arguments     : None

*

* Returns       : None

*

********************************************************************************************************

*/

 

void Xtra_Int_4 (void) interrupt 4 using 1

{

EA = 0;

Check_Task_Max_SP();

Xtra_Int(SER0W);     /* Passes SER0W for identification purposes */

}

 

/*

********************************************************************************************************

*/

 

/*

********************************************************************************************************

*

* Function name : Xtra_Int_5

*

* Function type : Interrupt Service Routine

*

* Description   : This is the Timer 2 ISR whose associated interrupt number is 5.

*

* Arguments     : None

*

* Returns       : None

*

********************************************************************************************************

*/

#if ( (CPU == 8032) && (TICK_TIMER != 2) )

 

void Xtra_Int_5 (void) interrupt 5 using 1

{

EA = 0;

TF2 = 0;

Check_Task_Max_SP();

Xtra_Int(TIM2W);     /* Passes TIM2W for identification purposes */

}

 

#endif

/*

********************************************************************************************************

*/

 

/*

********************************************************************************************************

*

* Function name : Xtra_Int

*

* Function type : Interrupt Handling (Internal function)

*

* Description   : This function performs the operations required by the previous ISRs.

*

* Arguments     : task_intflag           Represents the flag mask for a given interrupt against which the

*                                                    byte storing the flags of each task will be compared in order to

*                                                    determine whether any task has been waiting for the interrupt in

*                                                    question.

*

* Returns       : None

*

********************************************************************************************************

*/

 

void Xtra_Int (uchar task_intflag) using 1

{

uchar data k;

IntFlag = 0;

for (k = 0; k < NOOFTASKS; k ++)

{

if ((TaskFlags[k] & task_intflag) == task_intflag)

{

TaskFlags[k] &= ~task_intflag;

IntFlag = 1;

TTs[k] = NOT_TIMING; /* If it found that a task  */

ReadyQTop++;            /* has been waiting for the */

*ReadyQTop = k;        /* given interrupt, it no      */

}                                /* longer requires to wait  */

}                                      /* and is therefore placed  */

/* on the READY queue.         */

 

if ((IntFlag == 1) && (Running == IDLE_TASK))

{

TinQFlag = 1;     /* If tasks are known to now reside in the  */

QShift();        /* READY queue while the idle task is           */

}                          /* running, a task switch is purposely      */

/* induced, such that these tasks can run.  */

else

{

if (IntFlag == 1)  /* Otherwise, the ISR exits after  */

TinQFlag = 1;  /* interrupts are re-enabled.      */

EA = 1;

}

}

 

 

/*

********************************************************************************************************

*/

 

/*

********************************************************************************************************

*                                                          RTOS KERNEL HEADER FILE

*

* For use with CRTOS_V2.c – Co-Operative RTOS written in C based on PaulOS by Ing. Paul P. Debono

*                                  for use with the 8051 family of microcontrollers

*

* File     : CRTOS_V2.h

* Revision : 7C

* Date     : February 2005

* By    : John Blaut, Paul P. Debono

*

*                 B. Eng. (Hons.) Elec. Course Final Year Project

*                 University Of Malta

*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*                                              DATA TYPE DEFINITIONS

********************************************************************************************************

*/

 

typedef unsigned char uchar;

typedef unsigned int  uint;

typedef unsigned long ulong;

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*                                            RTOS USER DEFINITIONS

********************************************************************************************************

*/

#define CPU                  8051  // set to 8051 or 8032

#define TICK_TIMER  0       // Set to 0, 1 or 2 to select which timer to use as the RTOS tick timer

#define TICKTIME 10      // Length of RTOS basic tick in msec – refer to the RTOS timing definitions

 

#define NOOFTASKS      8           // Number of tasks used in application

#define MAINSTACK      0x67 // Start address of stack area (see ?STACK *.M51 file)

 

#define STACKSIZE      0x0F // Number of bytes to allocate for the stack

#define STACK_CHECK    0           // Stack size checking flag

 

 

/*

********************************************************************************************************

*/

 

/*

********************************************************************************************************

*                                                 RTOS MACROS

********************************************************************************************************

*/

 

#define OS_CPU_IDLE()        PCON |= 0x01      // Sets the microprocessor in idle mode

#define OS_CPU_DOWN()        PCON |= 0x02      // Sets the microprocessor in power-down mode

 

#if STACK_CHECK // If stack size checking is enabled sets the current SP value to be the maximum SP

// for the current task in case it is higher than its present value

 

#define Check_Task_Max_SP();  MaxSPTs[Running] = (SP > MaxSPTs[Running]) ? SP : MaxSPTs[Running];

 

#else      // Macro defined as nothing in order that it does nothing since stack size checking is disabled

#define     Check_Task_Max_SP();

#endif

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*                                         RTOS TIMING DEFINITIONS

********************************************************************************************************

*/

 

#define MSEC  900                                             // In theory 922 counts represent 1 msec assuming an

// 11.0592 MHz crystal. (Used 900 to compensate for

// overheads) One can experiment with other values

// depending on accuracy required.

 

#define TICKS_PER_SEC  (1000 / TICKTIME)          // Ensure that TICKTIME’s value is chosen such that this

#define TICKS_PER_MIN  (60000 / TICKTIME)         // quotient and hence all the following quotients result

#define TICKS_PER_HOUR (3600000 / TICKTIME)   // in an integer. In theory, maximum value of TICKTIME

#define TICKS_PER_DAY  (86400000 / TICKTIME)  // is given by the value corresponding to CLOCK = 65535

#define CLOCK                (TICKTIME * MSEC)    // i.e. approx. 70-72 – However respecting the condition

#define BASIC_TICK     (65535 – CLOCK + 1)    // above, max. acceptable TICKTIME = 50 msecs. Hence all

// suitable values are: 1, 2, 4, 5, 8, 10, 20, 25, 40, 50

// For reliable time-dependent results a value of 10 or

// above is recommended depending upon the application

 

#define NOT_TIMING           0     // An indefinite period of waiting time in the RTOS is given by a value of 0

 

/*

********************************************************************************************************

*/

 

/*

********************************************************************************************************

*                                                          COMPILE-TIME ERROR TRAPPING

********************************************************************************************************

*/

 

#if (CPU != 8032) && (CPU != 8051)

#error Invalid CPU Setting

#endif

 

#if (NOOFTASKS > 254)

#error Number of tasks is out of range. The ReadyQ can store up to 254 tasks

#endif

 

#if (CPU == 8032)

#if ((MAINSTACK + STACKSIZE) > 0x100)

#error Internal RAM Space exceeded. Please recheck the MAINSTACK and STACKSIZE definitions

#endif

#elif (CPU == 8051)

#if ((MAINSTACK + STACKSIZE) > 0x80)

#error Internal RAM Space exceeded. Please recheck the MAINSTACK and STACKSIZE definitions

#endif

#endif

 

#if ((TICKTIME * 11059200 / 12000) > 65535)

#error Tick time value exceeds valid range of the timer counter setting

#endif

 

#if ((TICKTIME * 11059200 / 12000) < 65535) && ((1000 % TICKTIME) != 0)

#error Undesirable TICKTIME setting. Please choose from 1, 2, 4, 8, 10, 20, 25, 40, 50 ms

#endif

 

#if (CLOCK > 65535)

#error Timer counter setting exceeded valid range. Please recheck the TICKTIME and MSEC definitions

#endif

 

/*

********************************************************************************************************

*/

 

 

 

/*

********************************************************************************************************

*                                         TASK-RELATED DEFINITIONS

********************************************************************************************************

*/

 

#define SIGS        0x80       // Signal-received flag mask

#define SIGW        0x40       // Waiting-for-singal flag mask

#define SIGV           0x20      // Periodic Interval flag

#define SER0W       0x10       // Serial interrupt flag mask     (Interrupt number 4)

#define EXT1W       0x02       // External interrupt 1 flag mask (Interrupt number 2)

#define EXT0W       0x01       // External interrupt 0 flag mask (Interrupt number 0)

 

#if (TICK_TIMER == 0)

#define TIM1W       0x08    // Timer 1 interrupt flag mask    (Interrupt number 3)

#define TIM2W       0x04    // Timer 2 interrupt flag mask    (Interrupt number 5)

#elif (TICK_TIMER == 1)

#define TIM0W       0x08    // Timer 0 interrupt flag mask    (Interrupt number 1)

#define TIM2W       0x04    // Timer 2 interrupt flag mask    (Interrupt number 5)

#elif (TICK_TIMER == 2)

#define TIM0W       0x08    // Timer 0 interrupt flag mask    (Interrupt number 1)

#define TIM1W       0x04    // Timer 1 interrupt flag mask    (Interrupt number 3)

#endif

#define IDLE_TASK  NOOFTASKS  // Main endless loop in application given a task number equal to NOOFTASKS

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*                                ENHANCED EVENT-WAITING ADD-ON MACROS

********************************************************************************************************

*

* These macros perform the same functions of the WAITT, WAITS and PERIODIC calls but rather than ticks

* they accept absolute time values as parameters in terms of days, hours, minutes, seconds and millisecs

* This difference is denoted by the _A suffix – eg. WAITT_A() is the absolute-time version of WAITT()

*

* Range of values accepted:

*

* Using a minimum TICKTIME of 1 msec :       1 msecs –   49 days, 17 hours,  2 mins, 47 secs, 295 msecs

* Using a recommended TICKTIME of 10 msec : 10 msecs –  497 days,  2 hours, 27 mins, 52 secs, 950 msecs

* Using a maximum TICKTIME of 50 msec :     50 msecs – 2485 days, 12 hours, 19 mins, 24 secs, 750 msecs

 

* If the conversion from absolute time to ticks results in 0 (all parameters being 0 or overflow) this

* result is only accepted by WAITS() by virtue of how the WAITT(), WAITS() and PERIODIC() calls were

* written. In the case of the WAITT() and PERIODIC() calls the tick count would automatically be

* changed to 1 meaning an interval of eg. 50 msecs in case the TICKTIME is defined to be 50 msecs

*

* Liberal use of parentheses is made in the following macros in case the arguments might be expressions

*

********************************************************************************************************

*/

 

#define WAITT_A(D,H,M,S,ms)        WAITT((ulong)((TICKS_PER_DAY*(##D)) + (TICKS_PER_HOUR*(##H)) + \

(TICKS_PER_MIN*(##M)) + (TICKS_PER_SEC*(##S)) + ((##ms)/TICKTIME)))

 

#define WAITS_A(D,H,M,S,ms) WAITS((ulong)((TICKS_PER_DAY*(##D)) + (TICKS_PER_HOUR*(##H)) + \

(TICKS_PER_MIN*(##M)) + (TICKS_PER_SEC*(##S)) + ((##ms)/TICKTIME)))

 

#define PERIODIC_A(D,H,M,S,ms)     PERIODIC((ulong)((TICKS_PER_DAY*(##D)) + (TICKS_PER_HOUR*(##H)) + \

(TICKS_PER_MIN*(##M)) + (TICKS_PER_SEC*(##S)) + ((##ms)/TICKTIME)))

 

/*

********************************************************************************************************

*/

 

 

/*

********************************************************************************************************

*                                         FUNCTION PROTOTYPES

********************************************************************************************************

*

*

*  The following RTOS system calls do not receive any  parameters :

*  —————————————————————-

*/

 

void  DEFER (void);    // Stops current task and passes control to next task in queue

void  KILL (void);     // Kills a task – sets it waiting forever

uchar SCHECK (void); // Checks if running task’s signal bit is set

void  WAITV  (void); // Waits for end of task’s periodic interval

uchar  RUNNING_TASK_ID(void);  // Returns the number of the currently executing task

 

/*

*  The following RTOS system calls do receive parameters :

*  ——————————————————-

*/

 

void INIT_RTOS (uchar iemask);               // Initialises all RTOS variables

void RTOSGO (uchar prior);                   // Starts the RTOS running with prioities if required

void SIGNL (uchar task);                     // Signals a task

void WAITI (uchar intnum);                   // Waits for an event (interrupt) to occur

void WAITT (ulong ticks);                    // Waits for a timeout period given by a defined number of ticks

void WAITS (ulong ticks);                    // Waits for a signal to arrive within a given number of ticks

void PERIODIC (ulong ticks);           // Sets task to behave periodically every given number of ticks

void CREATE (uchar task, uint taskadd); // Creates a task

 

/*

*  Other functions used internally by the RTOS :

*  ———————————————

*/

 

void QShift (void);                            // Task swapping function

void RTOS_Timer_Int (void);              // RTOS Scheduler ISR

void Xtra_Int (uchar task_intflag);      // Function used by ISRs other than the RTOS Scheduler

void Xtra_Int_0 (void);                        // External Interrupt 0 ISR

 

#if (TICK_TIMER != 0 )

void Xtra_Int_1 (void);             // Timer 0 ISR

#endif

 

void  Xtra_Int_2 (void);                 // External Interrupt 1 ISR

 

#if (TICK_TIMER != 1 )

void  Xtra_Int_3 (void);             // Timer 1 ISR

#endif

 

void  Xtra_Int_4 (void);                 // Serial Port ISR

 

#if (TICK_TIMER != 2 )

void  Xtra_Int_5 (void);            // Interrupt 5 (Timer 2) is not available on the 8051

#endif

/*

********************************************************************************************************

*/