MicroC/OS II Quick Reference
This Quick Reference describes the calling interface for a subset of the services supplied by MicroC/OS-II. Complete documentation and the complete sources for MicroC/OS-II are available in Jean Labrosse's book MicroC/OS II: The Real-Time Kernel. In this book you'll learn about kernel structure, task and time management, intertask communications and synchronization, and dynamic memory allocation in MicroC/OS-II. This latest release of MicroC/OS has been completely revised and includes many new features. Hardcover, disk included, 524pp, ISBN 0-87930-543-6. Available in your local bookstore, or order direct by phone, fax, or email:
OSInit()
void OSInit(void);
OSInit() initializes MicroC/OS-II and must be called prior to calling OSStart(), which actually starts multitasking.
void OSIntEnter(void);
OSIntEnter() notifies MicroC/OS-II that an ISR is being processed. This allows MicroC/OS-II to keep track of interrupt nesting. OSIntEnter() is used in conjunction with OSIntExit().
void OSIntExit(void);
OSIntExit() notifies MicroC/OS-II that an ISR has completed. This allows MicroC/OS-II to keep track of interrupt nesting. OSIntExit() is used in conjunction with OSIntEnter(). When the last nested interrupt completes, MicroC/OS-II calls the scheduler to determine if a higher priority task has been made ready to run, in which case, the interrupt returns to the higher priority task instead of the interrupted task.
void *OSMboxAccept(OS_EVENT *pevent);
OSMboxAccept() allows you to see if a message is available from the desired mailbox. Unlike OSMboxPend(), OSMboxAccept() does not suspend the calling task if a message is not available. If a message is available, the message is returned to your application and the content of the mailbox is cleared. This call is typically used by ISRs because an ISR is not allowed to wait for a message at a mailbox.
Arguments
pevent is a pointer to the mailbox from which the message is received. This pointer is returned to your application when the mailbox is created [see OSMboxCreate()].
Return Value
A pointer to the message if one is available; NULL if the mailbox does not contain a message.
OS_EVENT *OSMboxCreate(void *msg);
OSMboxCreate() creates and initializes a mailbox. A mailbox allows tasks or ISRs to send a pointer-sized variable (message) to one or more tasks.
Arguments
msg is used to initialize the contents of the mailbox. The mailbox is empty when msg is a NULL pointer. The mailbox initially contains a message when msg is non-NULL.
Return Value
A pointer to the event control block allocated to the mailbox. If no event control block is available, OSMboxCreate() returns a NULL pointer.
void *OSMboxPend(OS_EVENT *pevent, INT16U timeout, INT8U *err);
OSMboxPend() is used when a task expects to receive a message. The message is sent to the task either by an ISR or by another task. The message received is a pointer-sized variable and its use is application specific. If a message is present in the mailbox when OSMboxPend() is called, the message is retrieved, the mailbox is emptied, and the retrieved message is returned to the caller. If no message is present in the mailbox, OSMboxPend() suspends the current task until either a message is received or a user-specified timeout expires. If a message is sent to the mailbox and multiple tasks are waiting for the message, MicroC/OS-II resumes the highest priority task waiting to run. A pended task that has been suspended with OSTaskSuspend() can receive a message. However, the task remains suspended until it is resumed by calling OSTaskResume().
Arguments
pevent is a pointer to the mailbox from which the message is received. This pointer is returned to your application when the mailbox is created [see OSMboxCreate()].
timeout allows the task to resume execution if a message is not received from the mailbox within the specified number of clock ticks. A timeout value of 0 indicates that the task wants to wait forever for the message. The maximum timeout is 65,535 clock ticks. The timeout value is not synchronized with the clock tick. The timeout count begins decrementing on the next clock tick, which could potentially occur immediately.
err is a pointer to a variable that holds an error code. OSMboxPend() sets *err to one of the following:
• OS_NO_ERR if a message was received.
• OS_TIMEOUT if a message was not received within the specified timeout period.
• OS_ERR_PEND_ISR if you called this function from an ISR and MicroC/OS-II has to suspend it. In general, you should not call OSMboxPend() from an ISR, but MicroC/OS-II checks for this situation anyway.
• OS_ERR_EVENT_TYPE pevent is not pointing to a mailbox.
Return Value
OSMboxPend() returns the message sent by either a task or an ISR and *err is set to OS_NO_ERR. If a message is not received within the specified timeout period, the returned message is a NULL pointer and *err is set to OS_TIMEOUT.
INT8U OSMboxPost(OS_EVENT *pevent, void *msg);
OSMboxPost() sends a message to a task through a mailbox. A message is a pointer-sized variable and its use is application specific. If a message is already in the mailbox, an error code is returned indicating that the mailbox is full. OSMboxPost() then immediately returns to its caller and the message is not placed in the mailbox. If any task is waiting for a message at the mailbox, the highest priority task waiting receives the message. If the task waiting for the message has a higher priority than the task sending the message, the higher priority task is resumed and the task sending the message is suspended. In other words, a context switch occurs.
Arguments
pevent is a pointer to the mailbox into which the message is deposited. This pointer is returned to your application when the mailbox is created [see OSMboxCreate()].
msg is the actual message sent to the task. msg is a pointer-sized variable and is application specific. You must never post a NULL pointer because this indicates that the mailbox is empty.
Return Value
OSMboxPost() returns one of two error codes:
• OS_NO_ERR if the message was deposited in the mailbox.
• OS_MBOX_FULL if the mailbox already contained a message.
• OS_ERR_EVENT_TYPE pevent is not pointing to a mailbox.
INT8U OSMboxQuery(OS_EVENT *pevent, OS_MBOX_DATA *pdata);
OSMboxQuery() obtains information about a message mailbox. Your application must allocate an OS_MBOX_DATA data structure, which is used to receive data from the event control block of the message mailbox. OSMboxQuery() allows you to determine whether any tasks are waiting for a message at the mailbox and how many tasks are waiting (by counting the number of 1s in the .OSEventTbl[] field). You can also examine the current content of the mailbox. Note that the size of .OSEventTbl[] is established by the #define constant OS_EVENT_TBL_SIZE (see uCOS_II.H).
Arguments
pevent is a pointer to the mailbox. This pointer is returned to your application when the mailbox is created [see OSMboxCreate()].
pdata is a pointer to a data structure of type OS_MBOX_DATA, which contains the following fields:
void *OSMsg; /* Copy of the message stored in the mailbox */ INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* Copy of the mailbox wait list */ INT8U OSEventGrp;
Return Value
OSMboxQuery() returns one of two error codes:
• OS_NO_ERR if the call was successful.
• OS_ERR_EVENT_TYPE if you didn’t pass a pointer to a message mailbox.
OS_MEM *OSMemCreate(void *addr, INT32U nblks, INT32U blksize, INT8U *err);
OSMemCreate() creates and initializes a memory partition. A memory partition contains a user-specified number of fixed-size memory blocks. Your application can obtain one of these memory blocks and, when done, release the block back to the partition.
Arguments
addr is the address of the start of a memory area that is used to create fixed-size memory blocks. Memory partitions can be created either using static arrays or malloc() during startup.
nblks contains the number of memory blocks available from the specified partition. You must specify at least two memory blocks per partition.
blksize specifies the size (in bytes) of each memory block within a partition. A memory block must be large enough to hold at least a pointer.
err is a pointer to a variable that holds an error code. OSMemCreate() sets *err to
• OS_NO_ERR if the memory partition was created successfully,
• OS_MEM_INVALID_PART if a free memory partition was not available,
• OS_MEM_INVALID_BLKS if you didn’t specify at least two memory blocks per partition, or
• OS_MEM_INVALID_SIZE if you didn’t specify a block size that can contain at least a pointer variable.
Return Value
OSMemCreate() returns a pointer to the created memory partition control block if one is available. If no memory partition control block is available, OSMemCreate() returns a NULL pointer.
OSMemGet()
void *OSMemGet(OS_MEM *pmem, INT8U *err);
OSMemGet obtains a memory block from a memory partition. It is assumed that your application knows the size of each memory block obtained. Also, your application must return the memory block [using OSMemPut()] when it no longer needs it. You can call OSMemGet() more than once until all memory blocks are allocated.
Arguments
pmem is a pointer to the memory partition control block that is returned to your application from the OSMemCreate() call.
err is a pointer to a variable that holds an error code. OSMemGet() sets *err to one of the following:
• OS_NO_ERR if a memory block was available and returned to your application.
• OS_MEM_NO_FREE_BLKS if the memory partition didn’t contain any more memory blocks to allocate.
Return Value
OSMemGet() returns a pointer to the allocated memory block if one is available. If no memory block is available from the memory partition, OSMemGet() returns a NULL pointer.
OSMemPut()
INT8U OSMemPut(OS_MEM *pmem, void *pblk);
OSMemPut() returns a memory block to a memory partition. It is assumed that you will return the memory block to the appropriate memory partition.
Arguments
pmem is a pointer to the memory partition control block that is returned to your application from the OSMemCreate() call.
pblk is a pointer to the memory block to be returned to the memory partition.
Return Value
OSMemPut() returns one of the following error codes:
• OS_NO_ERR if a memory block was available and returned to your application.
• OS_MEM_FULL if the memory partition could not accept more memory blocks. This is surely an indication that something is wrong because you are returning more memory blocks than you obtained using OSMemGet()
.
INT8U OSMemQuery(OS_MEM *pmem, OS_MEM_DATA *pdata);
OSMemQuery() obtains information about a memory partition. Basically, this function returns the same information found in the OS_MEM data structure, but in a new data structure called OS_MEM_DATA. OS_MEM_DATA also contains an additional field that indicates the number of memory blocks in use.
Arguments
pmem is a pointer to the memory partition control block that is returned to your application from the OSMemCreate() call.
pdata is a pointer to a data structure of type OS_MEM_DATA, which contains the following fields:
void *OSAddr; /* Points to beginning address of the memory partition */ void *OSFreeList; /* Points to beginning of the free list of memory blocks */ INT32U OSBlkSize; /* Size (in bytes) of each memory block */ INT32U OSNBlks; /* Total number of blocks in the partition */ INT32U OSNFree; /* Number of memory blocks free */ INT32U OSNUsed; /* Number of memory blocks used */
Return Value
OSMemQuery() always returns OS_NO_ERR.
void *OSQAccept(OS_EVENT *pevent);
OSQAccept() checks to see if a message is available in the desired message queue. Unlike OSQPend(), OSQAccept() does not suspend the calling task if a message is not available. If a message is available, it is extracted from the queue and returned to your application. This call is typically used by ISRs because an ISR is not allowed to wait for messages at a queue.
Arguments
pevent is a pointer to the message queue from which the message is received. This pointer is returned to your application when the message queue is created [see OSQCreate()].
Return Value
A pointer to the message if one is available; NULL if the message queue does not contain a message.
OS_EVENT *OSQCreate(void **start, INT8U size);
OSQCreate() creates a message queue. A message queue allows tasks or ISRs to send pointer-sized variables (messages) to one or more tasks. The meaning of the messages sent are application specific.
Arguments
start is the base address of the message storage area. A message storage area is declared as an array of pointers to voids.
size is the size (in number of entries) of the message storage area.
Return Value
OSQCreate() returns a pointer to the event control block allocated to the queue. If no event control block is available, OSQCreate() returns a NULL pointer.
OSQFlush()
INT8U *OSQFlush(OS_EVENT *pevent);
OSQFlush() empties the contents of the message queue and eliminates all the messages sent to the queue. This function takes the same amount of time to execute whether tasks are waiting on the queue (and thus no messages are present) or the queue contains one or more messages.
Arguments
pevent is a pointer to the message queue. This pointer is returned to your application when the message queue is created [see OSQCreate()].
Return Value
OSQFlush() returns one of the following codes:
• OS_NO_ERR if the message queue was flushed.
• OS_ERR_EVENT_TYPE if you attempted to flush an object other than a message queue.
OSQPend()
void *OSQPend(OS_EVENT *pevent, INT16U timeout, INT8U *err);
OSQPend() is used when a task wants to receive messages from a queue. The messages are sent to the task either by an ISR or by another task. The messages received are pointer-sized variables, and their use is application specific. If a at least one message is present at the queue when OSQPend() is called, the message is retrieved and returned to the caller. If no message is present at the queue, OSQPend() suspends the current task until either a message is received or a user-specified timeout expires. If a message is sent to the queue and multiple tasks are waiting for such a message, then MicroC/OS-II resumes the highest priority task that is waiting. A pended task that has been suspended with OSTaskSuspend() can receive a message. However, the task remains suspended until it is resumed by calling OSTaskResume().
Arguments
pevent is a pointer to the queue from which the messages are received. This pointer is returned to your application when the queue is created [see OSQCreate()].
timeout allows the task to resume execution if a message is not received from the mailbox within the specified number of clock ticks. A timeout value of 0 indicates that the task wants to wait forever for the message. The maximum timeout is 65,535 clock ticks. The timeout value is not synchronized with the clock tick. The timeout count starts decrementing on the next clock tick, which could potentially occur immediately.
err is a pointer to a variable used to hold an error code. OSQPend() sets *err to one of the following:
• OS_NO_ERR if a message was received.
• OS_TIMEOUT if a message was not received within the specified timeout.
• OS_ERR_PEND_ISR if you called this function from an ISR and MicroC/OS-II would have to suspend it. In general, you should not call OSQPend() from an ISR. MicroC/OS-II checks for this situation anyway.
• OS_ERR_EVENT_TYPE pevent is not pointing to a message queue.
Return Value
OSQPend() returns a message sent by either a task or an ISR, and *err is set to OS_NO_ERR. If a timeout occurs, OSQPend() returns a NULL pointer and sets *err to OS_TIMEOUT.
OSQPost()
INT8U OSQPost(OS_EVENT *pevent, void *msg);
OSQPost() sends a message to a task through a queue. A message is a pointer-sized variable, and its use is application specific. If the message queue is full, an error code is returned to the caller. In this case, OSQPost() immediately returns to its caller, and the message is not placed in the queue. If any task is waiting for a message at the queue, the highest priority task receives the message. If the task waiting for the message has a higher priority than the task sending the message, the higher priority task resumes and the task sending the message is suspended; that is, a context switch occurs. Message queues are first-in-first-out (FIFO), which means that the first message sent is the first message received.
Arguments
pevent is a pointer to the queue into which the message is deposited. This pointer is returned to your application when the queue is created [see OSQCreate()].
msg is the actual message sent to the task. msg is a pointer-sized variable and is application specific. You must never post a NULL pointer.
Return Value
OSQPost() returns one of two error codes:
• OS_NO_ERR if the message was deposited in the queue.
• OS_Q_FULL if the queue was already full.
• OS_ERR_EVENT_TYPE pevent is not pointing to a message queue.
INT8U OSQPostFront(OS_EVENT *pevent, void *msg);
OSQPostFront() sends a message to a task through a queue. OSQPostFront() behaves very much like OSQPost(), except that the message is inserted at the front of the queue. This means that OSQPostFront() makes the message queue behave like a last-in-first-out (LIFO) queue instead of a first-in-first-out (FIFO) queue. The message is a pointer-sized variable, and its use is application specific. If the message queue is full, an error code is returned to the caller. OSQPostFront() immediately returns to its caller and the message is not placed in the queue. If any tasks are waiting for a message at the queue, the highest priority task receives the message. If the task waiting for the message has a higher priority than the task sending the message, the higher priority task is resumed and the task sending the message is suspended; that is, a context switch occurs.
Arguments
pevent is a pointer to the queue into which the message is deposited. This pointer is returned to your application when the queue is created [see OSQCreate()].
msg is the actual message sent to the task. msg is a pointer-sized variable and is application specific. You must never post a NULL pointer.
Return Value
OSQPostFront() returns one of two error codes:
• OS_NO_ERR if the message was deposited in the queue.
• OS_Q_FULL if the queue was already full.
• OS_ERR_EVENT_TYPE pevent is not pointing to a message queue.
OSQQuery()
INT8U OSQQuery(OS_EVENT *pevent, OS_Q_DATA *pdata);
OSQQuery() obtains information about a message queue. Your application must allocate an OS_Q_DATA data structure used to receive data from the event control block of the message queue. OSQQuery() allows you to determine whether any tasks are waiting for messages at the queue, how many tasks are waiting (by counting the number of 1s in the .OSEventTbl[] field), how many messages are in the queue, and what the message queue size is. OSQQuery() also obtains the next message that would be returned if the queue is not empty. Note that the size of .OSEventTbl[] is established by the #define constant OS_EVENT_TBL_SIZE (see uCOS_II.H).
Arguments
pevent is a pointer to the message queue. This pointer is returned to your application when the queue is created [see OSQCreate()].
pdata is a pointer to a data structure of type OS_Q_DATA, which contains the following fields:
void *OSMsg; /* Next message if one available */ INT16U OSNMsgs; /* Number of messages in the queue */ INT16U OSQSize; /* Size of the message queue */ INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* Message queue wait list */ INT8U OSEventGrp;
Return Value
OSQQuery() returns one of two error codes:
• OS_NO_ERR if the call was successful.
• OS_ERR_EVENT_TYPE if you didn’t pass a pointer to a message queue.
void OSSchedLock(void);
OSSchedLock() prevents task rescheduling until its counterpart, OSSchedUnlock(), is called. The task that calls OSSchedLock() keeps control of the CPU even though other higher priority tasks are ready to run. However, interrupts are still recognized and serviced (assuming interrupts are enabled). OSSchedLock() and OSSchedUnlock() must be used in pairs. MicroC/OS-II allows OSSchedLock() to be nested up to 254 levels deep. Scheduling is enabled when an equal number of OSSchedUnlock() calls have been made.
void OSSchedUnlock(void);
OSSchedUnlock() re-enables task scheduling whenever it is paired with OSSchedLock().
INT16U OSSemAccept(OS_EVENT *pevent);
OSSemAccept() checks to see if a resource is available or an event has occurred. Unlike OSSemPend(), OSSemAccept() does not suspend the calling task if the resource is not available. Use OSSemAccept() from an ISR to obtain the semaphore.
Arguments
pevent is a pointer to the semaphore that guards the resource. This pointer is returned to your application when the semaphore is created [see OSSemCreate()].
Return Value
When OSSemAccept() is called and the semaphore value is greater than 0, the semaphore value is decremented and the value of the semaphore before the decrement is returned to your application. If the semaphore value is 0 when OSSemAccept() is called, the resource is not available and 0 is returned to your application.
OS_EVENT *OSSemCreate(WORD value);
OSSemCreate() creates and initializes a semaphore. A semaphore
• allows a task to synchronize with either an ISR or a task,
• gains exclusive access to a resource, and
• signals the occurrence of an event.
Arguments
value is the initial value of the semaphore and can be between 0 and 65535.
Return Value
OSSemCreate() returns a pointer to the event control block allocated to the semaphore. If no event control block is available, OSSemCreate() returns a NULL pointer.
void OSSemPend(OS_EVENT *pevent, INT16U timeout, INT8U *err);
OSSemPend() is used when a task wants exclusive access to a resource, needs to synchronize its activities with an ISR or a task, or is waiting until an event occurs. If a task calls OSSemPend() and the value of the semaphore is greater than 0, OSSemPend() decrements the semaphore and returns to its caller. However, if the value of the semaphore is 0, OSSemPend() places the calling task in the waiting list for the semaphore. The task waits until a task or an ISR signals the semaphore or the specified timeout expires. If the semaphore is signaled before the timeout expires, MicroC/OS-II resumes the highest priority task waiting for the semaphore. A pended task that has been suspended with OSTaskSuspend() can obtain the semaphore. However, the task remains suspended until it is resumed by calling OSTaskResume().
Arguments
pevent is a pointer to the semaphore. This pointer is returned to your application when the semaphore is created [see OSSemCreate()].
timeout allows the task to resume execution if a message is not received from the mailbox within the specified number of clock ticks. A timeout value of 0 indicates that the task will wait forever for the message. The maximum timeout is 65,535 clock ticks. The timeout value is not synchronized with the clock tick. The timeout count begins decrementing on the next clock tick, which could potentially occur immediately.
err is a pointer to a variable used to hold an error code. OSSemPend() sets *err to one of the following:
• OS_NO_ERR if the semaphore was available.
• OS_TIMEOUT if the semaphore was not signaled within the specified timeout.
• OS_ERR_PEND_ISR if you called this function from an ISR and MicroC/OS-II would have to suspend it. In general, you should not call OSMboxPend() from an ISR. MicroC/OS-II checks for this situation.
• OS_ERR_EVENT_TYPE pevent is not pointing to a semaphore.
Return Value
None
INT8U OSSemPost(OS_EVENT *pevent);
A semaphore is signaled by calling OSSemPost(). If the semaphore value is 0 or more, it is incremented and OSSemPost() returns to its caller. If tasks are waiting for the semaphore to be signaled, OSSemPost() removes the highest priority task pending for the semaphore from the waiting list and makes this task ready to run. The scheduler is then called to determine if the awakened task is now the highest priority task ready to run.
Arguments
pevent is a pointer to the semaphore. This pointer is returned to your application when the semaphore is created [see OSSemCreate()].
Return Value
OSSemPost() returns one of two error codes:
• OS_NO_ERR if the semaphore was signaled successfully.
• OS_SEM_OVF if the semaphore count overflowed.
• OS_ERR_EVENT_TYPE pevent is not pointing to a semaphore.
INT8U OSSemQuery(OS_EVENT *pevent, OS_SEM_DATA *pdata);
OSSemQuery() obtains information about a semaphore. Your application must allocate an OS_SEM_DATA data structure used to receive data from the event control block of the semaphore. OSSemQuery() allows you to determine whether any tasks are waiting on the semaphore and how many tasks are waiting (by counting the number of 1s in the .OSEventTbl[] field) and obtains the semaphore count. Note that the size of .OSEventTbl[] is established by the #define constant OS_EVENT_TBL_SIZE (see uCOS_II.H).
Arguments
pevent is a pointer to the semaphore. This pointer is returned to your application when the semaphore is created [see OSSemCreate()].
pdata is a pointer to a data structure of type OS_SEM_DATA, which contains the following fields:
INT16U OSCnt; /* Current semaphore count */ INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* Semaphore wait list */ INT8U OSEventGrp;
Return Value
OSSemQuery() returns one of two error codes:
• OS_NO_ERR if the call was successful.
• OS_ERR_EVENT_TYPE if you didn’t pass a pointer to a semaphore.
OSStart()
void OSStart(void);
OSStart() starts multitasking under MicroC/OS-II.
Arguments
None
Return Value
None
OSStatInit()
void OSStatInit(void);
OSStatInit() determines the maximum value that a 32-bit counter can reach when no other task is executing. This function must be called when only one task is created in your application and when multitasking has started; that is, this function must be called from the first, and only, task created.
Arguments
None
Return Value
None
INT8U OSTaskChangePrio(INT8U oldprio, INT8U newprio);
OSTaskChangePrio() changes the priority of a task.
Arguments
oldprio is the priority number of the task to change.
newprio is the new task’s priority.
Return Value
OSTaskChangePrio() returns one of the following error codes:
• OS_NO_ERR if the task’s priority was changed.
• OS_PRIO_INVALID if either the old priority or the new priority is equal to or exceeds OS_LOWEST_PRIO.
• OS_PRIO_EXIST if newprio already exists.
• OS_PRIO_ERR if no task with the specified “old” priority exists (i.e., the task specified by oldprio does not exist).
INT8U OSTaskCreate(void (*task)(void *pd), void *pdata, OS_STK *ptos,
INT8U prio);
OSTaskCreate() creates a task so it can be managed by MicroC/OS-II. Tasks can be created either prior to the start of multitasking or by a running task. A task cannot be created by an ISR. A task must be written as an infinite loop, as shown below, and must not return.
OSTaskCreate() is used for backward compatibility with MicroC/OS and when the added features of OSTaskCreateExt() are not needed.
Depending on how the stack frame was built, your task will have interrupts either enabled or disabled. You need to check with the processor-specific code for details.
Arguments
task is a pointer to the task’s code.
pdata is a pointer to an optional data area used to pass parameters to the task when it is created. Where the task is concerned, it thinks it was invoked and passed the argument pdata as follows:
void Task (void *pdata) { . /* Do something with 'pdata' */ for (;;) { /* Task body, always an infinite loop. */ . . /* Must call one of the following services: */ /* OSMboxPend() */ /* OSQPend() */ /* OSSemPend() */ /* OSTimeDly() */ /* OSTimeDlyHMSM() */ /* OSTaskSuspend() (Suspend self) */ /* OSTaskDel() (Delete self) */ . . } }
ptos is a pointer to the task’s top-of-stack. The stack is used to store local variables, function parameters, return addresses, and CPU registers during an interrupt. The size of the stack is determined by the task’s requirements and the anticipated interrupt nesting. Determining the size of the stack involves knowing how many bytes are required for storage of local variables for the task itself and all nested functions, as well as requirements for interrupts (accounting for nesting). If the configuration constant OS_STK_GROWTH is set to 1, the stack is assumed to grow downward (i.e., from high to low memory). ptos thus needs to point to the highest valid memory location on the stack. If OS_STK_GROWTH is set to 0, the stack is assumed to grow in the opposite direction (i.e., from low to high memory).
prio is the task priority. A unique priority number must be assigned to each task and the lower the number, the higher the priority.
Return Value
OSTaskCreate() returns one of the following error codes:
• OS_NO_ERR if the function was successful.
• OS_PRIO_EXIST if the requested priority already exists.
• OS_PRIO_INVALID if prio is higher than OS_LOWEST_PRIO.
• OS_NO_MORE_TCB if MicroC/OS-II doesn’t have any more OS_TCB s to assign.
INT8U OSTaskCreateExt(void (*task)(void *pd), void *pdata, OS_STK *ptos,
INT8U prio, INT16U, id, OS_STK *pbos, INT32U stk_size,
void *pext, INT16U opt);
OSTaskCreateExt() creates a task to be managed by MicroC/OS-II. This function serves the same purpose as OSTaskCreate(), except that it allows you to specify additional information about your task to MicroC/OS-II. Tasks can be created either prior to the start of multitasking or by a running task. A task cannot be created by an ISR. A task must be written as an infinite loop, as shown below, and must not return. Depending on how the stack frame was built, your task will have interrupts either enabled or disabled. You need to check with the processor-specific code for details. Note that the first four arguments are exactly the same as the ones for OSTaskCreate(). This was done to simplify the migration to this new and more powerful function.
Arguments
task is a pointer to the task’s code.
pdata is a pointer to an optional data area, which is used to pass parameters to the task when it is created. Where the task is concerned, it thinks it was invoked and passed the argument pdata as follows:
void Task (void *pdata) { . /* Do something with 'pdata' */ for (;;) { /* Task body, always an infinite loop. */ . . /* Must call one of the following services: */ /* OSMboxPend() */ /* OSQPend() */ /* OSSemPend() */ /* OSTimeDly() */ /* OSTimeDlyHMSM() */ /* OSTaskSuspend() (Suspend self) */ /* OSTaskDel() (Delete self) */ . . } }
ptos is a pointer to the task’s top-of-stack. The stack is used to store local variables, function parameters, return addresses, and CPU registers during an interrupt. The size of this stack is determined by the task’s requirements and the anticipated interrupt nesting. Determining the size of the stack involves knowing how many bytes are required for storage of local variables for the task itself and all nested functions, as well as requirements for interrupts (accounting for nesting). If the configuration constant OS_STK_GROWTH is set to 1, the stack is assumed to grow downward (i.e., from high to low memory). ptos thus needs to point to the highest valid memory location on the stack. If OS_STK_GROWTH is set to 0, the stack is assumed to grow in the opposite direction (i.e., from low to high memory).
prio is the task priority. A unique priority number must be assigned to each task: the lower the number, the higher the priority (i.e., the importance) of the task.
id is the task’s ID number. At this time, the ID is not currently used in any other function and has simply been added in OSTaskCreateExt() for future expansion. You should set id to the same value as the task’s priority.
pbos is a pointer to the task’s bottom-of-stack. If the configuration constant OS_STK_GROWTH is set to 1, the stack is assumed to grow downward (i.e., from high to low memory); thus, pbos must point to the lowest valid stack location. If OS_STK_GROWTH is set to 0, the stack is assumed to grow in the opposite direction (i.e., from low to high memory); thus, pbos must point to the highest valid stack location. pbos is used by the stack-checking function OSTaskStkChk().
stk_size specifies the size of the task’s stack in number of elements. If OS_STK is set to INT8U, then stk_size corresponds to the number of bytes available on the stack. If OS_STK is set to INT16U, then stk_size contains the number of 16-bit entries available on the stack. Finally, if OS_STK is set to INT32U, then stk_size contains the number of 32-bit entries available on the stack.
pext is a pointer to a user-supplied memory location (typically a data structure) used as a TCB extension. For example, this user memory can hold the contents of floating-point registers during a context switch, the time each task takes to execute, the number of times the task is switched-in, and so on.
opt contains task-specific options. The lower 8 bits are reserved by MicroC/OS-II, but you can use the upper 8 bits for application-specific options. Each option consists of one or more bits. The option is selected when the bit(s) is(are) set. The current version of MicroC/OS-II supports the following options:
• OS_TASK_OPT_STK_CHK specifies whether stack checking is allowed for the task.
• OS_TASK_OPT_STK_CLR specifies whether the stack needs to be cleared.
• OS_TASK_OPT_SAVE_FP specifies whether floating-point registers will be saved. This option is only valid if your processor has floating-point hardware and the processor-specific code saves the floating-point registers.
Refer to uCOS_II.H for other options.
Return Value
OSTaskCreateExt() returns one of the following error codes:
• OS_NO_ERR if the function was successful.
• OS_PRIO_EXIST if the requested priority already exist.
• OS_PRIO_INVALID if prio is higher than OS_LOWEST_PRIO.
• OS_NO_MORE_TCB if MicroC/OS-II doesn’t have any more OS_TCB s to assign.
INT8U OSTaskDel(INT8U prio);
OSTaskDel() deletes a task by specifying the priority number of the task to delete. The calling task can be deleted by specifying its own priority number or OS_PRIO_SELF (if the task doesn’t know its own priority number). The deleted task is returned to the dormant state. The deleted task is created by calling either OSTaskCreate() or OSTaskCreateExt() to make the task active again.
Arguments
prio is the priority number of the task to delete. You can delete the calling task by passing OS_PRIO_SELF, in which case, the next highest priority task is executed.
Return Value
OSTaskDel() returns one of the following error codes:
• OS_NO_ERR if the task didn’t delete itself.
• OS_TASK_DEL_IDLE if you tried to delete the idle task.
• OS_TASK_DEL_ERR if the task to delete does not exist.
• OS_PRIO_INVALID if you specified a task priority higher than OS_LOWEST_PRIO.
• OS_TASK_DEL_ISR if you tried to delete a task from an ISR.
INT8U OSTaskDelReq(INT8U prio);
OSTaskDelReq() requests that a task delete itself. Basically, use OSTaskDelReq() when you need to delete a task that can potentially own resources (e.g., the task may own a semaphore). In this case, you don’t want to delete the task until the resource is released. The requesting task calls OSTaskDelReq() to indicate that the task needs to be deleted. Deletion of the task is, however, deferred to the task being deleted. In other words, the task is actually deleted when it regains control of the CPU. For example, suppose Task 10 needs to be deleted. The task wanting to delete this task (example Task 5) would call OSTaskDelReq(10). When Task 10 executes, it calls OSTaskDelReq(OS_PRIO_SELF) and monitors the return value. If the return value is OS_TASK_DEL_REQ, then Task 10 is asked to delete itself. At this point, Task 10 calls OSTaskDel(OS_PRIO_SELF). Task 5 knows whether Task 10 has been deleted by calling OSTaskDelReq(10) and checking the return code. If the return code is OS_TASK_NOT_EXIST, then Task 5 knows that Task 10 has been deleted. Task 5 may have to check periodically until OS_TASK_NOT_EXIST is returned.
Arguments
prio is the task’s priority number of the task to delete. If you specify OS_PRIO_SELF, you are asking whether another task wants the current task to be deleted.
Return Value
OSTaskDelReq() returns one of the following error codes:
• OS_NO_ERR if the task deletion has been registered.
• OS_TASK_NOT_EXIST if the task does not exist. The requesting task can monitor this return code to see if the task was actually deleted.
• OS_TASK_DEL_IDLE if you asked to delete the idle task (this is obviously not allowed).
• OS_PRIO_INVALID if you specified a task priority higher than OS_LOWEST_PRIO or you have not specified OS_PRIO_SELF.
• OS_TASK_DEL_REQ if a task (possibly another task) requested that the running task be deleted.
INT8U OSTaskQuery(INT8U prio, OS_TCB *pdata);
OSTaskQuery() obtains information about a task. Your application must allocate an OS_TCB data structure to receive a “snapshot” of the desired task’s control block. Your copy will contain every field in the OS_TCB structure. You should be careful when accessing the contents of the OS_TCB structure, especially OSTCBNext and OSTCBPrev, because they point to the next and previous OS_TCB in the chain of created tasks, respectively.
Arguments
prio is the priority of the task you wish to obtain data from. You can obtain information about the calling task by specifying OS_PRIO_SELF.
pdata is a pointer to a structure of type OS_TCB, which contains a copy of the task’s control block.
Return Value
OSTaskQuery() returns one of three error codes:
• OS_NO_ERR if the call was successful.
• OS_PRIO_ERR if you tried to obtain information from an invalid task.
• OS_PRIO_INVALID if you specified a priority higher than OS_LOWEST_PRIO.
INT8U OSTaskResume(INT8U prio);
OSTaskResume() resumes a task that was suspended through the OSTaskSuspend() function. In fact, OSTaskResume() is the only function that can “unsuspend” a suspended task.
Arguments
prio specifies the priority of the task to resume.
Return Value
OSTaskResume() returns one of the following error codes:
• OS_NO_ERR if the call was successful.
• OS_TASK_RESUME_PRIO if the task you are attempting to resume does not exist.
• OS_TASK_NOT_SUSPENDED if the task to resume has not been suspended.
• OS_PRIO_INVALID if prio is higher or equal to OS_LOWEST_PRIO.
INT8U OSTaskStkChk(INT8U prio, INT32U *pfree, INT32U *pused);
OSTaskStkChk() determines a task’s stack statistics. Specifically, it computes the amount of free stack space as well as the amount of stack space used by the specified task. This function requires that the task be created with OSTaskCreateExt() and that you specify OS_TASK_OPT_STK_CHK in the opt argument.
Stack sizing is done by walking from the bottom of the stack and counting the number of 0 entries on the stack until a nonzero value is found. Of course, this assumes that the stack is cleared when the task is created. For that purpose, you need to set OS_TASK_STK_CLR to 1 in your configuration. You could set OS_TASK_STK_CLR to 0 if your startup code clears all RAM and you never delete your tasks. This would reduce the execution time of OSTaskCreateExt().
Arguments
prio is the priority of the task you want to obtain stack information about. You can check the stack of the calling task by passing OS_PRIO_SELF.
pdata is a pointer to a variable of type OS_STK_DATA, which contains the following fields:
INT32U OSFree; /* Number of bytes free on the stack */ INT32U OSUsed; /* Number of bytes used on the stack */
Return Value
OSTaskStkChk() returns one of the following error codes:
• OS_NO_ERR if you specified valid arguments and the call was successful.
• OS_PRIO_INVALID if you specified a task priority higher than OS_LOWEST_PRIO, or you didn’t specify OS_PRIO_SELF.
• OS_TASK_NOT_EXIST if the specified task does not exist.
• OS_TASK_OPT_ERR if you did not specify OS_TASK_OPT_STK_CHK when the task was created by OSTaskCreateExt() or if you created the task by using OSTaskCreate().
INT8U OSTaskSuspend(INT8U prio);
OSTaskSuspend() suspends (or blocks) execution of a task unconditionally. The calling task can be suspended by specifying its own priority number or OS_PRIO_SELF if the task doesn’t know its own priority number. In this case, another task needs to resume the suspended task. If the current task is suspended, rescheduling occurs and MicroC/OS-II runs the next highest priority task ready to run. The only way to resume a suspended task is to call OSTaskResume().
Task suspension is additive. This means that if the task being suspended is delayed until n ticks expire, the task is resumed only when both the time expires and the suspension is removed. Also, if the suspended task is waiting for a semaphore and the semaphore is signaled, the task is removed from the semaphore wait list (if it is the highest priority task waiting for the semaphore) but execution is not resumed until the suspension is removed.
Arguments
prio specifies the priority of the task to suspend. You can suspend the calling task by passing OS_PRIO_SELF, in which case, the next highest priority task is executed.
Return Value
OSTaskSuspend() returns one of the following error codes:
• OS_NO_ERR if the call was successful.
• OS_TASK_SUSPEND_IDLE if you attempted to suspend the MicroC/OS-II idle task, which is not allowed.
• OS_PRIO_INVALID if you specified a priority higher than the maximum allowed (i.e., you specified a priority of OS_LOWEST_PRIO or more) or you didn’t specify OS_PRIO_SELF.
• OS_TASK_SUSPEND_PRIO if the task you are attempting to suspend does not exist.
void OSTimeDly(INT16U ticks);
OSTimeDly() allows a task to delay itself for a number of clock ticks. Rescheduling always occurs when the number of clock ticks is greater than zero. Valid delays range from zero to 65,535 ticks. A delay of 0 means that the task is not delayed and OSTimeDly() returns immediately to the caller. The actual delay time depends on the tick rate (see OS_TICKS_PER_SEC in the configuration file OS_CFG.H).
Arguments
ticks is the number of clock ticks to delay the current task.
Return Value
None
void OSTimeDlyHMSM(INT8U hours, INT8U minutes, INT8U seconds, INT8U milli);
OSTimeDlyHMSM() allows a task to delay itself for a user-specified amount of time specified in hours, minutes, seconds, and milliseconds. This is a more convenient and natural format than ticks. Rescheduling always occurs when at least one of the parameters is nonzero.
Arguments
hours is the number of hours the task will be delayed. The valid range of values is 0 to 255.
minutes is the number of minutes the task will be delayed. The valid range of values is 0 to 59.
seconds is the number of seconds the task will be delayed. The valid range of values is 0 to 59.
milli is the number of milliseconds the task will be delayed. The valid range of values is 0 to 999. Note that the resolution of this argument is in multiples of the tick rate. For instance, if the tick rate is set to 10ms, a delay of 5ms results in no delay. The delay is rounded to the nearest tick. Thus, a delay of 15ms actually results in a delay of 20ms.
Return Value
OSTimeDlyHMSM() returns one of the following error codes:
• OS_NO_ERR if you specified valid arguments and the call was successful.
• OS_TIME_INVALID_MINUTES if the minutes argument is greater than 59.
• OS_TIME_INVALID_SECONDS if the seconds argument is greater than 59.
• OS_TIME_INVALID_MILLI if the milliseconds argument is greater than 999.
• OS_TIME_ZERO_DLY if all four arguments are 0.
INT8U OSTimeDlyResume(INT8U prio);
OSTimeDlyResume() resumes a task that has been delayed through a call to either OSTimeDly() or OSTimeDlyHMSM().
Arguments
prio specifies the priority of the task to resume.
Return Value
OSTimeDlyResume() returns one of the following error codes:
• OS_NO_ERR if the call was successful.
• OS_PRIO_INVALID if you specified a task priority greater than OS_LOWEST_PRIO.
• OS_TIME_NOT_DLY if the task is not waiting for time to expire.
• OS_TASK_NOT_EXIST if the task has not been created.
INT32U OSTimeGet(void);
OSTimeGet() obtains the current value of the system clock. The system clock is a 32-bit counter that counts the number of clock ticks since power was applied or since the system clock was last set.
Arguments
None
Return Value
The current system clock value (in number of ticks).
void OSTimeSet(INT32U ticks);
OSTimeSet() sets the system clock. The system clock is a 32-bit counter that counts the number of clock ticks since power was applied or since the system clock was last set.
Arguments
ticks is the desired value for the system clock, in ticks.
Return Value
None
void OSTimeTick(void);
OSTimeTick() processes a clock tick. MicroC/OS-II checks all tasks to see if they are either waiting for time to expire [because they called OSTimeDly() or OSTimeDlyHMSM()] or waiting for events to occur until they timeout.
Arguments
None
Return Value
None
INT16U OSVersion(void);
OSVersion() obtains the current version of MicroC/OS-II.
Arguments
None
Return Value
The version is returned as x.yy multiplied by 100. For example, version 2.00 is returned as 200.
OS_EXIT_CRITICAL()
OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL() are macros used to disable and enable, respectively, the processor’s interrupts.
Arguments
None
Return Value
None