<< Previous | Index | Next >> | |
|
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 fileNewv251.pdf
contains all of the features added since version 2.00 andRelv251.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 whichOSTimeTick
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 duringOSInit
. 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 callingOSInit()
. 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 eitherOSTaskCreate
orOSTaskCreateExt,
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 stacksThese 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 stacksOSTaskCreate(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 macroOS_TASK_STAT_EN
which is located inucos2.lib
). If only 6 stacks were declared, one of the calls toOSTaskCreate
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.
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.
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.
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 TA-ISR Required?
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.
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 anipres
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 flagbios_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 inbios_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, thenbios_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 thexpc
is saved and restored properly, is made tobios_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 1ld hl,bios_intnesting ; nesting counter == 1?
dec (hl) (9)
jr nz,taisr_noswitchld a,(bios_swpend) ; switch pending? (10)
or a
jr z,taisr_noswitchpush de (11)
push bc
ex af,af'
push af
exx
push hl
push de
push bc
push iylcall bios_intexit
pop iy
pop bc
pop de
pop hl
exx
pop af
ex af,af'
pop bc
pop detaisr_noswitch:
pop iptaisr_done:
pop hl (12)
pop af
ipres
ret
#endasm18.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.
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:
The configuration constants used in µC/OS-II
How to override the default configuration supplied in
UCOS2.LIB
The necessary steps to get an application running
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 inos_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+1If 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 64If 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 stacksIn 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. Finallyucos2.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 viaOSSetTicksPerSec
(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
#use dcrtcp.lib
A call to
OSInit()
must be made before callingsock_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 macroMAX_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. SinceMAX_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 ofOS_EVENTS
(semaphores, queues, mailboxes, event flags, or mutexes) required by the program.If either
MAX_TCP_SOCKET_BUFFERS
orMAX_UDP_SOCKET_BUFFERS
is not defined by the application program prior to the #use statements forucos.lib
anddcrtcp.lib
default values will be assigned.If
MAX_TCP_SOCKET_BUFFERS
is not defined in the application program, it will be defined asMAX_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 ifUSE_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 callsOSSemPend()
, 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 toOSSemPend()
. If F7 is pressed at the statement that callsOSSemPend()
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 |