1. Introduction

 


 

CoOS is a Real Time Operating System (RTOS). Like a normal operating system, CoOS works with tasks. Because this microcontroller has only one core, it can only execute one task a time but it uses software interrupts to change fast between tasks.. A software interrupt works on the same principal as a hardware interrupt, it can jump to another subroutine and run that code first. This is what a RTOS does, a number of tasks is created and executed and because of the fast switching between tasks the Simplecortex is basically multitasking and can run multiple tasks at once without the programmer worrying about it.

With CoOS it is possible to manage which subroutine has to be executed first. Each task can be given a priority from 0 to 10. The task with the highest priority will be executed first. It is also possible to give a task temporarily the highest priority, this is called a Mutex.

Scheduling is needed to start the operating system, scheduling means that there is a plan what tasks need to be executed in what order and how fast. When CoOS is started CoOS does this automatically. 

Flags are used to communicate between tasks. 
CoOS has a maximum of 32 flags.

The examples can be downloaded from our repository.
The Full documentation of CoOS made by CooCox can be found here.

Why use CoOS?
Normally a microcontroller will executed a certain piece of code sentence by sentence. CoOS can stop in the middle of a subroutine and continue at another subroutine.
In this way it is for example possible to send data to an LCD and run an Ethernet webserver at the same time.

Advantages:
- Multitasking
 
Disadvantages:
- CoOS uses more memory, about 5K flash and 2K RAM.
- It is not possible to use SLEEP mode because the software interrupts will wake-up the microcontroller immediately.

This list shows the minimum and maximum timings that are needed to run CoOS.

Create defined task, no task switch      5.3us / 5.8us
Create defined task, switch task           7.5us / 8.6us
Delete task (ExitTask)                           4.8us / 5.2us
Task switch (SwitchContext)                 1.5us / 1.5us
Task switch (upon set flag)                   7.5us / 8.1us
Task switch (upon sent semaphore)     6.3us / 7.0us
Task switch (upon sent mail)                6.1us / 7.1us
Task switch (upon sent queue)             7.0us / 7.6us
Set Flag (no task switch)                      1.3us / 1.3us
Send semaphore (no task switch)        1.6us / 1.6us
Send mail (no task switch)                   1.5us / 1.5us
Send queue (no task switch)                1.8us / 1.8us



2. Includes

 
#include <CoOS.h>                                            /*!< CoOS header file */
#include "LPC17xx.h"
#include "lpc_types.h"
#include "GPIO.h"


3. Create a new task

 
Each task should be given a memory size (a stack size). for the example we used this:

#define STACK_SIZE_TASKA 128                       /*!< Define "taskA" task size 128 bytes */
#define STACK_SIZE_TASKB 128                       /*!< Define "taskB" task size 128 bytes */
#define STACK_SIZE_TASKC 128                       /*!< Define "taskC" task size 128 bytes */

Also a variable string must be defined so that the data can be saved at this memory addresses.

OS_STK     taskA_stk[STACK_SIZE_TASKA];      /*!< Define "taskA" task stack */
OS_STK     taskB_stk[STACK_SIZE_TASKB];      /*!< Define "taskB" task stack */
OS_STK     taskC_stk[STACK_SIZE_TASKC];      /*!< Define "led" task stack   */

 

4. Status


A task can be in one of the following states in CoOS.
 
Ready State(TASK_READY):
Ready tasks are tasks that can be executed (they are not waiting or dormant). They are not currently executing
because another task of equal or higher priority is already in the Running state. A task will be in this state after it is created.

Running State(TASK_RUNNING):
When a task is executing, the task is in Running state.

Waiting State(TASK_WAITING):
Wait for an event to occur. A task will be in the waiting state if it is waiting for a event in CoOS.

The Dormant State(TASK_DORMANT):
The task has been deleted and can not be used again. The dormant state is not the same as the waiting state. Tasks in the waiting state can be reactivated and be available again for scheduling when its waiting events have satisfied. However, tasks in the dormant state can never be reactivated.

The state of a task can be changed in the above four states. CoSuspendTask() can be used to convert a task which in the running or ready state to the waiting state. With calling CoAwakeTask() it is possible to convert the state of a task from the waiting state to the ready state.

The following picture shows which transitions are possible:

Coos


5. Example


This example uses 3 tasks ( taskA, taskB, taskC).
the main code looks like this:
 

int main ()
{
 
  CoInitOS ();                                                     /*!< Initial CooCox CoOS          */
 
 
  /*!< Create three tasks    */
  CoCreateTask (taskA,0,0,&taskA_stk[STACK_SIZE_TASKA-1],STACK_SIZE_TASKA);
  CoCreateTask (taskB,0,1,&taskB_stk[STACK_SIZE_TASKB-1],STACK_SIZE_TASKB);
  CoCreateTask (taskC,0,2,&taskC_stk[STACK_SIZE_TASKC-1],STACK_SIZE_TASKC);
 
  CoStartOS ();                                                  /*!< Start multitask               */
 
 
  while (1);                                                        /*!< The code can not reach here       */
}

What happened is the CoOS (Real Time Operating System) is initialized.
The next stap is to create all tasks. When thats done the CoOS can be started.

Warning: the main code must be in a loop. Else the Operating System will crash.

These are the 3 tasks:

void taskA (void* pdata)
{
// place your code here.
while(1);
}

void taskB (void* pdata)
{
// place your code here.
while(1);
}

void taskC (void* pdata)
{
// place your code here.
while(1);
}

Warning: every task must end with a loop. No matter if the code is in a loop or it will be executed for one time, every task must end with a loop otherwise the task wil end in a hardfault. A hardfault is when something went so wrong that the whole CPU crashed. A loop can be made by including While(1); into the task.

6. Mutex


Mutexes can solve the "mutually exclusion" problem in CoOS. Coocox has solved this issue by the method of priority inheritance.Priority inversion means that a high-priority task is waiting for the low-priority task to release resources, at the same time the low-priority task is waiting for the middle priority task’s. In laymens terms, the high prioraty task can't function because it needs data from a low resource task that is waiting for a middle resource task to finish. There are two classical methods to prevent this from happening:
 
  • The priority inheritance strategy: The task which is possessing the critical section inherits the highest priority of all the tasks that request for this critical section. When the task exits from the critical section, it will restore to its original priority.
  • The ceiling priority strategy: Upgrade the priority of the task which requests a certain resource to the highest priority of all the tasks that be likely to access this resource (and the highest priority is called the ceiling priority of this resource).
 
The mutex sections work like this: Al tasks have a priority, when a task have a low priority, but one or a few lines of code that needs to be in the higher priority (must be executed directly) those lines of code must be in a mutex. Everything that is in the mutex gets the highest priority.

An example:

OS_MutexID mutexID;                        // create a mutex variable

void myTaskA(void* pdata)
{
       mutexID = CoCreateMutex ( );       // create a mutex section
       CoEnterMutexSection(mutexID );   // enter the mutex section
       // critical code
       CoLeaveMutexSection(mutexID );  // leave the mutex section
}
void myTaskB(void* pdata)
{
        CoEnterMutexSection(mutexID );   // enter the mutex section
        // critical code
        CoLeaveMutexSection(mutexID );   // leave the mutex section
}


7. Critical section


CoOS can handle critical code, if you have a piece of code that HAS to be executed in one go no matter what, use this method:
Different from other kernels, CooCox CoOS does not handle the critical code section by closing interrupts, but locking the scheduler. Therefore, CoOS has a shorter latency for interrupt compared with others.
Since the time of enabling the interrupt relates to system responsiveness towards the real-time events, it is one of the most important factors offered by the real-time kernel developers. By locking the scheduler we can improve system real-time feature to the maximum comparing to other approaches. Since CooCox CoOS manages the critical section by forbidding to schedule task, user applications cannot call any API functions which will suspend the current running task in critical sections, such as CoExitTask ( ), CoSuspendTask ( ), CoTickDelay ( ), CoTimeDelay ( ), CoEnterMutexSection ( ), CoPendSem ( ), CoPendMail ( ), CoPendQueueMail ( ), CoWaitForSingleFlag ( ), CoWaitForMultipleFlags ( ) and so on.

Example:
 
void myTaskA(void* pdata)
{
  for (;;) {  
CoSchedLock ( );                                   // Enter Critical Section
                                                              // Critical Code
CoSchedUnlock ( );                                // Exit Critical Section
  }
}


 8. Flags


Flags can be used to comminicate between tasks. A task can set or reset a flag andanother task can check the statos of a flag or wait with executing until a flag is set.
There are two ways of using flags: a single flag and muliple flags. multiple flags must wait for each other, so the single flag is faster. CoOS supports up to 32 flags.
There are two kinds of flags in CooCox CoOS: the ones reset manually and the ones reset automatically.
When a task has waited for a flag which reset automatically, the system will convert the flag to not-ready state. If the flag is reset manually, there won’t be any side effect. Therefore, when a flag which reset manually converts to the ready state, all the tasks which waiting for this event will convert to the ready state as far as you call CoClearFlag() to reset the flag to the not-ready state. When a flag which reset automatically converts to the ready state, only one task which waiting for this event will convert to the ready state. Since the waiting list of the event flags is ordered by the principle of FIFO, towards the event which reset automatically only the first task of the waiting list converts to the ready state and others that waiting for this flag are still in the waiting state. Suppose there are three tasks (A, B, C) waiting for the same flag I which resets manually. When I is ready, all the tasks will be converted (A, B, C) to the ready state and then inserted into the ready list. Suppose I is a flag which reset automatically and the tasks (A, B, C) are listed in sequence in the waiting list. When I is ready, it will inform task A. Then I will be converted to the not-ready state. Therefore B and C will keep waiting for the next ready state of flag I in the waiting list. You can create a flag by calling CoCreateFlag() in CooCox CoOS. After being created, you can call CoWaitForSingleFlag() and CoWaitForMultipleFlags() to wait for a single flag or multiple flags.

Example for use of a single flag: 
 
/*---------------------------- Inlcude ---------------------------------------*/
 
#include <CoOS.h>                          /*!< CoOS header file             */
#include "LPC17xx.h"
#include "lpc_types.h"
#include "GPIO.h"
/*---------------------------- Symbol Define -------------------------------*/
#define STACK_SIZE_TASKA 128              /*!< Define "taskA" task size */
#define STACK_SIZE_TASKB 128              /*!< Define "taskA" task size */
 
/*---------------------------- Variable Define -------------------------------*/
OS_STK     taskA_stk[STACK_SIZE_TASKA];      /*!< Define "taskA" task stack */
OS_STK     taskB_stk[STACK_SIZE_TASKB];      /*!< Define "taskB" task stack */
        
OS_FlagID flagID;                                           // declare a flag
                
void taskA(void* pdata)                              // This is one of the two tasks that is created in the main loop
{
GPIOSetDir(1, 18, 1);                                        // Set PIO1_18 as output
    uint32_t flipflop = 0;                                     // Make a local variable and give it the value 0
    flagID = CoCreateFlag(0, 0);                        // Create a flag and set it in manual reset modus
  for (;;) {                                                          // Make a never ending loop
      if(flipflop == 0)                                           // If variable is zero make variable 1 and clear the flag
      {
          flipflop = 1;
          CoClearFlag(flagID);
      }
      else                                                            // If variable is not zero make variable 0 and set the flag
      {
          flipflop = 0;
          CoSetFlag(flagID);
      }
      GPIOSetValue(1, 18, flipflop);                     // Set PIO1_18 HIGH or LOW
    CoTickDelay (100);                                        // A delay of 100 milliseconds
  }
}
void taskB (void* pdata){                                   // This is one of the two tasks that is created in the main loop
    GPIOSetDir(1, 19, 1);                                     // Set PIO1_19 as output
    StatusType result;                                         // Create a status type variable
  for (;;)                                                              // Make a never ending loop
  {
      GPIOSetValue(1, 19, 0);                               // Make PIO1_19 LOW
      result = CoWaitForSingleFlag(flagID, 500); // Put the status of the flag in the variable, if the flag wasn't recieved in 500mS a timeout occurs
      GPIOSetValue(1, 19, 1);                               // Make PIO1_19 HIGH
  }
}
int main (){
  CoInitOS ();                 /*!< Initial CooCox CoOS          */
  /*!< Create three tasks    */
  CoCreateTask (taskA,0,0,&taskA_stk[STACK_SIZE_TASKA-1],STACK_SIZE_TASKA);
  CoCreateTask (taskB,0,1,&taskB_stk[STACK_SIZE_TASKB-1],STACK_SIZE_TASKB);
  CoStartOS ();                /*!< Start multitask               */
  while (1);                /*!< The code don''t reach here       */
}
 
Example for use of multiple flags:

/*---------------------------- Inlcude ---------------------------------------*/
#include <CoOS.h>                          /*!< CoOS header file             */
#include "LPC17xx.h"
#include "lpc_types.h"
#include "GPIO.h"
/*---------------------------- Symbol Define -------------------------------*/
#define STACK_SIZE_TASKA 128              /*!< Define "taskA" task size */
#define STACK_SIZE_TASKB 128              /*!< Define "taskA" task size */
/*---------------------------- Variable Define -------------------------------*/
OS_STK     taskA_stk[STACK_SIZE_TASKA];      /*!< Define "taskA" task stack */
OS_STK     taskB_stk[STACK_SIZE_TASKB];      /*!< Define "taskB" task stack */
        
OS_FlagID flagID;        // declare a flag
                
void myTaskA(void* pdata)
{
    uint32_t flag;
    StatusType err;
    flagID  = CoCreateFlag(0, 0);                           // create 3 flags
    flagID1 = CoCreateFlag(0, 0);
    flagID2 = CoCreateFlag(0, 0);
    flag = flagID|flagID1|flagID2;                          // variable flag is flagID or flagID or flagID2
    CoWaitForMultipleFlags(flag,OPT_WAIT_ANY,0,&err);   
   for (;;)
  {    
  }
}
void taskB (void* pdata){
    CoSetFlag(flagID1);                                                       // Set flagID
  for (;;)
  {
  }
}
void myISR(void)
{
      CoEnterISR();                                             // Enter interrupt
      isr_SetFlag(flagID2);                                  // Set flagID2
      CoExitISR();                                               // Leave interrupt
}

int main (){
  CoInitOS ();                 /*!< Initial CooCox CoOS          */
  /*!< Create three tasks    */
  CoCreateTask (taskA,0,0,&taskA_stk[STACK_SIZE_TASKA-1],STACK_SIZE_TASKA);
  CoCreateTask (taskB,0,1,&taskB_stk[STACK_SIZE_TASKB-1],STACK_SIZE_TASKB);
  CoStartOS ();                /*!< Start multitask               */
  while (1);                /*!< The code don''t reach here       */
}


9. Priority


By creating a task a priority can be set.
If the priority of the current created task is higher than the
running task, the system start a task scheduling and distribute
the execution time to the current task.

When a the task is running the priority level can be set again.
That can be done by this code:

CoSetPriority(task ID, Priority);

Note:
1.to be set is in the waiting list and the priority of this
task being reset to is higher than the current running one, run a task
scheduling.
2. The changing of the priority will influence the order of the lists that
relevant to this priority, such as the mutex list, the event waiting list
and so on.

You can delete a task by calling CoExitTask ( ) or CoDelTask (taskID) in CooCox CoOS. CoExitTask ( ) is called to delete the current running task while CoDelTask (taskID) to delete others. If the incoming parameter is the current task ID, CoDelTask (taskID) can also delete the current task.







Copyright 2011. Joomla 1.7 templates - Joomla template maker. The Simplecortex is developed by BRC-Electronics