=========== Delay Timer =========== Delay timer is a simple and very useful way of controlling when a task runs. To implement the timer we first need to declare one a delay counter for each task and initalize them to 0. .. code-block:: c // Global timer variables. One for each task. int taskOneDelayCount; int taskTwoDelayCount; void main(void) { // Initialize tasks // Initialize timers to 0. taskOneDelayCount = 0; taskTwoDelayCount = 0; Switch_To_Current(); } Next we need to modify the scheduler so that it checks the delay counters. And we need to create a function that will set the delay for a task whenever its called. .. code-block:: c void DelayTimer(int numOfTicks); Also want to force a context switch whenever a task wants a delay. When the task calls for a delay it should be stopped immediately. That is the delay begins when the task calls the delay function. The only way to do that is to force a context switch right away. .. code-block:: c void scheduler(int sp) { WRITEREG32(T0IR, 0xFF); // Reset timer // Check counters if (taskOneDelayCount > 0) taskOneDelayCount--; if (taskTwoDelayCount > 0) taskTwoDelayCount--; if (taskID == 1) { // Only switch to a task if it's delay count is at zero if (taskTwoDelayCount == 0) { stackOneSP = sp; // Store stack pointer for task 1 taskID = 2; // Set the taskID to task 2 currentSP = stackTwoSP; // Set the current stack pointer to task 2's stack pointer } } else { // Only switch to a task if it's delay count is at zero if (taskOneDelayCount == 0) { stackTwoSP = sp; // Store stack pointer for task 2 taskID = 1; // Set the taskID to task 1 currentSP = stackOneSP; // Set the current stack pointer to task 1's stack pointer } } } .. code-block:: c int currentTaskId; // The ID of the current task int currentSP; // The value of the current task's stack pointer struct TaskBlock { int stackPointer; int delayCount; } TaskBlock taskBlocks[NUMBER_OF_TASKS]; // Allocate space for stacks int stackOne[STACKSIZE]; int stackTwo[STACKSIZE]; int stackThree[STACKSIZE]; void CreateTask(int id, int* stack, void* task_address) { taskBlocks[id].stackPointer = initialize_stack(stack, task_address); taskBlocks[id].delayCount = 0; } void StartOS() { currentTaskId = 1; currentSP = taskBlocks[currentTaskId].stackPointer; // Run the current task switch_to_current(); // This call never returns to this function. } void main(void) { // Create tasks CreateTask(1, stackOne, (void*)taskOne); CreateTask(2, stackTwo, (void*)taskTwo); CreateTask(3, stackIdle, (void*)taskIdle); StartOS(); } Scheduler ========= Changes Timer interrupt should call a timer handler that will acknowledge the VIC then call the context switching code. That will let us call the scheduler whenever we want independently of the timer. .. code-block:: c void DelayTask(int numOfTicks) { taskBlocks[currentTaskId].delayCount = numOfTicks; Scheduler(); } .. code-block:: c