<< Previous | Index | Next >>

18. µC/OS-II

Not available with SE versions of Dynamic C.

µC/OS-II is a simple, clean, efficient, easy-to-use real-time operating system that runs on the Rabbit microprocessor and is fully supported by the Dynamic C development environment. µC/OS-II is capable of intertask communication and synchronization via the use of semaphores, mailboxes, and queues. User-definable system hooks are supplied for added system and configuration control during task creation, task deletion, context switches, and time ticks.

For more information on µC/OS-II, please refer to Jean J. Labrosse's book, MicroC/OS-II, The Real-Time Kernel (ISBN: 0-87930-543-6). The data structures (e.g. Event Control Block) referenced in the Dynamic C µC/OS-II function descriptions are fully explained in Labrosse's book. It can be purchased at the Z-World store, www.zworld.com/store/home.html, or at http://www.ucos-ii.com/.

Starting with Dynamic C version 7.21, the Rabbit version of µC/OS-II includes the new features and API changes available in version 2.51 of µC/OS-II. The documentation for these changes is included with Dynamic C in Samples/UCos-II. The file Newv251.pdf contains all of the features added since version 2.00 and Relv251.pdf contains release notes for version 2.51.

18.1 Changes to µC/OS-II

To take full advantage of services provided by Dynamic C, minor changes have been made to µC/OS-II.

18.1.1 Ticks per Second

In most implementations of µC/OS-II, OS_TICKS_PER_SEC informs the operating system of the rate at which OSTimeTick is called; this macro is used as a constant to match the rate of the periodic interrupt. In µC/OS-II for the Rabbit, however, changing this macro will change the tick rate of the operating system set up during OSInit. Usually, a real-time operating system has a tick rate of 10 Hz to 100 Hz, or 10-100 ticks per second. Since the periodic interrupt on the Rabbit occurs at a rate of 2 kHz, it is recommended that the tick rate be a power of 2 (e.g., 16, 32, or 64). Keep in mind that the higher the tick rate, the more overhead the system will incur.

In the Rabbit version of µC/OS-II, the number of ticks per second defaults to 64. The actual number of ticks per second may be slightly different than the desired ticks per second if TicksPerSec does not evenly divide 2048.

Changing the default tick rate is done by simply defining OS_TICKS_PER_SEC to the desired tick rate before calling OSInit(). E.g. to change the tick rate to 32 ticks per second:


#define OS_TICKS_PER_SEC 32
...
OSInit();
...
OSStart();

18.1.2 Task Creation

In a µC/OS-II application, stacks are declared as static arrays, and the address of either the top or bottom (depending on the CPU) of the stack is passed to OSTaskCreate. In a Rabbit-based system, the Dynamic C development environment provides a superior stack allocation mechanism that µC/OS-II incorporates. Rather than declaring stacks as static arrays, the number of stacks of particular sizes are declared, and when a task is created using either OSTaskCreate or OSTaskCreateExt, only the size of the stack is passed, not the memory address. This mechanism allows a large number of stacks to be defined without using up root RAM.

There are five macros located in ucos2.lib that define the number of stacks needed of five different sizes. In order to have three 256 byte stacks, one 512 byte stack, two 1024 byte stacks, one 2048 byte stack, and no 4096 byte stacks, the following macro definitions would be used:


#define STACK_CNT_256      3    // number of 256 byte stacks
#define STACK_CNT_512 1 // number of 512 byte stacks
#define STACK_CNT_1K 2 // number of 1K stacks
#define STACK_CNT_2K 1 // number of 2K stacks
#define STACK_CNT_4K 0 // number of 4K stacks

These macros can be placed into each µC/OS-II application so that the number of each size stack can be customized based on the needs of the application. Suppose that an application needs 5 tasks, and each task has a consecutively larger stack. The macros and calls to OSTaskCreate would look as follows


#define STACK_CNT_256     2     // number of 256 byte stacks
#define STACK_CNT_512 2 // number of 512 byte stacks
#define STACK_CNT_1K 1 // number of 1K stacks
#define STACK_CNT_2K 1 // number of 2K stacks
#define STACK_CNT_4K 1 // number of 4K stacks
OSTaskCreate(task1, NULL, 256, 0);
OSTaskCreate(task2, NULL, 512, 1);
OSTaskCreate(task3, NULL, 1024, 2);
OSTaskCreate(task4, NULL, 2048, 3);
OSTaskCreate(task5, NULL, 4096, 4);

Note that the macro STACK_CNT_256 is set to 2 instead of 1. µC/OS-II always creates an idle task which runs when no other tasks are in the ready state. Note also that there are two 512 byte stacks instead of one. This is because the program is given a 512 byte stack. If the application utilizes the µC/OS-II statistics task, then the number of 512 byte stacks would have to be set to 3. (Statistic task creation can be enabled and disabled via the macro OS_TASK_STAT_EN which is located in ucos2.lib). If only 6 stacks were declared, one of the calls to OSTaskCreate would fail.

If an application uses OSTaskCreateExt, which enables stack checking and allows an extension of the Task Control Block, fewer parameters are needed in the Rabbit version of µC/OS-II. Using the macros in the example above, the tasks would be created as follows:


OSTaskCreateExt(task1, NULL, 0, 0, 256, NULL, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);

OSTaskCreateExt(task2, NULL, 1, 1, 512, NULL, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);

OSTaskCreateExt(task3, NULL, 2, 2, 1024, NULL, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);

OSTaskCreateExt(task4, NULL, 3, 3, 2048, NULL, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);

OSTaskCreateExt(task5, NULL, 4, 4, 4096, NULL, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);

18.1.3 Restrictions

At the time of this writing, µC/OS-II for Dynamic C is not compatible with the use of slice statements. Also, see the function description for OSTimeTickHook() for important information about preserving registers if that stub function is replaced by a user-defined function.

Due to Dynamic C's stack allocation scheme, special care should be used when posting messages to either a mailbox or a queue. A message is simply a void pointer, allowing the application to determine its meaning. Since tasks can have their stacks in different segments, auto pointers declared on the stack of the task posting the message should not be used since the pointer may be invalid in another task with a different stack segment.

18.2 Tasking Aware Interrupt Service Routines (TA-ISR)

Special care must be taken when writing an interrupt service routine (ISR) that will be used in conjunction with µC/OS-II so that µC/OS-II scheduling will be performed at the proper time.

18.2.1 Interrupt Priority Levels

µC/OS-II for the Rabbit reserves interrupt priority levels 2 and 3 for interrupts outside of the kernel. Since the kernel is unaware of interrupts above priority level 1, interrupt service routines for interrupts that occur at interrupt priority levels 2 and 3 should not be written to be tasking aware. Also, a µC/OS-II application should only disable interrupts by setting the interrupt priority level to 1, and should never raise the interrupt priority level above 1.

18.2.2 Possible ISR Scenarios

There are several different scenarios that must be considered when writing an ISR for use with µC/OS-II. Depending on the use of the ISR, it may or may not have to be written so that it is tasking aware. Consider the scenario in the Figure below. In this situation, the ISR for Interrupt X does not have to be tasking aware since it does not re-enable interrupts before completion and it does not post to a semaphore, mailbox, or queue.

Figure 6. Type 1 ISR

If, however, an ISR needs to signal a task to the ready state, then the ISR must be tasking aware. In the example in the Figure below, the TA-ISR increments the interrupt nesting counter, does the work necessary for the ISR, readies a higher priority task, decrements the nesting count, and returns to the higher priority task.

Figure 7. Type 2 ISR

It may seem as though the ISR in this Figure does not have to increment and decrement the nesting count. This is, however, very important. If the ISR for Interrupt X is called during an ISR that re-enables interrupts before completion, scheduling should not be performed when Interrupt X completes; scheduling should instead be deferred until the least nested ISR completes. The next Figure shows an example of this situation.

Figure 8. Type 2 ISR Nested Inside Type 3 ISR

As can be seen here, although the ISR for interrupt Z does not signal any tasks by posting to a semaphore, mailbox, or queue, it must increment and decrement the interrupt nesting count since it re-enables interrupts (ipres) prior to finishing all of its work.

18.2.3 General Layout of a TA-ISR

A TA-ISR is just like a standard ISR except that it does some extra checking and house-keeping. The following table summarizes when to use a TA-ISR.
Table 18-2. Use of TA-ISR
µC/OS-II Application
Type 11
Type 22
Type 33
TA-ISR Required?
No
Yes
Yes
1 Type 1--Leaves interrupts disabled and does not signal task to ready state

2 Type 2--Leaves interrupts disabled and signals task to ready state

3 Type 3--Reenables interrupts before completion

The following Figure shows the logical flow of a TA-ISR.

Figure 9. Logical Flow of a TA-ISR

18.2.3.1 Sample Code for a TA-ISR

Fortunately, the Rabbit BIOS and libraries provide all of the necessary flags to make TA-ISRs work. With the code found in Listing 1, minimal work is needed to make a TA-ISR function correctly with µC/OS-II. TA-ISRs allow µC/OS-II the ability to have ISRs that communicate with tasks as well as the ability to let ISRs nest, thereby reducing interrupt latency.

Just like a standard ISR, the first thing a TA-ISR does is to save the registers that it is going to use (1). Once the registers are saved, the interrupt source is cleared (2) and the nesting counter is incremented (3). Note that bios_intnesting is a global interrupt nesting counter provided in the Dynamic C libraries specifically for tracking the interrupt nesting level. If an ipres instruction is executed (4) other interrupts can occur before this ISR is completed, making it necessary for this ISR to be a TA-ISR. If it is possible for the ISR to execute before µC/OS-II has been fully initialized and started multi-tasking, a check should be made (5) to insure that µC/OS-II is in a known state, especially if the TA-ISR signals a task to the ready state (6). After the TA-ISR has done its necessary work (which may include making a higher priority task than is currently running ready to run), OSIntExit must be called (7). This µC/OS-II function determines the highest priority task ready to run, sets it as the currently running task, and sets the global flag bios_swpend if a context switch needs to take place. Interrupts are disabled since a context switch is treated as a critical section (8). If the TA-ISR decrements the nesting counter and the count does not go to zero, then the nesting level is saved in bios_intnesting (9), the registers used by the TA-ISR are restored, interrupts are re-enabled (if not already done in (4)), and the TA-ISR returns (12). However, if decrementing the nesting counter in (9) causes the counter to become zero, then bios_swpend must be checked to see if a context switch needs to occur (10). If a context switch is not pending, then the nesting level is set (9) and the TA-ISR exits (12). If a context switch is pending, then the remaining context of the previous task is saved and a long call, which insures that the xpc is saved and restored properly, is made to bios_intexit (11). bios_intexit is responsible for switching to the stack of the task that is now ready to run and executing a long call to switch to the new task. The remainder of (11) is executed when a previously preempted task is allowed to run again.

Listing 1


#asm
taskaware_isr::
   push   af ;
push regs needed by isr (1)
   push   hl ;
clear interrupt source (2)
   ld     hl,bios_intnesting       ;
increase the nesting count (3)
   inc   (hl)
   ;
ipres (optional) (4)
   ;
do processing necessary for interrupt
   ld     a,(OSRunning)            ;MCOS multitasking yet?   (5)
   or     a
   jr     z,taisr_decnesting
   ; possibly signal task to become ready                           (6)
   call   OSIntExit                 ;
sets bios_swpend if higher
                                    ; prio ready            (7)
taisr_decnesting:
   push   ip (8)
   ipset  1
   ld     hl,bios_intnesting        ; nesting counter == 1?
   dec    (hl) (9)
   jr     nz,taisr_noswitch
   ld     a,(bios_swpend)           ; switch pending? (10)
   or     a
   jr     z,taisr_noswitch
   push   de (11)
   push   bc
   ex     af,af'
   push   af
   exx
   push   hl
   push   de
   push   bc
   push   iy
   lcall  bios_intexit    pop    iy
   pop    bc
   pop    de
   pop    hl
   exx
   pop    af
   ex     af,af'
   pop    bc
   pop    de
taisr_noswitch:
   pop   ip
taisr_done:
   pop    hl (12)
   pop    af
   ipres
   ret
#endasm

18.3 Library Reentrancy

When writing a µC/OS-II application, it is important to know which Dynamic C library functions are non-reentrant. If a function is non-reentrant, then only one task may access the function at a time, and access to the function should be controlled with a µC/OS-II semaphore. The following is a list of Dynamic C functions that are non-reentrant.

Library
Non-reentrant Functions
MATH.LIB randg, randb, rand
RS232.LIB All
RTCLOCK.LIB write_rtc, tm_wr
STDIO.LIB kbhit, getchar, gets, getswf, selectkey
STRING.LIB atof1, atoi1, strtok
SYS.LIB clockDoublerOn, clockDoublerOff, useMainOsc, useClockDivider, use32kHzOsc
VDRIVER.LIB VdGetFreeWd, VdReleaseWd
XMEM.LIB WriteFlash
JRIO.LIB digOut, digOn, digOff, jrioInit, anaIn, anaOut, cof_anaIn
JR485.LIB All
1 reentrant but sets the global _xtoxErr flag

The serial port functions (RS232.LIB functions) should be used in a restricted manner with µC/OS-II. Two tasks can use the same port as long as both are not reading, or both are not writing; i.e., one task can read from serial port X and another task can write to serial port X at the same time without conflict.

18.4 How to Get a µC/OS-II Application Running

µC/OS-II is a highly configureable, real-time operating system. It can be customized using as many or as few of the operating system's features as needed. This section outlines:

It is assumed that the reader has a familiarity with µC/OS-II or has a µC/OS-II reference (MicroC/OS-II, The Real-Time Kernel by Jean J. Labrosse is highly recommended).

18.4.1 Default Configuration

µC/OS-II usually relies on the include file os_cfg.h to get values for the configuration constants. In the Dynamic C implementation of µC/OS-II, these constants, along with their default values, are in os_cfg.lib. A default stack configuration is also supplied in os_cfg.lib. µC/OS-II for the Rabbit uses a more intelligent stack allocation scheme than other µC/OS-II implementations to take better advantage of unused memory.

The default configuration allows up to 10 normally created application tasks running at 64 ticks per second. Each task has a 512-byte stack. There are 2 queues specified, and 10 events. An event is a queue, mailbox or semaphore. You can define any combination of these three for a total of 10. If you want more than 2 queues, however, you must change the default value of OS_MAX_QS.

Some of the default configuration constants are:


// Maximum number of events (semaphores, queues, mailboxes)
#define OS_MAX_EVENTS 10
// Maximum number of tasks (less stat and idle tasks)
#define OS_MAX_TASKS 10
// Maximum number of queues in system
#define OS_MAX_QS 2
// Maximum number of memory partitions
#define OS_MAX_MEM_PART 1
// Enable normal task creation
#define OS_TASK_CREATE_EN 1
// Disable extended task creation
#defineOS_TASK_CREATE_EXT_EN 0
// Disable task deletion
#define OS_TASK_DEL_EN 0
// Disable statistics task creation
#define OS_TASK_STAT_EN 0
// Enable queue usage
#define OS_Q_EN 1
// Disable memory manager
#define OS_MEM_EN 0
// Enable mailboxes
#define OS_MBOX_EN 1
// Enable semaphores
#define OS_SEM_EN 1
// number of ticks in one second
#define OS_TICKS_PER_SEC 64
// number of 256 byte stacks (idle task stack)
#define STACK_CNT_256 1
// number of 512-byte stacks (task stacks + initial program stack)
#define STACK_CNT_512 OS_MAX_TASKS+1

If a particular portion of µC/OS-II is disabled, the code for that portion will not be compiled, making the overall size of the operating system smaller. Take advantage of this feature by customizing µC/OS-II based on the needs of each application.

18.4.2 Custom Configuration

In order to customize µC/OS-II by enabling and disabling components of the operating system, simply redefine the configuration constants as necessary for the application.


#define OS_MAX_EVENTS          2
#define OS_MAX_TASKS 20
#define OS_MAX_QS 1
#define OS_MAX_MEM_PART 15
#define OS_TASK_STAT_EN 1
#define OS_Q_EN 0
#define OS_MEM_EN 1
#define OS_MBOX_EN 0
#define OS_TICKS_PER_SEC 64

If a custom stack configuration is needed also, define the necessary macros for the counts of the different stack sizes needed by the application.


#define STACK_CNT_256 1  // idle task stack
#define STACK_CNT_512 2 // initial program + stat task stack
#define STACK_CNT_1K 10 // task stacks
#define STACK_CNT_2K 10 // number of 2K stacks

In the application code, follow the µC/OS-II and stack configuration constants with a #use "ucos2.lib" statement. This ensures that the definitions supplied outside of the library are used, rather than the defaults in the library.

This configuration uses 20 tasks, two semaphores, up to 15 memory partitions that the memory manager will control, and makes use of the statistics task. Note that the configuration constants for task creation, task deletion, and semaphores are not defined, as the library defaults will suffice. Also note that 10 of the application tasks will each have a 1024 byte stack, 10 will each have a 2048 byte stack, and an extra stack is declared for the statistics task.

18.4.3 Examples

The following sample programs demonstrate the use of the default configuration supplied in UCOS2.LIB and a custom configuration which overrides the defaults.

Example 1

In this application, ten tasks are created and one semaphore is created. Each task pends on the semaphore, gets a random number, posts to the semaphore, displays its random number, and finally delays itself for three seconds.

Looking at the code for this short application, there are several things to note. First, since µC/OS-II and slice statements are mutually exclusive (both rely on the periodic interrupt for a "heartbeat"), #use "ucos2.lib" must be included in every µC/OS-II application (1). In order for each of the tasks to have access to the random number generator semaphore, it is declared as a global variable (2). In most cases, all mailboxes, queues, and semaphores will be declared with global scope. Next, OSInit() must be called before any other µC/OS-II function to ensure that the operating system is properly initialized (3). Before µC/OS-II can begin running, at least one application task must be created. In this application, all tasks are created before the operating system begins running (4). It is perfectly acceptable for tasks to create other tasks. Next, the semaphore each task uses is created (5). Once all of the initialization is done, OSStart() is called to start µC/OS-II running (6). In the code that each of the tasks run, it is important to note the variable declarations. The default storage class in Dynamic C is static, so to ensure that the task code is reentrant, all are declared auto (7). Each task runs as an infinite loop and once this application is started, µC/OS-II will run indefinitely.


// 1. Explicitly use uC/OS-II library
#use "ucos2.lib"
void RandomNumberTask(void *pdata); // 2. Declare semaphore global so all tasks have access
OS_EVENT* RandomSem;
void main()
{
int i;
// 3. Initialize OS internals
OSInit();
for(i = 0; i < OS_MAX_TASKS; i++) // 4. Create each of the system tasks
OSTaskCreate(RandomNumberTask, NULL, 512, i);
// 5. semaphore to control access to random number generator
RandomSem = OSSemCreate(1);
// 6. Begin multitasking
OSStart();
}
void RandomNumberTask(void *pdata)
{
//
7. Declare as auto to ensure reentrancy.
auto OS_TCB data;
auto INT8U err;
auto INT16U RNum;
OSTaskQuery(OS_PRIO_SELF, &data);
while(1)
{
//
Rand is not reentrant, so access must be controlled via a semaphore.
OSSemPend(RandomSem, 0, &err);
RNum = (int)(rand() * 100);
OSSemPost(RandomSem);
printf("Task%d's random #: %d\n",data.OSTCBPrio,RNum);
// Wait 3 seconds in order to view output from each task.
OSTimeDlySec(3);
}
}

Example 2

This application runs exactly the same code as Example 1, except that each of the tasks are created with 1024 byte stacks. The main difference between the two is the configuration of µC/OS-II.

First, each configuration constant that differs from the library default is defined. The configuration in this example differs from the default in that it allows only two events (the minimum needed when using only one semaphore), 20 tasks, no queues, no mailboxes, and the system tick rate is set to 32 ticks per second (1). Next, since this application uses tasks with 1024 byte stacks, it is necessary to define the configuration constants differently than the library default (2). Notice that one 512 byte stack is declared. Every Dynamic C program starts with an initial stack, and defining STACK_CNT_512 is crucial to ensure that the application has a stack to use during initialization and before multi-tasking begins. Finally ucos2.lib is explicitly used (3). This ensures that the definitions in (1 and 2) are used rather than the library defaults. The last step in initialization is to set the number of ticks per second via OSSetTicksPerSec (4).

The rest of this application is identical to example 1 and is explained in the previous section.


// 1. Define necessary configuration constants for uC/OS-II
#define OS_MAX_EVENTS 2
#define OS_MAX_TASKS 20
#define OS_MAX_QS 0
#define OS_Q_EN 0
#define OS_MBOX_EN 0
#define OS_TICKS_PER_SEC 32
// 2. Define necessary stack configuration constants
#define STACK_CNT_512 1            // initial program stack
#define STACK_CNT_1K OS_MAX_TASKS   // task stacks
// 3. This ensures that the above definitions are used
#use "ucos2.lib"
void RandomNumberTask(void *pdata); // Declare semaphore global so all tasks have access
OS_EVENT* RandomSem;
void main(){
int i;
// Initialize OS internals
OSInit();
for(i = 0; i < OS_MAX_TASKS; i++){ // Create each of the system tasks
OSTaskCreate(RandomNumberTask, NULL, 1024, i);
}
//
semaphore to control access to random number generator
RandomSem = OSSemCreate(1);
// 4. Set number of system ticks per second
OSSetTicksPerSec(OS_TICKS_PER_SEC);
// Begin multi-tasking
OSStart();
}
void RandomNumberTask(void *pdata)
{
//
Declare as auto to ensure reentrancy.
auto OS_TCB data;
auto INT8U err;
auto INT16U RNum;

OSTaskQuery(OS_PRIO_SELF, &data);
while(1)
{
//
Rand is not reentrant, so access must be controlled via a semaphore.
OSSemPend(RandomSem, 0, &err);
RNum = (int)(rand() * 100);
OSSemPost(RandomSem);
printf("Task%02d's random #: %d\n",data.OSTCBPrio,RNum); // Wait 3 seconds in order to view output from each task.
OSTimeDlySec(3);
}
}

18.5 Compatibility with TCP/IP

The TCP/IP stack is reentrant and may be used with the µC/OS real-time kernel. The line


#use ucos2.lib

must appear before the line


#use dcrtcp.lib

A call to OSInit() must be made before calling sock_init().

18.5.1 Socket Locks

Each socket used in a µC/OS-II application program has an associated socket lock. Each socket lock uses one semaphore of type OS_EVENT. Therefore, the macro MAX_OS_EVENTS must take into account each of the socket locks, plus any events that the application program may be using (semaphores, queues, mailboxes, event flags, or mutexes).

Determining OS_MAX_EVENTS may get a little tricky, but it isn't too bad if you know what your program is doing. Since MAX_SOCKET_LOCKS is defined as:


#define MAX_SOCKET_LOCKS (MAX_TCP_SOCKET_BUFFERS + MAX_UDP_SOCKET_BUFFERS)

OS_MAX_EVENTS may be defined as:


#define OS_MAX_EVENTS MAX_TCP_SOCKET_BUFFERS + MAX_UDP_SOCKET_BUFFERS + 2 + z

The constant "2" is included for the two global locks used by TCP/IP, and z is the number of OS_EVENTS (semaphores, queues, mailboxes, event flags, or mutexes) required by the program.

If either MAX_TCP_SOCKET_BUFFERS or MAX_UDP_SOCKET_BUFFERS is not defined by the application program prior to the #use statements for ucos.lib and dcrtcp.lib default values will be assigned.

If MAX_TCP_SOCKET_BUFFERS is not defined in the application program, it will be defined as MAX_SOCKETS. If, however, MAX_SOCKETS is not defined in the application program, MAX_TCP_SOCKET_BUFFERS will be 4.

If MAX_UDP_SOCKET_BUFFERS is not defined in the application program, it will be defined as 1 if USE_DHCP is defined, or 0 otherwise.

For more information regarding TCP/IP, please see the Dynamic C TCP/IP User's Manual, available online at zworld.com or rabbitsemiconductor.com.

18.6 Debugging Tips

Dynamic C version 7.20 introduced more control when single stepping through a µC/OS-II program. Prior to 7.20, single stepping occurred in whichever task was currently running. It was not possible to limit the single stepping to one task.

Starting with Dynamic C 7.20, single stepping may be limited to the currently running task by using F8 (Step over). If the task is suspended, single stepping will also be suspended. When the task is put back in a running state, single stepping will continue at the statement following the statement that suspended execution of the task.

Hitting F7 (Trace into) at a statement that suspends execution of the current task will cause the program to step into the next active task that has debug information. It may be useful to put a watch on the global variable OSPrioCur to see which task is currently running.

For example, if the current task is going to call OSSemPend() on a semaphore that is not in the signaled state, the task will be suspended and other tasks will run. If F8 is pressed at the statement that calls OSSemPend(), the debugger will not single step in the other running tasks that have debug information; single stepping will continue at the statement following the call to OSSemPend(). If F7 is pressed at the statement that calls OSSemPend() instead of F8, the debugger will single step in the next task with debug information that is put into the running state.


<< Previous | Index | Next >>
Z-World, Inc.
www.zworld.com
Phone: 1.530.757.3737
Fax: 1.530.757.3792
Rabbit Semiconductor
www.rabbitsemiconductor.com
Phone: 1.530.757.8400
Fax: 1.530.757.8402