The code of the listings below shows a more complete example and contains three tasks, a mutual exclusion semaphore, and a message queue.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
/*
***********************************************************************************************
* INCLUDE FILES
***********************************************************************************************
*/
#include <app_cfg.h>
#include <bsp.h>
#include <os.h>
/*
***********************************************************************************************
* LOCAL GLOBAL VARIABLES
***********************************************************************************************
*/
static OS_TCB AppTaskStartTCB; (1)
static OS_TCB AppTask1_TCB;
static OS_TCB AppTask2_TCB;
static OS_MUTEX AppMutex; (2)
static OS_Q AppQ; (3)
static CPU_STK AppTaskStartStk[APP_TASK_START_STK_SIZE]; (4)
static CPU_STK AppTask1_Stk[128];
static CPU_STK AppTask2_Stk[128];
/*
***********************************************************************************************
* FUNCTION PROTOTYPES
***********************************************************************************************
*/
static void AppTaskStart (void *p_arg); (5)
static void AppTask1 (void *p_arg);
static void AppTask2 (void *p_arg); |
Panel | ||
---|---|---|
| ||
(1) Here we allocate storage for the (2) A mutual exclusion semaphore (a.k.a. a mutex) is a kernel object (a data structure) that is used to protect a shared resource from being accessed by more than one task. A task that wants to access the shared resource must obtain the mutex before it is allowed to proceed. The owner of the resource relinquishes the mutex when it has finished accessing the resource. This process is demonstrated in this example. (3) A message queue is a kernel object through which Interrupt Service Routines (ISRs) and/or tasks send messages to other tasks. The sender “formulates” a message and sends it to the message queue. The task(s) wanting to receive these messages wait on the message queue for messages to arrive. If there are already messages in the message queue, the receiver immediately retrieves those messages. If there are no messages waiting in the message queue, then the receiver will be placed in a wait list associated with the message queue. This process will be demonstrated in this example. (4) A stack is allocated for each task. (5) The prototype of the tasks are declared. |
The listing below shows the C entry point, i.e. main()
.
Anchor Listing - app.c (2nd Part) Listing - app.c (2nd Part)
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
void main (void) { OS_ERR err; BSP_IntDisAll(); OSInit(&err); /* Check for 'err' */ OSMutexCreate((OS_MUTEX *)&AppMutex, (1) (CPU_CHAR *)"My App. Mutex", (OS_ERR *)&err); /* Check for 'err' */ OSQCreate ((OS_Q *)&AppQ, (2) (CPU_CHAR *)"My App Queue", (OS_MSG_QTY )10, (OS_ERR *)&err); /* Check for 'err' */ OSTaskCreate((OS_TCB *)&AppTaskStartTCB, (3) (CPU_CHAR *)"App Task Start", (OS_TASK_PTR )AppTaskStart, (void *)0, (OS_PRIO )APP_TASK_START_PRIO, (CPU_STK *)&AppTaskStartStk[0], (CPU_STK_SIZE)APP_TASK_START_STK_SIZE / 10, (CPU_STK_SIZE)APP_TASK_START_STK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, (void *)0, (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), (OS_ERR *)&err); /* Check for 'err' */ OSStart(&err); /* Check for 'err' */ } |
Panel | ||
---|---|---|
| ||
(1) Creating a mutex is simply a matter of calling You can assign an ASCII name to the mutex, which is useful when debugging. (2) You create the message queue by calling You can assign an ASCII name to the message queue which can also be useful during debugging. You need to specify how many messages the message queue is allowed to receive. This value must be greater than zero. If the sender sends messages faster than they can be consumed by the receiving task, messages will be lost. This can be corrected by either increasing the size of the message queue, or increasing the priority of the receiving task. (3) The first application task is created. |
The listing below shows how to create other tasks once multitasking as started.
Anchor Listing - app.c (3rd Part) Listing - app.c (3rd Part)
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
static void AppTaskStart (void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
BSP_Init();
CPU_Init();
BSP_OS_TickInit();
OSTaskCreate((OS_TCB *)&AppTask1_TCB, (1)
(CPU_CHAR *)"App Task 1",
(OS_TASK_PTR )AppTask1,
(void *)0,
(OS_PRIO )5,
(CPU_STK *)&AppTask1_Stk[0],
(CPU_STK_SIZE)0,
(CPU_STK_SIZE)128,
(OS_MSG_QTY )0,
(OS_TICK )0,
(void *)0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
OSTaskCreate((OS_TCB *)&AppTask2_TCB, (2)
(CPU_CHAR *)"App Task 2",
(OS_TASK_PTR )AppTask2,
(void *)0,
(OS_PRIO )6,
(CPU_STK *)&AppTask2_Stk[0],
(CPU_STK_SIZE)0,
(CPU_STK_SIZE)128,
(OS_MSG_QTY )0,
(OS_TICK )0,
(void *)0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
BSP_LED_Off(0);
while (1) {
BSP_LED_Toggle(0);
OSTimeDlyHMSM((CPU_INT16U) 0,
(CPU_INT16U) 0,
(CPU_INT16U) 0,
(CPU_INT32U)100,
(OS_OPT )OS_OPT_TIME_HMSM_STRICT,
(OS_ERR *)&err);
}
} |
Panel | ||
---|---|---|
| ||
(1) Task #1 is created by calling (2) Task #2 is created and if it has a higher priority than |
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
static void AppTask1 (void *p_arg)
{
OS_ERR err;
CPU_TS ts;
p_arg = p_arg;
while (1) {
OSTimeDly ((OS_TICK )1, (1)
(OS_OPT )OS_OPT_TIME_DLY,
(OS_ERR *)&err);
OSQPost ((OS_Q *)&AppQ, (2)
(void *)1;
(OS_MSG_SIZE)sizeof(void *),
(OS_OPT )OS_OPT_POST_FIFO,
(OS_ERR *)&err);
OSMutexPend((OS_MUTEX *)&AppMutex, (3)
(OS_TICK )0,
(OS_OPT )OS_OPT_PEND_BLOCKING;
(CPU_TS *)&ts,
(OS_ERR *)&err);
/* Access shared resource */ (4)
OSMutexPost((OS_MUTEX *)&AppMutex, (5)
(OS_OPT )OS_OPT_POST_NONE,
(OS_ERR *)&err);
}
} |
Panel | ||
---|---|---|
| ||
(1) The task starts by waiting for one tick to expire before it does anything useful. If the µC/OS-III tick rate is configured for 1000 Hz, the task will be suspended for 1 millisecond. (2) The task then sends a message to another task using the message queue (3) The task then waits on the mutual exclusion semaphore since it needs to access a shared resource with another task. If the resource is already owned by another task, (4) When (5) When the task is done with the shared resource, it must call |
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
static void AppTask2 (void *p_arg)
{
OS_ERR err;
void *p_msg;
OS_MSG_SIZE msg_size;
CPU_TS ts;
CPU_TS ts_delta;
p_arg = p_arg;
while (1) {
p_msg = OSQPend((OS_Q *)&AppQ, (1)
(OS_MSG_SIZE *)&msg_size,
(OS_TICK )0,
(OS_OPT )OS_OPT_PEND_BLOCKING,
(CPU_TS *)&ts,
(OS_ERR *)&err);
ts_delta = OS_TS_GET() - ts; (2)
/* Process message received */ (3)
}
} |
Panel | ||
---|---|---|
| ||
(1) Task #2 starts by waiting for messages to be sent through the message queue When the message is received Also, when the message is received, “ (2) Knowing when the message was sent allows the user to determine how long it took this task to get the message. This is done by reading the current timestamp and subtracting the timestamp of when the message was sent. Note that the receiving task may not get the message immediately since ISRs or other higher-priority tasks might execute before the receiver gets to run. (3) Here you would add your own code to process the received message. |