📄 emCompress-Embed User Guide & Reference Manual
📄 emCompress-LZMA User Guide & Reference Manual
📄 emCompress-ToGo User Guide & Reference Manual
📄 emCrypt User Guide & Reference Manual
📄 emDropbox User Guide & Reference Manual
📄 emFile User Guide & Reference Manual
📄 emFloat User Guide & Reference Manual
📄 emNet User Guide & Reference Manual
📄 emRun User Guide & Reference Manual
📄 emSecure-ECDSA User Guide & Reference Manual
📄 emSecure-RSA User Guide & Reference Manual
📄 emSSH User Guide & Reference Manual
📄 emSSL User Guide & Reference Manual
📄 emUSB-Device User Guide & Reference Manual
📄 emUSB-Host User Guide & Reference Manual
📄 emVNC User Guide & Reference Manual
📄 emWeb User Guide & Reference Manual
📄 emWin User Guide & Reference Manual
📄 IoT Toolkit User Guide & Reference Manual
📄 SEGGER Assembler User Guide & Reference Manual
📄 SEGGER Compiler User Guide & Reference Manual
📄 SEGGER Linker User Guide & Reference Manual
📄 SEGGER SystemView User Guide
📄 SEGGER Online Documentation
📄 AppWizard User Guide & Reference Manual
📄 embOS Real-Time Operating System User Guide & Reference Manual for embOS-Base and embOS-MPU
📄 embOS-Ultra Real-Time Operating System User Guide & Reference Manual for embOS-Ultra and embOS-Ultra-MPU

embOS-Ultra
Real-Time Operating System User Guide & Reference Manual for embOS-Ultra and embOS-Ultra-MPU
Document: UM01076
Software Version: 5.20.0
Document revision: 0

Introduction and Basic Concepts

What is embOS?

embOS is a priority-controlled multitasking system, designed to be used as an embedded operating system for the development of real-time applications for a variety of microcontrollers.

embOS is a high-performance tool that has been optimized for minimal memory consumption in both RAM and ROM, as well as high speed and versatility. Throughout the development process of embOS, the limited resources of microcontrollers have always been kept in mind. The internal structure of the real-time operating system (RTOS) has been optimized in a variety of applications with different customers, to fit the needs of industry. Fully source-compatible implementations of embOS are available for a variety of microcontrollers, making it well worth the time and effort to learn how to structure real-time programs with an RTOS.

embOS is highly modular. This means that only those functions that are required are linked into an application, keeping the ROM size very small. A couple of files are supplied in source code to make sure that you do not loose any flexibility by using embOS libraries and that you can customize the system to fully fit your needs.

The tasks you create can easily and safely communicate with each other using a number of communication mechanisms such as semaphores, mailboxes, and events.

Some features of embOS include:

embOS editions

embOS is the general term for four different embOS editions:

embOS-Classic

embOS-Classic is a preemptive RTOS designed to be the foundation for developing embedded applications. Now in its 4th decade of continuous use and enhancement, its reliability and performance underpin the firmware in every J-Link and J-Trace.

embOS-Ultra

embOS-Ultra is a revolutionary RTOS using cycle-resolution timing to improve timing and performance and to reduce energy consumption. Using SEGGER’s innovative Cycle-based Scheduling, embOS-Ultra is the first choice for applications requiring ultra low power or extremely high precision. Its time resolution is based on the CPU cycle and provides the highest precision possible. Removing iterative scheduler calls from the kernel reduces the energy consumption significantly.

embOS-MPU

embOS-MPU adds comprehensive memory protection to embOS which tightens the safety of embedded devices. All unprivileged tasks are 100% sandboxed, making devices suitable for any safety-critical application. embOS-MPU uses the hardware’s memory protection unit and additional implemented software mechanisms to prevent one task from affecting the entire system. This guarantees that even if a bug occurs in one task, all other tasks and the operating system itself continue their execution, enhancing both the stability and safety of embedded applications.

embOS-Safe

embOS-Safe is the pre-certified version of embOS. embOS-Safe has been certified in accordance with TÜV SÜD Germany. Certification is compliant with IEC 61508 SIL 3, IEC 62304 Class C, and ISO 26262 ASIL D.

Differences between embOS-Classic and embOS-Ultra

The main difference between embOS-Classic and embOS-Ultra is that the latter requires no periodic system tick. Instead, with embOS-Ultra, system tick interrupts occur only when the scheduler needs to perform a time-based action.

embOS-Classic with periodic system tick

embOS-Classic uses a hardware timer to generate periodic system tick interrupts which are utilized as a time base. In most applications the system tick occurs each millisecond, but can also be changed to occur with any other period. Since the period might differ, all timeouts and periods are specified in system ticks instead of, for example, milliseconds.

Even if there is only one task that is executed for several consecutive system ticks (which means the scheduler will not be executed during this time), the system tick interrupt will still occur periodically and thereby “waste” computation time. Furthermore, time-based functionality like task delays or timeouts are always aligned to the system tick interrupt. A task delay cannot expire between two system tick interrupts, but with the next system tick interrupt only which then triggers the scheduler. Therefore tasks that shall delay for a period that is shorter than a system tick, can only accomplish this by actively waiting until the desired period has elapsed.

embOS-Ultra with flexible system tick

embOS-Ultra does not rely on a periodic system tick, but uses a flexible system tick that is specifically configured by the operating system to occur whenever a time-based action is required. This avoids unnecessary system tick interrupts and also allows delays and timeouts to expire at arbitrary points in time (limited by the frequency of the used hardware timer only). As there are no periodic tick interrupts, however, the system time can no longer be held in system ticks, but is held in counter cycles instead. For the same reason, timed embOS-Ultra API functions use milliseconds instead of system ticks unless explicitly stated otherwise (in which case microseconds or counter cycles are used instead).

Hardware timer

While embOS-Classic requires the target hardware to provide a hardware timer, embOS-Ultra requires the target hardware to provide a hardware timer and a continuously running counter (although the latter may also be part of the former). With embOS-Ultra, the hardware timer is used to generate timer interrupts, while the continuously running counter provides a time base to calculate the current system time in counter cycles.

For example, applications could use a hardware timer that generates interrupts when its continuously running counter matches a specific value. In that case, the counter would serve for long-term stability, while the compare register is used to generate interrupts when required. Alternatively, it also is possible to use any hardware timer for generating interrupts and an additional continuously running counter for long-term stability. In both cases, the continuously running counter should never be stopped by the application since it is essential to long-term stability. This mandates that the used hardware counter can not be powererd down during low-power modes of the used microcontroller.

The frequencies of the used timer and counter may differ, specifically when using different timers/counters. Unless explicitly stated otherwise, the embOS-Ultra manual always refers to counter cycles when it mentions cycles.

The maximum period of the hardware timer is of no relevance to embOS-Ultra: If the next time-based action is further in the future than the maximum period of the used hardware timer, the operating system will simply set up the timer multiple times until the desired point in time is reached.

For more information on how to implement the hardware timer routines, please refer to Board Support Packages.

embOS ports

embOS is available for many core and compiler combinations. The embOS sources are written in C but a small part is written in assembler and therefore core and compiler specific. Hence, an embOS port is always technically limited to one core or core family and one compiler. An embOS port includes several board support packages for different devices and evaluation boards. Each board support package includes a project for a specific IDE. In most embOS ports the same IDE is used for all board support packages.

Additional documentation

Some embOS aspects are core and compiler specific and explained in a separate embOS manual which is shipped in the according embOS port shipment. For example an embOS port could provide additional core specific API functions which are described in the core and compiler specific manual.

Example Cover of embOS-Classic Cortex-M ES Manual

Naming convention

All embOS ports use the same naming convention: embOS_<edition>_<core>_<compiler>. For example: embOS_Classic_CortexM_ES, embOS-Classic for Cortex-M and Embedded Studio

Version number convention

SEGGER releases new embOS versions with new features and bug fixes. As soon as a new embOS version is released embOS ports are updated to this version.

Generic embOS

Each release of the generic embOS sources has a unique version number:

V<Major>.<Minor>.<Patch>

For example:

V5.20.0

Major: 5
Minor: 20
Patch: 0

Major and minor values are used for new features. The patch value is used for bug fixes only.

embOS Ports

An updated embOS port has the same version number as the used generic embOS sources, plus an additional revision for the port. This is because an embOS port may be updated for changes in the CPU/compiler specific part, while still using the same generic embOS sources. The complete version number for a specific embOS port is defined as:

V<Major>.<Minor>.<Patch>.<Revision>

For example:

V5.20.0.0

Major: 5
Minor: 20
Patch: 0
Revision: 0

Singletasking systems (superloop)

The classic way of designing embedded systems does not use the services of an RTOS, which is also called “superloop design”. Typically, no real time kernel is used, so interrupt service routines (ISRs) are used for the real-time parts of the application and for critical operations (at interrupt level). This type of system is typically used in small, simple systems or if real-time behavior is not critical.

Typically, since no real-time kernel and only one stack is used, both program (ROM) size and RAM size are smaller for simple applications when compared to using an RTOS. Obviously, there are no inter-task synchronization problems with a superloop application. However, superloops can become difficult to maintain if the program becomes too large or uses complex interactions. As sequential processes cannot interrupt themselves, reaction times depend on the execution time of the entire sequence, resulting in a poor real-time behavior.

Advantages & disadvantages

Advantages

Disadvantages

Using embOS in superloop applications

In a true superloop application, no tasks are used, hence the biggest advantage of using an RTOS cannot be utilized unless the application is re-written for multitasking. However, even with just one single task, using embOS offers the following advantages:

Migrating from superloop to multi-tasking

A common situation is that an application exists for some time and has been designed as a single-task super-loop-application. At some point, the disadvantages of this approach result in a decision to use an RTOS. The typical question now usually is: How do I do this?

The easiest way is to start with one of the sample applications that come with embOS and to add the existing “super-loop code” into one task. At this point, you should also ensure that the stack size of this task is sufficient. Later, additional functionality is added to the software and can be put in one or more additional tasks; the functionality of the super-loop can also be distributed over multiple tasks.

Multitasking systems

In a multitasking system, there are different ways to distribute CPU time among different tasks. This process is called scheduling.

Task switches

There are two types of task switches, also called context switches: Cooperative and preemptive task switches.

A cooperative task switch is performed by the task itself. As its name indicates, it requires the cooperation of the task: it suspends itself by calling a blocking RTOS function, e.g. OS_TASK_Delay_ms() or OS_TASKEVENT_GetBlocked().

A preemptive task switch, on the other hand, is a task switch that is caused externally. For example, a task of higher priority becomes ready for execution and, as a result, the scheduler suspends the current task in favor of that task.

Cooperative multitasking

Cooperative multitasking requires all tasks to cooperate by using blocking functions. A task switch can only take place if the running task blocks itself by calling a blocking function such as OS_TASK_Delay_ms() or OS_MAILBOX_GetBlocked(). This is illustrated in the diagram below.

If tasks in a pure cooperative multi-tasking system do not cooperate, the system “hangs”. This means that other tasks have no chance of being executed by the CPU while the first task is being carried out. Even if an ISR makes a higher-priority task ready to run, the interrupted task will be resumed and completes before the task switch is made.

A pure cooperative multi-tasking system has the disadvantage of longer reaction times when high priority tasks become ready for execution. This makes their usage in embedded real-time systems uncommon.

Preemptive multitasking

An RTOS like embOS operates with preemptive multitasking. The highest-priority task in the READY state always executes as long as the task is not suspended by a call of any blocking operating system function. A high-priority task waiting for an event is signaled READY as soon as the event occurs. The event can be set by an interrupt handler, which then activates the task immediately. Other tasks with lower priority are suspended (preempted) for as long as the high-priority task is executing. Usually, an RTOS utilizes a timer interrupt that interrupts tasks and thereby allows to perform task switches whenever timed task switches are necessary.

Preemptive multitasking may be switched off in sections of a program where task switches are prohibited, known as critical regions. embOS itself will also temporarily disable preemptive task switches during critical operations, which might be performed during the execution of some embOS API functions.

Threads vs. Processes

In this context, a task is a program running on the CPU core of a microcontroller. Without a multitasking kernel (an RTOS), only one task can be executed by the CPU. This is called a single-task system. The RTOS, on the other hand, allows the execution of multiple tasks on a single CPU. All tasks execute as if they completely “owned” the entire CPU. The tasks are scheduled for execution, meaning that the RTOS can activate and deactivate each task according to its priority, with the highest priority task being executed in general.

Threads are tasks that share the same memory layout, hence any two threads can access the same memory locations. If virtual memory is used, the same virtual to physical translation and access rights are used.
With embOS, all tasks are threads: they all have the same memory access rights and translation (in systems with virtual memory).

Processes are tasks with their own memory layout. Two processes cannot normally access the same memory locations. Different processes typically have different access rights and (in case of MMUs) different translation tables. Processes are not supported with the current version of embOS.

Scheduling

There are different algorithms used by schedulers to determine which task to execute. But all schedulers have one thing in common: they distinguish between tasks that are ready to be executed (in the READY state) and other tasks that are suspended for some reason (delay, waiting for mailbox, waiting for semaphore, waiting for event, etc). The scheduler selects one of the tasks in the READY state and activates it (executes the body of this task). The task which is currently executing is referred to as the running task. The main difference between schedulers is the way they distribute computation time between tasks in the READY state.

Priority-controlled scheduling algorithm

In real-world applications, different tasks require different response times. For example, in an application that controls a motor, a keyboard, and a display, the motor usually requires faster reaction time than the keyboard and the display. E.g., even while the display is being updated, the motor needs to be controlled. This renders preemptive multitasking essential. Round-robin might work, but as it cannot guarantee any specific reaction time, a more suitable algorithm should be used.

In priority-controlled scheduling, every task is assigned a priority. Depending on these priorities, a task is chosen for execution according to one simple rule:

Note

The scheduler activates the task that has the highest priority of all tasks and is ready for execution.

This means that every time a task with a priority higher than the running task becomes ready, it becomes the running task, and the previous task gets preempted. However, the scheduler can be switched off in sections of a program where task switches are prohibited, known as critical regions.

embOS uses a priority-controlled scheduling algorithm with round-robin between tasks of identical priority. One hint at this point: round-robin scheduling is a nice feature because you do not need to decide whether one task is more important than another. Tasks with identical priority cannot block each other for longer periods than their time slices. But round-robin scheduling also costs time if two or more tasks of identical priority are ready and no task of higher priority is, because execution constantly switches between the identical-priority tasks. It usually is more efficient to assign distinct priority to each task, thereby avoiding unnecessary task switches.

Round-robin scheduling algorithm

With round-robin scheduling, the scheduler has a list of tasks and, when deactivating the running task, it activates the next task that is in the READY state. Round-robin can be used with either preemptive or cooperative multitasking. It works well if you do not need to guarantee response time. Round-robin scheduling can be illustrated as follows:

The possession of the CPU changes periodically after a predefined execution time among all tasks with the same priority. This time is specified in time slices and may be defined individually for each task.

Priority inversion / priority inheritance

The rule the scheduler obeys is:

Activate the task that has the highest priority of all tasks in the READY state.

But what happens if the highest-priority task is blocked because it is waiting for a resource owned by a lower-priority task? According to the above rule, it would wait until the low-priority task is resumed and releases the resource. Up to this point, everything works as expected. Problems arise when a task with medium priority becomes ready during the execution of the higher prioritized task.

When the higher priority task is suspended waiting for the resource, the task with the medium priority will run until it finishes its work, because it has a higher priority than the low-priority task. In this scenario, a task with medium priority runs in place of the task with high priority. This is known as priority inversion.

The low priority task claims the mutex with OS_MUTEX_LockBlocked(). An interrupt activates the high priority task, which also calls OS_MUTEX_LockBlocked(). Meanwhile a task with medium priority becomes ready and runs when the high priority task is suspended. The task with medium priority eventually calls OS_TASK_Delay_ms() and is therefore suspended. The task with lower priority now continues and calls OS_MUTEX_Unlock() to release the mutex. After the low priority task releases the mutex, the high priority task is activated and claims the mutex.

To avoid this situation, embOS temporarily raises the low-priority task to high priority until it releases the resource. This unblocks the task that originally had the highest priority and can now be resumed. This is known as priority inheritance.

With priority inheritance, the low priority task inherits the priority of the waiting high priority task as long as it holds the mutex. The lower priority task is activated instead of the medium priority task when the high priority task tries to claim the mutex.

Change of task status

A task may be in one of several states at any given time. When a task is created, it is placed into the READY state.

A task in the READY state is activated as soon as there is no other task in the READY state with higher priority. Only one task may be running at a time. If a task with higher priority becomes READY, this higher priority task is activated and the preempted task remains in the READY state.

The running task may be delayed for or until a specified time; in this case it is placed into the WAITING state and the next-highest-priority task in the READY state is activated.

The running task might need to wait for an event (or semaphore, mailbox or queue). If the event has not yet occurred, the task is placed into the waiting state and the next-highest-priority task in the READY state is activated.

A non-existent task is one that is not yet available to embOS; it either has been terminated or was not created at all.

The following illustration shows all possible task states and transitions between them.

How task switching works

A real-time multitasking system lets multiple tasks run like multiple single-task programs, quasi-simultaneously, on a single CPU. A task consists of three parts in the multitasking world:

The task’s stack has the same function as in a single-task system: storage of return addresses of function calls, parameters and local variables, and temporary storage of intermediate results and register values. Each task can have a different stack size. More information can be found in chapter Stacks.

The task control block (TCB) is a data structure assigned to a task when it is created. The TCB contains status information for the task, including the stack pointer, task priority, current task status (ready, waiting, reason for suspension) and other management data. Knowledge of the stack pointer allows access to the other registers, which are typically stored (pushed onto) the stack when the task is created and each time it is suspended. This information allows an interrupted task to continue execution exactly where it left off. TCBs are only accessed by the RTOS.

Switching stacks

The following diagram demonstrates the process of switching from one stack to another.

The scheduler deactivates the task to be suspended (Task 0) by saving the processor registers on its stack. It then activates the higher-priority task (Task 1) by loading the stack pointer (SP) and the processor registers from the values stored on Task 1’s stack.

Deactivating a task

The scheduler deactivates the task to be suspended (Task 0) as follows:

  1. Save (push) the processor registers on the task’s stack.
  2. Save the stack pointer in the Task Control Block.

Activating a task

The scheduler activates the higher-priority task (Task 1) by performing the sequence in reverse order:

  1. Load (pop) the stack pointer (SP) from the Task Control Block.
  2. Load the processor registers from the values stored on Task 1’s stack.

Polling vs. Event based programming

The easiest way to communicate between different pieces of code is by using global variables. In an application without RTOS you could set a flag in an UART interrupt routine and poll in main() for the flag until it is set.

static int           UartRxFlag;
static unsigned char Data;

void UartRxISR(void) {
  UartRxFlag = 1;
  Data = UART_RX_REGISTER;
}

int main(void) {
  while (1) {
    if (UartRxFlag != 0) {
      printf("Uart: %u", Data);
      UartRxFlag = 0;
    }
  }
  return 0;
}

This has the disadvantage that the CPU cannot execute any other part of the application while it waits for new UART characters.

An RTOS offers the opportunity to implement an event based application. Such an event can be an interrupt. UartRxTask() calls OS_MAILBOX_GetBlocked() and is suspended until a new message is stored in the mailbox. UartRxISR() stores a new message (the received character) in the mailbox with OS_MAILBOX_Put(). Therefore UartRxTask() is executed only when a new UART character is received and does not waste any precious computation time and energy. Additionally the CPU can execute other parts of the application in the meantime.

void UartRxISR(void) {
  unsigned char Data;

  OS_INT_Enter();
  Data = UART_RX_REGISTER;
  OS_MAILBOX_Put(&Mailbox, &Data);
  OS_INT_Leave();
}

void UartRxTask(void) {
  unsigned char c;
  while (1) {
     OS_MAILBOX_GetBlocked(&Mailbox, &c);
     printf("Uart: %u", c);
  }
}

Synchronization and communication primitives

Synchronization primitives

In a multitasking (multithreaded) program, multiple tasks work completely separately. Because they all work in the same application, it will be necessary for them to synchronize with each other. Semaphores, mutexes and readers-write locks are used for task synchronization and to manage resources of any kind.

For details and samples, refer to the chapters Mutex, Semaphore and Readers-Writer Lock.

Event driven primitives

A task can wait for a particular event without consuming any CPU time. The idea is as simple as it is convincing, there is no sense in polling if we can simply activate a task once the event it is waiting for occurs. This saves processor cycles and energy and ensures that the task can respond to the event without delay. Typical applications for events are those where a task waits for some data, a pressed key, a received command or character, or the pulse of an external real-time clock.

For further details, refer to the chapters Task Event and Event Object.

Communication primitives

A mailbox is a data buffer managed by the RTOS. It is used for sending a message from a task or an ISR to a task. It works without conflicts even if multiple tasks and interrupts try to access the same mailbox simultaneously. embOS activates any task that is waiting for a message in a mailbox the moment it receives new data and, if necessary, switches to this task.
A queue works in a similar manner, but handles larger messages than mailboxes, and each message may have an individual size.

For more information, refer to the chapters Mailbox and Queue.

How the OS gains control

Upon CPU reset, the special-function registers are set to their default values. After reset, program execution begins: The PC register is set to the start address defined by the start vector or start address (depending on the CPU). This start address is usually in a startup module shipped with the C compiler, and is sometimes part of the standard library.

The startup code performs the following:

The main() function is the part of your program which takes control immediately after the C startup. Normally, embOS works with the standard C startup module without any modification. If there are any changes required, they are documented in the CPU & Compiler Specifics manual of the embOS documentation.

With embOS, the main() function is still part of your application program. Essentially, main() creates one or more tasks and then starts multitasking by calling OS_Start(). From this point, the scheduler controls which task is executed.

Startup_code()
  main()
    OS_Init();
    OS_InitHW();
    OS_TASK_CREATE();
    OS_Start();

The main() function will not be interrupted by any of the created tasks because those tasks execute only following the call to OS_Start(). It is therefore usually recommended to create all or most of your tasks here, as well as your control structures such as mailboxes and semaphores. Good practice is to write software in the form of modules which are (up to a point) reusable. These modules usually have an initialization routine, which creates any required task(s) and control structures. A typical main() function looks similar to the following example:

Example

int main(void) {
  OS_Init();      // Initialize embOS (must be first)
  OS_InitHW();    // Initialize hardware for embOS (in RTOSInit.c)
  // Call Init routines of all program modules which in turn will create
  // the tasks they need ... (Order of creation may be important)
  MODULE1_Init();
  MODULE2_Init();
  MODULE3_Init();
  MODULE4_Init();
  MODULE5_Init();
  OS_Start();     // Start multitasking
  return 0;
}

With the call to OS_Start(), the scheduler starts the highest-priority task created in main(). Note that OS_Start() is called only once during the startup process and does not return.

Valid context for embOS API

Some embOS functions may only be called from specific locations inside your application. We distinguish between main() (before the call of OS_Start()), privileged and unprivileged task, interrupt routine and embOS software timer.
With embOS-Classic there are privileged tasks only. With embOS-MPU a task is a unprivileged task after the call to OS_MPU_SwitchToUnprivState().

Note

Please consult the embOS API tables to determine whether an embOS function is allowed from within a specific execution context. Please find the API tables at beginning of each chapter.

Example

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_TASK_Delay_ms() Suspends the calling task for a specified amount of milliseconds, or waits actively when called from main().

This table entry says it is allowed to call OS_TASK_Delay_ms() from main() and a privileged/unprivileged task but not from an embOS software timer or an interrupt handler. Please note the differentiation between privileged and unprivileged tasks is relevant only for embOS-MPU. With embOS all tasks are privileged.

Debug check

An embOS debug build will check for violations of these rules and call OS_Error() with an according error code:

Error code Description
OS_ERR_ILLEGAL_IN_MAIN Not a legal API call from main().
OS_ERR_ILLEGAL_IN_TASK Not a legal API call after OS_Start().
OS_ERR_ILLEGAL_AFTER_OSSTART OS_Start() called twice.
OS_ERR_OS_INT_ENTER_CALLED OS_INT_Enter() has been called, but CPU is not in ISR state.
OS_ERR_ILLEGAL_IN_TIMER Not a legal API call from an embOS software timer.
OS_ERR_OS_INT_ENTER_NOT_CALLED OS_INT_Enter() has not been called, but CPU is in ISR state.
OS_ERR_ILLEGAL_OUT_ISR Not a legal API call outside an interrupt.

Blocking and Non blocking embOS API

Most embOS API comes in three different version: Non blocking, blocking and blocking with a timeout. The embOS API uses a specific naming convention for those API functions. API functions which do not block a task have no suffix. API functions which could block a task have the suffix “Blocked”. API functions which could block a task but have a timeout have the suffix “Timed”.
Blocking API functions (with or without a timeout) must not be called from any context other than a task context.

Non blocking API

Non blocking API functions always return at once, irrespective of the state of the OS object. The return value can be checked in order to find out if e.g. new data is available in a mailbox.

static OS_MAILBOX MyMailbox;
static char Buffer[10];

void Task(void) {
  char r;
  while (1) {
    r = OS_MAILBOX_Get(MyMailbox, Buffer);
    if (r == 0u) {
      // Process message
    }
  }
}

Blocking API

Blocking API functions suspend the task until it is activated again by another embOS API function. The task does not cause any CPU load while it is waiting for the next activation.

static OS_MAILBOX MyMailbox;
static char Buffer[10];

void Task(void) {
  while (1) {
    // Suspend task until a new message is available
    OS_MAILBOX_GetBlocked(MyMailbox, Buffer);
    // Process message
  }
}

Blocking API with timeout

These API functions have an additional timeout. They are blocking until the timeout occurs.

static OS_MAILBOX MyMailbox;
static char Buffer[10];

void Task(void) {
  char r;
  while (1) {
    // Suspend task until a new message is available or the timeout occurs
    r = OS_MAILBOX_GetTimed(MyMailbox, Buffer, 10);
    if (r == 0u) {
      // Process message
    }
  }
}

embOS API with timeout

Usage

The embOS system time in OS_Global.Time is based on a hardware counter.

embOS API functions like OS_TASK_Delay() and OS_TASKEVENT_GetTimed() expect a timeout value as a parameter. Unless explicitly specified otherwise, the timeout unit is given in milliseconds.

Implementation details

OS_Global.Time holds the system time in counter cycles since the start of the counter and always is a signed 64-bit variable. After OS_Global.Time reaches 0xFFFFFFFFFFFFFFFF, it starts at 0x0 again - but even with a counter frequency of 1 Gigahertz, this only happens after ~585 years.

When calling OS_TASK_Delay_ms(), or any other API function with a timeout (e.g. OS_EVENT_GetTimed()), embOS calculates the end time and stores it in OS_Global.TimeDex. The end time is the current time plus the desired timeout.

OS_Global.TimeDex = OS_Global.Time + Timeout;

Example:
At OS_Global.Time = 500, the applications calls OS_TASK_Delay_Cycles(1000);
This results in OS_Global.TimeDex = 1500.

With each system tick, embOS checks whether the current system time is equal or greater than OS_Global.TimeDex. This is implemented as a subtraction of signed values. This calculation guarantees that wrap-arounds are handled correctly as long as the timeout value limitation (explained below) is respected.

if ((OS_Global.Time - OS_Global.TimeDex) >= 0) {
  // Timeout has expired
} else {
  // Timeout has not yet expired
}

Description

The actual width of embOS timing variables is core specific, but for the following examples we assume 8-bit variables for easier understanding. The range is 0x00 to 0xFF, where 0x00 to 0x7F represent positive values and 0x80 to 0xFF negative values.

0x00  0
0x01  1
...
0x7F  127
0x80  -128
...
0xFF  -1

Four cases exist: Both OS_Global.Time and OS_Global.TimeDex are positive values, both are negative values, and one positive and one negative value (and vice versa).

OS_Global.Time and OS_Global.TimeDex are positive

OS_Global.Time    = 100  (0x64)
Timeout           = 20   (0x14)
OS_Global.TimeDex = 120  (0x78)
OS_Global.Time - OS_Global.TimeDex = -20 < 0 => Timeout has not yet expired

OS_Global.Time    = 121  (0x79)
OS_Global.TimeDex = 120  (0x78)
OS_Global.Time - OS_Global.TimeDex = 1 >= 0 => Timeout has expired

OS_Global.Time and OS_Global.TimeDex are negative

OS_Global.Time    = -128  (0x80)
Timeout           = 8     (0x08)
OS_Global.TimeDex = -120  (0x88)
OS_Global.Time - OS_Global.TimeDex = -8 < 0 => Timeout has not yet expired

OS_Global.Time    = -119  (0x89)
OS_Global.TimeDex = -120  (0x78)
OS_Global.Time - OS_Global.TimeDex = 1 >= 0 => Timeout has expired

OS_Global.Time is positive and OS_Global.TimeDex is negative

OS_Global.Time    = 120   (0x88)
Timeout           = 16    (0x10)
OS_Global.TimeDex = -120  (0x88)
OS_Global.Time - OS_Global.TimeDex = -16 < 0 => Timeout has not yet expired

OS_Global.Time    = -119  (0x89)
OS_Global.TimeDex = -120  (0x88)
OS_Global.Time - OS_Global.TimeDex = 1 >= 0 => Timeout has expired

OS_Global.Time is negative and OS_Global.TimeDex is positive

OS_Global.Time    = -1
Timeout           = 16
OS_Global.TimeDex = 15
OS_Global.Time - OS_Global.TimeDex = -16 < 0 => Timeout has not yet expired

OS_Global.Time    = 16
OS_Global.TimeDex = 15
OS_Global.Time - OS_Global.TimeDex = 1 >= 0 => Timeout has expired

Limitation

This check may only be performed if the difference between OS_Global.Time and OS_Global.TimeDex is less than half of the available range minus one. Otherwise, it is undecidable whether OS_Global.Time has lapped OS_Global.TimeDex. The following example shows how the calculation fails if the timeout limit is violated.

8-bit range => Maximum timeout value = 128 - 1 = 127

OS_Global.Time    = 0
Invalid Timeout   = 130
OS_Global.TimeDex = 130
OS_Global.Time - OS_Global.TimeDex = 126 > 0
=> Wrong result, Timeout has not yet expired

Conclusion

As long as the timeout limitation is not violated, a wrap-around of OS_Global.Time is no problem. As shown in the above examples all calculations are performed correctly. Therefore you will find the timeout limitation in the timeout parameter description of all according API functions.

RTOS objects

Most embOS API functions require an according RTOS object. The RTOS object is based on a C structure and stores application specific information. For example, if you create a new task with OS_TASK_Create(), you will need to specify a task control block. OS_TASK_Create() expects a pointer to an RTOS object of the type OS_TASK to store information like the task priority.

Examples for RTOS objects:

It is the developer’s responsibility to allocate RAM for the RTOS object. The memory can be allocated statically or dynamically. Whether it is preferable to use static or dynamic memory allocation depends on the application. Both methods can be used with embOS and also within the same embOS application.

The RTOS object must be located in RAM; it is the developer’s responsibility to allocate sufficient memory for it. Furthermore, the RTOS object must not be located at address 0x00. If the target has RAM at address 0x00, the linker file should define the RAM start at e.g. address 0x04. Consequently, NULL must never be passed to an embOS API function that expects an RTOS object as parameter (unless explicitly stated otherwise in the respective API function description).

Static allocation

static OS_MUTEX _Mutex;

int main(void) {
  ...
  OS_MUTEX_Create(&_Mutex);
  ...
  return 0;
}

Dynamic allocation

static OS_MUTEX* _pMutex;

int main(void) {
  ...
  _pMutex = (OS_MUTEX*)malloc(sizeof(OS_MUTEX));
  if (_pMutex != NULL) {
    OS_MUTEX_Create(_pMutex);
  }
  ...
  return 0;
}

Note

An RTOS object may be modified by an embOS API function only. You must not modify an RTOS object directly. For example, you must not free memory containing an RTOS object which is still in use.

Bad examples

Write to a member of an RTOS object:

static OS_MUTEX _Mutex;

int main(void) {
  ...
  OS_MUTEX_Create(&_Mutex);
  _Mutex.UseCnt = 42;
  ...
  return 0;
}

Memory freed while the RTOS object is still in use:

static OS_MUTEX* _pMutex;

void Task(void) {
  while (1) {
    OS_MUTEX_LockBlocked(_pMutex);
  }
}

int main(void) {
  ...
  _pMutex = (OS_MUTEX*)malloc(sizeof(OS_MUTEX));
  OS_MUTEX_Create(_pMutex);
  free(_pMutex);
  ...
  OS_Start();
  return 0;
}

embOS types

In addition to embOS object types, embOS uses further data types for API routine arguments and return values.
Per default they are defined as:

Type C type
OS_I8 signed char
OS_U8 unsigned char
OS_I16 signed short
OS_U16 unsigned short
OS_I32 signed long
OS_U32 unsigned long
OS_I64 signed long long
OS_U64 unsigned long long
OS_UINT unsigned int
OS_BOOL unsigned char (0 = false / 1 = true)
OS_TIME long long
OS_TASKEVENT unsigned char (8/16-bit CPU) / unsigned long (32-bit CPU)
OS_TASK_PRIO unsigned char (8/16-bit CPU) / unsigned long (32-bit CPU)

Callback / Hook routines

Both terms are used with embOS and mean the same. Some embOS API functions use a function pointer parameter for a callback routine. The callback routine must be implemented by the application and is defined as determined by the function pointer type. The following function pointer types are used:

Type Definition
OS_ROUTINE_VOID void Routine(void)
OS_ROUTINE_VOID_PTR void Routine(void* p)
OS_ROUTINE_BOOL_VOID_PTR OS_BOOL Routine(void* p, void* pParam)
OS_ROUTINE_CHAR void Routine(OS_U8 Data)
OS_ROUTINE_WD_PTR void Routine(OS_CONST_PTR OS_WD* pWD)
OS_ROUTINE_TASK_PTR void Routine(OS_CONST_PTR OS_TASK* pTask)
OS_ROUTINE_TASK_PTR_ERRORCODE void Routine(OS_CONST_PTR OS_TASK* pTask, OS_MPU_ERRORCODE ErrorCode)

Example

void OS_WD_Config(OS_ROUTINE_VOID* pfTrigger, OS_ROUTINE_WD_PTR* pfReset);

static void _TriggerRoutine(void) {
  ...
}

static void _ResetRoutine(OS_CONST_PTR OS_WD* pWD) {
  ...
}

int main(void) {
  ...
  OS_WD_Config(&_TriggerRoutine, &_ResetRoutine);
  ...
  return 0;
}

embOS library modes

embOS comes in different builds or versions of the libraries. The reason for different builds is that requirements vary during development. While developing software, the performance (and resource usage) is not as important as in the final version which usually goes as release build into the product. But during development, even small programming errors should be caught by use of assertions. These assertions are compiled into the debug build of the embOS libraries and make the code a little bigger (about 50%) and also slightly slower than the release or stack-check build used for the final product.

This concept gives you the best of both worlds: a compact and very efficient build for your final product (release or stack-check build of the libraries), and a safer (though bigger and slower) build for development which will catch most common application programming errors. Of course, you may also use the release build of embOS during development, but it will not catch these errors.

The features are enabled and disabled with compile-time switches in the C source code. For example the macro OS_DEBUG controls whether the debug code is included in the build. Please have a look in the chapter Compile time switches for more details.

The following features are included in the different embOS builds:

Debug code

The embOS debug code detects application programming errors like calling an API function from an invalid context. An application using an embOS debug library has to include OS_Error.c. OS_Error.c contains the OS_Error() function which will be called if a debug assertion fails. It is advisable to always use embOS debug code during development.

Stack Check

The embOS stack check detects overflows of task stacks, system stack and interrupt stack. Furthermore, it enables additional information in embOSView and IDE RTOS plug-ins, and provides additional embOS API regarding stack information. An application using an embOS stack check library has to include OS_Error.c. OS_Error.c contains the OS_Error() function which will be called if a stack overflow occurs.

Profiling

The embOS profiling code makes precise information available about the execution time of individual tasks. You may always use the profiling libraries, but they induce larger task control blocks as well as additional ROM and runtime overhead. This overhead is usually acceptable, but for best performance you may want to use non-profiling builds of embOS if you do not use this feature.

Libraries including support for profiling do also include the support for SystemView.

embOS API Trace

embOS API trace saves information about called API in a trace buffer. The trace data can be visualized in e.g. SystemView.

embOSView API Trace

embOSView API trace saves information about called API in a trace buffer. The trace data can be visualized in embOSView.

Round-Robin

Round-Robin lets all tasks at the same priority execute periodically for a pre-defined period of time.

Object Names

Tasks and OS object names can be used to easily identify a task or e.g. a mailbox in tools like embOSView, SystemView or IDE RTOS plug-ins.

Task Context Extension

For some applications it might be useful or required to have individual data in tasks that are unique to the task or to execute specific actions at context switch. With the task context extension support each task control block includes function pointer to a save and a restore routine which are executed during the context switch from and to the task.

Available library modes

In your application program, you need to let the compiler know which build of embOS you are using. This is done by adding the corresponding define to your preprocessor settings and linking the appropriate library file. If the preprocessor setting does not match the library, a linker error will occur. Using the preprocessor define, RTOS.h will set embOS structures to the same configuration that was used during the creation of the library, thus ensuring identical structure definitions in both the application and the library. If no preprocessor setting is given, OS_Config.h will be included and will set a library mode automatically (see OS_Config.h).

Name / Define Debug Code Stack Check Profiling embOS API Trace embOSView API Trace Round-Robin Object Names Task Context Extension
OS_LIBMODE_XR
OS_LIBMODE_R
OS_LIBMODE_S
OS_LIBMODE_SP
OS_LIBMODE_D
OS_LIBMODE_DP
OS_LIBMODE_DT
OS_LIBMODE_SAFE

OS_Config.h

OS_Config.h is part of every embOS port and located in the Start\Inc folder. Use of OS_Config.h is optional but makes it easier to define the embOS library mode: Instead of defining OS_LIBMODE_* in your preprocessor settings, you may define DEBUG=1 in your preprocessor settings in debug compile configurations and define nothing in the preprocessor settings in release compile configurations. Subsequently, OS_Config.h will automatically define OS_LIBMODE_DP for debug compile configurations and OS_LIBMODE_R for release compile configurations. OS_Config.h will be included only when no OS_LIBMODE_* is defined.

Compile Configuration Preprocessor Define Define Set by OS_Config.h
Debug DEBUG=1 OS_LIBMODE_DP
Release OS_LIBMODE_R

Note

The macro DEBUG may not be appropriate for a specific project. For example the identifier may already be used in other 3rd party software or it is preferred to use another macro like NDEBUG. You can customize OS_Config.h to fully fit your needs and keep it with your next embOS update.

OS_LIBMODE_SAFE

OS_LIBMODE_SAFE is usually used with embOS-Safe only for the safety certified embOS library. OS_LIBMODE_SAFE excludes/adds some embOS features which are not mentioned above:

embOS API not supported with OS_LIBMODE_SAFE

Additional embOS API supported with OS_LIBMODE_SAFE

Kernel

Introduction

The embOS kernel is started with OS_Start() in main() after the kernel was initialized with OS_Init(). Typically, applications will also initialize the required hardware, and create at least one task before calling OS_Start(). OS_Start() usually never returns but runs the embOS scheduler which decides which task to run next. It is possible to stop and de-initialize the kernel with OS_Stop() and OS_DeInit().

Example

int main(void) {
  OS_Init();    // Initialize embOS
  OS_InitHW();  // Initialize required hardware
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_Start();   // Start embOS

  return 0;
}

Interrupts in main()

OS_Start() enables interrupts, but interrupts may also be used in main(). It is not necessary to disable interrupts in main(). When using embOS interrupts in main(), please ensure they are enabled after OS_Init() only. It is good practice to call OS_Init() as first instruction in main().

void UART_ISR(void) {
  // Handle UART interrupt
}

int main(void) {
  OS_Init();    // Initialize embOS
  UART_Init();  // Initialize UART and UART interrupts
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_Start();   // Start embOS

  return 0;
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_ConfigStop() Configures the OS_Stop() function.
OS_DeInit() De-initializes the embOS kernel.
OS_Init() Initializes the embOS kernel.
OS_IsRunning() Determines whether the embOS kernel was started by a call to OS_Start().
OS_Start() Starts the embOS kernel.
OS_Stop() Stops the embOS kernel and returns from OS_Start().

OS_ConfigStop()

Description

Configures the OS_Stop() function.

Prototype

void OS_ConfigStop(OS_MAIN_CONTEXT* pContext,
                   void*            Addr,
                   OS_U32           Size);

Parameters

Parameter Description
pContext Pointer to an object of type OS_MAIN_CONTEXT.
Addr Address of the buffer which is used to save the main() stack.
Size Size of the buffer.

Additional information

This function configures the OS_Stop() function. When configured, OS_Start() saves the context and stack from within main(), which subsequently are restored by OS_Stop(). The main() context and stack are saved to the resources configured by OS_ConfigStop(). Only the stack that was actually used during main() is saved. Therefore, the size of the buffer depends on the used stack. The structure OS_MAIN_CONTEXT is core and compiler specific; it is specifically defined with each embOS port.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
227: OS_ERR_ILLEGAL_IN_TASK

For details, refer to the chapter Runtime application errors.

Example

#include "RTOS.h"
#include "stdio.h"

#define BUFFER_SIZE    (32u)
static OS_U8           Buffer[BUFFER_SIZE];  // Buffer for main stack copy
static OS_MAIN_CONTEXT MainContext;          // Main context control structure
static OS_STACKPTR int StackHP[128];         // Task stack
static OS_TASK         TCBHP;                // Task control block

static void HPTask(void) {
  OS_TASK_Delay_ms(50);
  OS_INT_Disable();
  OS_Stop();
}

int main(void) {
  int TheAnswerToEverything = 42;
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_ConfigStop(&MainContext, Buffer, BUFFER_SIZE);
  OS_Start();     // Start embOS
  //
  // We arrive here because OS_Stop() was called.
  // The local stack variable still has its value.
  //
  printf("%d", TheAnswerToEverything);
  while (TheAnswerToEverything == 42) {
  }
  return 0;
}

OS_DeInit()

Description

De-initializes the embOS kernel.

Prototype

void OS_DeInit(void);

Additional information

OS_DeInit() can be used to de-initializes the embOS kernel and the hardware which was initialized in OS_Init(). OS_DeInit() is usually used after returning from OS_Start(). It does not de-initialize the hardware which was configured in e.g. OS_InitHW() but it resets all embOS variables to their default values.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
227: OS_ERR_ILLEGAL_IN_TASK

For details, refer to the chapter Runtime application errors.

Example

#define BUFFER_SIZE    (32u)

static OS_STACKPTR int StackHP[128]  // Task stacks
static OS_TASK         TCBHP;        // Task control blocks
static OS_U8           Buffer[BUFFER_SIZE];
static OS_MAIN_CONTEXT MainContext;

static void HPTask(void) {
  while (1) {
    OS_TASK_Delay_ms(50);
    OS_Stop();
  }
}

int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_ConfigStop(&MainContext, Buffer, BUFFER_SIZE);
  OS_Start();     // Start embOS
  OS_DeInit();
  OS_DeInitHW();
  DoSomeThingElse();
  //
  // Start embOS for the 2nd time
  //
  OS_Init();
  OS_InitHW();
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_ConfigStop(&MainContext, Buffer, BUFFER_SIZE);
  OS_Start();
  return 0;
}

OS_Init()

Description

Initializes the embOS kernel.

Prototype

void OS_Init(void);

Additional information

In library mode OS_LIBMODE_SAFE all RTOS variables are explicitly initialized. All other library modes presume that, according to the C standard, all initialized variables have their initial value and all non initialized variables are set to zero.

Note

OS_Init() must be called prior to any other embOS API.
When using embOS API in C++ constructors, please be aware C++ constructors might be executed before main().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
227: OS_ERR_ILLEGAL_IN_TASK

For details, refer to the chapter Runtime application errors.

Example

#include "RTOS.h"

static OS_STACKPTR int StackHP[128], StackLP[128];  // Task stacks
static OS_TASK         TCBHP, TCBLP;                // Task control blocks

static void HPTask(void) {
  while (1) {
    OS_TASK_Delay_ms(50);
  }
}

static void LPTask(void) {
  while (1) {
    OS_TASK_Delay_ms(200);
  }
}

/*********************************************************************
*
*       main()
*/
int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_TASK_CREATE(&TCBLP, "LP Task",  50, LPTask, StackLP);
  OS_Start();     // Start embOS
  return 0;
}

OS_IsRunning()

Description

Determines whether the embOS kernel was started by a call to OS_Start().

Prototype

OS_BOOL OS_IsRunning(void);

Return value

= 0 Kernel is not started.
≠ 0 Kernel is running, OS_Start() has been called.

Additional information

This function may be helpful for some functions which might be called from main() or from running tasks. As long as the kernel is not started and a function is called from main(), blocking task switches are not allowed. A function which may be called from a task or main() may use OS_IsRunning() to determine whether a subsequent call to a blocking API function is allowed.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void PrintStatus() {
  OS_BOOL b;

  b = OS_ISRunning();
  if (b == 0) {
    printf("embOS scheduler not started, yet.\n");
  } else {
    printf("embOS scheduler is running.\n");
  }
}

OS_Start()

Description

Starts the embOS scheduler.

Prototype

void OS_Start(void);

Additional information

This function starts the embOS scheduler, which will activate and start the task with the highest priority.

OS_Start() marks embOS as running; this may be examined by a call of the function OS_IsRunning(). OS_Start() automatically enables interrupts. It must be called from main() context only.

embOS will reuse the main stack after OS_Start() was called. Therefore, local data located on the main stack may not be used after calling OS_Start(). If OS_Stop() is used, OS_ConfigStop() will save the main stack and restore it upon stopping embOS.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

165: OS_ERR_INIT_NOT_CALLED
228: OS_ERR_ILLEGAL_AFTER_OSSTART

For details, refer to the chapter Runtime application errors.

Example

#include "RTOS.h"

static OS_STACKPTR int StackHP[128], StackLP[128];  // Task stacks
static OS_TASK         TCBHP, TCBLP;                // Task control blocks

static void HPTask(void) {
  while (1) {
    OS_TASK_Delay_ms(50);
  }
}

static void LPTask(void) {
  while (1) {
    OS_TASK_Delay_ms(200);
  }
}

/*********************************************************************
*
*       main()
*/
int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_TASK_CREATE(&TCBLP, "LP Task",  50, LPTask, StackLP);
  OS_Start();     // Start embOS
  return 0;
}

OS_Stop()

Description

Stops the embOS kernel and returns from OS_Start().

Prototype

void OS_Stop(void);

Additional information

This function stops the embOS kernel and the application returns from OS_Start().
OS_ConfigStop() must be called prior to OS_Stop(). OS_Stop() restores context and stack to their state prior to calling OS_Start(). OS_Stop() does not deinitialize any hardware. It’s the application’s responsibility to de-initialize all hardware that was initialized, for example, during OS_InitHW().

It is possible to restart embOS after OS_Stop(). To do so, OS_Init() must be called and any task must be recreated. It also is the application’s responsibility to initialize all embOS variables to their default values. With the embOS source code, this can easily be achieved using the compile time switch OS_INIT_EXPLICITLY.

With some cores it is not possible to save and restore the main() stack. This is e.g. true for 8051. Hence, in that case no functionality should be implemented that relies on the stack to be preserved. But OS_Stop() can be used anyway.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
250: OS_ERR_CONFIG_OSSTOP

For details, refer to the chapter Runtime application errors.

Example

#include "RTOS.h"
#include "stdio.h"

#define BUFFER_SIZE    (32u)
static OS_U8           Buffer[BUFFER_SIZE];
static OS_MAIN_CONTEXT MainContext;

static OS_STACKPTR int StackHP[128];
static OS_TASK         TCBHP;

static void HPTask(void) {
  OS_TASK_Delay_ms(50);
  OS_Stop();
}

int main(void) {
  int TheAnswerToEverything = 42;
  OS_Init();
  OS_InitHW();
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_ConfigStop(&MainContext, Buffer, BUFFER_SIZE);
  OS_Start();
  //
  // We arrive here because OS_Stop() was called.
  // The local stack variable still has its value.
  //
  printf("%d", TheAnswerToEverything);
  while (1) {
  }
  return 0;
}

Task

Introduction

A task that should run under embOS needs a task control block (TCB), a task stack, and a task body written in C. The following rules apply to task routines:

Example of a task routine as an endless loop

void Task1(void) {
  while(1) {
    DoSomething();         // Do something
    OS_TASK_Delay_ms(10);  // Give other tasks a chance to run
  }
}

Example of a task routine that terminates itself

void Task2(void) {
  char DoSomeMore;
  do {
    DoSomeMore = DoSomethingElse();  // Do something
    OS_TASK_Delay_ms(10);            // Give other tasks a chance to run
  } while (DoSomeMore);
  OS_TASK_Terminate(NULL);           // Terminate this task
}

There are different ways to create a task: On the one hand, embOS offers a simple macro to facilitate task creation, which is sufficient in most cases. However, if you are dynamically creating and deleting tasks, a function is available allowing “fine-tuning” of all parameters. For most applications, at least initially, we recommend using the macro.

Cooperative vs. preemptive task switches

In general, preemptive task switches are an important feature of an RTOS. Preemptive task switches are required to guarantee responsiveness of high-priority, time critical tasks. However, it may be desirable to disable preemptive task switches for certain tasks in some circumstances. The default behavior of embOS is to allow preemptive task switches in all circumstances.

Disabling preemptive task switches for tasks of equal priority

In some situations, preemptive task switches between tasks running at identical priorities are not desirable. To inhibit time slicing of equal-priority tasks, the time slice of the tasks running at identical priorities must be set to zero as in the example below:

#include "RTOS.h"

#define PRIO_COOP       10
#define TIME_SLICE_NULL  0

static OS_STACKPTR int StackHP[128], StackLP[128];  // Task stacks
static OS_TASK         TCBHP, TCBLP;                // Task control blocks

static void TaskEx(void* pData) {
  while (1) {
    OS_TASK_Delay_ms((OS_TIME)pData);
  }
}

/*********************************************************************
*
*       main()
*/
int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  BSP_Init();     // Initialize LED ports
  OS_TASK_CreateEx(&TCBHP, "HP Task", PRIO_COOP, TaskEx, StackHP,
                  sizeof(StackHP), TIME_SLICE_NULL, (void *) 50);
  OS_TASK_CreateEx(&TCBLP, "LP Task", PRIO_COOP, TaskEx, StackLP,
                  sizeof(StackLP), TIME_SLICE_NULL, (void *) 200);
  OS_Start();     // Start embOS
  return 0;
}

Completely disabling preemptions for a task

This is simple: The first line of code should be OS_TASK_EnterRegion() as shown in the following sample:

void MyTask(void* pContext) {
  OS_TASK_EnterRegion();  // Disable preemptive context switches
  while (1) {
    // Do something. In the code, make sure that you call a blocking
    // function periodically to give other tasks a chance to run.
  }
}

This will entirely disable preemptive context switches from that particular task and will therefore affect the timing of higher-priority tasks. Do not use this carelessly.

Extending the task context

For some applications it might be useful or required to have individual data in tasks that are unique to the task. Local variables, declared in the task, are unique to the task and remain valid, even when the task is suspended and resumed again. When the same task function is used for multiple tasks, local variables in the task may be used, but cannot be initialized individually for every task. embOS offers different options to extend the task context.

Passing one parameter to a task during task creation

Very often it is sufficient to have just one individual parameter passed to a task. Using the OS_TASK_CREATEEX() or OS_TASK_CreateEx() function to create a task allows passing a void-pointer to the task. The pointer may point to individual data, or may represent any data type that can be held within a pointer.

Extending the task context individually at runtime

Sometimes it may be required to have an extended task context for individual tasks to store global data or special CPU registers such as floating-point registers in the task context. The standard libraries for file I/O, locale support and others may require task-local storage for specific data like errno and other variables. embOS enables extension of the task context for individual tasks during runtime by a call of OS_TASK_SetContextExtension(). The sample application file OS_ExtendTaskContext.c delivered in the application samples folder of embOS demonstrates how the individual task context extension can be used.

Extending the task context by using own task structures

When complex data is needed for an individual task context, the OS_TASK_CREATEEX() or OS_TASK_CreateEx() functions may be used, passing a pointer to individual data structures to the task. Alternatively you may define your own task structure which can be used. Note, that the first item in the task structure must be an embOS task control structure OS_TASK. This can be followed by any amount and type of additional data of different types.

The following code shows the example application OS_ExtendedTask.c which is delivered in the sample application folder of embOS.

#include "RTOS.h"

/*********************************************************************
*
*       Types, local
*
**********************************************************************
*/

//
// Custom task structure with extended task context.
//
typedef struct {
  OS_TASK Task;     // OS_TASK has to be the first element
  OS_TIME Timeout;  // Any other data type may be used to extend the context
  char*   pString;  // Any number of elements may be used to extend the context
} MY_APP_TASK;

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/
static OS_STACKPTR int StackHP[128], StackLP[128];  // Task stacks
static MY_APP_TASK     TCBHP, TCBLP;                // Task-control-blocks

/*********************************************************************
*
*       Local functions
*
**********************************************************************
*/

/*********************************************************************
*
*       MyTask()
*/
static void MyTask(void) {
  MY_APP_TASK* pThis;
  OS_TIME      Timeout;
  char*        pString;

  pThis = (MY_APP_TASK*)OS_TASK_GetID();
  while (1) {
    Timeout = pThis->Timeout;
    pString = pThis->pString;
    OS_COM_SendString(pString);
    OS_TASK_Delay_ms(Timeout);
  }
}

/*********************************************************************
*
*       Global functions
*
**********************************************************************
*/

/*********************************************************************
*
*       main()
*/
int main(void) {
  OS_Init();    // Initialize embOS
  OS_InitHW();  // Initialize required hardware
  //
  // Create the extended tasks just as normal tasks.
  // Note that the first parameter has to be of type OS_TASK
  //
  OS_TASK_CREATE(&TCBHP.Task, "HP Task", 100, MyTask, StackHP);
  OS_TASK_CREATE(&TCBLP.Task, "LP Task",  50, MyTask, StackLP);
  //
  // Give task contexts individual data
  //
  TCBHP.Timeout = 200;
  TCBHP.pString = "HP task running\n";
  TCBLP.Timeout = 500;
  TCBLP.pString = "LP task running\n";
  OS_Start();   // Start embOS
  return 0;
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_TASK_AddContextExtension() Adds the specified task context extension.
OS_TASK_AddTerminateHook() Adds the specified hook (callback) routine to the list of routines which are called when a task is terminated.
OS_TASK_Create() Creates a new task.
OS_TASK_CreateEx() Creates a new task and passes a parameter to the task.
OS_TASK_Delay_Cycles() Suspends the calling task for a specified amount of cycles, or waits actively when called from main().
OS_TASK_Delay_ms() Suspends the calling task for a specified amount of milliseconds, or waits actively when called from main().
OS_TASK_Delay_ns() Suspends the calling task for a specified amount of nanoseconds, or waits actively when called from main().
OS_TASK_Delay_us() Suspends the calling task for a specified amount of microseconds, or waits actively when called from main().
OS_TASK_DelayUntil_Cycles() Suspends the calling task until a specified time in cycles, or waits actively when called from main().
OS_TASK_DelayUntil_ms() Suspends the calling task until a specified time in milliseconds, or waits actively when called from main().
OS_TASK_DelayUntil_ns() Suspends the calling task until a specified time in nanoseconds, or waits actively when called from main().
OS_TASK_DelayUntil_us() Suspends the calling task until a specified time in microseconds, or waits actively when called from main().
OS_TASK_GetID() Returns a pointer to the task control block structure of the currently scheduled task.
OS_TASK_GetName() Returns a pointer to the name of the specified task.
OS_TASK_GetNumTasks() Returns the number of tasks.
OS_TASK_GetPriority() Returns the task priority of the specified task.
OS_TASK_GetStatus() Returns the current task status of the the specified task.
OS_TASK_GetSuspendCnt() Returns the suspension count and thus suspension state of the specified task.
OS_TASK_GetTimeSliceRem() Returns the remaining time slice value of the specified task in milliseconds.
OS_TASK_IsTask() Determines whether the specified task control block belongs to a valid task.
OS_TASK_Index2Ptr() Returns the task control block of the task with the specified Index.
OS_TASK_RemoveAllTerminateHooks() Removes all hook functions from the OS_ON_TERMINATE_HOOK list which contains the list of functions that are called when a task is terminated.
OS_TASK_RemoveTerminateHook() OS_TASK_RemoveTerminateHook() removes the specified hook function from the OS_ON_TERMINATE_HOOK list which contains the list of functions that are called when a task is terminated.
OS_TASK_Resume() Resumes the specified suspended task.
OS_TASK_ResumeAll() Decrements the suspend count of all tasks that have a nonzero suspend count and resumes these tasks when their respective suspend count reaches zero.
OS_TASK_SetContextExtension() Makes global variables or processor registers task-specific.
OS_TASK_SetDefaultContextExtension() Sets the specified context extension as the default task context extension.
OS_TASK_SetDefaultStartHook() Sets a default hook routine which is executed before a task starts.
OS_TASK_SetInitialSuspendCnt() Sets the initial suspend count for newly created tasks to 1 or 0.
OS_TASK_SetName() Set the specified task name for the specified task.
OS_TASK_SetPriority() Assigns the specified task priority to the specified task.
OS_TASK_SetTimeSlice() Assigns the specified time-slice period to a specified task.
OS_TASK_Suspend() Suspends the specified task and increments the task’s suspend count.
OS_TASK_SuspendAll() Suspends all tasks except the running task.
OS_TASK_Terminate() Ends (terminates) the specified task.
OS_TASK_Wake() Ends delay of the specified task immediately.
OS_TASK_Yield() Calls the scheduler to force a task switch.

OS_TASK_AddContextExtension()

Description

Adds the specified task context extension. The task context can be extended with OS_TASK_SetContextExtension() only once. Additional task context extensions can be added with OS_TASK_AddContextExtension(). OS_TASK_AddContextExtension() can also be called for the first task context extension.
The function OS_TASK_AddContextExtension() requires an additional parameter of type OS_EXTEND_TASK_CONTEXT_LINK which is used to create a task specific linked list of task context extensions.

Prototype

void OS_TASK_AddContextExtension
             (OS_EXTEND_TASK_CONTEXT_LINK* pExtendContextLink,
              OS_CONST_PTR                 OS_EXTEND_TASK_CONTEXT *pExtendContext);

Parameters

Parameter Description
pExtendContextLink Pointer to the OS_EXTEND_TASK_CONTEXT_LINK structure.
pExtendContext Pointer to the OS_EXTEND_TASK_CONTEXT structure which contains the addresses of the specific save and restore functions that save and restore the extended task context during task switches.

Additional information

The object of type OS_EXTEND_TASK_CONTEXT_LINK is task specific and must only be used for one task. It can be located e.g. on the task stack. pExtendContext, pExtendContext->pfSave and pExtendContext->pfRestore must not be NULL.

Note

embOS interrupts must not be enabled in the save and restore functions.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

116: OS_ERR_EXTEND_CONTEXT
128: OS_ERR_INV_TASK
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

static void HPTask(void) {
  OS_EXTEND_TASK_CONTEXT_LINK p;
  //
  // Extend task context by VFP registers
  //
  OS_TASK_SetContextExtension(&_SaveRestoreVFP);
  //
  // Extend task context by global variable
  //
  OS_TASK_AddContextExtension(&p, &_SaveRestoreGlobalVar);
  a = 1.2;
  while (1) {
    b = 3 * a;
    GlobalVar = 1;
    OS_TASK_Delay_ms(10);
  }
}

OS_TASK_AddTerminateHook()

Description

Adds the specified hook (callback) routine to the list of routines which are called when a task is terminated.

Prototype

void OS_TASK_AddTerminateHook(OS_ON_TERMINATE_HOOK* pHook,
                              OS_ROUTINE_TASK_PTR*  pfRoutine);

Parameters

Parameter Description
pHook Pointer to a variable of type OS_ON_TERMINATE_HOOK which will be inserted into the linked list of routines to be called during OS_TASK_Terminate().
pfRoutine Pointer to the routine of type OS_ROUTINE_TASK_PTR which shall be called when a task is terminated.

Additional information

For some applications, it may be useful to allocate memory or objects specific to tasks. For other applications, it may be useful to have task-specific information on the stack. When a task is terminated, the task-specific objects may become invalid. A callback routine may be hooked into OS_TASK_Terminate() by calling OS_TASK_AddTerminateHook() to allow the application to invalidate all task-specific objects before the task is terminated.

The callback routine pfRoutine of type OS_ROUTINE_TASK_PTR receives the address of the terminated task as its parameter (see description in chapter Callback / Hook routines).

Note

The variable of type OS_ON_TERMINATE_HOOK must reside in memory as a global or static variable. It may be located on a task stack, as local variable, but it must not be located on any stack of any task that might be terminated.

If a task terminates itself, its task control block and task stack are still used until the scheduler switches to another task or OS_Idle(). You must not use the task control block or task stack for anything else before the scheduler was executed. For example you must not free the task control block or task stack in the hook routine when using heap memory for the task control block or task stack.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

OS_ON_TERMINATE_HOOK _TerminateHook;

void TerminateHookFunc(OS_CONST_PTR OS_TASK* pTask) {
  // This function is executed upon calling OS_TASK_Terminate().
  if (pTask == &MyTask) {
    free(MytaskBuffer);
  }
}
...
int main(void) {
  OS_TASK_AddTerminateHook(&_TerminateHook, TerminateHookFunc);
  ...
}

OS_TASK_Create()

Description

Creates a new task.

Prototype

void OS_TASK_Create(      OS_TASK*         pTask,
                    const char*            sName,
                          OS_TASK_PRIO     Priority,
                          OS_ROUTINE_VOID* pfRoutine,
                          void             OS_STACKPTR *pStack,
                          OS_UINT          StackSize,
                          OS_UINT          TimeSlice);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK.
sName Pointer to the name of the task. Can be NULL if not used. embOS does not copy the task name, but uses the pointer exclusively. When using an embOS build without task name support, this parameter is ignored.
Priority Priority of the task. Must be within the following range:
1 ≤ Priority ≤ 28 - 1 = 0xFF for 8/16-bit CPUs
1 ≤ Priority ≤ 232 - 1 = 0xFFFFFFFF for 32-bit CPUs
Higher values indicate higher priorities. The type OS_TASK_PRIO is defined as a 32-bit value for 32-bit CPUs and as an 8-bit value for 8 or 16-bit CPUs by default.
pfRoutine Pointer to the routine of type OS_ROUTINE_VOID that shall run as the task body.
pStack Pointer to an area of memory in RAM that will serve as stack area for the task. The size of this block of memory determines the size of the stack area.
StackSize Size of stack in bytes.
TimeSlice Time slice value for round-robin scheduling. Has an effect only if other tasks are running at the same priority. It denotes the time (in milliseconds) that the task will run before it suspends, and must be in the following range: 0 ≤ TimeSlice ≤ 255.

Additional information

OS_TASK_Create() creates a task and makes it ready for execution. The newly created task will be activated by the scheduler as soon as there is no other task with higher priority ready for execution.

OS_TASK_Create() can be called either from main() during initialization or from any other task. The recommended strategy is to create all tasks during initialization in main() to keep the structure of your application easy to maintain.

The absolute value of Priority is of no importance, only the value in comparison to the priorities of other tasks matters. If there is another task with the same priority, the new task will be scheduled prior to the existing one.
In embOS builds that do not support round-robin, unique priorities must be assigned to each individual task.

The stack indicated by pStack must reside in an area that the CPU can address as stack. Most CPUs cannot use the entire memory area as stack and require the stack to be aligned to a multiple of the processor word size.

A TimeSlice value of zero is allowed and disables round-robin task switches (see sample in chapter Disabling preemptive task switches for tasks of equal priority).

Note

With embOS-MPU OS_MPU_ConfigMem() must be called before creating any task.

Note

Up until embOS V5.8.2, OS_TASK_Create() expected the task name and time-slice parameters to be omitted in OS_LIBMODE_XR. From embOS V5.10.0 onward, OS_TASK_Create() expects all parameters to be present independent of the library mode. This means existing applications which call OS_TASK_Create() in OS_LIBMODE_XR need to be updated accordingly.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

120: OS_ERR_TASK_STACK
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
170: OS_ERR_2USE_TASK
202: OS_ERR_TASK_PRIORITY

For details, refer to the chapter Runtime application errors.

Note

embOS offers a macro that calls OS_TASK_Create() with two pre-defined parameters, OS_TASK_CREATE(), allowing to more easily create tasks. OS_TASK_CREATE() determines the value of StackSize automatically using sizeof(). This is possible only if the memory area has been defined at compile time. Furthermore, OS_TASK_CREATE() uses a default TimeSlice of 2. If the macro shall be used, its definition is as follows:

#define OS_TASK_CREATE(pTask, pName, Priority, pRoutine, pStack) \
  OS_TASK_Create((pTask),                                        \
                 (pName),                                        \
                 (OS_PRIO)(Priority),                            \
                 (pRoutine),                                     \
                 (void OS_STACKPTR*)(pStack),                    \
                 sizeof(pStack),                                 \
                 2u                                              \
                )

Example

#include "RTOS.h"

static OS_STACKPTR int StackHP[128], StackLP[128];  // Task stacks
static OS_TASK         TCBHP, TCBLP;                // Task control blocks

static void HPTask(void) {
  while (1) {
    OS_TASK_Delay_ms(50);
  }
}

static void LPTask(void) {
  while (1) {
    OS_TASK_Delay_ms(200);
  }
}

int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_Create(&TCBHP, "HP Task", 100, HPTask, StackHP, sizeof(StackHP), 2);
  OS_TASK_CREATE(&TCBLP, "LP Task",  50, LPTask, StackLP);
  OS_Start();     // Start embOS
  return 0;
}

OS_TASK_CreateEx()

Description

Creates a new task and passes a parameter to the task.

Prototype

void OS_TASK_CreateEx(      OS_TASK*             pTask,
                      const char*                sName,
                            OS_TASK_PRIO         Priority,
                            OS_ROUTINE_VOID_PTR* pfRoutine,
                            void                 OS_STACKPTR *pStack,
                            OS_UINT              StackSize,
                            OS_UINT              TimeSlice,
                            void*                pContext);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK.
sName Pointer to the name of the task. Can be NULL if not used. embOS does not copy the task name, but uses the pointer exclusively. When using an embOS build without task name support, this parameter is ignored.
Priority Priority of the task. Must be within the following range:
1 ≤ Priority ≤ 28 - 1 = 0xFF for 8/16-bit CPUs
1 ≤ Priority ≤ 232 - 1 = 0xFFFFFFFF for 32-bit CPUs
Higher values indicate higher priorities. The type OS_TASK_PRIO is defined as a 32-bit value for 32-bit CPUs and as an 8-bit value for 8 or 16-bit CPUs by default.
pfRoutine Pointer to the routine of type OS_ROUTINE_VOID_PTR that shall run as the task body.
pStack Pointer to an area of memory in RAM that will serve as stack area for the task. The size of this block of memory determines the size of the stack area.
StackSize Size of stack in bytes.
TimeSlice Time slice value for round-robin scheduling. Has an effect only if other tasks are running at the same priority. It denotes the time (in embOS system ticks) that the task will run before it suspends, and must be in the following range: 0 ≤ TimeSlice ≤ 255.
pContext Parameter passed to the created task.

Additional information

This function works the same way as OS_TASK_Create(), but allows passing a parameter, pContext, to the task. Using a void pointer as additional parameter gives the flexibility to pass any kind of data to the task function.

Note

With embOS-MPU OS_MPU_ConfigMem() must be called before creating any task.

Note

Up until embOS V5.8.2, OS_TASK_CreateEx() expected the task name and time-slice parameters to be omitted in OS_LIBMODE_XR. From embOS V5.10.0 onward, OS_TASK_CreateEx() expects all parameters to be present independent of the library mode. This means existing applications which call OS_TASK_CreateEx() in OS_LIBMODE_XR need to be updated accordingly.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

120: OS_ERR_TASK_STACK
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
170: OS_ERR_2USE_TASK
202: OS_ERR_TASK_PRIORITY

For details, refer to the chapter Runtime application errors.

Note

embOS offers a macro that calls OS_TASK_CreateEx() with two pre-defined parameters, OS_TASK_CREATEEX(), allowing to more easily create tasks. OS_TASK_CREATEEX() determines the value of StackSize automatically using sizeof(). This is possible only if the memory area has been defined at compile time. Furthermore, OS_TASK_CREATEEX() uses a default TimeSlice of 2. If the macro shall be used, its definition is as follows:

#define OS_TASK_CREATEEX(pTask, pName, Priority, pRoutine, pStack, pContext)
  OS_TASK_CreateEx((pTask),
                   (pName),
                   (OS_PRIO)(Priority),
                   (pRoutine),
                   (void OS_STACKPTR*)(pStack),
                   sizeof(pStack),
                   2u,
                   (pContext)
                  )

Example

#include "RTOS.h"

static OS_STACKPTR int StackHP[128], StackLP[128];  // Task stacks
static OS_TASK         TCBHP, TCBLP;                // Task control blocks

static void Task(void* pContext) {
  while (1) {
    OS_TASK_Delay_ms((int)pContext);
  }
}

int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_CreateEx(&TCBHP, "HP Task", 100, Task,
                  StackHP, sizeof(StackHP), 2, (void*) 50);
  OS_TASK_CREATEEX(&TCBLP, "LP Task",  50, Task,
                  StackLP, (void*)200);
  OS_Start();     // Start embOS
  return 0;
}

OS_TASK_Delay_Cycles()

Description

Suspends the calling task for a specified amount of cycles, or waits actively when called from main().

Prototype

void OS_TASK_Delay_Cycles(OS_U32 Cycles);

Parameters

Parameter Description
Cycles Number of cycles to delay.

Additional information

After the expiration of the delay, the task is made ready and activated according to the rules of the scheduler. A delay can be ended prematurely by another task or by an interrupt handler calling OS_TASK_Wake().

If OS_TASK_Delay_Cycles() is called from main(), it will actively wait for the timeout to expire. Therefore, interrupts must be enabled.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TASK_Delay_Cycles().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

154: OS_ERR_INTERRUPT_DISABLED
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Hello(void) {
  printf("Hello");
  printf("No output will occur for the next 5000 Cycles.\n");
  OS_TASK_Delay_Cycles(5000);
  printf("Delay is over.\n");
}

OS_TASK_Delay_ms()

Description

Suspends the calling task for a specified amount of milliseconds, or waits actively when called from main().

Prototype

void OS_TASK_Delay_ms(OS_U32 ms);

Parameters

Parameter Description
ms Number of milliseconds to delay.

Additional information

After the expiration of the delay, the task is made ready and activated according to the rules of the scheduler. A delay can be ended prematurely by another task or by an interrupt handler calling OS_TASK_Wake().

If OS_TASK_Delay_ms() is called from main(), it will actively wait for the timeout to expire. Therefore, interrupts must be enabled.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TASK_Delay_ms().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

154: OS_ERR_INTERRUPT_DISABLED
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Hello(void) {
  printf("Hello");
  printf("No output will occur for the next 5000 milliseconds.\n");
  OS_TASK_Delay_ms(5000);
  printf("Delay is over.\n");
}

OS_TASK_Delay_ns()

Description

Suspends the calling task for a specified amount of nanoseconds, or waits actively when called from main().

Prototype

void OS_TASK_Delay_ns(OS_U32 ns);

Parameters

Parameter Description
ns Number of nanoseconds to delay.

Additional information

After the expiration of the delay, the task is made ready and activated according to the rules of the scheduler. A delay can be ended prematurely by another task or by an interrupt handler calling OS_TASK_Wake().

If OS_TASK_Delay_ns() is called from main(), it will actively wait for the timeout to expire. Therefore, interrupts must be enabled.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TASK_Delay_ns().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

154: OS_ERR_INTERRUPT_DISABLED
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Hello(void) {
  printf("Hello");
  printf("No output will occur for the next 5000 nanoseconds.\n");
  OS_TASK_Delay_ns(5000);
  printf("Delay is over.\n");
}

OS_TASK_Delay_us()

Description

Suspends the calling task for a specified amount of microseconds, or waits actively when called from main().

Prototype

void OS_TASK_Delay_us(OS_U32 us);

Parameters

Parameter Description
us Number of microseconds to delay.

Additional information

After the expiration of the delay, the task is made ready and activated according to the rules of the scheduler. A delay can be ended prematurely by another task or by an interrupt handler calling OS_TASK_Wake().

If OS_TASK_Delay_us() is called from main(), it will actively wait for the timeout to expire. Therefore, interrupts must be enabled.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TASK_Delay_us().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

154: OS_ERR_INTERRUPT_DISABLED
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Hello(void) {
  printf("Hello");
  printf("No output will occur for the next 5000 microseconds.\n");
  OS_TASK_Delay_us(5000);
  printf("Delay is over.\n");
}

OS_TASK_DelayUntil_Cycles()

Description

Suspends the calling task until a specified time in cycles, or waits actively when called from main().

Prototype

void OS_TASK_DelayUntil_Cycles(OS_TIME Cycles);

Parameters

Parameter Description
Cycles Time in cycles to delay until. Must be within the following range:
(Cycles - OS_Global.Time) ≤ 263 - 1 = 0x7FFFFFFFFFFFFFFF.
Please note that these are signed values.

Additional information

OS_TASK_DelayUntil_Cycles() suspends the calling task until the global time-variable OS_Global.Time (see OS_Global.Time) reaches the specified value. If the specified value is already in the past, OS_TASK_DelayUntil_Cycles() returns immediately. The main advantage of this function is that it avoids potentially accumulating delays.

If OS_TASK_DelayUntil_Cycles() is called from main(), it will actively wait for the timeout to expire. Therefore, interrupts must be enabled.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TASK_DelayUntil_Cycles().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

154: OS_ERR_INTERRUPT_DISABLED
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Hello(void) {
  OS_U64 t0;

  t0 = OS_TIME_Get_Cycles;
  while (1) {
    printf("Hello");
    printf("No output will occur for the next 5000 Cycles.\n");
    t0 += 5000u;
    OS_TASK_DelayUntil_Cycles((OS_TIME)t0);
    printf("Delay is over.\n");
  }
}

OS_TASK_DelayUntil_ms()

Description

Suspends the calling task until a specified time in milliseconds, or waits actively when called from main().

Prototype

void OS_TASK_DelayUntil_ms(OS_TIME ms);

Parameters

Parameter Description
ms Time in milliseconds to delay until. The given value is converted into Cycles automatically and the result must be within the following range:
(Cycles - OS_Global.Time) ≤ 263 - 1 = 0x7FFFFFFFFFFFFFFF.
Please note that these are signed values.

Additional information

OS_TASK_DelayUntil_ms() suspends the calling task until the global time-variable OS_Global.Time (see OS_Global.Time) reaches the specified value. If the specified value is already in the past, OS_TASK_DelayUntil_ms() returns immediately. The main advantage of this function is that it avoids potentially accumulating delays.

If OS_TASK_DelayUntil_ms() is called from main(), it will actively wait for the timeout to expire. Therefore, interrupts must be enabled.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TASK_DelayUntil_ms().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

154: OS_ERR_INTERRUPT_DISABLED
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

int sec, min;

void TaskShowTime(void) {
  OS_U64 t0;

  t0 = OS_TIME_Get_ms();
  while (1) {
    ShowTime();  // Routine to display time
    t0 += 1000u;
    OS_TASK_DelayUntil_ms((OS_TIME)t0);
    if (sec < 59) {
      sec++;
    } else {
      sec = 0;
      min++;
    }
  }
}

If the example above used OS_TASK_Delay_ms() instead of OS_TASK_DelayUntil_ms(), this could lead to accumulating overhead between delays if OS_TASK_Delay_ms() is not called exactly each second (which may e.g. happen if interrupts or higher priority tasks are executed instead). This would cause the simple “clock” to be slow. Using OS_TASK_DelayUntil_ms() avoids this accumulating overhead.Using OS_TASK_DelayUntil_ms() avoids this accumulating overhead.

OS_TASK_DelayUntil_ns()

Description

Suspends the calling task until a specified time in nanoseconds, or waits actively when called from main().

Prototype

void OS_TASK_DelayUntil_ns(OS_TIME ns);

Parameters

Parameter Description
ns Time in nanoseconds to delay until. The given value is converted into Cycles automatically and the result must be within the following range:
(Cycles - OS_Global.Time) ≤ 263 - 1 = 0x7FFFFFFFFFFFFFFF.
Please note that these are signed values.

Additional information

OS_TASK_DelayUntil_ns() suspends the calling task until the global time-variable OS_Global.Time (see OS_Global.Time) reaches the specified value. If the specified value is already in the past, OS_TASK_DelayUntil_ns() returns immediately. The main advantage of this function is that it avoids potentially accumulating delays.

If OS_TASK_DelayUntil_ns() is called from main(), it will actively wait for the timeout to expire. Therefore, interrupts must be enabled.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TASK_DelayUntil_ns().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

154: OS_ERR_INTERRUPT_DISABLED
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Hello(void) {
  OS_U64 t0;

  t0 = OS_TIME_Get_ns();
  while (1) {
    printf("Hello");
    printf("No output will occur for the next 5000 nanoseconds.\n");
    t0 += 5000u;
    OS_TASK_DelayUntil_ns((OS_TIME)t0);
    printf("Delay is over.\n");
  }
}

OS_TASK_DelayUntil_us()

Description

Suspends the calling task until a specified time in microseconds, or waits actively when called from main().

Prototype

void OS_TASK_DelayUntil_us(OS_TIME us);

Parameters

Parameter Description
us Time in microseconds to delay until. The given value is converted into Cycles automatically and the result must be within the following range:
(Cycles - OS_Global.Time) ≤ 263 - 1 = 0x7FFFFFFFFFFFFFFF.
Please note that these are signed values.

Additional information

OS_TASK_DelayUntil_us() suspends the calling task until the global time-variable OS_Global.Time (see OS_Global.Time) reaches the specified value. If the specified value is already in the past, OS_TASK_DelayUntil_us() returns immediately. The main advantage of this function is that it avoids potentially accumulating delays.

If OS_TASK_DelayUntil_us() is called from main(), it will actively wait for the timeout to expire. Therefore, interrupts must be enabled.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TASK_DelayUntil_us().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

154: OS_ERR_INTERRUPT_DISABLED
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Hello(void) {
  OS_U64 t0;

  t0 = OS_TIME_Get_us();
  while (1) {
    printf("Hello");
    printf("No output will occur for the next 5000 microseconds.\n");
    t0 += 5000u;
    OS_TASK_DelayUntil_us((OS_TIME)t0);
    printf("Delay is over.\n");
  }
}

OS_TASK_GetID()

Description

Returns a pointer to the task control block structure of the currently scheduled task. This pointer is unique for the task and is used as a task Id.

Prototype

OS_TASK *OS_TASK_GetID(void);

Return value

= NULL No task is executing.
NULL Pointer to the task control block of the currently running task.

Additional information

When called from a task, this function may be used for determining which task is currently executing. This can be helpful if the action(s) of a function depend(s) on which task is executing it.

If called from an interrupt service routine, this function may be used to determine the interrupted task (if any).

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void PrintCurrentTaskID(void) {
  OS_TASK* pTask;
  pTask = OS_TASK_GetID();
  printf("Task ID 0x%x\n", pTask);
}

OS_TASK_GetName()

Description

Returns a pointer to the name of the specified task.

Prototype

char *OS_TASK_GetName(OS_CONST_PTR OS_TASK *pTask);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK or NULL for the current task.

Return value

A pointer to the name of the task. NULL indicates that the task has no name. If NULL is passed for pTask, the function returns the name of the running task. If there is no currently running task, the return value is “OS_Idle()”. If pTask is not NULL it must specify a valid task.

When using an embOS build without task name support, OS_TASK_GetName() returns “n/a” in any case. The embOS OS_LIBMODE_XR library mode does not support task names.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void PrintTaskName(void) {
  char* s;
  s = OS_TASK_GetName(NULL);
  printf("Task name: %s\n", s);
}

OS_TASK_GetNumTasks()

Description

Returns the number of tasks.

Prototype

int OS_TASK_GetNumTasks(void);

Return value

Number of tasks.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void PrintNumberOfTasks(void) {
  int NumTasks;
  NumTasks = OS_TASK_GetNumTasks();
  printf("Number of tasks %d\n", NumTasks);
}

OS_TASK_GetPriority()

Description

Returns the task priority of the specified task.

Prototype

OS_TASK_PRIO OS_TASK_GetPriority(OS_CONST_PTR OS_TASK *pTask);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK or NULL for the current task.

Return value

Priority of the specified task (range 1 to 255 for 8/16-bit CPUs and up to 4294967295 for 32-bit CPUs).

Additional information

If NULL is passed for pTask, the currently running task is used. If this function is not called from a task context, no task might currently be running and there is no valid task. A debug build of embOS will call OS_Error() in this case. We suggest to call this function from a context other than the task context with a pointer to a valid task control block only.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void PrintPriority(const OS_TASK* pTask) {
  OS_PRIO Prio;
  Prio = OS_TASK_GetPriority(pTask);
  printf("Priority of task 0x%x = %u\n", pTask, Prio);
}

OS_TASK_GetStatus()

Description

Returns the current task status of the the specified task.

Prototype

OS_TASK_STATUS OS_TASK_GetStatus(OS_CONST_PTR OS_TASK *pTask);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK or NULL for the current task.

Return value

Task status.

Possible return values are:
READY_FOR_EXECUTION
DELAYED
WAITS_FOR_TASKEVENT
WAITS_FOR_TASKEVENT_WITH_TIMEOUT
WAITS_FOR_MUTEX
WAITS_FOR_MUTEX_WITH_TIMEOUT
WAITS_FOR_COMMUNICATION
WAITS_FOR_SEMAPHORE
WAITS_FOR_SEMAPHORE_WITH_TIMEOUT
WAITS_FOR_MEMPOOL
WAITS_FOR_MEMPOOL_WITH_TIMEOUT
WAITS_FOR_MESSAGE_IN_QUEUE
WAITS_FOR_MESSAGE_IN_QUEUE_WITH_TIMEOUT
WAITS_FOR_SPACE_IN_MAILBOX
WAITS_FOR_SPACE_IN_MAILBOX_WITH_TIMEOUT
WAITS_FOR_MESSAGE_IN_MAILBOX
WAITS_FOR_MESSAGE_IN_MAILBOX_WITH_TIMEOUT
WAITS_FOR_EVENTOBJECT
WAITS_FOR_EVENTOBJECT_WITH_TIMEOUT
WAITS_FOR_SPACE_IN_QUEUE
WAITS_FOR_SPACE_IN_QUEUE_WITH_TIMEOUT
WAITS_FOR_MULITPLE_OBJECTS
WAITS_FOR_MULITPLE_OBJECTS_WITH_TIMEOUT
RUNNING
SUSPENDED

Additional information

If NULL is passed for pTask, the currently running task is used. If this function is not called from a task context, no task might currently be running and there is no valid task. A debug build of embOS will call OS_Error() in this case. We suggest to call this function from a context other than the task context with a pointer to a valid task control block only.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void PrintTaskStatus(void) {
  OS_TASK_STATUS status;

  status = OS_TASK_GetStatus(&TCB);
  printf("Task status: %u\n", status);
}

OS_TASK_GetSuspendCnt()

Description

Returns the suspension count and thus suspension state of the specified task. This function may be used to examine whether a task is suspended by previous calls of OS_TASK_Suspend().

Prototype

OS_U8 OS_TASK_GetSuspendCnt(OS_CONST_PTR OS_TASK *pTask);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK or NULL for the current task.

Return value

Suspension count of the specified task.

= 0 Task is not suspended.
> 0 Task is suspended by at least one call of OS_TASK_Suspend().

Additional information

If NULL is passed for pTask, the currently running task is used. If this function is not called from a task context, no task might currently be running and there is no valid task. A debug build of embOS will call OS_Error() in this case. We suggest to call this function from a context other than the task context with a pointer to a valid task control block only.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void ResumeTask(OS_TASK* pTask) {
  OS_U8 SuspendCnt;
  SuspendCnt = OS_TASK_GetSuspendCnt(pTask);
  while (SuspendCnt > 0u) {
    OS_TASK_Resume(pTask);  // May cause a task switch
    SuspendCnt--;
  }
}

OS_TASK_GetTimeSliceRem()

Description

Returns the remaining time slice value of the specified task in milliseconds.

Prototype

OS_U8 OS_TASK_GetTimeSliceRem(OS_CONST_PTR OS_TASK *pTask);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK or NULL for the current task.

Return value

Remaining time slice value of the task in milliseconds.

Additional information

If NULL is passed for pTask, the currently running task is used. If this function is not called from a task context, no task might currently be running and there is no valid task. A debug build of embOS will call OS_Error() in this case. We suggest to call this function from a context other than the task context with a pointer to a valid task control block only.

The return value is valid only when using an embOS build with round-robin support. In all other builds it will be 0. The embOS OS_LIBMODE_XR library mode does not support round-robin.

In an embOS build with round-robin support, OS_TIME_ConfigSysTimer() must have been called before calling OS_TASK_GetTimeSliceRem().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void PrintRemainingTimeSlices(void) {
  OS_U8 slices;

  slices = OS_TASK_GetTimeSliceRem(NULL);
  printf("Remaining Time Slices: %d\n", slices);
}

OS_TASK_IsTask()

Description

Determines whether the specified task control block belongs to a valid task.

Prototype

OS_BOOL OS_TASK_IsTask(OS_CONST_PTR OS_TASK *pTask);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK.

Return value

= 0 TCB is not used by any task.
≠ 0 TCB is used by a task.

Additional information

This function checks if the specified task is present in the internal task list. When a task is terminated it is removed from the internal task list. In applications that create and terminate tasks dynamically, this function may be useful to determine whether the task control block and stack for one task may be reused for another task.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void PrintTCBStatus(OS_TASK* pTask) {
  OS_BOOL b;

  b = OS_TASK_IsTask(pTask);
  if (b == 0u) {
    printf("TCB can be reused for another task.\n");
  } else {
    printf("TCB refers to a valid task.\n");
  }
}

OS_TASK_Index2Ptr()

Description

Returns the task control block of the task with the specified Index.

Prototype

OS_TASK *OS_TASK_Index2Ptr(int TaskIndex);

Parameters

Parameter Description
TaskIndex Index of a task control block in the task list.
This is a zero based index. TaskIndex 0 identifies the first task control block.

Return value

= NULL No task control block with this index found.
NULL Pointer to the task control block with the index TaskIndex.

Additional information

The order of the tasks in the task list is not defined by the order of task creation and changes at runtime. Tasks are ordered in the task list by their task priority. Therefore OS_TASK_Index2Ptr() is usually used only to iterate through the complete task list (e.g. to print all task names).

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void PrintAllTaskNames(void) {
  OS_TASK* pTask;
  int      TaskIndex;

  TaskIndex = 0;
  OS_TASK_EnterRegion();
  do {
    pTask = OS_TASK_Index2Ptr(TaskIndex);
    if (pTask != NULL) {
      printf("%s\n", pTask->sName);
    }
    TaskIndex++;
  } while (pTask != NULL);
  OS_TASK_LeaveRegion();
}

OS_TASK_RemoveAllTerminateHooks()

Description

Removes all hook functions from the OS_ON_TERMINATE_HOOK list which contains the list of functions that are called when a task is terminated.

Prototype

void OS_TASK_RemoveAllTerminateHooks(void);

Additional information

OS_TASK_RemoveAllTerminateHooks() removes all hook functions which were previously added by OS_TASK_AddTerminateHook().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

OS_ON_TERMINATE_HOOK _TerminateHook;

void TerminateHookFunc(OS_CONST_PTR OS_TASK* pTask) {
  // This function is called when OS_TASK_Terminate() is called.
  if (pTask == &MyTask) {
    free(MytaskBuffer);
  }
}
...
int main(void) {
  OS_TASK_AddTerminateHook(&_TerminateHook, TerminateHookFunc);
  OS_TASK_RemoveAllTerminateHooks();
  ...
}

OS_TASK_RemoveTerminateHook()

Description

OS_TASK_RemoveTerminateHook() removes the specified hook function from the OS_ON_TERMINATE_HOOK list which contains the list of functions that are called when a task is terminated.

Prototype

void OS_TASK_RemoveTerminateHook(OS_CONST_PTR OS_ON_TERMINATE_HOOK *pHook);

Parameters

Parameter Description
pHook Pointer to a variable of type OS_ON_TERMINATE_HOOK.

Additional information

OS_TASK_RemoveTerminateHook() removes the specified hook routine which was previously added by OS_TASK_AddTerminateHook().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

OS_ON_TERMINATE_HOOK _TerminateHook;

void TerminateHookFunc(OS_CONST_PTR OS_TASK* pTask) {
  // This function is called when OS_TASK_Terminate() is called.
  if (pTask == &MyTask) {
    free(MytaskBuffer);
  }
}
...
int main(void) {
  OS_TASK_AddTerminateHook(&_TerminateHook, TerminateHookFunc);
  OS_TASK_RemoveTerminateHook(&_TerminateHook);
  ...
}

OS_TASK_Resume()

Description

Resumes the specified suspended task.

Prototype

void OS_TASK_Resume(OS_TASK* pTask);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK.

Additional information

OS_TASK_Resume() decrements the specified task’s suspend count. When the resulting value is zero, the execution of the specified task is resumed.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
161: OS_ERR_ILLEGAL_IN_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
201: OS_ERR_RESUME_BEFORE_SUSPEND

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example of OS_TASK_Suspend().

OS_TASK_ResumeAll()

Description

Decrements the suspend count of all tasks that have a nonzero suspend count and resumes these tasks when their respective suspend count reaches zero.

Prototype

void OS_TASK_ResumeAll(void);

Additional information

This function may be helpful to synchronize or start multiple tasks at the same time. The function resumes all tasks, no specific task must be addressed. The function may be used together with the functions OS_TASK_SuspendAll() and OS_TASK_SetInitialSuspendCnt().
The function may cause a task switch when a task with higher priority than the calling task is resumed. The task switch will be executed after all suspended tasks are resumed.
The function may be called even when no task is suspended.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

161: OS_ERR_ILLEGAL_IN_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example of OS_TASK_SetInitialSuspendCnt().

OS_TASK_SetContextExtension()

Description

Makes global variables or processor registers task-specific. The function may be used for a variety of purposes. Typical applications are:

This allows the user to extend the task context as required. A major advantage is that the task extension is task-specific. This means that the additional information (such as floating-point registers) needs to be saved only by tasks that actually use these registers. The advantage is that the task switching time of other tasks is not affected. The same is true for the required stack space: Additional stack space is required only for the tasks which actually save the additional registers.

Prototype

void OS_TASK_SetContextExtension
                             (OS_CONST_PTR OS_EXTEND_TASK_CONTEXT *pExtendContext);

Parameters

Parameter Description
pExtendContext Pointer to the OS_EXTEND_TASK_CONTEXT structure which contains the addresses of the specific save and restore functions that save and restore the extended task context during task switches.

Additional information

The OS_EXTEND_TASK_CONTEXT structure is defined as follows:

typedef struct OS_EXTEND_TASK_CONTEXT {
void* (*pfSave) ( void* pStack);
void* (*pfRestore)(const void* pStack);
} OS_EXTEND_TASK_CONTEXT;

Note

In embOS V4.16 and earlier the OS_EXTEND_TASK_CONTEXT structure was defined as follows:

typedef struct OS_EXTEND_TASK_CONTEXT_STRUCT {
void (*pfSave) ( void OS_STACKPTR * pStack);
void (*pfRestore)(const void OS_STACKPTR * pStack);
} OS_EXTEND_TASK_CONTEXT;

The Save/Restore functions did not return the stack pointer. When updating from embOS V4.16 and earlier to embOS V4.20 and later please update your Save/Restore functions accordingly.

pExtendContext, pExtendContext->pfSave and pExtendContext->pfRestore must not be NULL. The save and restore functions must be declared according the function type used in the structure. The sample below shows how the task stack must be addressed to save and restore the extended task context.

The embOS kernel pushes during the context switch the task context on the task stack. The stack pointer value after the push operation is stored in the task control block and passed to the Save routine. The Save routine pushes the extended task context data onto the task stack. To do so it must reserve the necessary bytes on the task stack and return the adjusted stack pointer. The adjusted stack pointer is used for the next task context extension Save routine (if any).

The Restore routines are executed in the same order. For example task context extensions A, B and C are used. When the kernel saves the task context the Save routines of task context extensions A, B and C are called. When the kernel restores the task context the Restore routines of the task context extensions A, B and C are called in the same order.

The embOS OS_LIBMODE_XR library mode does not support task context extension.

Note

The task context can be extended only once per task with OS_TASK_SetContextExtension(). The function must not be called multiple times for one task. Additional task context extensions can be set with OS_TASK_AddContextExtension().

Note

embOS interrupts must not be enabled in the save and restore functions.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

116: OS_ERR_EXTEND_CONTEXT
128: OS_ERR_INV_TASK
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

#include "RTOS.h"

//
// Custom structure with task context extension.
// In this case, the extended task context consists of just
// a single member, which is a global variable.
//
typedef struct {
  int GlobalVar;
} CONTEXT_EXTENSION;

static OS_STACKPTR int StackHP[128], StackLP[128];  // Task stacks
static OS_TASK         TCBHP, TCBLP;                // Task control blocks
static int             GlobalVar;

static void OS_STACKPTR* _Save(void OS_STACKPTR* pStack) {
  CONTEXT_EXTENSION* p;

  p = (CONTEXT_EXTENSION*)pStack;
#if (OS_STACK_GROWS_TOWARD_HIGHER_ADDR == 1)
  p++;
#else
  p--;
#endif
  p->GlobalVar = GlobalVar;
  return (void OS_STACKPTR*)p;
}

static void OS_STACKPTR* _Restore(const void OS_STACKPTR* pStack) {
  const CONTEXT_EXTENSION* p;

  p = (CONTEXT_EXTENSION*)pStack;
#if (OS_STACK_GROWS_TOWARD_HIGHER_ADDR == 1)
  p++;
#else
  p--;
#endif
  GlobalVar = p->GlobalVar;
  return (void OS_STACKPTR*)p;
}

const OS_EXTEND_TASK_CONTEXT _SaveRestore = {
  _Save,    // Function pointer to save the task context
  _Restore  // Function pointer to restore the task context
};

static void HPTask(void) {
  OS_TASK_SetContextExtension(&_SaveRestore);
  GlobalVar = 1;
  while (1) {
    OS_TASK_Delay_ms(10);
  }
}

static void LPTask(void) {
  OS_TASK_SetContextExtension(&_SaveRestore);
  GlobalVar = 2;
  while (1) {
    OS_TASK_Delay_ms(50);
  }
}

int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_TASK_CREATE(&TCBLP, "LP Task",  50, LPTask, StackLP);
  OS_Start();     // Start embOS
  return 0;
}

OS_TASK_SetDefaultContextExtension()

Description

Sets the specified context extension as the default task context extension.

Prototype

void OS_TASK_SetDefaultContextExtension
                             (OS_CONST_PTR OS_EXTEND_TASK_CONTEXT *pExtendContext);

Parameters

Parameter Description
pExtendContext Pointer to the OS_EXTEND_TASK_CONTEXT structure which contains the addresses of the specific save and restore functions that save and restore the extended task context during task switches.

Additional information

After calling this function all newly started tasks will automatically use this context extension. The same task context extension is used for all tasks.
pExtendContext, pExtendContext->pfSave and pExtendContext->pfRestore must not be NULL. An embOS debug build calls OS_Error(OS_ERR_EXTEND_CONTEXT) when one of the function pointers is NULL).

Note

embOS interrupts must not be enabled in the save and restore functions.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

116: OS_ERR_EXTEND_CONTEXT
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

extern const OS_EXTEND_TASK_CONTEXT _SaveRestore;

int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_SetDefaultContextExtension(&_SaveRestore);
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_TASK_CREATE(&TCBLP, "LP Task",  50, LPTask, StackLP);
  OS_Start();     // Start embOS
  return 0;
}

OS_TASK_SetDefaultStartHook()

Description

Sets a default hook routine which is executed before a task starts. May be used to perform additional initialization for newly created tasks.

Prototype

void OS_TASK_SetDefaultStartHook(OS_ROUTINE_VOID* pfRoutine);

Parameters

Parameter Description
pfRoutine Pointer to the routine of type OS_ROUTINE_VOID which shall be called when a task is started.

Additional information

After calling OS_TASK_SetDefaultStartHook() all newly created tasks will automatically call this hook routine when the tasks are started for the first time. The same hook routine is used for all tasks. If NULL is passed no hook routine gets executed.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void _HookRoutine(void) {  // This routine is automatically executed before
  DoSomething();           // HPTask() gets executed
}

void HPTask(void) {
  while (1) {
    OS_TASK_Delay_ms(10);
  }
}

int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_SetDefaultStartHook(_HookRoutine);  // Set task start hook routine
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_Start();     // Start embOS
  return 0;
}

OS_TASK_SetInitialSuspendCnt()

Description

Sets the initial suspend count for newly created tasks to 1 or 0. May be used to create tasks which are initially suspended.

Prototype

void OS_TASK_SetInitialSuspendCnt(OS_U8 SuspendCnt);

Parameters

Parameter Description
SuspendCnt 1: Tasks will be created in suspended state.
0: Tasks will be created normally, unsuspended.

Additional information

Can be called at any time from main(), any task, ISR or software timer. After calling this function with nonzero SuspendCnt, all newly created tasks will be automatically suspended with a suspend count of one. This function may be used to inhibit further task switches, which may be useful during system initialization.

Note

When this function is called from main() to initialize all tasks in suspended state, at least one task must be resumed before the system is started by a call of OS_Start(). The initial suspend count should be reset to allow normal creation of tasks before the system is started.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

//
// High priority task started first after OS_Start().
//
void InitTask(void) {
  OS_TASK_SuspendAll();             // Prevent execution of all other existing tasks.
  OS_TASK_SetInitialSuspendCnt(1);  // Prevent execution of subsequently created tasks.
  ...    // New tasks may be created, but will not execute.
  ...    // Even when InitTask() blocks itself, no other task may execute.
  OS_TASK_SetInitialSuspendCnt(0);  // Reset initial suspend count for new tasks.
  OS_TASK_ResumeAll();              // Resume all tasks that were blocked before or
                                    // were created in suspended state. May cause a
                                    // task switch.
  while (1) {
    ...  // Do the normal work.
  }
}

OS_TASK_SetName()

Description

Set the specified task name for the specified task. Allows modification of a task name at runtime.

Prototype

void OS_TASK_SetName(      OS_TASK* pTask,
                     const char*    sName);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK or NULL for the current task.
sName Pointer to a null-terminated string which is used as task name. embOS does not copy the task name, but uses the pointer exclusively.

Additional information

If NULL is passed for pTask, the currently running task is used. If this function is not called from a task context, no task might currently be running and there is no valid task. A debug build of embOS will call OS_Error() in this case. We suggest to call this function from a context other than the task context with a pointer to a valid task control block only.

When using an embOS build without task name support, OS_TASK_SetName() performs no modifications at all. The embOS OS_LIBMODE_XR library mode does not support task names.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void Task(void) {
  OS_TASK_SetName(NULL, "Initializer Task");
  while (1) {
    OS_TASK_Delay_ms(100);
  }
}

OS_TASK_SetPriority()

Description

Assigns the specified task priority to the specified task.

Prototype

void OS_TASK_SetPriority(OS_TASK*     pTask,
                         OS_TASK_PRIO Priority);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK or NULL for the current task.
Priority Priority of the task. Must be within the following range:
1 ≤ Priority ≤ 28 - 1 = 0xFF for 8/16-bit CPUs
1 ≤ Priority ≤ 232 - 1 = 0xFFFFFFFF for 32-bit CPUs
Higher values indicate higher priorities. The type OS_TASK_PRIO is defined as 32-bit value for 32-bit CPUs and 8-bit value for 8 or 16-bit CPUs per default.

Additional information

If NULL is passed for pTask, the currently running task is used. If this function is not called from a task context, no task might currently be running and there is no valid task. A debug build of embOS will call OS_Error() in this case. We suggest to call this function from a context other than the task context with a pointer to a valid task control block only.

Calling this function might lead to an immediate task switch.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void Task(void) {
  OS_TASK_SetPriority(NULL, 20);    // Change priority of this task to 20.
  while (1) {
    OS_TASK_Delay_ms(100);
  }
}

OS_TASK_SetTimeSlice()

Description

Assigns the specified time-slice period to a specified task.

Prototype

OS_U8 OS_TASK_SetTimeSlice(OS_TASK* pTask,
                           OS_U8    TimeSlice);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK or NULL for the current task.
TimeSlice New time slice period for the task in milliseconds. Must be within the following range:
0 ≤ TimeSlice ≤ 255.

Return value

Previous time slice period of the task in milliseconds.

Additional information

If NULL is passed for pTask, the currently running task is used. If this function is not called from a task context, no task might currently be running and there is no valid task. A debug build of embOS will call OS_Error() in this case. We suggest to call this function from a context other than the task context with a pointer to a valid task control block only.

Setting the time slice period only affects tasks running in round-robin mode. The new time slice period is interpreted as a reload value: It is used with the next activation of the task, but does does not affect the remaining time slice of a running task.

A time slice value of zero is allowed, but disables round-robin task switches (see Disabling preemptive task switches for tasks of equal priority).

OS_TASK_SetTimeSlice() assigns a time-slice only when using an embOS build with round-robin support. The return value is valid only when using an embOS build without round-robin support. The embOS OS_LIBMODE_XR library mode does not support round-robin. In all other builds it will be 0.

In an embOS build with round-robin support, OS_TIME_ConfigSysTimer() must have been called before calling OS_TASK_SetTimeSlice().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Task(void) {
  OS_TASK_SetTimeSlice(NULL, 4);    // Give this task a higher time slice
  while (1) {
    OS_TASK_Delay_ms(100);
  }
}

OS_TASK_Suspend()

Description

Suspends the specified task and increments the task’s suspend count.

Prototype

void OS_TASK_Suspend(OS_TASK* pTask);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK.

Additional information

If NULL is passed for pTask, the currently running task is used. If this function is not called from a task context, no task might currently be running and there is no valid task. A debug build of embOS will call OS_Error() in this case. We suggest to call this function from a context other than the task context with a pointer to a valid task control block only.

Execution of the specified task is suspended immediately and the task’s suspend count is incremented. The task can only be restarted by a call of OS_TASK_Resume() or OS_TASK_ResumeAll().
Every task has a suspend count with a maximum value of 3, thus you must not call OS_TASK_Suspend() more often than the maximum value without calling OS_TASK_Resume(). OS_TASK_Suspend() must not be called from an interrupt handler or software timer as this function may cause an immediate task switch.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
200: OS_ERR_SUSPEND_TOO_OFTEN

For details, refer to the chapter Runtime application errors.

Example

void HighPrioTask(void) {
  OS_TASK_Suspend(NULL);         // Suspends itself, low priority task will be executed
}

void LowPrioTask(void) {
  OS_TASK_Resume(&HighPrioTCB);  // Resumes the high priority task
}

OS_TASK_SuspendAll()

Description

Suspends all tasks except the running task.

Prototype

void OS_TASK_SuspendAll(void);

Additional information

This function may be used to inhibit task switches. It may be useful during application initialization or supervising.
The calling task will not be suspended.
After calling OS_TASK_SuspendAll(), the calling task may block or suspend itself. No other task will be activated unless one or more tasks are resumed again. The tasks may be resumed individually by a call of OS_TASK_Resume() or all at once by a call of OS_TASK_ResumeAll().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example of OS_TASK_SetInitialSuspendCnt().

OS_TASK_Terminate()

Description

Ends (terminates) the specified task.

Prototype

void OS_TASK_Terminate(OS_TASK* pTask);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK. A value of NULL terminates the current task.

Additional information

The specified task will terminate immediately. The memory used for stack and task control block can be reassigned.

All resources which are held by a task are released upon its termination. Any task may be terminated regardless of its state.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void Task(void) {
  OS_TASK_Terminate(&TCBHP);  // Terminate HPTask()
  DoSomething();
  OS_TASK_Terminate(NULL);    // Terminate itself
}

OS_TASK_Wake()

Description

Ends delay of the specified task immediately.

Prototype

void OS_TASK_Wake(OS_TASK* pTask);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK.

Additional information

Places the specified task, which is already suspended for a certain amount of time by a call to OS_TASK_Delay(), OS_TASK_Delay_ms(), OS_TASK_Delay_ns(), OS_TASK_Delay_us(), OS_TASK_Delay_Cycles(), OS_TASK_DelayUntil(), OS_TASK_DelayUntil_ms(), OS_TASK_DelayUntil_ns(), OS_TASK_DelayUntil_us(), or OS_TASK_DelayUntil_Cycles() back into the READY state.
The specified task will be activated immediately if it has a higher priority than the task that had the highest priority before. If the specified task is not in the WAITING state (e.g. when it has already been activated, or the delay has already expired, or for some other reason), calling this function has no effect.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
161: OS_ERR_ILLEGAL_IN_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

#include "RTOS.h"

static OS_STACKPTR int StackHP[128], StackLP[128];  // Task stacks
static OS_TASK         TCBHP, TCBLP;                // Task control blocks

static void HPTask(void) {
  while (1) {
    OS_TASK_Delay_ms(50);
  }
}

static void LPTask(void) {
  while (1) {
    OS_TASK_Delay_ms(10);
    OS_TASK_Wake(&TCBHP);  // Wake HPTask() which is in delay state
  }
}

/*********************************************************************
*
*       main()
*/
int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_TASK_CREATE(&TCBLP, "LP Task",  50, LPTask, StackLP);
  OS_Start();     // Start embOS
  return 0;
}

OS_TASK_Yield()

Description

Calls the scheduler to force a task switch.

Prototype

void OS_TASK_Yield(void);

Additional information

If the task is running on round-robin, it will be suspended if there is another task with equal priority ready for execution.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

#include "RTOS.h"

static OS_STACKPTR int StackHP[128], StackLP[128];  // Task stacks
static OS_TASK         TCBHP, TCBLP;                // Task control blocks

static void HPTask(void) {
  while (1) {
    DoSomething();
  }
}

static void LPTask(void) {
  while (1) {
    DoSomethingElse();
    //
    // This task doesn't need the complete time slice.
    // Give another task with the same priority the chance to run
    //
    OS_TASK_Yield();
  }
}

/*********************************************************************
*
*       main()
*/
int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_TASK_CREATE(&TCBLP, "LP Task", 100, LPTask, StackLP);
  OS_Start();     // Start embOS
  return 0;
}

Software Timer

Introduction

A software timer is an object that calls a user-specified routine after a specified delay. An unlimited number of software timers can be created.

embOS software timers can be stopped, started and re-triggered much like hardware timers. When defining a timer, you specify a routine to be called after the expiration of the delay. Timer routines are similar to interrupt routines: they have a priority higher than the priority of any task. For that reason they should be kept short just like interrupt routines.

Software timers are called by embOS with interrupts enabled, so they can be interrupted by any hardware interrupt. But software timers run to completion and cannot interrupt each other or be interrupted by a preemptive task switch. Generally, software timer run in single-shot mode, which means they expire exactly once and call their callback routine exactly once. By calling OS_TIMER_Restart() from within the callback routine, the timer is restarted with its initial delay time and therefore functions as a periodic timer.

The state of timers can be checked by the functions OS_TIMER_GetStatus(), OS_TIMER_GetRemainingPeriod_Cycles(), OS_TIMER_GetRemainingPeriod_ms(), OS_TIMER_GetRemainingPeriod_ns(), OS_TIMER_GetRemainingPeriod_us(), OS_TIMER_GetPeriod_Cycles(), OS_TIMER_GetPeriod_ms(), OS_TIMER_GetPeriod_ns(), and OS_TIMER_GetPeriod_us().

Example

#include "RTOS.h"
#include "BSP.h"

static OS_TIMER Timer0, Timer1;

static void Callback0(void) {
  BSP_ToggleLED(0);
  OS_TIMER_Restart(&Timer0);
}

static void Callback1(void) {
  BSP_ToggleLED(1);
  OS_TIMER_Restart(&Timer1);
}

int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  BSP_Init();     // Initialize LED ports
  OS_TIMER_Create_ms(&Timer0, Callback0,  50u);
  OS_TIMER_Start(&Timer0);
  OS_TIMER_Create_ms(&Timer1, Callback1, 200u);
  OS_TIMER_Start(&Timer1);
  OS_Start();     // Start embOS
  return 0;
}

Extended software timers

Sometimes it may be useful to pass a parameter to the timer callback function. This allows the callback function to be shared between different software timers. Since version 3.32m of embOS, the extended timer structure and related extended timer functions were implemented to allow parameter passing to the callback function. Except for the different callback function with parameter passing, extended timers behave exactly the same as regular embOS software timers and may be used in parallel with these.

Example

#include "RTOS.h"
#include "BSP.h"

static OS_TIMER_EX TimerEx0, TimerEx1;

static void Callback(void* Led) {
  BSP_ToggleLED((int)Led);
  OS_TIMER_RestartEx(OS_TIMER_GetCurrentEx());
}

int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  BSP_Init();     // Initialize LED ports
  OS_TIMER_CreateEx_ms(&TimerEx0, Callback,  50u, (void*)0);
  OS_TIMER_StartEx(&TimerEx0);
  OS_TIMER_CreateEx_ms(&TimerEx1, Callback, 200u, (void*)1);
  OS_TIMER_StartEx(&TimerEx1);
  OS_Start();     // Start embOS
  return 0;
}

Note

embOS software timers can be configured for arbitrary periods either in milliseconds, microseconds, nanoseconds, or cycles. Internally, however, any software timer period is held in cycles. This requires conversion of any period given in milli-, nano- or microseconds. Due to using finite-precision arithmetic, that conversion is prone to roundoff errors: Depending on the frequency of the used hardware counter, the conversion may result in a software timer period that is short by a maximum of one single cycle. If this needs to be avoided by the application, the timer period should be configured in cycles by using appropriate software timer API functions.

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_TIMER_Create_Cycles() Creates a software timer without starting it.
OS_TIMER_Create_ms() Creates a software timer without starting it.
OS_TIMER_Create_ns() Creates a software timer without starting it.
OS_TIMER_Create_us() Creates a software timer without starting it.
OS_TIMER_CreateEx_Cycles() Creates an extended software timer without starting it.
OS_TIMER_CreateEx_ms() Creates an extended software timer without starting it.
OS_TIMER_CreateEx_ns() Creates an extended software timer without starting it.
OS_TIMER_CreateEx_us() Creates an extended software timer without starting it.
OS_TIMER_Delete() Stops and deletes the specified software timer.
OS_TIMER_DeleteEx() Stops and deletes an extended software timer.
OS_TIMER_GetCurrent() Returns a pointer to the data structure of the timer that just expired.
OS_TIMER_GetCurrentEx() Returns a pointer to the data structure of the extended software timer that just expired.
OS_TIMER_GetPeriod_Cycles() Returns the reload value of the specified software timer in cycles.
OS_TIMER_GetPeriod_ms() Returns the reload value of the specified software timer in milliseconds.
OS_TIMER_GetPeriod_ns() Returns the reload value of the specified software timer in nanoseconds.
OS_TIMER_GetPeriod_us() Returns the reload value of the specified software timer in microseconds.
OS_TIMER_GetPeriodEx_Cycles() Returns the reload value of an extended software timer in cycles.
OS_TIMER_GetPeriodEx_ms() Returns the reload value of an extended software timer in milliseconds.
OS_TIMER_GetPeriodEx_ns() Returns the reload value of an extended software timer in nanoseconds.
OS_TIMER_GetPeriodEx_us() Returns the reload value of an extended software timer in microseconds.
OS_TIMER_GetRemainingPeriod_Cycles() Returns the remaining timer value of the specified software timer in cycles.
OS_TIMER_GetRemainingPeriod_ms() Returns the remaining timer value of the specified software timer in milliseconds.
OS_TIMER_GetRemainingPeriod_ns() Returns the remaining timer value of the specified software timer in nanoseconds.
OS_TIMER_GetRemainingPeriod_us() Returns the remaining timer value of the specified software timer in microseconds.
OS_TIMER_GetRemainingPeriodEx_Cycles() Returns the remaining timer value of an extended software timer in cycles.
OS_TIMER_GetRemainingPeriodEx_ms() Returns the remaining timer value of an extended software timer in milliseconds.
OS_TIMER_GetRemainingPeriodEx_ns() Returns the remaining timer value of an extended software timer in nanoseconds.
OS_TIMER_GetRemainingPeriodEx_us() Returns the remaining timer value of an extended software timer in microseconds.
OS_TIMER_GetStatus() Returns the current timer status of the specified software timer.
OS_TIMER_GetStatusEx() Returns the current timer status of an extended software timer.
OS_TIMER_Restart() Restarts the specified software timer with its initial time value.
OS_TIMER_RestartEx() Restarts an extended software timer with its initial time value.
OS_TIMER_SetPeriod_Cycles() Sets a new timer reload value for the specified software timer in cycles.
OS_TIMER_SetPeriod_ms() Sets a new timer reload value for the specified software timer in milliseconds.
OS_TIMER_SetPeriod_ns() Sets a new timer reload value for the specified software timer in nanoseconds.
OS_TIMER_SetPeriod_us() Sets a new timer reload value for the specified software timer in microseconds.
OS_TIMER_SetPeriodEx_Cycles() Sets a new timer reload value for an extended software timer in cycles.
OS_TIMER_SetPeriodEx_ms() Sets a new timer reload value for an extended software timer in milliseconds.
OS_TIMER_SetPeriodEx_ns() Sets a new timer reload value for an extended software timer in nanoseconds.
OS_TIMER_SetPeriodEx_us() Sets a new timer reload value for an extended software timer in microseconds.
OS_TIMER_Start() Starts the specified software timer.
OS_TIMER_StartEx() Starts an extended software timer.
OS_TIMER_Stop() Stops the specified software timer.
OS_TIMER_StopEx() Stops an extended software timer.
OS_TIMER_Trigger() Ends the specified software timer at once and calls the timer callback function.
OS_TIMER_TriggerEx() Ends an extended software timer at once and calls the timer callback function.

OS_TIMER_Create_Cycles()

Description

Creates a software timer without starting it.

Prototype

void OS_TIMER_Create_Cycles(OS_TIMER*        pTimer,
                            OS_ROUTINE_VOID* pfTimerRoutine,
                            OS_U32           Cycles);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.
pfTimerRoutine Pointer to the routine of type OS_ROUTINE_VOID which shall be called by the kernel after the timer period has expired.
Cycles Initial period in cycles. Must not be zero.

Additional information

Once the period has expired, the callback routine will be called immediately (unless the current task is in a critical region or has interrupts disabled). The timer is not automatically started. This must be done explicitly by a call of OS_TIMER_Start() or OS_TIMER_Restart().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_Create_Cycles().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
171: OS_ERR_2USE_TIMER
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER Timer;

static void Callback(void) {
  BSP_ToggleLED(0);
  OS_TIMER_Restart(&Timer);  // Make timer periodic
}

void InitFunc(void) {
  OS_TIMER_Create_Cycles(&Timer, Callback, 48000000u);
  OS_TIMER_Start(&Timer);
}

OS_TIMER_Create_ms()

Description

Creates a software timer without starting it.

Prototype

void OS_TIMER_Create_ms(OS_TIMER*        pTimer,
                        OS_ROUTINE_VOID* pfTimerRoutine,
                        OS_U32           ms);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.
pfTimerRoutine Pointer to the routine of type OS_ROUTINE_VOID which shall be called by the kernel after the timer period has expired.
ms Initial period in milliseconds. Must not be zero.

Additional information

Once the period has expired, the callback routine will be called immediately (unless the current task is in a critical region or has interrupts disabled). The timer is not automatically started. This must be done explicitly by a call of OS_TIMER_Start() or OS_TIMER_Restart().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_Create_ms().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
171: OS_ERR_2USE_TIMER
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER Timer;

static void Callback(void) {
  BSP_ToggleLED(0);
  OS_TIMER_Restart(&Timer);  // Make timer periodic
}

void InitFunc(void) {
  OS_TIMER_Create_ms(&Timer, Callback, 100u);
  OS_TIMER_Start(&Timer);
}

OS_TIMER_Create_ns()

Description

Creates a software timer without starting it.

Prototype

void OS_TIMER_Create_ns(OS_TIMER*        pTimer,
                        OS_ROUTINE_VOID* pfTimerRoutine,
                        OS_U32           ns);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.
pfTimerRoutine Pointer to the routine of type OS_ROUTINE_VOID which shall be called by the kernel after the timer period has expired.
ms Initial period in nanoseconds. Must not be zero.

Additional information

Once the period has expired, the callback routine will be called immediately (unless the current task is in a critical region or has interrupts disabled). The timer is not automatically started. This must be done explicitly by a call of OS_TIMER_Start() or OS_TIMER_Restart().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_Create_ns().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
171: OS_ERR_2USE_TIMER
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER Timer;

static void Callback(void) {
  BSP_ToggleLED(0);
  OS_TIMER_Restart(&Timer);  // Make timer periodic
}

void InitFunc(void) {
  OS_TIMER_Create_ns(&Timer, Callback, 100000000u);
  OS_TIMER_Start(&Timer);
}

OS_TIMER_Create_us()

Description

Creates a software timer without starting it.

Prototype

void OS_TIMER_Create_us(OS_TIMER*        pTimer,
                        OS_ROUTINE_VOID* pfTimerRoutine,
                        OS_U32           us);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.
pfTimerRoutine Pointer to the routine of type OS_ROUTINE_VOID which shall be called by the kernel after the timer period has expired.
us Initial period in microseconds. Must not be zero.

Additional information

Once the period has expired, the callback routine will be called immediately (unless the current task is in a critical region or has interrupts disabled). The timer is not automatically started. This must be done explicitly by a call of OS_TIMER_Start() or OS_TIMER_Restart().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_Create_us().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
171: OS_ERR_2USE_TIMER
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER Timer;

static void Callback(void) {
  BSP_ToggleLED(0);
  OS_TIMER_Restart(&Timer);  // Make timer periodic
}

void InitFunc(void) {
  OS_TIMER_Create_us(&Timer, Callback, 100000u);
  OS_TIMER_Start(&Timer);
}

OS_TIMER_CreateEx_Cycles()

Description

Creates an extended software timer without starting it.

Prototype

void OS_TIMER_CreateEx_Cycles(OS_TIMER_EX*         pTimerEx,
                              OS_ROUTINE_VOID_PTR* pfTimerRoutine,
                              OS_U32               Cycles,
                              void*                pData);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.
pfTimerRoutine Pointer to the routine of type OS_ROUTINE_VOID_PTR which shall be called by the kernel after the timer period has expired.
Cycles Initial period in cycles. Must not be zero.
pData A void pointer which is used as parameter for the extended timer callback function.

Additional information

Once the period has expired, the callback routine will be called immediately (unless the current task is in a critical region or has interrupts disabled). The timer is not automatically started. This must be done explicitly by a call of OS_TIMER_Start() or OS_TIMER_Restart().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_CreateEx_Cycles().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
171: OS_ERR_2USE_TIMER
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER_EX TimerEx0, TimerEx1;

static void Callback(void* pData) {
  BSP_ToggleLED((int)pData);
  OS_TIMER_RestartEx(NULL);  // Make timer periodic
}

void InitFunc(void) {
  OS_TIMER_CreateEx_Cycles(&TimerEx0, Callback, 12000000u, (void*)0);
  OS_TIMER_StartEx(&TimerEx0);
  OS_TIMER_CreateEx_Cycles(&TimerEx1, Callback, 48000000u, (void*)1);
  OS_TIMER_StartEx(&TimerEx1);
}

OS_TIMER_CreateEx_ms()

Description

Creates an extended software timer without starting it.

Prototype

void OS_TIMER_CreateEx_ms(OS_TIMER_EX*         pTimerEx,
                          OS_ROUTINE_VOID_PTR* pfTimerRoutine,
                          OS_U32               ms,
                          void*                pData);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.
pfTimerRoutine Pointer to the routine of type OS_ROUTINE_VOID_PTR which shall be called by the kernel after the timer period has expired.
ms Initial period in milliseconds. Must not be zero.
pData A void pointer which is used as parameter for the extended timer callback function.

Additional information

Once the period has expired, the callback routine will be called immediately (unless the current task is in a critical region or has interrupts disabled). The timer is not automatically started. This must be done explicitly by a call of OS_TIMER_Start() or OS_TIMER_Restart().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_CreateEx_ms().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
171: OS_ERR_2USE_TIMER
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER_EX TimerEx0, TimerEx1;

static void Callback(void* pData) {
  BSP_ToggleLED((int)pData);
  OS_TIMER_RestartEx(NULL);  // Make timer periodic
}

void InitTask(void) {
  OS_TIMER_CreateEx_ms(&TimerEx0, Callback,  50u, (void*)0);
  OS_TIMER_StartEx(&TimerEx0);
  OS_TIMER_CreateEx_ms(&TimerEx1, Callback, 200u, (void*)1);
  OS_TIMER_StartEx(&TimerEx1);
}

OS_TIMER_CreateEx_ns()

Description

Creates an extended software timer without starting it.

Prototype

void OS_TIMER_CreateEx_ns(OS_TIMER_EX*         pTimerEx,
                          OS_ROUTINE_VOID_PTR* pfTimerRoutine,
                          OS_U32               ns,
                          void*                pData);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.
pfTimerRoutine Pointer to the routine of type OS_ROUTINE_VOID_PTR which shall be called by the kernel after the timer period has expired.
ns Initial period in nanoseconds. Must not be zero.
pData A void pointer which is used as parameter for the extended timer callback function.

Additional information

Once the period has expired, the callback routine will be called immediately (unless the current task is in a critical region or has interrupts disabled). The timer is not automatically started. This must be done explicitly by a call of OS_TIMER_Start() or OS_TIMER_Restart().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_CreateEx_ns().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
171: OS_ERR_2USE_TIMER
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER_EX TimerEx0, TimerEx1;

static void Callback(void* pData) {
  BSP_ToggleLED((int)pData);
  OS_TIMER_RestartEx(NULL);  // Make timer periodic
}

void InitFunc(void) {
  OS_TIMER_CreateEx_ns(&TimerEx0, Callback,  50000000u, (void*)0);
  OS_TIMER_StartEx(&TimerEx0);
  OS_TIMER_CreateEx_ns(&TimerEx1, Callback, 200000000u, (void*)1);
  OS_TIMER_StartEx(&TimerEx1);
}

OS_TIMER_CreateEx_us()

Description

Creates an extended software timer without starting it.

Prototype

void OS_TIMER_CreateEx_us(OS_TIMER_EX*         pTimerEx,
                          OS_ROUTINE_VOID_PTR* pfTimerRoutine,
                          OS_U32               us,
                          void*                pData);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.
pfTimerRoutine Pointer to the routine of type OS_ROUTINE_VOID_PTR which shall be called by the kernel after the timer period has expired.
us Initial period in microseconds. Must not be zero.
pData A void pointer which is used as parameter for the extended timer callback function.

Additional information

Once the period has expired, the callback routine will be called immediately (unless the current task is in a critical region or has interrupts disabled). The timer is not automatically started. This must be done explicitly by a call of OS_TIMER_Start() or OS_TIMER_Restart().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_CreateEx_us().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
171: OS_ERR_2USE_TIMER
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER_EX TimerEx0, TimerEx1;

static void Callback(void* pData) {
  BSP_ToggleLED((int)pData);
  OS_TIMER_RestartEx(NULL);  // Make timer periodic
}

void InitFunc(void) {
  OS_TIMER_CreateEx_us(&TimerEx0, Callback,  50000u, (void*)0);
  OS_TIMER_StartEx(&TimerEx0);
  OS_TIMER_CreateEx_us(&TimerEx1, Callback, 200000u, (void*)1);
  OS_TIMER_StartEx(&TimerEx1);
}

OS_TIMER_Delete()

Description

Stops and deletes the specified software timer.

Prototype

void OS_TIMER_Delete(OS_TIMER* pTimer);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.

Additional information

The timer is stopped and therefore removed from the linked list of running timers.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER Timer;

void Task(void) {
  //
  // Create and implicitly start timer
  //
  OS_TIMER_Create_ms(&Timer, Callback, 100u);
  ...
  //
  // Delete timer
  //
  OS_TIMER_Delete(&Timer);
}

OS_TIMER_DeleteEx()

Description

Stops and deletes an extended software timer.

Prototype

void OS_TIMER_DeleteEx(OS_TIMER_EX* pTimerEx);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.

Additional information

The extended software timer is stopped and removed from the linked list of running timers. In debug builds of embOS, the timer is also marked invalid.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER_EX TimerEx;

void Task(void) {
  //
  // Create and implicitly start timer
  //
  OS_TIMER_CreateEx_ms(&TimerEx, Callback, 100u, (void*)&TCB);
  OS_TIMER_StartEx(&TimerEx);
  ...
  //
  // Delete timer
  //
  OS_TIMER_DeleteEx(&TimerEx);
}

OS_TIMER_GetCurrent()

Description

Returns a pointer to the software timer object whose callback is currently executing.

Prototype

OS_TIMER *OS_TIMER_GetCurrent(void);

Return value

= NULL No software timer callback is currently being executed.
NULL Pointer to the software timer object of type OS_TIMER.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

#include "RTOS.h"

static OS_TIMER Timer0, Timer1;

static void Callback(void) {
  OS_TIMER* pTimer = OS_TIMER_GetCurrent();
  OS_TIMER_Restart(pTimer);  // Make timer periodic
}

int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TIMER_Create_ms(&Timer0, Callback,  50u);
  OS_TIMER_Start(&Timer0);
  OS_TIMER_Create_ms(&Timer1, Callback, 200u);
  OS_TIMER_Start(&Timer1);
  OS_Start();     // Start embOS
  return 0;
}

OS_TIMER_GetCurrentEx()

Description

Returns a pointer to the extended software timer object whose callback is currently executing.

Prototype

OS_TIMER_EX* OS_TIMER_GetCurrentEx(void);

Return value

= NULL No software timer callback is currently being executed.
NULL Pointer to the software timer object of type OS_TIMER_EX.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

#include "RTOS.h"

static OS_TIMER_EX TimerEx0, TimerEx1;

static void Callback(void* pData) {
  OS_TIMER* pTimerEx = OS_TIMER_GetCurrentEx();
  OS_TIMER_RestartEx(pTimerEx);  // Make timer periodic
}

int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TIMER_CreateEx_ms(&TimerEx0, Callback,  50u, (void*)0);
  OS_TIMER_StartEx(&TimerEx0);
  OS_TIMER_CreateEx_ms(&TimerEx1, Callback, 200u, (void*)1);
  OS_TIMER_StartEx(&TimerEx0);
  OS_Start();     // Start embOS
  return 0;
}

OS_TIMER_GetPeriod_Cycles()

Description

Returns the reload value of the specified software timer in cycles.

Prototype

OS_U64 OS_TIMER_GetPeriod_Cycles(OS_CONST_PTR OS_TIMER *pTimer);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.

Return value

The returned value is the reload value of a software timer in cycles.

Additional information

The period returned is the reload value of the timer which was set as initial value when the timer was created or which was modified by a call of OS_TIMER_SetPeriod(), OS_TIMER_SetPeriod_Cycles(), OS_TIMER_SetPeriod_ms(), OS_TIMER_SetPeriod_ns(), or OS_TIMER_SetPeriod_us(). This reload value will be used as time period when the timer is retriggered by OS_TIMER_Restart().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetPeriod_Cycles().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintPeriod(OS_TIMER* pTimer) {
  int period;

  period = OS_TIMER_GetPeriod_Cycles(pTimer);
  printf("Period is %u cycles.\n", period);
}

OS_TIMER_GetPeriod_ms()

Description

Returns the reload value of the specified software timer in milliseconds.

Prototype

OS_U32 OS_TIMER_GetPeriod_ms(OS_CONST_PTR OS_TIMER *pTimer);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.

Return value

The returned value is the reload value of a software timer in milliseconds.

Additional information

The period returned is the reload value of the timer which was set as initial value when the timer was created or which was modified by a call of OS_TIMER_SetPeriod(), OS_TIMER_SetPeriod_Cycles(), OS_TIMER_SetPeriod_ms(), OS_TIMER_SetPeriod_ns(), or OS_TIMER_SetPeriod_us(). However, due to finite integer arithmetic being used (both when converting milliseconds into cycles and when converting cycles into milliseconds), the returned period can be prone to rounding errors if the target’s counter frequency is not a multiple of 1 kHz. This reload value will be used as time period when the timer is retriggered by OS_TIMER_Restart().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetPeriod_ms().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintPeriod(OS_TIMER* pTimer) {
  int period;

  period = OS_TIMER_GetPeriod_ms(pTimer);
  printf("Period is %u milliseconds.\n", period);
}

OS_TIMER_GetPeriod_ns()

Description

Returns the reload value of the specified software timer in nanoseconds.

Prototype

OS_U64 OS_TIMER_GetPeriod_ns(OS_CONST_PTR OS_TIMER *pTimer);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.

Return value

The returned value is the reload value of a software timer in nanoseconds.

Additional information

The period returned is the reload value of the timer which was set as initial value when the timer was created or which was modified by a call of OS_TIMER_SetPeriod(), OS_TIMER_SetPeriod_Cycles(), OS_TIMER_SetPeriod_ms(), OS_TIMER_SetPeriod_ns(), or OS_TIMER_SetPeriod_us(). However, due to finite integer arithmetic being used (both when converting nanoseconds into cycles and when converting cycles into nanoseconds), the returned period can be prone to rounding errors if the target’s counter frequency is not a multiple of 1 kHz. This reload value will be used as time period when the timer is retriggered by OS_TIMER_Restart().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetPeriod_ns().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintPeriod(OS_TIMER* pTimer) {
  int period;

  period = OS_TIMER_GetPeriod_ns(pTimer);
  printf("Period is %u nanoseconds.\n", period);
}

OS_TIMER_GetPeriod_us()

Description

Returns the reload value of the specified software timer in microseconds.

Prototype

OS_U64 OS_TIMER_GetPeriod_us(OS_CONST_PTR OS_TIMER *pTimer);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.

Return value

The returned value is the reload value of a software timer in microseconds.

Additional information

The period returned is the reload value of the timer which was set as initial value when the timer was created or which was modified by a call of OS_TIMER_SetPeriod(), OS_TIMER_SetPeriod_Cycles(), OS_TIMER_SetPeriod_ms(), OS_TIMER_SetPeriod_ns(), or OS_TIMER_SetPeriod_us(). However, due to finite integer arithmetic being used (both when converting microseconds into cycles and when converting cycles into microseconds), the returned period can be prone to rounding errors if the target’s counter frequency is not a multiple of 1 kHz. This reload value will be used as time period when the timer is retriggered by OS_TIMER_Restart().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetPeriod_us().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintPeriod(OS_TIMER* pTimer) {
  int period;

  period = OS_TIMER_GetPeriod_us(pTimer);
  printf("Period is %u microseconds.\n", period);
}

OS_TIMER_GetPeriodEx_Cycles()

Description

Returns the current reload value of an extended software timer in cycles.

Prototype

OS_TIME OS_TIMER_GetPeriodEx_Cycles(OS_CONST_PTR OS_TIMER_EX* pTimerEx);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.

Return value

The returned value is the current reload value of an extended software timer in cycles.

Additional information

The period returned is the reload value of the timer which was set as initial value when the timer was created or which was modified by a call of OS_TIMER_SetPeriodEx_Cycles(), OS_TIMER_SetPeriodEx_ms(), OS_TIMER_SetPeriodEx_ns(), or OS_TIMER_SetPeriodEx_us(). This reload value will be used as time period when the timer is re-triggered by OS_TIMER_RestartEx().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetPeriodEx_Cycles().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintPeriodEx(OS_TIMER_EX* pTimerEx) {
  int period;

  period = OS_TIMER_GetPeriodEx_Cycles(pTimerEx);
  printf("Period is %u cycles.\n", period);
}

OS_TIMER_GetPeriodEx_ms()

Description

Returns the reload value of an extended software timer in milliseconds.

Prototype

OS_TIME OS_TIMER_GetPeriodEx_ms(OS_CONST_PTR OS_TIMER_EX* pTimerEx);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.

Return value

The returned value is the current reload value of an extended software timer in milliseconds.

Additional information

The period returned is the reload value of the timer which was set as initial value when the timer was created or which was modified by a call of OS_TIMER_SetPeriodEx(), OS_TIMER_SetPeriodEx_Cycles(), OS_TIMER_SetPeriodEx_ms(), or OS_TIMER_SetPeriodEx_us(). This reload value will be used as time period when the timer is re-triggered by OS_TIMER_RestartEx().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetPeriodEx_ms().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintPeriodEx(OS_TIMER_EX* pTimerEx) {
  int period;

  period = OS_TIMER_GetPeriodEx_ms(pTimerEx);
  printf("Period is %u milliseconds.\n", period);
}

OS_TIMER_GetPeriodEx_ns()

Description

Returns the reload value of an extended software timer in nanoseconds.

Prototype

OS_TIME OS_TIMER_GetPeriodEx_ns(OS_CONST_PTR OS_TIMER_EX* pTimerEx);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.

Return value

The returned value is the current reload value of an extended software timer in nanoseconds.

Additional information

The period returned is the reload value of the timer which was set as initial value when the timer was created or which was modified by a call of OS_TIMER_SetPeriodEx(), OS_TIMER_SetPeriodEx_Cycles(), OS_TIMER_SetPeriodEx_ms(), or OS_TIMER_SetPeriodEx_us(). This reload value will be used as time period when the timer is re-triggered by OS_TIMER_RestartEx().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetPeriodEx_ns().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintPeriodEx(OS_TIMER_EX* pTimerEx) {
  int period;

  period = OS_TIMER_GetPeriodEx_ns(pTimerEx);
  printf("Period is %u nanoseconds.\n", period);
}

OS_TIMER_GetPeriodEx_us()

Description

Returns the reload value of an extended software timer in microseconds.

Prototype

OS_TIME OS_TIMER_GetPeriodEx_us(OS_CONST_PTR OS_TIMER_EX* pTimerEx);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.

Return value

The returned value is the current reload value of an extended software timer in microseconds.

Additional information

The period returned is the reload value of the timer which was set as initial value when the timer was created or which was modified by a call of OS_TIMER_SetPeriodEx(), OS_TIMER_SetPeriodEx_Cycles(), OS_TIMER_SetPeriodEx_ms(), or OS_TIMER_SetPeriodEx_us(). This reload value will be used as time period when the timer is re-triggered by OS_TIMER_RestartEx().

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetPeriodEx_us().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintPeriodEx(OS_TIMER_EX* pTimerEx) {
  int period;

  period = OS_TIMER_GetPeriodEx_us(pTimerEx);
  printf("Period is %u microseconds.\n", period);
}

OS_TIMER_GetRemainingPeriod_Cycles()

Description

Returns the remaining timer value of the specified software timer in cycles.

Prototype

OS_U64 OS_TIMER_GetRemainingPeriod_Cycles(OS_CONST_PTR OS_TIMER *pTimer);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.

Return value

The returned timer value is the remaining timer time in cycles until expiration of the timer.

Additional information

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetRemainingPeriod_Cycles().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintRemainingPeriod_Cycles(OS_TIMER* pTimer) {
  int period;

  period = OS_TIMER_GetRemainingPeriod_Cycles(pTimer);
  printf("Remaining period is %u cycles.\n", period);
}

OS_TIMER_GetRemainingPeriod_ms()

Description

Returns the remaining timer value of the specified software timer in milliseconds.

Prototype

OS_U32 OS_TIMER_GetRemainingPeriod_ms(OS_CONST_PTR OS_TIMER *pTimer);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.

Return value

The returned timer value is the remaining timer time in milliseconds until expiration of the timer.

Additional information

Due to finite integer arithmetic being used when converting cycles into milliseconds, the returned remaining period can be prone to rounding errors if the target’s counter frequency is not a multiple of 1 kHz.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetRemainingPeriod_ms().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintRemainingPeriod_ms(OS_TIMER* pTimer) {
  int period;

  period = OS_TIMER_GetRemainingPeriod_ms(pTimer);
  printf("Remaining period is %u milliseconds.\n", period);
}

OS_TIMER_GetRemainingPeriod_ns()

Description

Returns the remaining timer value of the specified software timer in nanoseconds.

Prototype

OS_U64 OS_TIMER_GetRemainingPeriod_ns(OS_CONST_PTR OS_TIMER *pTimer);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.

Return value

The returned timer value is the remaining timer time in nanoseconds until expiration of the timer.

Additional information

Due to finite integer arithmetic being used when converting cycles into nanoseconds, the returned remaining period can be prone to rounding errors if the target’s counter frequency is not a multiple of 1 kHz.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetRemainingPeriod_ns().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintRemainingPeriod_ms(OS_TIMER* pTimer) {
  int period;

  period = OS_TIMER_GetRemainingPeriod_ns(pTimer);
  printf("Remaining period is %u nanoseconds.\n", period);
}

OS_TIMER_GetRemainingPeriod_us()

Description

Returns the remaining timer value of the specified software timer in microseconds.

Prototype

OS_U64 OS_TIMER_GetRemainingPeriod_us(OS_CONST_PTR OS_TIMER *pTimer);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.

Return value

The returned timer value is the remaining timer time in microseconds until expiration of the timer.

Additional information

Due to finite integer arithmetic being used when converting cycles into microseconds, the returned remaining period can be prone to rounding errors if the target’s counter frequency is not a multiple of 1 kHz.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetRemainingPeriod_us().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintRemainingPeriod_us(OS_TIMER* pTimer) {
  int period;

  period = OS_TIMER_GetRemainingPeriod_us(pTimer);
  printf("Remaining period is %u microseconds.\n", period);
}

OS_TIMER_GetRemainingPeriodEx_Cycles()

Description

Returns the remaining timer value of an extended software timer in cycles.

Prototype

OS_TIME OS_TIMER_GetRemainingPeriodEx_Cycles(OS_CONST_PTR OS_TIMER_EX* pTimerEx);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.

Return value

The returned time value is the remaining timer value in cycles until expiration of the extended software timer.

Additional information

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetRemainingPeriodEx_Cycles().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintRemainingPeriodEx(OS_TIMER_EX* pTimerEx) {
  int period;

  period = OS_TIMER_GetRemainingPeriodEx_Cycles(pTimerEx);
  printf("Remaining period is %u cycles.\n", period);
}

OS_TIMER_GetRemainingPeriodEx_ms()

Description

Returns the remaining timer value of an extended software timer in milliseconds.

Prototype

OS_TIME OS_TIMER_GetRemainingPeriodEx_ms(OS_CONST_PTR OS_TIMER_EX* pTimerEx);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.

Return value

The returned time value is the remaining timer value in milliseconds until expiration of the extended software timer.

Additional information

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetRemainingPeriodEx_ms().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintRemainingPeriodEx(OS_TIMER_EX* pTimerEx) {
  int period;

  period = OS_TIMER_GetRemainingPeriodEx_ms(pTimerEx);
  printf("Remaining period is %u milliseconds.\n", period);
}

OS_TIMER_GetRemainingPeriodEx_ns()

Description

Returns the remaining timer value of an extended software timer in nanoseconds.

Prototype

OS_TIME OS_TIMER_GetRemainingPeriodEx_ns(OS_CONST_PTR OS_TIMER_EX* pTimerEx);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.

Return value

The returned time value is the remaining timer value in nanoseconds until expiration of the extended software timer.

Additional information

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetRemainingPeriodEx_ns().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintRemainingPeriodEx(OS_TIMER_EX* pTimerEx) {
  int period;

  period = OS_TIMER_GetRemainingPeriodEx_ns(pTimerEx);
  printf("Remaining period is %u nanoseconds.\n", period);
}

OS_TIMER_GetRemainingPeriodEx_us()

Description

Returns the remaining timer value of an extended software timer in microseconds.

Prototype

OS_TIME OS_TIMER_GetRemainingPeriodEx_us(OS_CONST_PTR OS_TIMER_EX* pTimerEx);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.

Return value

The returned time value is the remaining timer value in microseconds until expiration of the extended software timer.

Additional information

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_GetRemainingPeriodEx_us().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static void PrintRemainingPeriodEx(OS_TIMER_EX* pTimerEx) {
  int period;

  period = OS_TIMER_GetRemainingPeriodEx_us(pTimerEx);
  printf("Remaining period is %u microseconds.\n", period);
}

OS_TIMER_GetStatus()

Description

Returns the current timer status of the specified software timer.

Prototype

OS_BOOL OS_TIMER_GetStatus(OS_CONST_PTR OS_TIMER *pTimer);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.

Return value

Denotes whether the specified timer is running or not:

= 0 Timer has stopped.
≠ 0 Timer is running.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static void PrintStatus(OS_TIMER* pTimer) {
  if (OS_TIMER_GetStatus(pTimer) == (OS_BOOL)0) {
    printf("Timer has stopped");
  } else {
    printf("Timer is running");
  }
}

OS_TIMER_GetStatusEx()

Description

Returns the current timer status of an extended software timer.

Prototype

OS_BOOL OS_TIMER_GetStatusEx(OS_CONST_PTR OS_TIMER_EX* pTimerEx);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.

Return value

Denotes whether the specified timer is running or not:

= 0 Timer has stopped.
≠ 0 Timer is running.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static void PrintStatus(OS_TIMER_EX* pTimerEx) {
  if (OS_TIMER_GetStatusEx(pTimerEx) == (OS_BOOL)0) {
    printf("Timer has stopped");
  } else {
    printf("Timer is running");
  }
}

OS_TIMER_Restart()

Description

Restarts the specified software timer with its initial time value.

Prototype

void OS_TIMER_Restart(OS_TIMER* pTimer);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.

Additional information

OS_TIMER_Restart() restarts the software timer using the initial time value programmed at creation of the timer or which was set using one of the functions OS_TIMER_SetPeriod(), OS_TIMER_SetPeriod_Cycles(), OS_TIMER_SetPeriod_ms(), OS_TIMER_SetPeriod_ns(), or OS_TIMER_SetPeriod_us().
OS_TIMER_Restart() can be called regardless the state of the timer. A running timer will restart using the full initial time. A timer that was stopped before or had expired will be restarted.
If NULL is passed for pTimer, the currently running timer is restarted. This can be used from the software timer callback function only.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
171: OS_ERR_2USE_TIMER

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example for OS_TIMER_Create_ms().

OS_TIMER_RestartEx()

Description

Restarts an extended software timer with its initial time value.

Prototype

void OS_TIMER_RestartEx(OS_TIMER_EX* pTimerEx);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.

Additional information

OS_TIMER_RestartEx() restarts the extended software timer using the initial time value which was programmed at creation of the timer or which was set using one of the functions OS_TIMER_SetPeriodEx(), OS_TIMER_SetPeriodEx_Cycles(), OS_TIMER_SetPeriodEx_ms(), OS_TIMER_SetPeriodEx_ns(), or OS_TIMER_SetPeriodEx_us(). OS_TIMER_RestartEx() can be called regardless the state of the timer. A running timer will continue using the full initial time. A timer that was stopped before or had expired will be restarted.
If NULL is passed for pTimer, the currently running timer is restarted. This can be used from the software timer callback function only. If no timer is currently running, OS_Error() is called with the error code OS_ERR_INV_TIMER.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example for OS_TIMER_CreateEx_ms().

OS_TIMER_SetPeriod_Cycles()

Description

Sets a new timer reload value for the specified software timer in cycles.

Prototype

void OS_TIMER_SetPeriod_Cycles(OS_TIMER* pTimer,
                               OS_U32    Cycles);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.
Cycles Timer period in cycles. Must not be zero.

Additional information

OS_TIMER_SetPeriod_Cycles() initial time value of the specified software timer. Cycles is the reload value of the timer to be used as initial value when the timer is retriggered by OS_TIMER_Restart().
A call of OS_TIMER_SetPeriod_Cycles() does not affect the remaining time period of a software timer.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_SetPeriod_Cycles().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER Timer;

static void Callback(void) {
  TogglePulseOutput();       // Toggle output
  OS_TIMER_Restart(&Timer);  // Make timer periodic
}

void InitTask(void) {
  //
  // Create and implicitly start timer with first pulse in 50 milliseconds
  //
  OS_TIMER_Create_ms(&Timer, Callback, 50u);
  OS_TIMER_Start(&Timer);
  //
  // Set timer period to 48,000,000 cycles for further pulses
  //
  OS_TIMER_SetPeriod_Cycles(&Timer, 48000000u);
}

OS_TIMER_SetPeriod_ms()

Description

Sets a new timer reload value for the specified software timer in milliseconds.

Prototype

void OS_TIMER_SetPeriod_ms(OS_TIMER* pTimer,
                           OS_U32    ms);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.
ms Timer period in milliseconds. Must not be zero.

Additional information

OS_TIMER_SetPeriod_ms() sets the initial time value of the specified software timer. ms is the reload value of the timer to be used as initial value when the timer is retriggered by OS_TIMER_Restart().
A call of OS_TIMER_SetPeriod_ms() does not affect the remaining time period of a software timer.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_SetPeriod_ms().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER Timer;

static void Callback(void) {
  TogglePulseOutput();       // Toggle output
  OS_TIMER_Restart(&Timer);  // Make timer periodic
}

void InitTask(void) {
  //
  // Create and implicitly start timer with first pulse in 50 milliseconds
  //
  OS_TIMER_Create_ms(&Timer, Callback, 50u);
  OS_TIMER_Start(&Timer);
  //
  // Set timer period to 200 milliseconds for further pulses
  //
  OS_TIMER_SetPeriod_ms(&Timer, 200u);
}

OS_TIMER_SetPeriod_ns()

Description

Sets a new timer reload value for the specified software timer in nanoseconds.

Prototype

void OS_TIMER_SetPeriod_ns(OS_TIMER* pTimer,
                           OS_U32    ns);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.
us Timer period in nanoseconds. Must not be zero.

Additional information

OS_TIMER_SetPeriod_ns() sets the initial time value of the specified software timer. us is the reload value of the timer to be used as initial value when the timer is retriggered by OS_TIMER_Restart().
A call of OS_TIMER_SetPeriod_ns() does not affect the remaining time period of a software timer.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_SetPeriod_ns().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER Timer;

static void Callback(void) {
  TogglePulseOutput();       // Toggle output
  OS_TIMER_Restart(&Timer);  // Make timer periodic
}

void InitTask(void) {
  //
  // Create and implicitly start timer with first pulse in 50 milliseconds
  //
  OS_TIMER_Create_ms(&Timer, Callback, 50u);
  OS_TIMER_Start(&Timer);
  //
  // Set timer period to 200,000,000 nanoseconds for further pulses
  //
  OS_TIMER_SetPeriod_ns(&Timer, 200000000u);
}

OS_TIMER_SetPeriod_us()

Description

Sets a new timer reload value for the specified software timer in microseconds.

Prototype

void OS_TIMER_SetPeriod_us(OS_TIMER* pTimer,
                           OS_U32    us);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.
us Timer period in microseconds. Must not be zero.

Additional information

OS_TIMER_SetPeriod_us() sets the initial time value of the specified software timer. us is the reload value of the timer to be used as initial value when the timer is retriggered by OS_TIMER_Restart().
A call of OS_TIMER_SetPeriod_us() does not affect the remaining time period of a software timer.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_SetPeriod_us().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER Timer;

static void Callback(void) {
  TogglePulseOutput();       // Toggle output
  OS_TIMER_Restart(&Timer);  // Make timer periodic
}

void InitTask(void) {
  //
  // Create and implicitly start timer with first pulse in 50 milliseconds
  //
  OS_TIMER_Create_ms(&Timer, Callback, 50u);
  OS_TIMER_Start(&Timer);
  //
  // Set timer period to 200,000 microseconds for further pulses
  //
  OS_TIMER_SetPeriod_us(&Timer, 200000u);
}

OS_TIMER_SetPeriodEx_Cycles()

Description

Sets a new timer reload value for an extended software timer in cycles.

Prototype

void OS_TIMER_SetPeriodEx_Cycles(OS_TIMER_EX* pTimerEx,
                                 OS_TIME      Period);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.
Period Initial timer period in cycles. Must not be zero.

Additional information

OS_TIMER_SetPeriodEx_Cycles() sets the initial time value of the specified extended software timer. Cycles is the reload value in milliseconds to be used as initial value when the timer is re-triggered the next time by OS_TIMER_RestartEx().

A call of OS_TIMER_SetPeriodEx_Cycles() does not affect the remaining time period of an extended software timer.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_SetPeriodEx_Cycles().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER_EX Timer;
static OS_TASK     TCB;

static void TimerPulse(void* pTask) {
  if (pTask != NULL) {
    OS_TASKEVENT_Set(0x01, (OS_TASK*)pTask);
  }
  OS_TIMER_RestartEx(&Timer);  // Make timer periodic
}

void InitTask(void) {
  //
  // Create and implicitly start Pulse Timer with first pulse in 50 milliseconds
  //
  OS_TIMER_CreateEx_ms(&Timer, TimerPulse, 50, (void*)&TCB);
  OS_TIMER_StartEx(&Timer);
  //
  // Set timer period to 48,000,000 cycles for further pulses
  //
  OS_TIMER_SetPeriodEx_Cycles(&Timer, 48000000u);
}

OS_TIMER_SetPeriodEx_ms()

Description

Sets a new timer reload value for an extended software timer in milliseconds.

Prototype

void OS_TIMER_SetPeriodEx_ms(OS_TIMER_EX* pTimerEx,
                             OS_TIME      Period);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.
Period Initial timer period in milliseconds. Must not be zero.

Additional information

OS_TIMER_SetPeriodEx_ms() sets the initial time value of the specified extended software timer. ms is the reload value in milliseconds to be used as initial value when the timer is re-triggered the next time by OS_TIMER_RestartEx().

A call of OS_TIMER_SetPeriodEx_ms() does not affect the remaining time period of an extended software timer.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_SetPeriodEx_ms().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER_EX Timer;
static OS_TASK     TCB;

static void TimerPulse(void* pTask) {
  if (pTask != NULL) {
    OS_TASKEVENT_Set(0x01, (OS_TASK*)pTask);
  }
  OS_TIMER_RestartEx(&Timer);  // Make timer periodic
}

void InitTask(void) {
  //
  // Create and implicitly start Pulse Timer with first pulse in 50 milliseconds
  //
  OS_TIMER_CreateEx_ms(&Timer, TimerPulse, 50, (void*)&TCB);
  OS_TIMER_StartEx(&Timer);
  //
  // Set timer period to 200 milliseconds for further pulses
  //
  OS_TIMER_SetPeriodEx_ms(&Timer, 200);
}

OS_TIMER_SetPeriodEx_ns()

Description

Sets a new timer reload value for an extended software timer in nanoseconds.

Prototype

void OS_TIMER_SetPeriodEx_ns(OS_TIMER_EX* pTimerEx,
                             OS_TIME      Period);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.
Period Initial timer period period in nanoseconds. Must not be zero.

Additional information

OS_TIMER_SetPeriodEx_ns() sets the initial time value of the specified extended software timer. ms is the reload value in nanoseconds to be used as initial value when the timer is re-triggered the next time by OS_TIMER_RestartEx().

A call of OS_TIMER_SetPeriodEx_ns() does not affect the remaining time period of an extended software timer.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_SetPeriodEx_ns().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER_EX Timer;
static OS_TASK     TCB;

static void TimerPulse(void* pTask) {
  if (pTask != NULL) {
    OS_TASKEVENT_Set(0x01, (OS_TASK*)pTask);
  }
  OS_TIMER_RestartEx(&Timer);  // Make timer periodic
}

void InitTask(void) {
  //
  // Create and implicitly start Pulse Timer with first pulse in 50 milliseconds
  //
  OS_TIMER_CreateEx_ms(&Timer, TimerPulse, 50, (void*)&TCB);
  OS_TIMER_StartEx(&Timer);
  //
  // Set timer period to 200,000,000 nanoseconds for further pulses
  //
  OS_TIMER_SetPeriodEx_ns(&Timer, 200000000);
}

OS_TIMER_SetPeriodEx_us()

Description

Sets a new timer reload value for an extended software timer in microseconds.

Prototype

void OS_TIMER_SetPeriodEx_us(OS_TIMER_EX* pTimerEx,
                             OS_TIME      Period);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.
Period Initial timer period in microseconds. Must not be zero.

Additional information

OS_TIMER_SetPeriodEx_us() sets the initial time value of the specified extended software timer. us is the reload value in microseconds to be used as initial value when the timer is re-triggered the next time by OS_TIMER_RestartEx().

A call of OS_TIMER_SetPeriodEx_us() does not affect the remaining time period of an extended software timer.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_SetPeriodEx_us().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
205: OS_ERR_TIMER_PERIOD_INVALID
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER_EX Timer;
static OS_TASK     TCB;

static void TimerPulse(void* pTask) {
  if (pTask != NULL) {
    OS_TASKEVENT_Set(0x01, (OS_TASK*)pTask);
  }
  OS_TIMER_RestartEx(&Timer);  // Make timer periodic
}

void InitTask(void) {
  //
  // Create and implicitly start Pulse Timer with first pulse in 50 milliseconds
  //
  OS_TIMER_CreateEx_ms(&Timer, TimerPulse, 50, (void*)&TCB);
  OS_TIMER_StartEx(&Timer);
  //
  // Set timer period to 200,000 microseconds for further pulses
  //
  OS_TIMER_SetPeriodEx_us(&Timer, 200000u);
}

OS_TIMER_Start()

Description

Starts the specified software timer.

Prototype

void OS_TIMER_Start(OS_TIMER* pTimer);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.

Additional information

OS_TIMER_Start() is used for the following reasons:

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_Start().

Note

This function has no effect on running timers. It also has no effect on timers that are not running, but have expired: use OS_TIMER_Restart() to restart those timers.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
171: OS_ERR_2USE_TIMER
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example for OS_TIMER_Create().

OS_TIMER_StartEx()

Description

Starts an extended software timer.

Prototype

void OS_TIMER_StartEx(OS_TIMER_EX* pTimerEx);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.

Additional information

OS_TIMER_StartEx() is used for the following reasons:

Note

This function has no effect on running timers. It also has no effect on timers that are not running, but have expired. Use OS_TIMER_RestartEx() to restart those timers.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example for OS_TIMER_CreateEx().

OS_TIMER_Stop()

Description

Stops the specified software timer.

Prototype

void OS_TIMER_Stop(OS_TIMER* pTimer);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.

Additional information

The actual value of the software timer (the time until expiration) is maintained until OS_TIMER_Start() lets the timer continue. The function has no effect on timers that are not running, but have expired.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIMER_Stop().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER TIMER100;

static void Task(void) {
  OS_TIMER_Restart(&TIMER100);  // Start the timer
  ...
  OS_TIMER_Stop(&TIMER100);     // Stop the timer
}

OS_TIMER_StopEx()

Description

Stops an extended software timer.

Prototype

void OS_TIMER_StopEx(OS_TIMER_EX* pTimerEx);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.

Additional information

The actual value of the extended software timer (the time until expiration) is maintained until OS_TIMER_StartEx() lets the timer continue. The function has no effect on timers that are not running, but have expired.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER_EX TIMER100;

static void Task(void) {
  OS_TIMER_RestartEx(&TIMER100);  // Start the timer
  ...
  OS_TIMER_StopEx(&TIMER100);     // Stop the timer
}

OS_TIMER_Trigger()

Description

Ends the specified software timer at once and calls the timer callback function.

Prototype

void OS_TIMER_Trigger(OS_TIMER* pTimer);

Parameters

Parameter Description
pTimer Pointer to a software timer object of type OS_TIMER.

Additional information

OS_TIMER_Trigger() can be called regardless of the state of the timer. A running timer will be stopped and the callback function is called. For a timer that was stopped before or had expired the callback function will not be executed.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
161: OS_ERR_ILLEGAL_IN_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER TIMERUartRx;

void TimerUart(void) {
  HandleUartRx();
}

void UartRxIntHandler(void) {
  OS_TIMER_Trigger(&TIMERUartRx);  // Character received, stop the software timer
}

void UartSendNextCharachter(void) {
  OS_TIMER_Start(&TIMERUartRx);   // Send next UART character and wait for Rx character
}

int main(void) {
  OS_TIMER_Create(&TIMERUartRx, TimerUart, 20);
}

OS_TIMER_TriggerEx()

Description

Ends an extended software timer at once and calls the timer callback function.

Prototype

void OS_TIMER_TriggerEx (OS_TIMER_EX* pTimerEx);

Parameters

Parameter Description
pTimerEx Pointer to an extended software timer object of type OS_TIMER_EX.

Additional information

OS_TIMER_TriggerEx() can be called regardless of the state of the timer. A running timer will be stopped and the callback function is called. For a timer that was stopped before or had expired the callback function will not be executed.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

129: OS_ERR_INV_TIMER
161: OS_ERR_ILLEGAL_IN_TIMER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

static OS_TIMER_EX TIMERUartRx;
static OS_U32      UartNum;

void TimerUart(void* pNum) {
  HandleUartRx((OS_U32)pNum);
}

void UartRxIntHandler(void) {
  OS_TIMER_TriggerEx(&TIMERUartRx);  // Character received, stop the software timer
}

void UartSendNextCharachter(void) {
  OS_TIMER_StartEx(&TIMERUartRx);    // Send next UART character and wait for Rx character
}

int main(void) {
  UartNum = 0;
  OS_TIMER_CreateEx(&TIMERUartRx, TimerUart, 20, (void*)&UartNum);
}

Task Event

Introduction

Task events are a way of communicating between a task and another task, software timer or embOS interrupt handler. In contrast to event objects, task events are messages to a single, specified task. In other words, a task event is sent to a specified task.

The purpose of a task event is to enable a task to wait for a particular event (or for one of several events) to occur. This task can be kept inactive until the event is signaled by another task, a software timer or an embOS interrupt handler. An event can be, for example, the change of an input signal, the expiration of a hardware timer, a key press or the reception of a character.

Every task has an individual event bit mask. The width of the bit mask depends on the CPU. The bit mask width with 8/16-bit CPUs is 8 bit. The bit mask width with 32-bit CPUs is 32 bit. This means that 8 or 32 different events can be signaled to and distinguished by every task.

The width of the event bit mask can be modified with the macro OS_TASKEVENT. Changing the definition of OS_TASKEVENT can only be done when using the embOS sources in a project, or when the libraries are rebuilt from sources with the modified definition. Please have a look in the chapter Source Code for more details.

Example

#include "RTOS.h"

static OS_STACKPTR int StackHP[128], StackLP[128];  // Task stacks
static OS_TASK         TCBHP, TCBLP;                // Task control blocks

static void HPTask(void) {
  OS_TASKEVENT MyEvents;

  while (1) {
    MyEvents = OS_TASKEVENT_GetBlocked(3);          // Wait for event bits 0 or 1
    if (MyEvents & 1) {
      _HandleEvent0();
    } else
      _HandleEvent1();
    }
  }
}

static void LPTask(void) {
  while (1) {
    OS_TASK_Delay_ms(200);
    OS_TASKEVENT_Set(&TCBHP, 1);
  }
}

int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_TASK_CREATE(&TCBLP, "LP Task",  50, LPTask, StackLP);
  OS_Start();     // Start embOS
  return 0;
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_TASKEVENT_Clear() Returns the actual state of events and then clears all events of the specified task.
OS_TASKEVENT_ClearEx() Returns the actual state of events and then clears the specified events for the specified task.
OS_TASKEVENT_Get() Returns a list of events that have occurred for the specified task.
OS_TASKEVENT_GetBlocked() Waits for one of the events specified in the bit mask and clears the event memory when the function returns.
OS_TASKEVENT_GetSingleBlocked() Waits for one of the specified events and clears only those events that were specified in the event mask.
OS_TASKEVENT_GetSingleTimed() Waits for one of the specified events for a given time and clears only those events that were specified in the event mask.
OS_TASKEVENT_GetTimed() Waits for the specified events for a given time, and clears all task events when the function returns.
OS_TASKEVENT_Set() Signals event(s) to the specified task.

OS_TASKEVENT_Clear()

Description

Returns the actual state of events and then clears all events of the specified task.

Prototype

OS_TASKEVENT OS_TASKEVENT_Clear(OS_TASK* pTask);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK or NULL for the current task.

Return value

All events that have been signaled before clearing. If pTask is NULL, the function clears all events of the currently running task.

Additional information

If NULL is passed for pTask, the currently running task is used. If this function is not called from a task context, no task might currently be running and there is no valid task. A debug build of embOS will call OS_Error() in this case. We suggest to call this function from a context other than the task context with a pointer to a valid task control block only.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void Task(void) {
  OS_TASKEVENT MyEvents;

  MyEvents = OS_TASKEVENT_Clear(NULL);

  while (1) {
    //
    // Wait for event 0 or 1 to be signaled
    //
    MyEvents = OS_TASKEVENT_GetBlocked(3);
  }
}

OS_TASKEVENT_ClearEx()

Description

Returns the actual state of events and then clears the specified events for the specified task.

Prototype

OS_TASKEVENT OS_TASKEVENT_ClearEx(OS_TASK*     pTask,
                                  OS_TASKEVENT EventMask);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK or NULL for the current task.
EventMask The bit mask containing the event bits which shall be cleared.

Return value

All events that have been signaled before clearing. If pTask is NULL, the function clears the events of the currently running task.

Additional information

If NULL is passed for pTask, the currently running task is used. If this function is not called from a task context, no task might currently be running and there is no valid task. A debug build of embOS will call OS_Error() in this case. We suggest to call this function from a context other than the task context with a pointer to a valid task control block only.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void Task(void) {
  OS_TASKEVENT MyEvents;

  MyEvents = OS_TASKEVENT_ClearEx(NULL, 1);

  while (1) {
    //
    // Wait for event 0 or 1 to be signaled
    //
    MyEvents = OS_TASKEVENT_GetBlocked(3);
  }
}

OS_TASKEVENT_Get()

Description

Returns a list of events that have occurred for the specified task.

Prototype

OS_TASKEVENT OS_TASKEVENT_Get(OS_CONST_PTR OS_TASK *pTask);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK or NULL for the current task.

Return value

All events that have been signaled.

Additional information

By calling this function, all events remain signaled: event memory is not cleared. This is one way for a task to query which events are signaled. The task is not suspended if no events are signaled.

If NULL is passed for pTask, the currently running task is used. If this function is not called from a task context, no task might currently be running and there is no valid task. A debug build of embOS will call OS_Error() in this case. We suggest to call this function from a context other than the task context with a pointer to a valid task control block only.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void PrintEvents(void) {
  OS_TASKEVENT MyEvents;

  MyEvents = OS_TASKEVENT_Get(NULL);
  printf("Events %u\n", MyEvents);
}

OS_TASKEVENT_GetBlocked()

Description

Waits for one of the events specified in the bit mask and clears the event memory when the function returns.

Prototype

OS_TASKEVENT OS_TASKEVENT_GetBlocked(OS_TASKEVENT EventMask);

Parameters

Parameter Description
EventMask The event bit mask containing the event bits, which shall be waited for.

Return value

All events that have been signaled.

Additional information

If none of the specified events are signaled, the task is suspended. The first of the specified events will wake the task. These events are signaled by another task, a software timer or an interrupt handler. Any bit that is set in the event mask enables the corresponding event.

When a task waits on multiple events, all of the specified events shall be requested by a single call of OS_TASKEVENT_GetBlocked() and all events must be be handled when the function returns.

Note that all events of the task are cleared when the function returns, even those events that were not set in the parameters in the EventMask. The calling function must handle the returned value, otherwise events may get lost. Consecutive calls of OS_TASKEVENT_GetBlocked() with different event masks will not work, as all events are cleared when the function returns. If this is not desired, OS_TASKEVENT_GetSingleBlocked() may be used instead.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

void Task(void) {
  OS_TASKEVENT MyEvents;

  while(1) {
    //
    // Wait for event 0 or 1 to be signaled
    //
    MyEvents = OS_TASKEVENT_GetBlocked(3);
    //
    // Handle all events
    //
    if (MyEvents & 1) {
      _HandleEvent0();
    }
    if (MyEvents & 2) {
      _HandleEvent1();
    }
  }
}

For another example, see OS_TASKEVENT_Set().

OS_TASKEVENT_GetSingleBlocked()

Description

Waits for one of the specified events and clears only those events that were specified in the event mask.

Prototype

OS_TASKEVENT OS_TASKEVENT_GetSingleBlocked(OS_TASKEVENT EventMask);

Parameters

Parameter Description
EventMask The event bit mask containing the event bits, which shall be waited for and reset.

Return value

All requested events that have been signaled and were specified in the EventMask.

Additional information

If none of the specified events are signaled, the task is suspended. The first of the requested events will wake the task. These events are signaled by another task, a software timer, or an interrupt handler. Any bit in the event mask may enable the corresponding event. When the function returns, it delivers all of the requested events. The requested events are cleared in the event state of the task. All other events remain unchanged and will not be returned.

OS_TASKEVENT_GetSingleBlocked() may be used in consecutive calls with individual requests. Only requested events will be handled, no other events can get lost. When the function waits on multiple events, the returned value must be evaluated because the function returns when at least one of the requested events was signaled. When the function requests a single event, the returned value does not need to be evaluated.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

void Task(void) {
  OS_TASKEVENT MyEvents;

  while(1) {
    //
    // Wait for event 0 or 1 to be signaled
    //
    MyEvents = OS_TASKEVENT_GetSingleBlocked(3);
    //
    // Handle all events
    //
    if (MyEvents & 1) {
      _HandleEvent0();
    }
    if (MyEvents & 2) {
      _HandleEvent1();
    }
  }
}

OS_TASKEVENT_GetSingleTimed()

Description

Waits for one of the specified events for a given time and clears only those events that were specified in the event mask.

Prototype

OS_TASKEVENT OS_TASKEVENT_GetSingleTimed(OS_TASKEVENT EventMask,
                                         OS_U32       Timeout);

Parameters

Parameter Description
EventMask The event bit mask containing the event bits, which shall be waited for and reset.
Timeout Maximum time in milliseconds until the event must be signaled.

Return value

= 0 No event available within the specified timeout.
≠ 0 All events that have been signaled.

Additional information

If none of the specified events in the event mask are available, the task is suspended for the given time. The first of the specified events will wake the task if the event is signaled by another task, a software timer or an interrupt handler within the specified Timeout time.

If no event is signaled within the specified timeout, the calling task gets activated and return zero.

Any bit in the event mask may enable the corresponding event. All unmasked events remain unchanged.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TASKEVENT_GetSingleTimed().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Task(void) {
  OS_TASKEVENT MyEvents;

  while(1) {
    //
    // Wait for event 0 and 1 to be signaled within 10 milliseconds
    //
    MyEvents = OS_TASKEVENT_GetSingleTimed(3, 10);
    if (MyEvents == 0) {
      _HandleTimeout();
    } else {
      if (MyEvents & 1) {
        _HandleEvent0();
      }
      if (MyEvents & 2) {
        _HandleEvent1();
      }
    }
  }
}

OS_TASKEVENT_GetTimed()

Description

Waits for the specified events for a given time, and clears all task events when the function returns.

Prototype

OS_TASKEVENT OS_TASKEVENT_GetTimed(OS_TASKEVENT EventMask,
                                   OS_U32       Timeout);

Parameters

Parameter Description
EventMask The event bit mask containing the event bits, which shall be waited for.
Timeout Maximum time in milliseconds until the events must be signaled.

Return value

= 0 No event available within the specified timeout.
≠ 0 All events that have been signaled.

Additional information

If none of the specified events in the event mask are available, the task is suspended for the given time. The first of the specified events will wake the task if the event is signaled by another task, a software timer or an interrupt handler within the specified Timeout time.

If no event is signaled within the specified timeout, the calling task gets activated and return zero.

Note that the function returns all events that were signaled until the task continues execution, even those which were not requested. The calling function must handle the returned value, otherwise events may get lost. Consecutive calls of OS_TASKEVENT_GetTimed() with different event masks will not work, as all events are cleared when the function returns. If this is not desired, OS_TASKEVENT_GetSingleTimed() may be used instead.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TASKEVENT_GetTimed().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Task(void) {
  OS_TASKEVENT MyEvents;

  while(1) {
    //
    // Wait for event 0 and 1 to be signaled within 10 milliseconds
    //
    MyEvents = OS_TASKEVENT_GetTimed(3, 10);
    if ((MyEvents & 3) == 0) {
      _HandleTimeout();
    } else {
      if (MyEvents & 1) {
        _HandleEvent0();
      }
      if (MyEvents & 2) {
        _HandleEvent1();
      }
    }
  }
}

OS_TASKEVENT_Set()

Description

Signals event(s) to the specified task.

Prototype

void OS_TASKEVENT_Set(OS_TASK*     pTask,
                      OS_TASKEVENT Event);

Parameters

Parameter Description
pTask Pointer to a task control block of type OS_TASK.
Event The event bit mask containing the event bits, which shall be signaled.

Additional information

If the specified task is waiting for one of these events, it will be put in the READY state and activated according to the rules of the scheduler.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

128: OS_ERR_INV_TASK
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

The task that handles the serial input and the keyboard waits for a character to be received either via the keyboard (EVENT_KEYPRESSED) or serial interface (EVENT_SERIN):

#define EVENT_KEYPRESSED (1u << 0)
#define EVENT_SERIN      (1u << 1)

static OS_STACKPTR int Stack0[96];  // Task stacks
static OS_TASK         TCB0;        // Data area for tasks (task control blocks)

void Task0(void) {
  OS_TASKEVENT MyEvent;
  while(1)
    MyEvent = OS_TASKEVENT_GetBlocked(EVENT_KEYPRESSED | EVENT_SERIN)
    if (MyEvent & EVENT_KEYPRESSED) {
      // Handle key press
    }
    if (MyEvent & EVENT_SERIN) {
      // Handle serial reception
    }
  }
}

void Key_ISR(void) {                          // ISR for external interrupt
  OS_TASKEVENT_Set(&TCB0, EVENT_KEYPRESSED);  // Notify task that key was pressed
}

void UART_ISR(void) {                         // ISR for UART interrupt
  OS_TASKEVENT_Set(&TCB0, EVENT_SERIN);       // Notify task that a character was received
}

void InitTask(void) {
  OS_TASK_CREATE(&TCB0, "HPTask", 100, Task0, Stack0);
}

Event Object

Introduction

Event objects are another type of communication and synchronization object. In contrast to task-events, event objects are standalone objects which are not owned by any task.

The purpose of an event object is to enable one or multiple tasks to wait for a particular event to occur. The tasks can be kept suspended until the event is set by another task, a software timer, or an interrupt handler. An event can be, for example, the change of an input signal, the expiration of a timer, a key press, the reception of a character, or a complete command.

Compared to a task event, the signaling function does not need to know which task is waiting for the event to occur.

Using event object API

There are two groups of event object API functions. The first group does not have “mask” as part of their name and operates on the complete event object. These functions are OS_EVENT_Get(), OS_EVENT_GetBlocked(), OS_EVENT_GetTimed(), OS_EVENT_Pulse(), and OS_EVENT_Set(). The second group does have “mask” as part of the API name and operates on a event object bit mask. These functions are OS_EVENT_GetMask(), OS_EVENT_GetMaskBlocked(), OS_EVENT_GetMaskMode(), OS_EVENT_GetMaskTimed(), OS_EVENT_SetMask(), and OS_EVENT_SetMaskMode(). Any event object is in non-signaled state when the event object value is zero, and in signaled state when the event object value is unequal to zero. We do not recommend to use both API groups on the same event object. For example, you must not wait for an event object with OS_EVENT_GetBlocked() and signal that event object with OS_EVENT_SetMask(), but with OS_EVENT_Set().

Reset mode

Since version 3.88a of embOS, the reset behavior of the event can be controlled by different reset modes which may be passed as parameter to the new function OS_EVENT_CreateEx() or may be modified by a call of OS_EVENT_SetResetMode().

Mask mode

Since version 4.34 of embOS, the mask bits behavior of the event object can be controlled by different mask modes which may be passed to the new function OS_EVENT_CreateEx() or may be modified by a call of OS_EVENT_SetMaskMode().

Examples

Activate a task from interrupt by an event object

The following code example shows usage of an event object which is signaled from an ISR handler to activate a task. The waiting task should reset the event after waiting for it.

static OS_EVENT _Event;

static void _ISRHandler(void) {
  OS_INT_Enter();
  //
  // Wake up task to do the rest of the work
  //
  OS_EVENT_Set(&_Event);
  OS_INT_Leave();
}

static void Task(void) {
  while (1) {
    OS_EVENT_GetBlocked(&_Event);
    //
    // Do the rest of the work (which has not been done in the ISR)
    //
    ...
  }
}

Activating multiple tasks using a single event object

The following sample program shows how to synchronize multiple tasks with one event object.

#include "RTOS.h"

static OS_STACKPTR int StackHP[128], StackLP[128], StackHW[128];
static OS_TASK         TCBHP, TCBLP, TCBHW;
static OS_EVENT        HW_Event;

static void HPTask(void) {
  //
  // Wait until HW module is set up
  //
  OS_EVENT_GetBlocked(&HW_Event);
  while (1) {
    OS_TASK_Delay_ms(50);
  }
}

static void LPTask(void) {
  //
  // Wait until HW module is set up
  //
  OS_EVENT_GetBlocked(&HW_Event);
  while (1) {
    OS_TASK_Delay_ms(200);
  }
}

static void HWTask(void) {
  //
  // Wait until HW module is set up
  //
  OS_TASK_Delay_ms(100);
  //
  // Init done, send broadcast to waiting tasks
  //
  OS_EVENT_Set(&HW_Event);
  while (1) {
    OS_TASK_Delay_ms(40);
  }
}

int main(void) {
  OS_Init();                   // Initialize embOS
  OS_InitHW();                 // Initialize required hardware
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_TASK_CREATE(&TCBLP, "LP Task",  50, LPTask, StackLP);
  OS_TASK_CREATE(&TCBHW, "HWTask",   25, HWTask, StackHW);
  OS_EVENT_Create(&HW_Event);
  OS_Start();                  // Start multitasking
  return 0;
}

Using event object mask bits

The following sample program shows how to use event object mask bits.

#include "RTOS.h"

#define EVENT1_BITMASK  (1u << 0)
#define EVENT2_BITMASK  (1u << 1)

static OS_STACKPTR int StackTask1[128], StackTask2[128], StackLP[128];
static OS_TASK         TCBTask1, TCBTask2, TCBLP;
static OS_EVENT        _Event;

static void Task1(void) {
  OS_EVENT_GetMaskBlocked(&_Event, EVENT1_BITMASK);
  while (1) {
    OS_TASK_Delay_ms(50);
  }
}

static void Task2(void) {
  OS_EVENT_GetMaskBlocked(&_Event, EVENT2_BITMASK);
  while (1) {
    OS_TASK_Delay_ms(50);
  }
}

static void LPTask(void) {
  OS_EVENT_SetMask(&_Event, EVENT1_BITMASK);
  OS_EVENT_SetMask(&_Event, EVENT2_BITMASK);
  while (1) {
    OS_TASK_Delay_ms(200);
  }
}

int main(void) {
  OS_Init();                   // Initialize embOS
  OS_InitHW();                 // Initialize required hardware
  OS_TASK_CREATE(&TCBTask1, "Task 1",  100, Task1, StackTask1);
  OS_TASK_CREATE(&TCBTask2, "Task 2",  100, Task2, StackTask2);
  OS_TASK_CREATE(&TCBLP,    "LP Task",  50, LPTask, StackLP);
  OS_EVENT_Create(&_Event);
  OS_Start();                  // Start multitasking
  return 0;
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_EVENT_Create() Creates an event object.
OS_EVENT_CreateEx() Creates an extended event object and sets its reset behavior as well as mask bits behavior.
OS_EVENT_Delete() Deletes the specified event object.
OS_EVENT_Get() Retrieves the current state of the specified event object.
OS_EVENT_GetBlocked() Waits for the specified event object and suspends the task until the event has been signaled.
OS_EVENT_GetMask() Returns the bits of the specified event object that match the given EventMask.
OS_EVENT_GetMaskBlocked() Waits for the specified event bits in EventMask, depending on the current mask mode.
OS_EVENT_GetMaskMode() Retrieves the current mask mode (mask bits behavior) of the specified event object.
OS_EVENT_GetMaskTimed() Waits for the specified event bits EventMask with timeout, depending on the current mask mode.
OS_EVENT_GetResetMode() Returns the reset mode (reset behavior) of the specified event object.
OS_EVENT_GetTimed() Waits for an event and suspends the task for a specified time or until the specified event has been signaled.
OS_EVENT_Pulse() Signals the specified event object and resumes waiting tasks, then resets the event object to non-signaled state.
OS_EVENT_Reset() Resets the specified event object to non-signaled state.
OS_EVENT_ResetMask() Resets the specified mask bits in the specified event object to non-signaled state.
OS_EVENT_Set() Sets the specified event object to signaled state, or resumes tasks which are waiting at the event object.
OS_EVENT_SetMask() Sets the event mask bits of the specified event object.
OS_EVENT_SetMaskMode() Sets the mask mode of the specified event object to OR/AND logic.
OS_EVENT_SetResetMode() Sets the reset behavior of the specified event object to automatic, manual or semi-auto.

OS_EVENT_Create()

Description

Creates an event object.

Prototype

void OS_EVENT_Create(OS_EVENT* pEvent);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.

Additional information

On creation, the event is set to non-signaled state.

The event is created with the default reset behavior which is semi-auto. Since version 3.88a of embOS, the reset behavior of the event can be modified by a call of the function OS_EVENT_SetResetMode().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
178: OS_ERR_2USE_EVENT

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void HPTask(void) {
  OS_EVENT_GetMaskBlocked(&_Event, 3);  // Wait for bit 0 AND 1 to be set
}

void LPTask(void) {
  OS_EVENT_SetMask(&_Event, 1);         // Resumes HPTask due to OR logic
}

int main(void) {
  ...
  OS_EVENT_Create(&_Event);
  ...
  return 0;
}

OS_EVENT_CreateEx()

Description

Creates an extended event object and sets its reset behavior as well as mask bits behavior.

Prototype

void OS_EVENT_CreateEx(OS_EVENT*    pEvent,
                       unsigned int Mode);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.
Mode Specifies the reset and mask bits behavior of the event object. You can use one of the predefined reset modes:
OS_EVENT_RESET_MODE_SEMIAUTO
OS_EVENT_RESET_MODE_MANUAL
OS_EVENT_RESET_MODE_AUTO
and one of the mask modes:
OS_EVENT_MASK_MODE_OR_LOGIC
OS_EVENT_MASK_MODE_AND_LOGIC
which are described under additional information.

Additional information

On creation, the event is set to non-signaled state.

Since version 3.88a of embOS, the reset behavior of the event can be controlled by different reset modes which may be passed as parameter to the new function OS_EVENT_CreateEx() or may be modified by a call of OS_EVENT_SetResetMode().

Since version 4.34 of embOS, the mask bits behavior of the event object can be controlled by different mask modes which may be passed to the new function OS_EVENT_CreateEx() or may be modified by a call of OS_EVENT_SetMaskMode().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
178: OS_ERR_2USE_EVENT

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void HPTask(void) {
  OS_EVENT_GetMaskBlocked(&_Event, 3);  // Wait for bit 0 AND 1 to be set
}

void LPTask(void) {
  OS_EVENT_SetMask(&_Event, 1);         // Does not resume HPTask
  OS_EVENT_SetMask(&_Event, 2);         // Resume HPTask since both bits are now set
}

int main(void) {
  ...
  OS_EVENT_CreateEx(&_Event, OS_EVENT_RESET_MODE_AUTO |
                             OS_EVENT_MASK_MODE_AND_LOGIC);
  ...
  return 0;
}

OS_EVENT_Delete()

Description

Deletes the specified event object.

Prototype

void OS_EVENT_Delete(OS_EVENT* pEvent);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.

Additional information

Before deleting an event object, make sure that no task is waiting for the event object.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
212: OS_ERR_EVENT_DELETE
220: OS_ERR_EVENT_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void Task(void) {
  ...
  OS_EVENT_Delete(&_Event);
  ...
}

OS_EVENT_Get()

Description

Retrieves the current state of the specified event object.

Prototype

OS_BOOL OS_EVENT_Get(OS_CONST_PTR OS_EVENT *pEvent);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.

Return value

= 0 Event object is not set to signaled state.
≠ 0 Event object is set to signaled state.

Additional information

By calling this function, the actual state of the event object remains unchanged.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
220: OS_ERR_EVENT_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void Task(void) {
  OS_BOOL Status;

  Status = OS_EVENT_Get(&_Event);
  printf("Event Object Status: %d\n", Status);
}

OS_EVENT_GetBlocked()

Description

Waits for the specified event object and suspends the task until the event has been signaled.

Prototype

void OS_EVENT_GetBlocked(OS_EVENT* pEvent);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.

Additional information

The state of the event object after calling OS_EVENT_GetBlocked() depends on the reset mode of the event object which was set by creating the event object by a call of OS_EVENT_CreateEx() or OS_EVENT_SetResetMode().

The event is consumed when OS_EVENT_RESET_MODE_AUTO is selected. The event is not consumed when OS_EVENT_RESET_MODE_MANUAL is selected. With OS_EVENT_RESET_MODE_SEMIAUTO the event is consumed only when it was already set before.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
220: OS_ERR_EVENT_INVALID
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void HPTask(void) {
  OS_EVENT_GetBlocked(&_Event);  // Suspends the task
}

void LPTask(void) {
  OS_EVENT_Pulse(&_Event);       // Signals the HPTask
}

OS_EVENT_GetMask()

Description

Returns the bits of the specified event object that match the given EventMask.

Prototype

OS_TASKEVENT OS_EVENT_GetMask(OS_EVENT*    pEvent,
                              OS_TASKEVENT EventMask);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.
EventMask The bit mask containing the event bits which shall be retrieved.

Return value

All events that have been signaled and were specified in the EventMask.

Additional information

The returned event mask bits are consumed unless OS_EVENT_RESET_MODE_MANUAL is selected. The state of the event object after calling OS_EVENT_GetMask() depends on the reset mode of the event object which was set by creating the event object by a call of OS_EVENT_CreateEx() or OS_EVENT_SetResetMode().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
220: OS_ERR_EVENT_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void Task(void) {
  OS_TASKEVENT EventMask;

  EventMask = ~0;  // Request all event bits
  EventMask = OS_EVENT_GetMask(&_Event, EventMask);
  printf("Signaled Event Bits: 0x%X\n", EventMask);
}

OS_EVENT_GetMaskBlocked()

Description

Waits for the specified event bits in EventMask, depending on the current mask mode. The task is suspended until the event(s) have been signaled.

Prototype

OS_TASKEVENT OS_EVENT_GetMaskBlocked(OS_EVENT*    pEvent,
                                     OS_TASKEVENT EventMask);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.
EventMask The event bit mask containing the event bits, which shall be waited for.

Return value

All requested events that have been signaled and were specified in the EventMask.

Additional information

It returns the bits of the event object that match the given EventMask. The returned event mask bits are consumed unless OS_EVENT_RESET_MODE_MANUAL is selected. The state of the event object after calling OS_EVENT_GetMaskBlocked() depends on the reset mode of the event object which was set by creating the event object by a call of OS_EVENT_CreateEx() or OS_EVENT_SetResetMode().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
220: OS_ERR_EVENT_INVALID
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void Task(void) {
  ...
  //
  //  Waits either for the first or second, or for
  //  both event bits to be signaled, depending on
  //  the specified mask mode.
  //
  OS_EVENT_GetMaskBlocked(&_Event, 0x3);
  ...
}

OS_EVENT_GetMaskMode()

Description

Retrieves the current mask mode (mask bits behavior) of the specified event object.

Prototype

OS_EVENT_MASK_MODE OS_EVENT_GetMaskMode(OS_CONST_PTR OS_EVENT *pEvent);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.

Return value

The mask mode which is currently set.
Modes are defined in enum OS_EVENT_MASK_MODE.
OS_EVENT_MASK_MODE_OR_LOGIC (0x00u): Mask bits are used with OR logic (default).
OS_EVENT_MASK_MODE_AND_LOGIC (0x04u): Mask bits are used with AND logic.

Additional information

Since version 4.34 of embOS, the mask mode of an event object can be controlled by the OS_EVENT_CreateEx() function or set after creation using the new function OS_EVENT_SetMaskMode(). If needed, the current setting of the mask mode can be retrieved with OS_EVENT_GetMaskMode().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
220: OS_ERR_EVENT_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void Task(void) {
  OS_EVENT_MASK_MODE MaskMode;

  MaskMode = OS_EVENT_GetMaskMode(&_Event);
  if (MaskMode == OS_EVENT_MASK_MODE_OR_LOGIC) {
    printf("Logic: OR\n");
  } else {
    printf("Logic: AND\n");
  }
}

OS_EVENT_GetMaskTimed()

Description

Waits for the specified event bits EventMask with timeout, depending on the current mask mode.

Prototype

OS_TASKEVENT OS_EVENT_GetMaskTimed(OS_EVENT*    pEvent,
                                   OS_TASKEVENT EventMask,
                                   OS_U32       Timeout);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.
EventMask The event bit mask containing the event bits, which shall be waited for.
Timeout Maximum time in milliseconds until events must be signaled.

Return value

= 0 No event available within the specified timeout.
≠ 0 All events that have been signaled and were specified in the EventMask.

Additional information

The task is suspended for the specified time or until the event(s) have been signaled. It returns the bits of the event object that match the given EventMask. The returned event mask bits are consumed unless OS_EVENT_RESET_MODE_MANUAL is selected. The state of the event object after calling OS_EVENT_GetMaskTimed() depends on the reset mode of the event object which was set by creating the event object by a call of OS_EVENT_CreateEx() or OS_EVENT_SetResetMode().

OS_TIME_ConfigSysTimer() must have been called before calling OS_EVENT_GetMaskTimed().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
220: OS_ERR_EVENT_INVALID
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void Task(void) {
  ...
  //
  //  Waits either for the first or second, or for
  //  both event bits to be signaled, depending on
  //  the specified mask mode. The task resumes after
  //  1000 milliseconds, if the needed event bits were not
  //  signaled.
  //
  OS_EVENT_GetMaskTimed(&_Event, 0x3, 1000);
  ...
}

OS_EVENT_GetResetMode()

Description

Returns the reset mode (reset behavior) of the specified event object.

Prototype

OS_EVENT_RESET_MODE OS_EVENT_GetResetMode(OS_CONST_PTR OS_EVENT *pEvent);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.

Return value

The reset mode which is currently set.
Modes are defined in enum OS_EVENT_RESET_MODE.
OS_EVENT_RESET_MODE_SEMIAUTO (0x00u): As previous mode (default).
OS_EVENT_RESET_MODE_MANUAL (0x01u): Event remains set, has to be reset by task.
OS_EVENT_RESET_MODE_AUTO (0x02u): Event is reset automatically.

Additional information

Since version 3.88a of embOS, the reset mode of an event object can be controlled by the new OS_EVENT_CreateEx() function or set after creation using the new function OS_EVENT_SetResetMode(). If needed, the current setting of the reset mode can be retrieved with OS_EVENT_GetResetMode().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
220: OS_ERR_EVENT_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void Task(void) {
  OS_EVENT_RESET_MODE ResetMode;

  ResetMode = OS_EVENT_GetResetMode(&_Event);
  if (ResetMode == OS_EVENT_RESET_MODE_SEMIAUTO) {
    printf("Reset Mode: SEMIAUTO\n");
  } else if (ResetMode == OS_EVENT_RESET_MODE_MANUAL) {
    printf("Reset Mode: MANUAL\n");
  } else {
    printf("Reset Mode: AUTO\n");
  }
}

OS_EVENT_GetTimed()

Description

Waits for an event and suspends the task for a specified time or until the specified event has been signaled.

Prototype

char OS_EVENT_GetTimed(OS_EVENT* pEvent,
                       OS_U32    Timeout);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.
Timeout Maximum time in milliseconds until the event must be signaled.

Return value

= 0 Success, the event was signaled within the specified time.
≠ 0 If the event was not signaled within the specified time.

Additional information

The event is consumed unless OS_EVENT_RESET_MODE_MANUAL is selected.

OS_TIME_ConfigSysTimer() must have been called before calling OS_EVENT_GetTimed().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
220: OS_ERR_EVENT_INVALID
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void Task(void) {
  ...
  if (OS_EVENT_GetTimed(&_Event, 1000) == 0) {
    // event was signaled within timeout time, handle event
  } else {
    // event was not signaled within timeout time, handle timeout
  }
  ...
}

OS_EVENT_Pulse()

Description

Signals the specified event object and resumes waiting tasks, then resets the event object to non-signaled state.

Prototype

void OS_EVENT_Pulse(OS_EVENT* pEvent);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.

Additional information

If any tasks are waiting at the event object, the tasks are resumed. The event object remains in non-signaled state, regardless the reset mode.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
220: OS_ERR_EVENT_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void HPTask(void) {
  OS_EVENT_GetBlocked(&_Event);  // Suspends the task
}

void LPTask(void) {
  OS_EVENT_Pulse(&_Event);       // Signals the HPTask
}

OS_EVENT_Reset()

Description

Resets the specified event object to non-signaled state.

Prototype

void OS_EVENT_Reset(OS_EVENT* pEvent);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.

Additional information

OS_EVENT_Reset() may also be used with event mask and resets all mask bits.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
220: OS_ERR_EVENT_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void Task(void) {
  ...
  OS_EVENT_Reset(&_Event);
  ...
}

OS_EVENT_ResetMask()

Description

Resets the specified mask bits in the specified event object to non-signaled state.

Prototype

void OS_EVENT_ResetMask(OS_EVENT*    pEvent,
                        OS_TASKEVENT EventMask);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.
EventMask The event bit mask containing the event bits which shall be cleared.

Additional information

OS_EVENT_ResetMask() resets only the event mask bits specified in EventMask.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
220: OS_ERR_EVENT_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void Task(void) {
  ...
  OS_EVENT_ResetMask(&_Event, 1);
  ...
}

OS_EVENT_Set()

Description

Sets the specified event object to signaled state, or resumes tasks which are waiting at the event object.

Prototype

void OS_EVENT_Set(OS_EVENT* pEvent);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.

Additional information

If no tasks are waiting at the event object, the event object is set to signaled state. Any task that is already waiting for the event object will be resumed. The state of the event object after calling OS_EVENT_Set() then depends on the reset mode of the event object.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
220: OS_ERR_EVENT_INVALID

For details, refer to the chapter Runtime application errors.

Example

Examples on how to use the OS_EVENT_Set() function are shown in Examples.

OS_EVENT_SetMask()

Description

Sets the event mask bits of the specified event object.

Prototype

void OS_EVENT_SetMask(OS_EVENT*    pEvent,
                      OS_TASKEVENT EventMask);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.
EventMask The event bit mask containing the event bits, which shall be signaled.

Additional information

Any task that is already waiting for matching event mask bits on this event object will be resumed. OS_EVENT_SetMask() does not clear any event mask bits.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
220: OS_ERR_EVENT_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void Task(void) {
  OS_TASKEVENT EventMask;

  ...
  EventMask = 1 << ((sizeof(OS_TASKEVENT) * 8) - 1);  // Set MSB event bit
  OS_EVENT_SetMask(&_Event, EventMask);               // Signal MSB event bit
  ...
}

OS_EVENT_SetMaskMode()

Description

Sets the mask mode of the specified event object to OR/AND logic.

Prototype

void OS_EVENT_SetMaskMode(OS_EVENT*          pEvent,
                          OS_EVENT_MASK_MODE MaskMode);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.
MaskMode Event Mask mode.
Modes are defined in enum OS_EVENT_MASK_MODE.
OS_EVENT_MASK_MODE_OR_LOGIC (0x00u): Mask bits are used with OR logic (default).
OS_EVENT_MASK_MODE_AND_LOGIC (0x04u): Mask bits are used with AND logic.

Additional information

Since version 4.34 of embOS, the mask bits behavior of the event object can be controlled by different mask modes which may be passed to the new function OS_EVENT_CreateEx() or may be modified by a call of OS_EVENT_SetMaskMode(). The following mask modes are defined and can be used as parameter:

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
220: OS_ERR_EVENT_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void Task(void) {
  ...
  // Set the mask mode for the event object to AND logic
  OS_EVENT_SetMaskMode(&_Event, OS_EVENT_MASK_MODE_AND_LOGIC);
  ...
}

OS_EVENT_SetResetMode()

Description

Sets the reset behavior of the specified event object to automatic, manual or semi-auto.

Prototype

void OS_EVENT_SetResetMode(OS_EVENT*           pEvent,
                           OS_EVENT_RESET_MODE ResetMode);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.
ResetMode Controls the reset mode of the event object.
OS_EVENT_RESET_MODE_SEMIAUTO (0x00u): As previous mode (default).
OS_EVENT_RESET_MODE_MANUAL (0x01u): Event remains set, has to be reset by task.
OS_EVENT_RESET_MODE_AUTO (0x02u): Event is reset automatically.

Additional information

Implementation of event objects in embOS versions before 3.88a unfortunately was not consistent with respect to the state of the event after calling OS_EVENT_Set() or OS_EVENT_GetBlocked() functions. The state of the event was different when tasks were waiting or not.

Since embOS version 3.88a, the state of the event (reset behavior) can be controlled after creation by the new function OS_EVENT_SetResetMode(), or during creation by the new OS_EVENT_CreateEx() function. The following reset modes are defined and can be used as parameter:

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
220: OS_ERR_EVENT_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_EVENT _Event;

void Task(void) {
  // Set the reset mode for the event object to manual
  OS_EVENT_SetResetMode(&_Event, OS_EVENT_RESET_MANUAL);
}

Mutex

Introduction

Mutexes are used for managing resources by avoiding conflicts caused by simultaneous use of a resource. The resource managed can be of any kind: a part of the program that is not reentrant, a piece of hardware like the display, a flash memory that can only be written to by a single task at a time, a motor in a CNC control that can only be controlled by one task at a time, and a lot more.

The basic procedure is as follows:

Any task that uses a resource first claims it calling the OS_MUTEX_LockBlocked() or OS_MUTEX_Lock() routines of embOS. If the mutex is available, the program execution of the task continues, but the mutex is blocked for other tasks. If a second task now tries to acquire the same mutex while it is in use by the first task, this second task is suspended until the first task releases the mutex. However, if the first task that uses the mutex calls OS_MUTEX_LockBlocked() again for that mutex, it is not suspended because the mutex is blocked only for other tasks.

The following diagram illustrates the process of using a mutex:

A mutex contains a counter that keeps track of how many times the mutex has been claimed by calling OS_MUTEX_Lock() or OS_MUTEX_LockBlocked() by a particular task. It is released when that counter reaches zero, which means the OS_MUTEX_Unlock() routine must be called exactly the same number of times as OS_MUTEX_LockBlocked() or OS_MUTEX_Lock(). If it is not, the mutex remains blocked for other tasks.

On the other hand, a task cannot release a mutex that it does not own by calling OS_MUTEX_Unlock(). In debug builds of embOS, a call of OS_MUTEX_Unlock() for a mutex that is not owned by this task will result in a call to the error handler OS_Error().

Example of using a mutex

Here, two tasks access a (debug) terminal completely independently from each other. The terminal is a resource that needs to be protected with a mutex. One task may not interrupt another task which is writing to the terminal, as otherwise the following might occur:

To avoid this type of situation, every time the terminal is to be accessed by a task it is first claimed by a call to OS_MUTEX_LockBlocked() (and is automatically waited for if the mutex is blocked). After the terminal has been written to, it is released by a call to OS_MUTEX_Unlock().

The sample application file OS_Mutexes.c delivered in the application samples folder of embOS demonstrates how mutex can be used in the above scenario:

#include "RTOS.h"
#include <stdio.h>

static OS_STACKPTR int StackHP[128], StackLP[128];  // Task stacks
static OS_TASK         TCBHP, TCBLP;                // Task-control-blocks
static OS_MUTEX        Mutex;

static void _Write(char const* s) {
  OS_MUTEX_LockBlocked(&Mutex);
  printf(s);
  OS_MUTEX_Unlock(&Mutex);
}

static void HPTask(void) {
  while (1) {
    _Write("HPTask\n");
    OS_TASK_Delay_ms(50);
  }
}

static void LPTask(void) {
  while (1) {
    _Write("LPTask\n");
    OS_TASK_Delay_ms(200);
  }
}

int main(void) {
  OS_Init();                   // Initialize embOS
  OS_InitHW();                 // Initialize hardware for embOS
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_TASK_CREATE(&TCBLP, "LP Task",  50, LPTask, StackLP);
  OS_MUTEX_Create(&Mutex);     // Creates mutex
  OS_Start();                  // Start multitasking
  return 0;
}

Priority inversion / priority inheritance

embOS supports priority inheritance as a solution for the priority inversion problem when a mutex is used by multiple tasks. Please have a look in the chapter Priority inversion / priority inheritance for more details.

Deadlock

Occasionally, you might want to access two resources at once. Perhaps you are using one of the resources, and then discover that the other resource is needed as well. A problem exists if two tasks attempt to claim both resources but lock the associated mutexes in different orders.

HPTask runs first, claims Mutex_A and then calls OS_TASK_Delay_ms() which executes a task switch to LPTask. LPTask claims Mutex_B and tries to claim Mutex_A. Since Mutex_A is already acquired by HPTask it cannot be acquired by LPTask and LPTask is blocked. When the delay has expired HPTask tries to claim Mutex_B which is already acquired by LPTask. Both tasks are blocked now.

static void HPTask(void) {
  while (1) {
    OS_MUTEX_LockBlocked(&Mutex_A);
    OS_TASK_Delay_ms(1);
    OS_MUTEX_LockBlocked(&Mutex_B);
    OS_MUTEX_Unlock(&Mutex_B);
    OS_MUTEX_Unlock(&Mutex_A);
  }
}

static void LPTask(void) {
  while (1) {
    OS_MUTEX_LockBlocked(&Mutex_B);
    OS_MUTEX_LockBlocked(&Mutex_A);
    OS_MUTEX_Unlock(&Mutex_A);
    OS_MUTEX_Unlock(&Mutex_B);
  }
}

The best way to avoid this problem is to make sure that when tasks lock multiple mutexes, the tasks do so in the same order. When locks are always taken in a prescribed order, deadlock should not occur.

However, this technique cannot always be used. Sometimes, you must take the mutexes in an order other than prescribed. To prevent deadlock in such a situation, use OS_MUTEX_Lock() instead of the blocking API. One task must release its mutexes when the task discovers that deadlock would otherwise be inevitable.

static void HPTask(void) {
  while (1) {
    OS_MUTEX_LockBlocked(&Mutex_A);
    OS_TASK_Delay_ms(1);
    OS_MUTEX_LockBlocked(&Mutex_B);
    OS_MUTEX_Unlock(&Mutex_B);
    OS_MUTEX_Unlock(&Mutex_A);
  }
}

static void LPTask(void) {
  while (1) {
    OS_MUTEX_LockBlocked(&Mutex_B);
    if (OS_MUTEX_Lock(&Mutex_A) == 0) {
      OS_MUTEX_Unlock(&Mutex_B);
    } else {
      OS_MUTEX_Unlock(&Mutex_A);
      OS_MUTEX_Unlock(&Mutex_B);
    }
    OS_TASK_Delay_ms(1);
  }
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_MUTEX_Create() Creates a mutex.
OS_MUTEX_Delete() Deletes a specified mutex.
OS_MUTEX_GetOwner() Returns the mutex owner if any.
OS_MUTEX_GetValue() Returns the value of the usage counter of a specified mutex.
OS_MUTEX_IsMutex() Returns whether a mutex has already been created.
OS_MUTEX_Lock() Requests a specified mutex and blocks it for other tasks if it is available.
OS_MUTEX_LockBlocked() Claims a mutex and blocks it for other tasks.
OS_MUTEX_LockTimed() Tries to claim a mutex and blocks it for other tasks if it is available within a specified time.
OS_MUTEX_Unlock() Releases a mutex currently in use by a task.

OS_MUTEX_Create()

Description

Creates a mutex.

Prototype

void OS_MUTEX_Create(OS_MUTEX* pMutex);

Parameters

Parameter Description
pMutex Pointer to a mutex object of type OS_MUTEX.

Additional information

After creation, the mutex is not locked. The mutex counter value is zero.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
165: OS_ERR_INIT_NOT_CALLED
175: OS_ERR_2USE_MUTEX

For details, refer to the chapter Runtime application errors.

Example

static OS_MUTEX _Mutex;

int main(void) {
  ...
  OS_MUTEX_Create(&_Mutex);
  ...
  return 0;
}

OS_MUTEX_Delete()

Description

Deletes a specified mutex.

Prototype

void OS_MUTEX_Delete(OS_MUTEX* pMutex);

Parameters

Parameter Description
pMutex Pointer to a mutex object of type OS_MUTEX.

Additional information

The memory of that mutex may be reused for other purposes or may be used for creating another mutex using the same memory. Before deleting a mutex, make sure that no task is claiming the mutex.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

133: OS_ERR_INV_MUTEX
138: OS_ERR_MUTEX_DELETE
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_MUTEX _Mutex;

int Task(void) {
  ...
  OS_MUTEX_Delete(&_Mutex);
  ...
  return 0;
}

OS_MUTEX_GetOwner()

Description

Returns the mutex owner if any. When a task is currently using (blocking) the mutex the task Id (address of task according task control block) is returned.

Prototype

OS_TASK *OS_MUTEX_GetOwner(OS_CONST_PTR OS_MUTEX *pMutex);

Parameters

Parameter Description
pMutex Pointer to a mutex object of type OS_MUTEX.

Return value

= NULL The mutex is not used by any task.
NULL Task Id (address of the task control block).

Additional information

If a mutex was used in main() the return value of OS_MUTEX_GetOwner() is ambiguous. The return value NULL can mean it is currently used in main() or it is currently unused. Therefore, OS_MUTEX_GetOwner() must not be used to check if a mutex is available. Please use OS_MUTEX_GetValue() instead.

It is also good practice to free all used mutexes in main() before calling OS_Start().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

133: OS_ERR_INV_MUTEX
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please find an example at OS_MUTEX_GetValue().

OS_MUTEX_GetValue()

Description

Returns the value of the usage counter of a specified mutex.

Prototype

int OS_MUTEX_GetValue(OS_CONST_PTR OS_MUTEX *pMutex);

Parameters

Parameter Description
pMutex Pointer to a mutex object of type OS_MUTEX.

Return value

The counter value of the mutex.
A value of zero means the mutex is available.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

133: OS_ERR_INV_MUTEX
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_MUTEX _Mutex;

void CheckMutex(void) {
  int      Value;
  OS_TASK* Owner;

  Value = OS_MUTEX_GetValue(&_Mutex);
  if (Value == 0) {
    printf("Mutex is currently unused");
  } else {
    Owner = OS_MUTEX_GetOwner(&_Mutex);
    if (Owner == NULL) {
      printf("Mutex was used in main()");
    } else {
      printf("Mutex is currently used in task 0x%X", Owner);
    }
  }
}

OS_MUTEX_IsMutex()

Description

Returns whether a mutex has already been created.

Prototype

OS_BOOL OS_MUTEX_IsMutex(OS_CONST_PTR OS_MUTEX *pMutex);

Parameters

Parameter Description
pMutex Pointer to a mutex object of type OS_MUTEX.

Return value

= 0 Mutex has not been created or was deleted.
≠ 0 Mutex has already been created.

Additional information

OS_MUTEX_IsMutex() returns 1 if a mutex was created with OS_MUTEX_Create() and not yet deleted with OS_MUTEX_Delete(). OS_MUTEX_IsMutex() returns 0 if a mutex was not yet created with OS_MUTEX_Create() or it was deleted with OS_MUTEX_Delete().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_MUTEX _Mutex;

int main(void) {
  ...
  if (OS_MUTEX_IsMutex(&_Mutex) != (OS_BOOL)0) {
    printf("Mutex has already been created");
  } else {
    printf("Mutex has not yet been created");
  }
  ...
  return 0;
}

OS_MUTEX_Lock()

Description

Requests a specified mutex and blocks it for other tasks if it is available. Continues execution in any case.

Prototype

char OS_MUTEX_Lock(OS_MUTEX* pMutex);

Parameters

Parameter Description
pMutex Pointer to a mutex object of type OS_MUTEX.

Return value

= 0 Mutex was not available.
≠ 0 Mutex was available, now in use by calling task.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

133: OS_ERR_INV_MUTEX
159: OS_ERR_MUTEX_OVERFLOW
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Additional information

The following diagram illustrates how OS_MUTEX_Lock() works:

Example

if (OS_MUTEX_Lock(&Mutex_LCD)) {
  DispTime();                   // Access the resource LCD
  OS_MUTEX_Unlock(&Mutex_LCD);  // Resource LCD is no longer needed
} else {
  ... // Do something else
}

OS_MUTEX_LockBlocked()

Description

Claims a mutex and blocks it for other tasks.

Prototype

int OS_MUTEX_LockBlocked(OS_MUTEX* pMutex);

Parameters

Parameter Description
pMutex Pointer to a mutex object of type OS_MUTEX.

Return value

The counter value of the mutex.
A value greater than one denotes the mutex was already locked by the calling task.

Additional information

The following situations are possible:

An unlimited number of tasks can wait for a mutex. According to the rules of the scheduler, of all the tasks waiting for the mutex the task with the highest priority will acquire the mutex and continue program execution.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

133: OS_ERR_INV_MUTEX
159: OS_ERR_MUTEX_OVERFLOW
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_MUTEX _Mutex;

void Task(void) {
  ...
  OS_MUTEX_LockBlocked(&_Mutex);
  ...
  OS_MUTEX_Unlock(&_Mutex);
  ...
}

The following diagram illustrates how OS_MUTEX_LockBlocked() works:

OS_MUTEX_LockTimed()

Description

Tries to claim a mutex and blocks it for other tasks if it is available within a specified time.

Prototype

int OS_MUTEX_LockTimed(OS_MUTEX* pMutex,
                       OS_U32    Timeout);

Parameters

Parameter Description
pMutex Pointer to a mutex object of type OS_MUTEX.
Timeout Maximum time in milliseconds until the mutex must be available.

Return value

= 0 Failed, mutex not available before timeout.
≠ 0 Success, mutex available, current usage count of mutex.

A value greater than one denotes the mutex was already locked by the calling task.

Additional information

The following situations are possible:

When the calling task is blocked by higher priority tasks for a period longer than the timeout value, it may happen that the mutex becomes available before the calling task is resumed. Anyhow, the function will not claim the mutex because it was not available within the requested time.

An unlimited number of tasks can wait for a mutex. According to the rules of the scheduler, of all the tasks waiting for the mutex the task with the highest priority will acquire the mutex and continue program execution.

OS_TIME_ConfigSysTimer() must have been called before calling OS_MUTEX_LockTimed().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

133: OS_ERR_INV_MUTEX
159: OS_ERR_MUTEX_OVERFLOW
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_MUTEX _Mutex;

void Task(void) {
  ...
  if (OS_MUTEX_LockTimed(&_Mutex, 100)) {
    ... // Mutex acquired
  } else {
    ... // Timeout
  }
  ...
}

OS_MUTEX_Unlock()

Description

Releases a mutex currently in use by a task.

Prototype

void OS_MUTEX_Unlock(OS_MUTEX* pMutex);

Parameters

Parameter Description
pMutex Pointer to a mutex object of type OS_MUTEX.

Additional information

OS_MUTEX_Unlock() may be used on a mutex only after that mutex has been locked by calling OS_MUTEX_Lock(), OS_MUTEX_LockBlocked(), or OS_MUTEX_LockTimed(). OS_MUTEX_Unlock() decrements the usage counter of the mutex, which must never become negative.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

133: OS_ERR_INV_MUTEX
150: OS_ERR_UNUSE_BEFORE_USE
156: OS_ERR_MUTEX_OWNER
159: OS_ERR_MUTEX_OVERFLOW
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please find an example at OS_MUTEX_Lock().

Semaphore

Introduction

A semaphore is a mechanism that can be used to provide synchronization of tasks. Semaphores which allow an arbitrary resource count are called counting semaphores, while semaphores which are restricted to the values 0 and 1 are called binary semaphores.

One way to use semaphores is for signaling from one task (or ISR/software timer) to another task. For example, if two tasks need to execute the same total number of times over the long run: A counting semaphore can be created with an initial count of zero (no ’tokens’ in it). Every time the first task runs, it puts a token into the semaphore, thus incrementing the semaphore’s count. The second task of the pair waits at the semaphore for tokens to appear, and runs once for each new token, thus consuming the token and decrementing the semaphore’s count. If the first task runs with moderate bursts, the second task will eventually ’catch up’ to the same total number of executions.
Binary semaphores can be used for signaling from task to task, too, in situations where signals (counts, tokens) will not accumulate or need not be counted.

Counting semaphores are also used for regulating the access of tasks to multiple equivalent serially-shareable resources. For instance, 10 tasks may wish to share 4 identical printers. In this case, a counting semaphore can be created and initialized with 4 tokens. Tasks are then programmed to take a token before printing, and return the token after printing is done.

Example of using counter semaphore for signaling

Here, an interrupt is issued every time data is received from a peripheral source. The interrupt service routine then signals the arrival of data to a worker task, which subsequently processes that data. When the worker task is blocked from execution, e.g. by a higher-priority task, the semaphore’s counter effectively tracks the number of data packets to be processed by the worker task, which will be executed for that exact number of times when resumed.

The following sample application shows how semaphores can be used in the above scenario:

#include "RTOS.h"
#include <stdio.h>

static OS_STACKPTR int Stack[128];        // Task stack
static OS_TASK         TCB;               // Task control block
static OS_SEMAPHORE    Sema;              // Semaphore
static OS_TIMER        Timer;             // Timer to emulate interrupt

static void Task(void) {
  while(1) {
    OS_SEMAPHORE_TakeBlocked(&Sema);      // Wait for signaling of received data
    printf("Task is processing data\n");  // Act on received data
  }
}

static void TimerCallback(void) {
  // Software timer function to emulate an interrupt
  OS_SEMAPHORE_Give(&Sema);               // Signal data reception
  OS_TIMER_Restart(&Timer);
}

int main(void) {
  OS_Init();                              // Initialize embOS
  OS_InitHW();                            // Initialize required hardware
  OS_TIMER_Create(&Timer, TimerCallback, 10);
  OS_TIMER_Start(&Timer);
  OS_TASK_CREATE(&TCB, "Task", 100, Task, Stack);
  OS_SEMAPHORE_Create(&Sema, 0);          // Creates semaphore
  OS_Start();                             // Start embOS
  return 0;
}

Example of using semaphore for regulating the access to shareable resources:

Ten tasks need to print messages on four available printers. The access to the printer must not be interrupted by another task. It is not essential for a task which actual printer is used and the Printer() function does not care about this aspect (this is a limitation of the example but not relevant). The example creates the semaphore with 4 tokens. Each token represents one printer. If a task wants to use one of the printers it takes one token and give it back after the print job is done. When no token (printer) is available the task is suspended until a token is again available.

#include "RTOS.h"
#include <stdio.h>

#define NUM_PRINTERS  4
#define NUM_TASKS     10

static OS_STACKPTR int Stack[NUM_TASKS][128];  // Task stack
static OS_TASK         TCB[NUM_TASKS];         // Task control block
static OS_SEMAPHORE    Sema;                   // Semaphore

static void Print(const char* s) {
  OS_SEMAPHORE_TakeBlocked(&Sema);
  // Print message on one of the available printers
  OS_SEMAPHORE_Give(&Sema);
}

static void Task(void) {
  while(1) {
    Print("Hello World");
  }
}

int main(void) {
  OS_U32 i;

  OS_Init();                                 // Initialize embOS
  OS_InitHW();                               // Initialize required hardware
  for (i = 0u; i < NUM_TASKS; i++) {
    OS_TASK_CREATE(&TCB[i], "Task", 100, Task, Stack[i]);
  }
  OS_SEMAPHORE_Create(&Sema, NUM_PRINTERS);  // Creates semaphore
  OS_Start();                                // Start embOS
  return 0;
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_SEMAPHORE_Create() Creates a semaphore with a specified initial token count value.
OS_SEMAPHORE_Delete() Deletes the specified semaphore.
OS_SEMAPHORE_GetValue() Returns the semaphore token counter value of the specified semaphore.
OS_SEMAPHORE_Give() Increments the semaphore token counter of the specified semaphore.
OS_SEMAPHORE_GiveMax() Increments the semaphore token count of the specified semaphore up to the specified maximum value.
OS_SEMAPHORE_SetValue() Sets the semaphore token counter value of the specified semaphore.
OS_SEMAPHORE_Take() Decrements the semaphore token counter value of the specified semaphore, if it was not zero.
OS_SEMAPHORE_TakeBlocked() Decrements the semaphore token counter value of the specified semaphore.
OS_SEMAPHORE_TakeTimed() Decrements the semaphore token counter value of the specified semaphore if a semaphore token is available within the specified time.

OS_SEMAPHORE_Create()

Description

Creates a semaphore with a specified initial token count value.

Prototype

void OS_SEMAPHORE_Create(OS_SEMAPHORE* pSema,
                         OS_UINT       InitValue);

Parameters

Parameter Description
pSema Pointer to a semaphore object of type OS_SEMAPHORE.
InitValue Initial semaphore token count value:
0 ≤ InitValue ≤ 216 - 1 = 0xFFFF for 8/16-bit CPUs.
0 ≤ InitValue ≤ 232 - 1 = 0xFFFFFFFF for 32-bit CPUs.

Additional information

Note

embOS offers a macro that calls OS_SEMAPHORE_Create() with an initial count value of 0, allowing to more easily create semaphores. If the macro shall be used, its definition is as follows:

#define OS_SEMAPHORE_CREATE(ps) OS_SEMAPHORE_Create((ps), 0)

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
174: OS_ERR_2USE_SEMAPHORE

For details, refer to the chapter Runtime application errors.

Example

static OS_SEMA _Sema;

int main(void) {
  ...
  OS_SEMAPHORE_Create(&_Sema, 8);
  ...
  return 0;
}

OS_SEMAPHORE_Delete()

Description

Deletes the specified semaphore.

Prototype

void OS_SEMAPHORE_Delete(OS_SEMAPHORE* pSema);

Parameters

Parameter Description
pSema Pointer to a semaphore object of type OS_SEMAPHORE.

Additional information

Before deleting a semaphore, make sure that no task is waiting for it.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

132: OS_ERR_INV_SEMAPHORE
137: OS_ERR_SEMAPHORE_DELETE
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_SEMA _Sema;

void Task(void) {
  ...
  OS_SEMAPHORE_Delete(&_Sema);
  ...
}

OS_SEMAPHORE_GetValue()

Description

Returns the semaphore token counter value of the specified semaphore.

Prototype

int OS_SEMAPHORE_GetValue(OS_CONST_PTR OS_SEMAPHORE *pSema);

Parameters

Parameter Description
pSema Pointer to a semaphore object of type OS_SEMAPHORE.

Return value

The current semaphore token counter value.

Additional information

OS_SEMAPHORE_GetValue() can be used to get the current semaphore token value before calling e.g. OS_SEMAPHORE_TakeBlocked().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

132: OS_ERR_INV_SEMAPHORE
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_SEMA _Sema;

void PrintSemaValue(void) {
  int Value;

  Value = OS_SEMAPHORE_GetValue(&_Sema);
  printf("Sema Value: %d\n", Value)
}

OS_SEMAPHORE_SetValue()

Description

Sets the semaphore token counter value of the specified semaphore.

Prototype

OS_U8 OS_SEMAPHORE_SetValue(OS_SEMAPHORE* pSema,
                            OS_UINT       Value);

Parameters

Parameter Description
pSema Pointer to a semaphore object of type OS_SEMAPHORE.
Value Count value of the semaphore:
0 ≤ Value ≤ 216 - 1 = 0xFFFF for 8/16-bit CPUs.
0 ≤ Value ≤ 232 - 1 = 0xFFFFFFFF for 32-bit CPUs.

Return value

= 0: In any case. The return value can safely be ignored.

Additional information

If one ore more tasks are waiting for this semaphore, they will be put in the READY state and activated according to the rules of the scheduler.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

132: OS_ERR_INV_SEMAPHORE
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_SEMA _Sema;

void Task(void) {
  ...
  OS_SEMAPHORE_SetValue(&_Sema, 0);
  ...
}

OS_SEMAPHORE_Give()

Description

Increments the semaphore token counter of the specified semaphore.

Prototype

void OS_SEMAPHORE_Give(OS_SEMAPHORE* pSema);

Parameters

Parameter Description
pSema Pointer to a semaphore object of type OS_SEMAPHORE.

Additional information

OS_SEMAPHORE_Give() increments the semaphore token count. If one ore more tasks are waiting for this semaphore, they will be put in the READY state and activated according to the rules of the scheduler.

The semaphore token counter can have a maximum value of 0xFFFF for 8/16-bit CPUs or 0xFFFFFFFF for 32-bit CPUs. It is the responsibility of the application to make sure that this limit is not exceeded.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

121: OS_ERR_SEMAPHORE_OVERFLOW
132: OS_ERR_INV_SEMAPHORE
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example in the introduction of chapter Semaphores.

OS_SEMAPHORE_GiveMax()

Description

Increments the semaphore token count of the specified semaphore up to the specified maximum value.

Prototype

void OS_SEMAPHORE_GiveMax(OS_SEMAPHORE* pSema,
                          OS_UINT       MaxValue);

Parameters

Parameter Description
pSema Pointer to a semaphore object of type OS_SEMAPHORE.
MaxValue Count value of the semaphore:
1 ≤ MaxValue ≤ 216 - 1 = 0xFFFF for 8/16-bit CPUs.
1 ≤ MaxValue ≤ 232 - 1 = 0xFFFFFFFF for 32-bit CPUs.

Additional information

As long as current value of the semaphore token counter is below the specified maximum value, OS_SEMAPHORE_GiveMax() increments its token counter. If one ore more tasks are waiting for this semaphore, they will be put in the READY state and activated according to the rules of the scheduler.

Calling OS_SEMAPHORE_GiveMax() with a MaxValue of 1 makes a counting semaphore behave like a binary semaphore.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

132: OS_ERR_INV_SEMAPHORE
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_SEMA _Sema;

void Task(void) {
  ...
  OS_SEMAPHORE_GiveMax(&_Sema, 8);
  ...
}

OS_SEMAPHORE_Take()

Description

Decrements the semaphore token counter value of the specified semaphore, if it was not zero.

Prototype

OS_BOOL OS_SEMAPHORE_Take(OS_SEMAPHORE* pSema);

Parameters

Parameter Description
pSema Pointer to a semaphore object of type OS_SEMAPHORE.

Return value

= 0 Failed, no semaphore token available (semaphore token counter is zero).
≠ 0 Success, semaphore token was available and semaphore token counter was decremented once.

Additional information

This function never suspends the calling task. It may therefore also be called from an embOS interrupt routine. If the semaphore token counter is not zero, the counter is decremented. If the semaphore token counter is zero, OS_SEMAPHORE_Take() does not modify the semaphore token counter.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

132: OS_ERR_INV_SEMAPHORE
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_SEMA _Sema;

void Task(void) {
  ...
  if (OS_SEMAPHORE_Take(&_Sema) != 0) {
    printf("Semaphore decremented successfully.\n");
  } else {
    printf("Semaphore not signaled.\n");
  }
  ...
}

OS_SEMAPHORE_TakeBlocked()

Description

Decrements the semaphore token counter value of the specified semaphore.

Prototype

void OS_SEMAPHORE_TakeBlocked(OS_SEMAPHORE* pSema);

Parameters

Parameter Description
pSema Pointer to a semaphore object of type OS_SEMAPHORE.

Additional information

If the counter of the semaphore is not zero, the counter is decremented and program execution continues.

If the counter is zero, OS_SEMAPHORE_TakeBlocked() waits until the counter is incremented by another task, a timer or an interrupt handler by a call to OS_SEMAPHORE_Give(). The counter is then decremented and program execution continues. An unlimited number of tasks can wait for a semaphore. According to the rules of the scheduler, of all the tasks waiting for the semaphore, the task with the highest priority will continue program execution.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

132: OS_ERR_INV_SEMAPHORE
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example in the introduction of chapter Semaphores.

OS_SEMAPHORE_TakeTimed()

Description

Decrements the semaphore token counter value of the specified semaphore if a semaphore token is available within the specified time.

Prototype

OS_BOOL OS_SEMAPHORE_TakeTimed(OS_SEMAPHORE* pSema,
                               OS_U32        Timeout);

Parameters

Parameter Description
pSema Pointer to a semaphore object of type OS_SEMAPHORE.
Timeout Maximum time in milliseconds until the semaphore must be available.

Return value

= 0 Failed, semaphore not available before timeout.
≠ 0 Success, semaphore was available and counter decremented.

Additional information

If the semaphore token counter is not zero, the counter is decremented and program execution continues.

If the counter is zero, OS_SEMAPHORE_TakeTimed() waits until the semaphore token counter is incremented by another task, a timer, or an interrupt handler by a call to OS_SEMAPHORE_Give(). The counter is then decremented and program execution continues. If the semaphore token counter was incremented within the specified time the program execution continues, but returns a value of zero.

When the calling task is blocked by higher priority tasks for a period longer than the timeout value, it may happen that the semaphore becomes available after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the semaphore was not available within the requested time. In this case, the state of the semaphore is not modified by OS_SEMAPHORE_TakeTimed().

OS_TIME_ConfigSysTimer() must have been called before calling OS_SEMAPHORE_TakeTimed().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

132: OS_ERR_INV_SEMAPHORE
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_SEMA _Sema;

void Task(void) {
  ...
  if (OS_SEMAPHORE_TakeTimed(&_Sema, 100)) {
    ... // Semaphore acquired
  } else {
    ... // Timeout
  }
  ...
}

Readers-Writer Lock

Introduction

A readers-writer lock is a synchronization primitive that solves the readers-writer problem. A readers-writer lock allows concurrent access for read-only operations, while write operations require exclusive access. This means that multiple tasks can read the data in parallel but an exclusive lock is needed for writing or modifying data. When a writer is writing the data, all other writers or readers will be blocked until the writer has finished writing. A common use might be to control access to a data structure in memory that cannot be updated atomically and is invalid (and should not be read by another task) until the update is complete. An embOS readers-writer lock is implemented using semaphores and mutexes.

#include "RTOS.h"
#include "stdio.h"

#define NUM_READERS  2

static OS_STACKPTR int StackRd1[128], StackRd2[128], StackWr[128];
static OS_TASK         TCBRd1, TCBRd2, TCBWr;
static OS_RWLOCK       Lock;
static OS_U32          GlobalVar;

static void RdTask(void) {
  while (1) {
    OS_RWLOCK_RdLockBlocked(&Lock);
    printf("%u\n", GlobalVar);
    OS_RWLOCK_RdUnlock(&Lock);
  }
}

static void WrTask(void) {
  while (1) {
    OS_RWLOCK_WrLockBlocked(&Lock);
    GlobalVar++;
    OS_RWLOCK_WrUnlock(&Lock);
    OS_TASK_Delay_ms(10);
  }
}

int main(void) {
  OS_Init();    // Initialize embOS
  OS_InitHW();  // Initialize required hardware
  OS_TASK_CREATE(&TCBRd1, "Reader Task 1", 100, RdTask, StackRd1);
  OS_TASK_CREATE(&TCBRd2, "Reader Task 2", 100, RdTask, StackRd2);
  OS_TASK_CREATE(&TCBWr,  "Writer Task"  , 101, WrTask, StackWr);
  OS_RWLOCK_Create(&Lock, NUM_READERS);
  OS_Start();   // Start embOS
  return 0;
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_RWLOCK_Create() Creates a readers-writer lock.
OS_RWLOCK_Delete() Deletes the specified readers-writer lock.
OS_RWLOCK_RdLock() Claims the specified readers-writer lock and blocks it for writer tasks.
OS_RWLOCK_RdLockBlocked() Claims the specified readers-writer lock and blocks it for writer tasks.
OS_RWLOCK_RdLockTimed() Claims the specified readers-writer lock if the lock is available within the specified timeout and blocks it for writer tasks.
OS_RWLOCK_RdUnlock() Releases the specified readers-writer lock currently used by the reader task.
OS_RWLOCK_WrLock() Claims the specified readers-writer lock and blocks it for writer and reader tasks.
OS_RWLOCK_WrLockBlocked() Claims the specified readers-writer lock and blocks it for writer and reader tasks.
OS_RWLOCK_WrLockTimed() Claims the specified readers-writer lock if the lock is available within the specified timeout and blocks it for writer and reader tasks.
OS_RWLOCK_WrUnlock() Releases the specified readers-writer lock currently used by the writer task.

OS_RWLOCK_Create()

Description

Creates a readers-writer lock.

Prototype

void OS_RWLOCK_Create(OS_RWLOCK* pLock,
                      OS_UINT    NumReaders);

Parameters

Parameter Description
pLock Pointer to a readers-writer lock object of type OS_RWLOCK.
NumReaders Number of reader tasks. Maximum number is:
0 ≤ InitValue ≤ 216 - 1 = 0xFFFF for 8/16-bit CPUs.
0 ≤ InitValue ≤ 232 - 1 = 0xFFFFFFFF for 32-bit CPUs.

Additional information

If you use readers-writer lock from an unprivileged task you need not only access to the lock object itself but also to the semaphore and the mutex member. Please see embOS-MPU example below.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
258: OS_ERR_2USE_RWLOCK

For details, refer to the chapter Runtime application errors.

Example

#define NUM_READERS  2

static OS_RWLOCK Lock;

int main(void) {
  ...
  OS_RWLOCK_Create(&Lock, NUM_READERS);
  ...
  return 0;
}

Example using embOS-Ultra-MPU

static OS_RWLOCK Lock;

static const OS_MPU_OBJ _aList[] = {{&Lock,           OS_MPU_OBJTYPE_RWLOCK},
                                    {&Lock.Semaphore, OS_MPU_OBJTYPE_SEMA},
                                    {&Lock.Mutex,     OS_MPU_OBJTYPE_MUTEX},
                                    {NULL,            OS_MPU_OBJTYPE_INVALID}};

static void Task(void) {
  OS_MPU_SetAllowedObjects(&TCB, _aList);
  OS_MPU_SwitchToUnprivState();
  while (1) {
    OS_RWLOCK_RdLockBlocked(&Lock);
    ReadData();
    OS_RWLOCK_RdUnlock(&Lock);
  };
}

OS_RWLOCK_Delete()

Description

Deletes the specified readers-writer lock.

Prototype

void OS_RWLOCK_Delete(OS_RWLOCK* pLock);

Parameters

Parameter Description
pLock Pointer to a readers-writer lock object of type OS_RWLOCK.

Additional information

Before deleting a readers-writer lock, make sure that no task is waiting for it.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
257: OS_ERR_RWLOCK_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_RWLOCK Lock;

void Task(void) {
  ...
  OS_RWLOCK_Delete(&Lock);
  ...
}

OS_RWLOCK_RdLock()

Description

Claims the specified readers-writer lock and blocks it for writer tasks.

Prototype

OS_BOOL OS_RWLOCK_RdLock(OS_RWLOCK* pLock);

Parameters

Parameter Description
pLock Pointer to a readers-writer lock object of type OS_RWLOCK.

Return value

= 0 Failed, lock could not be claimed.
≠ 0 Success, lock was available.

Additional information

Reader tasks can still access the guarded object. OS_RWLOCK_RdLock() returns at once in any case.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

167: OS_ERR_CPU_STATE_ILLEGAL
257: OS_ERR_RWLOCK_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_RWLOCK Lock;

void Task(void) {
  OS_BOOL r;

  r = OS_RWLOCK_RdLock(&Lock);
  if (r != 0) {
    ReadSomeData();
    OS_RWLOCK_RdUnlock(&Lock);
  }
}

OS_RWLOCK_RdLockBlocked()

Description

Claims the specified readers-writer lock and blocks it for writer tasks.

Prototype

void OS_RWLOCK_RdLockBlocked(OS_RWLOCK* pLock);

Parameters

Parameter Description
pLock Pointer to a readers-writer lock object of type OS_RWLOCK.

Additional information

Reader tasks can still access the guarded object. OS_RWLOCK_RdLockBlocked() suspends the current task and returns once a read lock is available.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
257: OS_ERR_RWLOCK_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_RWLOCK Lock;

void Task(void) {
  OS_RWLOCK_RdLockBlocked(&Lock);
  ReadSomeData();
  OS_RWLOCK_RdUnlock(&Lock);
}

OS_RWLOCK_RdLockTimed()

Description

Claims the specified readers-writer lock if the lock is available within the specified timeout and blocks it for writer tasks.

Prototype

OS_BOOL OS_RWLOCK_RdLockTimed(OS_RWLOCK* pLock,
                              OS_U32     Timeout);

Parameters

Parameter Description
pLock Pointer to a readers-writer lock object of type OS_RWLOCK.
Timeout Maximum time in milliseconds until the lock must be available.

Return value

= 0 Failed, lock could not be claimed within the timeout.
≠ 0 Success, lock was available.

Additional information

Reader tasks can still access the guarded object. OS_RWLOCK_RdLockTimed() suspends the current task and returns once a reader lock is available or the timeout has expired.

OS_TIME_ConfigSysTimer() must have been called before calling OS_RWLOCK_RdLockTimed().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO
257: OS_ERR_RWLOCK_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_RWLOCK Lock;

void Task(void) {
  OS_BOOL r;

  r = OS_RWLOCK_RdLockTimed(&Lock, 100);
  if (r != 0) {
    ReadSomeData();
    OS_RWLOCK_RdUnlock(&Lock);
  }
}

OS_RWLOCK_RdUnlock()

Description

Releases the specified readers-writer lock currently used by the reader task.

Prototype

void OS_RWLOCK_RdUnlock(OS_RWLOCK* pLock);

Parameters

Parameter Description
pLock Pointer to a readers-writer lock object of type OS_RWLOCK.

Additional information

After OS_RWLOCK_RdUnlock() the lock can be used by another reader or the writer task.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

167: OS_ERR_CPU_STATE_ILLEGAL
257: OS_ERR_RWLOCK_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_RWLOCK Lock;

void Task(void) {
  OS_RWLOCK_RdLockBlocked(&Lock);
  ReadSomeData();
  OS_RWLOCK_RdUnlock(&Lock);
}

OS_RWLOCK_WrLock()

Description

Claims the specified readers-writer lock and blocks it for writer and reader tasks.

Prototype

OS_BOOL OS_RWLOCK_WrLock(OS_RWLOCK* pLock);

Parameters

Parameter Description
pLock Pointer to a readers-writer lock object of type OS_RWLOCK.

Return value

= 0 Failed, writer lock could not be claimed.
≠ 0 Success, writer lock was available.

Additional information

OS_RWLOCK_WrLock() returns at once in any case.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
257: OS_ERR_RWLOCK_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_RWLOCK Lock;

void Task(void) {
  OS_BOOL r;

  r = OS_RWLOCK_WrLock(&Lock);
  if (r != 0) {
    WriteSomeData();
    OS_RWLOCK_WrUnlock(&Lock);
  }
}

OS_RWLOCK_WrLockBlocked()

Description

Claims the specified readers-writer lock and blocks it for writer and reader tasks.

Prototype

void OS_RWLOCK_WrLockBlocked(OS_RWLOCK* pLock);

Parameters

Parameter Description
pLock Pointer to a readers-writer lock object of type OS_RWLOCK.

Additional information

It requires all readers to relinquish their locks before the writer lock can be acquired. OS_RWLOCK_WrLockBlocked() suspends the current task and returns once the write lock is available.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
257: OS_ERR_RWLOCK_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_RWLOCK Lock;

void Task(void) {
  OS_RWLOCK_WrLockBlocked(&Lock);
  WriteSomeData();
  OS_RWLOCK_WrUnlock(&Lock);
}

OS_RWLOCK_WrLockTimed()

Description

Claims the specified readers-writer lock if the lock is available within the specified timeout and blocks it for writer and reader tasks.

Prototype

OS_BOOL OS_RWLOCK_WrLockTimed(OS_RWLOCK* pLock,
                              OS_U32     Timeout);

Parameters

Parameter Description
pLock Pointer to a readers-writer lock object of type OS_RWLOCK.
Timeout Maximum time in milliseconds until the lock must be available.

Return value

= 0 Failed, lock could not be claimed.
≠ 0 Success, lock was available.

Additional information

It requires all readers to relinquish their locks before the writer lock can be acquired. OS_RWLOCK_WrLockTimed() suspends the current task and returns once the writer lock is available or the timeout has expired.

OS_TIME_ConfigSysTimer() must have been called before calling OS_RWLOCK_WrLockTimed().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO
257: OS_ERR_RWLOCK_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_RWLOCK Lock;

void Task(void) {
  OS_BOOL r;

  r = OS_RWLOCK_WrLockTimed(&Lock, 100);
  if (r != 0) {
    WriteSomeData();
    OS_RWLOCK_WrUnlock(&Lock);
  }
}

OS_RWLOCK_WrUnlock()

Description

Releases the specified readers-writer lock currently used by the writer task.

Prototype

void OS_RWLOCK_WrUnlock(OS_RWLOCK* pLock);

Parameters

Parameter Description
pLock Pointer to a readers-writer lock object of type OS_RWLOCK.

Additional information

After OS_RWLOCK_WrUnlock() the lock is available for other reader and writer tasks.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
257: OS_ERR_RWLOCK_INVALID

For details, refer to the chapter Runtime application errors.

Example

static OS_RWLOCK Lock;

void Task(void) {
  OS_RWLOCK_WrLockBlocked(&Lock);
  WriteSomeData();
  OS_RWLOCK_WrUnlock(&Lock);
}

Mailbox

Introduction

In the preceding chapters, task synchronization by the use of semaphores was described. Unfortunately, semaphores cannot transfer data from one task to another. If we need to transfer data between tasks for example via a buffer, we could use a mutex every time we accessed the buffer. But doing so would make the program less efficient. Another major disadvantage would be that we could not access the buffer from an interrupt handler, because the interrupt handler is not allowed to wait for the mutex.

One solution would be the usage of global variables. In this case we would need to disable interrupts each time and in each place that we accessed these variables. This is possible, but it is a path full of pitfalls. It is also not easy for a task to wait for a character to be placed in a buffer without polling the global variable that contains the number of characters in the buffer. Again, there is solution -- the task could be notified by an event signaled to the task each time a character is placed in the buffer. This is why there is an easier way to do this with a real-time OS: The use of mailboxes.

A mailbox is a buffer that is managed by the RTOS. The buffer behaves like a normal buffer; you can deposit something (called a message) and retrieve it later. Mailboxes usually work as FIFO: first in, first out. So a message that is deposited first will usually be retrieved first. “Message” might sound abstract, but very simply it means “item of data”. It will become clearer in the typical applications explained in the following section.

Limitations:

Both the number of mailboxes and buffers are limited only by the amount of available memory. However, the number of messages per mailbox, the message size per mailbox, and the buffer size per mailbox are limited by software design. The buffer must be big enough to hold the given number of messages of the specified size: Message size * Number of messages in bytes.

8 or 16-bit CPUs 32-bit CPUs
Maximum number of messages 32,767 2,147,483,647
Maximum message size 32,767 bytes 32,767 bytes
Maximum buffer size 65,535 bytes 4,294,967,295 bytes

These limitations have been placed on mailboxes to guarantee efficient coding and also to ensure efficient management. These limitations are typically not a problem.

A mailbox can be used by more than one producer, but must be used by one consumer only. This means that more than one task or interrupt handler is allowed to deposit new data into the mailbox, but it does not make sense to retrieve messages by multiple tasks.

Single-byte mailbox functions

In many (if not the most) situations, mailboxes are used simply to hold and transfer single-byte messages. This is the case, for example, with a mailbox that takes the character received or sent via serial interface, or typically with a mailbox used as a keyboard buffer. In some of these cases, time is very critical, especially if a lot of data is transferred in short periods of time.

To minimize the overhead caused by the mailbox management of embOS, variations on some mailbox functions are available for single-byte mailboxes. The general functions OS_MAILBOX_PutBlocked(), OS_MAILBOX_Put(), OS_MAILBOX_GetBlocked(), and OS_MAILBOX_Get() can transfer messages of sizes between 1 and 32,767 bytes each.

Their single-byte equivalents OS_MAILBOX_PutBlocked1(), OS_MAILBOX_Put1(), OS_MAILBOX_GetBlocked1(), and OS_MAILBOX_Get1() work the same way with the exception that they execute much faster because management is simpler. It is recommended to use the single-byte versions if you transfer a lot of single-byte data via mailboxes.

The routines OS_MAILBOX_PutBlocked1(), OS_MAILBOX_Put1(), OS_MAILBOX_GetBlocked1(), and OS_MAILBOX_Get1() work exactly the same way as their universal equivalents. The only difference is that they must only be used for single-byte mailboxes.

Example

#define MAX_MSG_SIZE  (9)  // Max. number of bytes per message
#define MAX_MSG_NUM   (2)  // Max. number of messages per Mailbox

static OS_STACKPTR int StackHP[128], StackLP[128];  // Task stacks
static OS_TASK         TCBHP, TCBLP;                // Task control blocks
static OS_MAILBOX      MyMailbox;
static char            MyMailboxBuffer[MAX_MSG_SIZE * MAX_MSG_NUM];

static void HPTask(void) {
  char aData[MAX_MSG_SIZE];

  while (1) {
    OS_MAILBOX_GetBlocked(&MyMailbox, (void *)aData);
    OS_COM_SendString(aData);
  }
}

static void LPTask(void) {
  while (1) {
    OS_MAILBOX_PutBlocked(&MyMailbox, "Hello\0  ");
    OS_MAILBOX_PutBlocked(&MyMailbox, "World !\n");
  }
}

int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_TASK_CREATE(&TCBLP, "LP Task",  50, LPTask, StackLP);
  OS_MAILBOX_Create(&MyMailbox, MAX_MSG_SIZE, MAX_MSG_NUM, &MyMailboxBuffer);
  OS_COM_SendString("embOS OS_Mailbox example");
  OS_COM_SendString("\n\nDemonstrating message passing\n");
  OS_Start();     // Start embOS
  return 0;
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_MAILBOX_Clear() Clears all messages in the specified mailbox.
OS_MAILBOX_Create() Creates a mailbox.
OS_MAILBOX_Delete() Deletes the specified mailbox.
OS_MAILBOX_Get() Retrieves a new message of a predefined size from the specified mailbox if a message is available.
OS_MAILBOX_Get1() Retrieves a new message of size 1 from the specified mailbox, if a message is available.
OS_MAILBOX_GetBlocked() Retrieves a new message of a predefined size from the specified mailbox.
OS_MAILBOX_GetBlocked1() Retrieves a new message of size 1 from the specified mailbox.
OS_MAILBOX_GetMessageCnt() Returns the number of messages currently available in the specified mailbox.
OS_MAILBOX_GetTimed() Retrieves a new message of a predefined size from the specified mailbox if a message is available within a given time.
OS_MAILBOX_GetTimed1() Retrieves a new message of size 1 from the specified mailbox if a message is available within a given time.
OS_MAILBOX_GetPtr() Retrieves a pointer to a new message of a predefined size from the specified mailbox if a message is available.
OS_MAILBOX_GetPtrBlocked() Retrieves a pointer to a new message of a predefined size from the specified mailbox.
OS_MAILBOX_IsInUse() Returns whether the specified mailbox is currently in use.
OS_MAILBOX_Peek() Peeks a message from the specified mailbox without removing the message.
OS_MAILBOX_Purge() Deletes the last retrieved message in the specified mailbox.
OS_MAILBOX_Put() Stores a new message of a predefined size in the specified mailbox if the mailbox is able to accept one more message.
OS_MAILBOX_Put1() Stores a new message of size 1 in the specified mailbox if the mailbox is able to accept one more message.
OS_MAILBOX_PutBlocked() Stores a new message of a predefined size in the specified mailbox.
OS_MAILBOX_PutBlocked1() Stores a new message of size 1 in the specified mailbox.
OS_MAILBOX_PutFront() Stores a new message of a predefined size into the specified mailbox in front of all other messages if the mailbox is able to accept one more message.
OS_MAILBOX_PutFront1() Stores a new message of size 1 into the specified mailbox in front of all other messages if the mailbox is able to accept one more message.
OS_MAILBOX_PutFrontBlocked() Stores a new message of a predefined size at the beginning of the specified mailbox in front of all other messages.
OS_MAILBOX_PutFrontBlocked1() Stores a new message of size 1 at the beginning of the specified mailbox in front of all other messages.
OS_MAILBOX_PutTimed() Stores a new message of a predefined size in the specified mailbox if the mailbox is able to accept one more message within a given time.
OS_MAILBOX_PutTimed1() Stores a new message of size 1 in the specified mailbox if the mailbox is able to accept one more message within a given time.
OS_MAILBOX_WaitBlocked() Waits until a message is available, but does not retrieve the message from the specified mailbox.
OS_MAILBOX_WaitTimed() Waits until a message is available or the timeout has expired, but does not retrieve the message from the specified mailbox.

OS_MAILBOX_Clear()

Description

Clears all messages in the specified mailbox.

Prototype

void OS_MAILBOX_Clear(OS_MAILBOX* pMailbox);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.

Additional information

A mailbox must not be cleared when it is in use. In use means the application currently holds a pointer to a message in the mailbox. OS_MAILBOX_Clear() may cause a task switch.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
147: OS_ERR_MAILBOX_INUSE
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBKey;

void ClearKeyBuffer(void) {
  OS_MAILBOX_Clear(&_MBKey);
}

OS_MAILBOX_Create()

Description

Creates a mailbox.

Prototype

void OS_MAILBOX_Create(OS_MAILBOX* pMailbox,
                       OS_U16      sizeofMsg,
                       OS_UINT     maxnofMsg,
                       void*       pBuffer);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
sizeofMsg Size of a message in bytes. Valid values are
1 ≤ sizeofMsg ≤ 32,767.
maxnofMsg Maximum number of messages. Valid values are
1 ≤ MaxnofMsg ≤ 32,767 on 8 or 16-bit CPUs, or
1 ≤ MaxnofMsg ≤ 2,147,483,647 on 32-bit CPUs.
pBuffer Pointer to a memory area used as buffer. The buffer must be big enough to hold the given number of messages of the specified size: sizeofMsg * maxnoMsg bytes. For 8/16-bit CPUs the total buffer size for one mailbox is limited to 65,536 bytes. For 32-bit CPUs the total buffer size for one mailbox is limited to 4,294,967,295 bytes.

Additional information

Mailboxes created with OS_MAILBOX_Create() resume a waiting task for every new message.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

106: OS_ERR_MB_BUFFER_SIZE
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
172: OS_ERR_2USE_MAILBOX

For details, refer to the chapter Runtime application errors.

Example

Mailbox used as keyboard buffer:

static OS_MAILBOX _MBKey;
char              MBKeyBuffer[6];

void InitKeyMan(void) {
  //
  // Create mailbox, functioning as type ahead buffer
  //
  OS_MAILBOX_Create(&_MBKey, 1, sizeof(MBKeyBuffer), &MBKeyBuffer);
}

Mailbox used for transferring complex commands from one task to another:

//
// Example of mailbox used for transferring commands to a task
// that controls a motor
//
typedef struct {
  char Cmd;
  int Speed[2];
  int Position[2];
} MOTORCMD;

OS_MAILBOX MBMotor;

#define NUM_MOTORCMDS 4

char BufferMotor[sizeof(MOTORCMD) * NUM_MOTORCMDS];

void MOTOR_Init(void) {
  // Create mailbox that holds commands messages
  OS_MAILBOX_Create(&MBMotor, sizeof(MOTORCMD), NUM_MOTORCMDS, &BufferMotor);
}

OS_MAILBOX_Delete()

Description

Deletes the specified mailbox.

Prototype

void OS_MAILBOX_Delete(OS_MAILBOX* pMailbox);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.

Additional information

A mailbox must not be deleted when it is in use or a task is waiting for it. In use means the application currently holds a pointer to a message in the mailbox.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
136: OS_ERR_MAILBOX_DELETE
147: OS_ERR_MAILBOX_INUSE
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBSerIn;

void Cleanup(void) {
  OS_MAILBOX_Delete(&_MBSerIn);
}

OS_MAILBOX_Get()

Description

Retrieves a new message of a predefined size from the specified mailbox if a message is available.

Prototype

char OS_MAILBOX_Get(OS_MAILBOX* pMailbox,
                    void*       pMessage);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the memory area that the message should be stored at. Make sure that there is sufficient space for an entire message. The message size was defined when the mailbox was created.

Return value

= 0 Success; message retrieved.
≠ 0 Message could not be retrieved (mailbox is empty); destination remains unchanged.

Additional information

If the mailbox is empty, no message is retrieved and the memory area where pMessage points to remains unchanged, but the program execution continues. This function never suspends the calling task. It may therefore also be called from an interrupt routine.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
147: OS_ERR_MAILBOX_INUSE
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

#define MESSAGE_SIZE  4

static OS_MAILBOX _MBData;
static char       _Buffer[MESSAGE_SIZE];

char GetData(void) {
  return OS_MAILBOX_Get(&_MBData, &_Buffer);
}

OS_MAILBOX_Get1()

Description

Retrieves a new message of size 1 from the specified mailbox, if a message is available.

Prototype

char OS_MAILBOX_Get1(OS_MAILBOX* pMailbox,
                     char*       pMessage);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the memory area that the message should be stored at. Make sure that there is sufficient space for an entire message. The message size was defined when the mailbox was created.

Return value

= 0 Success; message retrieved.
≠ 0 Message could not be retrieved (mailbox is empty); destination remains unchanged.

Additional information

If the mailbox is empty, no message is retrieved and the memory area where pMessage points to remains unchanged, but the program execution continues. This function never suspends the calling task. It may therefore also be called from an interrupt routine.

See Single-byte mailbox functions for differences between OS_MAILBOX_Get() and OS_MAILBOX_Get1().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
135: OS_ERR_MAILBOX_NOT1
147: OS_ERR_MAILBOX_INUSE
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBKey;

//
//  If a key has been pressed, it is taken out of the mailbox
//  and returned to caller. Otherwise zero is returned.
//
char GetKey(void) {
  char c = 0;

  OS_MAILBOX_Get1(&_MBKey, &c);
  return c;
}

OS_MAILBOX_GetBlocked()

Description

Retrieves a new message of a predefined size from the specified mailbox.

Prototype

void OS_MAILBOX_GetBlocked(OS_MAILBOX* pMailbox,
                           void*       pMessage);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the memory area that the message should be stored at. Make sure that there is sufficient space for an entire message. The message size was defined when the mailbox was created.

Additional information

If the mailbox is empty, the task is suspended until the mailbox receives a new message. Because this routine might require a suspension, it must not be called from an interrupt routine. Use OS_MAILBOX_Get()/OS_MAILBOX_Get1() instead if you need to retrieve data from a mailbox from within an interrupt routine.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
147: OS_ERR_MAILBOX_INUSE
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

#define MESSAGE_SIZE  4

static OS_MAILBOX _MBData;
static char       _Buffer[MESSAGE_SIZE];

char WaitData(void) {
  return OS_MAILBOX_GetBlocked(&_MBData, &_Buffer);
}

OS_MAILBOX_GetBlocked1()

Description

Retrieves a new message of size 1 from the specified mailbox.

Prototype

void OS_MAILBOX_GetBlocked1(OS_MAILBOX* pMailbox,
                            char*       pMessage);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the memory area that the message should be stored at. Make sure that there is sufficient space for an entire one byte message.

Additional information

If the mailbox is empty, the task is suspended until the mailbox receives a new message. Because this routine might require a suspension, it must not be called from an interrupt routine. Use OS_MAILBOX_Get()/OS_MAILBOX_Get1() instead if you need to retrieve data from a mailbox from within an interrupt routine.

See Single-byte mailbox functions for differences between OS_MAILBOX_GetBlocked() and OS_MAILBOX_GetBlocked1().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
135: OS_ERR_MAILBOX_NOT1
147: OS_ERR_MAILBOX_INUSE
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBKey;

char WaitKey(void) {
  char c;

  OS_MAILBOX_GetBlocked1(&_MBKey, &c);
  return c;
}

OS_MAILBOX_GetMessageCnt()

Description

Returns the number of messages currently available in the specified mailbox.

Prototype

OS_UINT OS_MAILBOX_GetMessageCnt(OS_CONST_PTR OS_MAILBOX *pMailbox);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.

Return value

The number of messages currently available in the mailbox.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBData;

void PrintAvailableMessages() {
  OS_UINT NumOfMsgs;

  NumOfMsgs = OS_MAILBOX_GetMessageCnt(&_MBData);
  printf("Mailbox contains %u messages.\n", NumOfMsgs);
}

OS_MAILBOX_GetTimed()

Description

Retrieves a new message of a predefined size from the specified mailbox if a message is available within a given time.

Prototype

char OS_MAILBOX_GetTimed(OS_MAILBOX* pMailbox,
                         void*       pMessage,
                         OS_U32      Timeout);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the memory area that the message should be stored at. Make sure that it points to a valid memory area and that there is sufficient space for an entire message. The message size (in bytes) was defined when the mailbox was created.
Timeout Maximum time in milliseconds until the requested message must be available.

Return value

= 0 Success; message retrieved.
≠ 0 Message could not be retrieved (mailbox is empty); destination remains unchanged.

Additional information

If the mailbox is empty, no message is retrieved and the task is suspended for the given timeout. The task continues execution according to the rules of the scheduler as soon as a message is available within the given timeout, or after the timeout value has expired. If the timeout has expired and no message was available within the timeout the memory area where pMessage points to remains unchanged.

When the calling task is blocked by higher priority tasks for a period longer than the timeout value, it may happen that message becomes available after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the message was not available within the requested time. In this case, no message is retrieved from the mailbox.

OS_TIME_ConfigSysTimer() must have been called before calling OS_MAILBOX_GetTimed().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
147: OS_ERR_MAILBOX_INUSE
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

#define MESSAGE_SIZE  4

static OS_MAILBOX _MBData;
static char       _Buffer[MESSAGE_SIZE];

char WaitData(void) {
  //
  // Wait for up to 10 milliseconds
  //
  return OS_MAILBOX_GetTimed(&_MBData, &_Buffer, 10);
}

OS_MAILBOX_GetTimed1()

Description

Retrieves a new message of size 1 from the specified mailbox if a message is available within a given time.

Prototype

char OS_MAILBOX_GetTimed1(OS_MAILBOX* pMailbox,
                          char*       pMessage,
                          OS_U32      Timeout);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the memory area that the message should be stored at. Make sure that it points to a valid memory area and that there is sufficient space for an entire message. The message size (in bytes) was defined when the mailbox was created.
Timeout Maximum time in milliseconds until the requested message must be available.

Return value

= 0 Success; message retrieved.
≠ 0 Message could not be retrieved (mailbox is empty); destination remains unchanged.

Additional information

If the mailbox is empty, no message is retrieved and the task is suspended for the given timeout. The task continues execution according to the rules of the scheduler as soon as a message is available within the given timeout, or after the timeout value has expired. If the timeout has expired and no message was available within the timeout the memory area where pMessage points to remains unchanged.

When the calling task is blocked by higher priority tasks for a period longer than the timeout value, it may happen that message becomes available after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the message was not available within the requested time. In this case, no message is retrieved from the mailbox.

OS_TIME_ConfigSysTimer() must have been called before calling OS_MAILBOX_GetTimed1().

See Single-byte mailbox functions for differences between OS_MAILBOX_GetTimed() and OS_MAILBOX_GetTimed1().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
135: OS_ERR_MAILBOX_NOT1
147: OS_ERR_MAILBOX_INUSE
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBKey;
//
//  If a key has been pressed, it is taken out of the mailbox
//  and returned to caller. Otherwise zero is returned.
//
char GetKey(void) {
  char c = 0;
  OS_MAILBOX_GetTimed1(&_MBKey, &c, 10);  // Wait for 10 milliseconds
  return c;
}

OS_MAILBOX_GetPtr()

Description

Retrieves a pointer to a new message of a predefined size from the specified mailbox if a message is available.

Prototype

char OS_MAILBOX_GetPtr(OS_MAILBOX* pMailbox,
                       void**      ppMessage);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
ppMessage Address of the pointer which will be set to the address of the message.

Return value

= 0 Success; message retrieved.
≠ 0 Message could not be retrieved (mailbox is empty); destination remains unchanged.

Additional information

If the mailbox is empty, no message is retrieved and ppMessage remains unchanged, but the program execution continues. This function never suspends the calling task. It may therefore also be called from an interrupt routine or software timer.

The retrieved message is not removed from the mailbox, this must be done by a call of OS_MAILBOX_Purge() after the message was processed. Only one message can be processed at a time. As long as the message is not removed from the mailbox, the mailbox is marked “in use”. Following calls of OS_MAILBOX_Clear(), OS_MAILBOX_Delete(), OS_MAILBOX_GetBlocked*() and OS_MAILBOX_GetPtrBlocked*() functions are not allowed until OS_MAILBOX_Purge() is called.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
147: OS_ERR_MAILBOX_INUSE
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBKey;

void PrintMessage(void) {
  char* p;
  char  r;

  r = OS_MAILBOX_GetPtr(&_MBKey, (void**)&p);
  if (r == 0) {
    printf("%d\n", *p);
    OS_MAILBOX_Purge(&_MBKey);
  }
}

OS_MAILBOX_GetPtrBlocked()

Description

Retrieves a pointer to a new message of a predefined size from the specified mailbox.

Prototype

void OS_MAILBOX_GetPtrBlocked(OS_MAILBOX* pMailbox,
                              void**      ppMessage);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
ppMessage Pointer to the memory area that a pointer to the message should be stored at. The message size (in bytes) was defined when the mailbox was created.

Additional information

If the mailbox is empty, the task is suspended until the mailbox receives a new message. Because this routine might require a suspension, it must not be called from an interrupt routine. Use OS_MAILBOX_GetPtr() instead if you need to retrieve data from a mailbox from within an interrupt routine.

The retrieved message is not removed from the mailbox, this must be done by a call of OS_MAILBOX_Purge() after the message was processed. Only one message can be processed at a time. As long as the message is not removed from the mailbox, the mailbox is marked “in use”. Following calls of OS_MAILBOX_Clear(), OS_MAILBOX_Delete(), OS_MAILBOX_GetBlocked*() and OS_MAILBOX_GetPtrBlocked*() functions are not allowed until OS_MAILBOX_Purge() is called.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
147: OS_ERR_MAILBOX_INUSE
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBKey;

void PrintMessage(void) {
  char* p;

  OS_MAILBOX_GetPtrBlocked(&_MBKey, (void**)&p);
  printf("%d\n", *p);
  OS_MAILBOX_Purge(&_MBKey);
}

OS_MAILBOX_IsInUse()

Description

Returns whether the specified mailbox is currently in use.

Prototype

OS_BOOL OS_MAILBOX_IsInUse(OS_CONST_PTR OS_MAILBOX *pMailbox);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.

Return value

= 0 Mailbox is not in use.
≠ 0 Mailbox is in use and may not be deleted or cleared.

Additional information

A mailbox must not be cleared or deleted when it is in use. In use means a task or function currently holds a pointer to a message in the mailbox.

OS_MAILBOX_IsInUse() can be used to examine the state of the mailbox before it can be cleared or deleted, as these functions must not be performed as long as the mailbox is used.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBKey;

void PrintMessage(void) {
  OS_BOOL IsInUse;

  IsInUse = OS_MAILBOX_IsInUse(&_MBKey);
  if (IsInUse == 0u) {
    printf("Mailbox is not in use.\n");
    OS_MAILBOX_Clear(&_MBKey);
  } else {
    printf("Mailbox is in use.\n");
  }
}

OS_MAILBOX_Peek()

Description

Peeks a message from the specified mailbox without removing the message. The message is copied to *pMessage if one was available.

Prototype

char OS_MAILBOX_Peek(OS_CONST_PTR OS_MAILBOX *pMailbox,
                     void*        pMessage);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to a buffer that should receive the message.

Return value

= 0 Success, message was available and is copied to *pMessage.
≠ 0 Mail could not be retrieved (mailbox is empty).

Additional information

This function is non-blocking and never suspends the calling task. It may therefore be called from an interrupt routine. If no message was available the memory area where pMessage points to remains unchanged.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

#define MESSAGE_SIZE  4

static OS_MAILBOX _MBData;
static char       _Buffer[MESSAGE_SIZE];

char PeekData(void) {
  return OS_MAILBOX_Peek(&_MBData, &_Buffer);
}

OS_MAILBOX_Purge()

Description

Deletes the last retrieved message in the specified mailbox.

Prototype

void OS_MAILBOX_Purge(OS_MAILBOX* pMailbox);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.

Additional information

This routine should be called by the task that retrieved the last message from the mailbox, after the message is processed.

Once a message was retrieved by a call of OS_MAILBOX_GetPtrBlocked() or OS_MAILBOX_GetPtr(), the message must be removed from the mailbox by a call of OS_MAILBOX_Purge() before a following message can be retrieved from the mailbox. Following calls of OS_MAILBOX_Clear(), OS_MAILBOX_Delete(), OS_MAILBOX_GetBlocked*() and OS_MAILBOX_GetPtrBlocked*() functions are not allowed until OS_MAILBOX_Purge() is called. You must call OS_MAILBOX_Purge() only once after retrieving a message from the mailbox.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
148: OS_ERR_MAILBOX_NOT_INUSE
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBKey;

void PrintMessage(void) {
  char* p;

  OS_MAILBOX_GetPtrBlocked(&_MBKey, (void**)&p);
  printf("%d\n", *p);
  OS_MAILBOX_Purge(&_MBKey);
}

OS_MAILBOX_Put()

Description

Stores a new message of a predefined size in the specified mailbox if the mailbox is able to accept one more message.

Prototype

char OS_MAILBOX_Put(OS_MAILBOX*  pMailbox,
                    OS_CONST_PTR void *pMessage);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the message to store.

Return value

= 0 Success; message stored.
≠ 0 Message could not be stored (mailbox is full).

Additional information

If the mailbox is full, the message is not stored. This function never suspends the calling task. It may therefore be called from an interrupt routine.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBData;

void AddMessage(struct Data* pData) {
  char Result;

  Result = OS_MAILBOX_Put(&_MBData, pData);
  if (Result != 0) {
    printf("Was not able to add the message to the mailbox.\n");
  }
}

OS_MAILBOX_Put1()

Description

Stores a new message of size 1 in the specified mailbox if the mailbox is able to accept one more message.

Prototype

char OS_MAILBOX_Put1(OS_MAILBOX*  pMailbox,
                     OS_CONST_PTR char *pMessage);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the message to store.

Return value

= 0 Success; message stored.
≠ 0 Message could not be stored (mailbox is full).

Additional information

If the mailbox is full, the message is not stored. This function never suspends the calling task. It may therefore be called from an interrupt routine.

See Single-byte mailbox functions for differences between OS_MAILBOX_Put() and OS_MAILBOX_Put1().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
135: OS_ERR_MAILBOX_NOT1
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBKey;
static char       _MBKeyBuffer[6];

char KEYMAN_StoreCond(char k) {
  return OS_MAILBOX_Put1(&_MBKey, &k); /* Store key if space in buffer */
}

This example can be used with the sample program shown earlier to handle a mailbox as keyboard buffer.

OS_MAILBOX_PutBlocked()

Description

Stores a new message of a predefined size in the specified mailbox.

Prototype

void OS_MAILBOX_PutBlocked(OS_MAILBOX*  pMailbox,
                           OS_CONST_PTR void *pMessage);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the message to store.

Additional information

If the mailbox is full, the calling task is suspended. Because this routine might require a suspension, it must not be called from an interrupt routine. Use OS_MAILBOX_Put()/OS_MAILBOX_Put1() instead if you need to store data in a mailbox from within an interrupt routine.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBData;

void AddMessage(struct Data* pData) {
  OS_MAILBOX_PutBlocked(&_MBData, pData);
}

OS_MAILBOX_PutBlocked1()

Description

Stores a new message of size 1 in the specified mailbox.

Prototype

void OS_MAILBOX_PutBlocked1(OS_MAILBOX*  pMailbox,
                            OS_CONST_PTR char *pMessage);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the message to store.

Additional information

If the mailbox is full, the calling task is suspended. Because this routine might require a suspension, it must not be called from an interrupt routine. Use OS_MAILBOX_Put()/OS_MAILBOX_Put1() instead if you need to store data in a mailbox from within an interrupt routine.

See Single-byte mailbox functions for differences between OS_MAILBOX_PutBlocked() and OS_MAILBOX_PutBlocked1().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
135: OS_ERR_MAILBOX_NOT1
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

Single-byte mailbox as keyboard buffer:

static OS_MAILBOX _MBKey;
static char       MBKeyBuffer[6];

void KEYMAN_StoreKey(char k) {
  OS_MAILBOX_PutBlocked1(&_MBKey, &k);  /* Store key, wait if no space in buffer */
}

void KEYMAN_Init(void) {
  /* Create mailbox functioning as type ahead buffer */
  OS_MAILBOX_Create(&_MBKey, 1, sizeof(MBKeyBuffer), &MBKeyBuffer);
}

OS_MAILBOX_PutFront()

Description

Stores a new message of a predefined size into the specified mailbox in front of all other messages if the mailbox is able to accept one more message. The new message will be retrieved first.

Prototype

char OS_MAILBOX_PutFront(OS_MAILBOX*  pMailbox,
                         OS_CONST_PTR void *pMessage);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the message to store.

Return value

= 0 Success; message stored.
≠ 0 Message could not be stored (mailbox is full).

Additional information

If the mailbox is full, the message is not stored. This function never suspends the calling task. It may therefore be called from an interrupt routine. This function is useful to store “emergency” messages into a mailbox which must be handled quickly. It may also be used in general instead of OS_MAILBOX_Put() to change the FIFO structure of a mailbox into a LIFO structure.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBData;

void AddMessage(struct Data* pData) {
  char Result;

  Result = OS_MAILBOX_PutFront(&_MBData, pData);
  if (Result != 0) {
    printf("Was not able to add the message to the mailbox.\n");
  }
}

OS_MAILBOX_PutFront1()

Description

Stores a new message of size 1 into the specified mailbox in front of all other messages if the mailbox is able to accept one more message. The new message will be retrieved first.

Prototype

char OS_MAILBOX_PutFront1(OS_MAILBOX*  pMailbox,
                          OS_CONST_PTR char *pMessage);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the message to store.

Return value

= 0 Success; message stored.
≠ 0 Message could not be stored (mailbox is full).

Additional information

If the mailbox is full, the message is not stored. This function never suspends the calling task. It may therefore be called from an interrupt routine. This function is useful to store “emergency” messages into a mailbox which must be handled quickly. It may also be used in general instead of OS_MAILBOX_Put() to change the FIFO structure of a mailbox into a LIFO structure.

See Single-byte mailbox functions for differences between OS_MAILBOX_PutFront() and OS_MAILBOX_PutFront1().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
135: OS_ERR_MAILBOX_NOT1
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBData;

void AddMessage(char c) {
  char Result;

  Result = OS_MAILBOX_PutFront1(&_MBData, &c);
  if (Result != 0) {
    printf("Was not able to add the message to the mailbox.\n");
  }
}

OS_MAILBOX_PutFrontBlocked()

Description

Stores a new message of a predefined size at the beginning of the specified mailbox in front of all other messages. This new message will be retrieved first.

Prototype

void OS_MAILBOX_PutFrontBlocked(OS_MAILBOX*  pMailbox,
                                OS_CONST_PTR void *pMessage);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the message to store.

Additional information

If the mailbox is full, the calling task is suspended. Because this routine might require a suspension, it must not be called from an interrupt routine. Use OS_MAILBOX_PutFront()/OS_MAILBOX_PutFront1() instead if you need to store data in a mailbox from within an interrupt routine.

This function is useful to store “emergency” messages into a mailbox which must be handled quickly. It may also be used in general instead of OS_MAILBOX_PutBlocked() to change the FIFO structure of a mailbox into a LIFO structure.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBData;

void AddMessage(struct Data* pData) {
  OS_MAILBOX_PutFrontBlocked(&_MBData, pData);
}

OS_MAILBOX_PutFrontBlocked1()

Description

Stores a new message of size 1 at the beginning of the specified mailbox in front of all other messages. This new message will be retrieved first.

Prototype

void OS_MAILBOX_PutFrontBlocked1(OS_MAILBOX*  pMailbox,
                                 OS_CONST_PTR char *pMessage);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the message to store.

Additional information

If the mailbox is full, the calling task is suspended. Because this routine might require a suspension, it must not be called from an interrupt routine. Use OS_MAILBOX_PutFront()/OS_MAILBOX_PutFront1() instead if you need to store data in a mailbox from within an interrupt routine.

This function is useful to store “emergency” messages into a mailbox which must be handled quickly. It may also be used in general instead of OS_MAILBOX_PutBlocked() to change the FIFO structure of a mailbox into a LIFO structure.

See Single-byte mailbox functions for differences between OS_MAILBOX_PutFrontBlocked() and OS_MAILBOX_PutFrontBlocked1().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
135: OS_ERR_MAILBOX_NOT1
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

Single-byte mailbox as keyboard buffer which will follow the LIFO pattern:

static OS_MAILBOX _MBCmd;
static char       _MBCmdBuffer[6];

void KEYMAN_StoreCommand(char k) {
  OS_MAILBOX_PutFrontBlocked1(&_MBCmd, &k);  // Store command, wait if no space in buffer
}

void KEYMAN_Init(void) {
  /* Create mailbox for command buffer */
  OS_MAILBOX_Create(&_MBCmd, 1, sizeof(_MBCmdBuffer), &_MBCmdBuffer);
}

OS_MAILBOX_PutTimed()

Description

Stores a new message of a predefined size in the specified mailbox if the mailbox is able to accept one more message within a given time. Returns when a new message has been stored in the mailbox (mailbox not full) or a timeout occurred.

Prototype

OS_BOOL OS_MAILBOX_PutTimed(OS_MAILBOX*  pMailbox,
                            OS_CONST_PTR void *pMessage,
                            OS_U32       Timeout);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the message to store.
Timeout Maximum time in milliseconds until the given message must be stored.

Return value

= 0 Success; message stored.
≠ 0 Message could not be stored within the given timeout (mailbox is full). destination remains unchanged.

Additional information

If the mailbox is full, no message is stored and the task is suspended for the given timeout. The task continues execution according to the rules of the scheduler as soon as a new message is accepted within the given timeout, or after the timeout value has expired.

When the calling task is blocked by higher priority tasks for a period longer than the timeout value, it may happen that the mailbox accepts new messages after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the mailbox was not available within the requested time. In this case, no message is stored in the mailbox.

OS_TIME_ConfigSysTimer() must have been called before calling OS_MAILBOX_PutTimed().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBData;

void AddMessage(char* pData) {
  OS_MAILBOX_PutTimed(&_MBData, pData, 10);  // Wait maximum 10 milliseconds
}

OS_MAILBOX_PutTimed1()

Description

Stores a new message of size 1 in the specified mailbox if the mailbox is able to accept one more message within a given time. Returns when a new message has been stored in the mailbox (mailbox not full) or a timeout occurred.

Prototype

OS_BOOL OS_MAILBOX_PutTimed1(OS_MAILBOX*  pMailbox,
                             OS_CONST_PTR char *pMessage,
                             OS_U32       Timeout);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pMessage Pointer to the message to store.
Timeout Maximum time in milliseconds until the given message must be stored.

Return value

= 0 Success; message stored.
≠ 0 Message could not be stored within the given timeout (mailbox is full). destination remains unchanged.

Additional information

If the mailbox is full, no message is stored and the task is suspended for the given timeout. The task continues execution according to the rules of the scheduler as soon as a new message is accepted within the given timeout, or after the timeout value has expired.

When the calling task is blocked by higher priority tasks for a period longer than the timeout value, it may happen that the mailbox accepts new messages after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the mailbox was not available within the requested time. In this case, no message is stored in the mailbox.

OS_TIME_ConfigSysTimer() must have been called before calling OS_MAILBOX_PutTimed1().

See Single-byte mailbox functions for differences between OS_MAILBOX_PutTimed() and OS_MAILBOX_PutTimed1().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
135: OS_ERR_MAILBOX_NOT1
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBKey;

void SetKey(char c) {
  OS_MAILBOX_PutTimed1(&_MBKey, &c, 10);  // Wait maximum 10 milliseconds
}

OS_MAILBOX_WaitBlocked()

Description

Waits until a message is available, but does not retrieve the message from the specified mailbox.

Prototype

void OS_MAILBOX_WaitBlocked(OS_MAILBOX* pMailbox);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.

Additional information

If the mailbox is empty, the task is suspended until a message is available, otherwise the task continues. The task continues execution according to the rules of the scheduler as soon as a message is available, but the message is not retrieved from the mailbox.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBData;

void Task(void) {
  while (1) {
    OS_MAILBOX_WaitBlocked(&_MBData);
    ...
  }
}

OS_MAILBOX_WaitTimed()

Description

Waits until a message is available or the timeout has expired, but does not retrieve the message from the specified mailbox.

Prototype

char OS_MAILBOX_WaitTimed(OS_MAILBOX* pMailbox,
                          OS_U32      Timeout);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
Timeout Maximum time in milliseconds until the requested message must be available.

Return value

= 0 Success; message available.
≠ 0 Timeout; no message available within the given timeout time.

Additional information

If the mailbox is empty, the task is suspended for the given timeout. The task continues execution according to the rules of the scheduler as soon as a message is available within the given timeout, or after the timeout value has expired.

When the calling task is blocked by higher priority tasks for a period longer than the timeout value, it may happen that message becomes available after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the message was not available within the requested time.

OS_TIME_ConfigSysTimer() must have been called before calling OS_MAILBOX_WaitTimed().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_MAILBOX _MBData;

void Task(void) {
  char Result;

  Result = OS_MAILBOX_WaitTimed(&_MBData, 10);
  if (Result == 0) {
    // Compute message
  } else {
    // Timeout
  }
}

Queue

Introduction

In the preceding chapter, inter-task communication using mailboxes was described. Mailboxes can handle small messages with fixed data size only. Queues enable inter-task communication with larger messages or with messages of differing lengths.

A queue consists of a data buffer and a control structure that is managed by the real-time operating system. The queue behaves like a normal buffer; you can deposit something (called a message) in the queue and retrieve it later. Queues work as FIFO: first in, first out. So a message that is deposited first will be retrieved first. There are three major differences between queues and mailboxes:

  1. Queues accept messages of differing lengths. When depositing a message into a queue, the message size is passed as a parameter.
  2. Retrieving a message from the queue does not copy the message, but returns a pointer to the message and its size. This enhances performance because the data is copied only when the message is written into the queue.
  3. The retrieving function must delete every message after processing it.
  4. A new message can only be retrieved from the queue when the previous message was deleted from the queue.

The queue data buffer contains the messages and some additional management information. Each message has a message header containing the message size. The define OS_Q_SIZEOF_HEADER defines the size of the message header. Additionally, the queue buffer will be aligned for those CPUs which need data alignment. Therefore the queue data buffer size must be bigger than the sum of all messages.

Limitations:

Both the number of queues and buffers are limited only by the amount of available memory. However, the individual message size and the buffer size per queue are limited by software design.

8 or 16-bit CPUs 32-bit CPUs
Maximum message size 32,767 bytes 2,147,483,647 bytes
Maximum buffer size 65,535 bytes 4,294,967,295 bytes

These limitations have been placed on queues to guarantee efficient coding and also to ensure efficient management. These limitations are typically not a problem.

Similar to mailboxes, queues can be used by more than one producer, but must be used by one consumer only. This means that more than one task or interrupt handler is allowed to deposit new data into the queue, but it does not make sense to retrieve messages by multiple tasks.

Example

#define MESSAGE_ALIGNMENT    (4u)  // Depends on core/compiler
#define MESSAGES_SIZE_HELLO  (7u + OS_Q_SIZEOF_HEADER + MESSAGE_ALIGNMENT)
#define MESSAGES_SIZE_WORLD  (9u + OS_Q_SIZEOF_HEADER + MESSAGE_ALIGNMENT)
#define QUEUE_SIZE           (MESSAGES_SIZE_HELLO + MESSAGES_SIZE_WORLD)

static OS_STACKPTR int StackHP[128], StackLP[128];  // Task stacks
static OS_TASK         TCBHP, TCBLP;                // Task-control-blocks
static OS_QUEUE        MyQueue;
static char            MyQBuffer[QUEUE_SIZE];

static void HPTask(void) {
  char* pData;

  while (1) {
    OS_QUEUE_GetPtrBlocked(&MyQueue, (void**)&pData);
    OS_COM_SendString(pData);
    OS_QUEUE_Purge(&MyQueue);
  }
}

static void LPTask(void) {
  while (1) {
    OS_QUEUE_Put(&MyQueue, "\nHello\0", 7);
    OS_QUEUE_Put(&MyQueue, "\nWorld !\0", 9);
    OS_TASK_Delay_ms(500);
  }
}

int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_TASK_CREATE(&TCBLP, "LP Task",  50, LPTask, StackLP);
  OS_QUEUE_Create(&MyQueue, &MyQBuffer, sizeof(MyQBuffer));
  OS_COM_SendString("embOS OS_Queue example");
  OS_COM_SendString("\n\nDemonstrating message passing\n");
  OS_Start();     // Start embOS
  return 0;
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_QUEUE_Clear() Clears all messages in the specified message queue.
OS_QUEUE_Create() Creates a message queue.
OS_QUEUE_Delete() Deletes the specific message queue.
OS_QUEUE_GetMessageCnt() Returns the number of messages that are currently stored in the specified message queue.
OS_QUEUE_GetMessageSize() Returns the size of the first message in the specified message queue.
OS_QUEUE_GetPtr() Retrieves a pointer to a message from the specified message queue if available.
OS_QUEUE_GetPtrBlocked() Retrieves a pointer to a message from the specified message queue.
OS_QUEUE_GetPtrTimed() Retrieves a pointer to a message from the specified message queue if available within the specified time.
OS_QUEUE_HasFreeSpace() Returns whether the message of size Size fits in the queue buffer.
OS_QUEUE_IsInUse() Delivers information whether the specified message queue is currently in use.
OS_QUEUE_PeekPtr() Retrieve the pointer to a message from the specified message queue.
OS_QUEUE_Purge() Deletes the last retrieved message in the specified message queue.
OS_QUEUE_Put() Stores a new message of given size in the specified message queue.
OS_QUEUE_PutEx() Stores a new message, of which the distinct parts are distributed in memory as indicated by a OS_QUEUE_SRCLIST structure, in the specified message queue.
OS_QUEUE_PutBlocked() Stores a new message of given size in the specified message queue.
OS_QUEUE_PutBlockedEx() Stores a new message, of which the distinct parts are distributed in memory as indicated by a OS_QUEUE_SRCLIST structure, in the specified message queue.
OS_QUEUE_PutTimed() Stores a new message of given size in the specified message queue if space is available within a given time.
OS_QUEUE_PutTimedEx() Stores a new message, of which the distinct parts are distributed in memory as indicated by a OS_QUEUE_SRCLIST structure, in the specified message queue.

OS_QUEUE_Clear()

Description

Clears all messages in the specified message queue.

Prototype

void OS_QUEUE_Clear(OS_QUEUE* pQ);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.

Additional information

A queue must not be cleared when it is in use. In use means the application currently holds a pointer to a message in the queue. OS_QUEUE_Clear() may cause a task switch.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

145: OS_ERR_QUEUE_INVALID
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
143: OS_ERR_QUEUE_INUSE

For details, refer to the chapter Runtime application errors.

Example

static OS_QUEUE _Queue;

void ClearQueue() {
  OS_QUEUE_Clear(&_Queue);
}

OS_QUEUE_Create()

Description

Creates a message queue.

Prototype

void OS_QUEUE_Create(OS_QUEUE* pQ,
                     void*     pBuffer,
                     OS_UINT   Size);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.
pBuffer Pointer to a memory area used as data buffer for the queue.
Size Size in bytes of the data buffer.

Additional information

The define OS_Q_SIZEOF_HEADER can be used to calculate the additional management information bytes needed for each message in the queue data buffer. But it does not account for the additional space needed for data alignment. Thus the number of messages that can actually be stored in the queue buffer depends on the message sizes. The message size will be round up to the next multiple of the size of an integer.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
177: OS_ERR_2USE_QUEUE

For details, refer to the chapter Runtime application errors.

Example

#define MESSAGE_CNT  100
#define MESSAGE_SIZE 100
#define MEMORY_QSIZE (MESSAGE_CNT * (MESSAGE_SIZE + OS_Q_SIZEOF_HEADER))

static OS_QUEUE _MemoryQ;
static char     _acMemQBuffer[MEMORY_QSIZE];

void MEMORY_Init(void) {
  OS_QUEUE_Create(&_MemoryQ, &_acMemQBuffer, sizeof(_acMemQBuffer));
}

OS_QUEUE_Delete()

Description

Deletes the specific message queue.

Prototype

void OS_QUEUE_Delete(OS_QUEUE* pQ);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.

Additional information

A queue must not be deleted when it is in use or a task is waiting for it. In use means the application currently holds a pointer to a message in the mailbox.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

143: OS_ERR_QUEUE_INUSE
145: OS_ERR_QUEUE_INVALID
146: OS_ERR_QUEUE_DELETE
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_QUEUE _QSerIn;

void Cleanup(void) {
  OS_QUEUE_Delete(&_QSerIn);
}

OS_QUEUE_GetMessageCnt()

Description

Returns the number of messages that are currently stored in the specified message queue.

Prototype

int OS_QUEUE_GetMessageCnt(OS_CONST_PTR OS_QUEUE *pQ);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.

Return value

The number of messages in the queue.

Additional information

If OS_QUEUE_GetMessageCnt() returns zero the message queue is empty.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

145: OS_ERR_QUEUE_INVALID
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_QUEUE _Queue;

void PrintNumberOfMessages() {
  int Cnt;

  Cnt = OS_QUEUE_GetMessageCnt(&_Queue);
  printf("%d messages available.\n", Cnt);
}

OS_QUEUE_GetMessageSize()

Description

Returns the size of the first message in the specified message queue.

Prototype

int OS_QUEUE_GetMessageSize(OS_CONST_PTR OS_QUEUE *pQ);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.

Return value

= 0 No data available.
> 0 Size of message in bytes.

Additional information

If the queue is empty OS_QUEUE_GetMessageSize() returns zero. If a message is available OS_QUEUE_GetMessageSize() returns the size of that message. The message is not retrieved from the queue.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

145: OS_ERR_QUEUE_INVALID
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_QUEUE _MemoryQ;

static void _MemoryTask(void) {
  int Len;

  while (1) {
    Len = OS_QUEUE_GetMessageSize(&_MemoryQ);  // Get message length
    if (Len > 0) {
      printf("Message with size %d retrieved\n", Len);
      OS_QUEUE_Purge(&_MemoryQ);               // Delete message
    }
    OS_TASK_Delay_ms(10);
  }
}

OS_QUEUE_GetPtr()

Description

Retrieves a pointer to a message from the specified message queue if available.

Prototype

int OS_QUEUE_GetPtr(OS_QUEUE* pQ,
                    void**    ppMessage);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.
ppMessage Address of the pointer which will be set to the address of the message.

Return value

= 0 No message available in queue (queue is empty).
> 0 Size of the message that was retrieved from the queue.

Additional information

If the queue is empty, OS_QUEUE_GetPtr() returns zero and ppMessage remains unchanged. This function never suspends the calling task. It may therefore be called from an interrupt routine or software timer.

The retrieved message is not removed from the queue, this must be done by a call of OS_QUEUE_Purge() after the message was processed. Only one message can be processed at a time. As long as the message is not removed from the queue, the queue is marked “in use”. Following calls of OS_QUEUE_Clear(), OS_QUEUE_Delete(), OS_QUEUE_GetPtr(), OS_QUEUE_GetPtrBlocked() and OS_QUEUE_GetPtrTimed() functions are not allowed until OS_QUEUE_Purge() is called.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

143: OS_ERR_QUEUE_INUSE
145: OS_ERR_QUEUE_INVALID
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_QUEUE _MemoryQ;

static void _MemoryTask(void) {
  int   Len;
  void* pData;

  while (1) {
    Len = OS_QUEUE_GetPtr(&_MemoryQ, &pData);  // Check message
    if (Len > 0) {
      Memory_WritePacket(*(U32*)pData, Len);   // Process message
      OS_QUEUE_Purge(&_MemoryQ);               // Delete message
    } else {
      DoSomethingElse();
    }
  }
}

OS_QUEUE_GetPtrBlocked()

Description

Retrieves a pointer to a message from the specified message queue.

Prototype

int OS_QUEUE_GetPtrBlocked(OS_QUEUE* pQ,
                           void**    ppMessage);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.
ppMessage Address of the pointer which will be set to the address of the message.

Return value

Size of the message in bytes.

Additional information

If the queue is empty, the calling task is suspended until the queue receives a new message. Because this routine might require a suspension, it must not be called from an interrupt routine or timer. Use OS_QUEUE_GetPtr() instead. The retrieved message is not removed from the queue, this must be done by a call of OS_QUEUE_Purge() after the message was processed. Only one message can be processed at a time. As long as the message is not removed from the queue, the queue is marked “in use”.

Following calls of OS_QUEUE_Clear(), OS_QUEUE_Delete(), OS_QUEUE_GetPtr(), OS_QUEUE_GetPtrBlocked() and OS_QUEUE_GetPtrTimed() functions are not allowed until OS_QUEUE_Purge() is called.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

143: OS_ERR_QUEUE_INUSE
145: OS_ERR_QUEUE_INVALID
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

static OS_QUEUE _MemoryQ;

static void _MemoryTask(void) {
  int   Len;
  void* pData;

  while (1) {
    Len = OS_QUEUE_GetPtrBlocked(&_MemoryQ, &pData); // Get message
    Memory_WritePacket(*(U32*)pData, Len);           // Process message
    OS_QUEUE_Purge(&_MemoryQ);                       // Delete message
  }
}

OS_QUEUE_GetPtrTimed()

Description

Retrieves a pointer to a message from the specified message queue if available within the specified time.

Prototype

int OS_QUEUE_GetPtrTimed(OS_QUEUE* pQ,
                         void**    ppMessage,
                         OS_U32    Timeout);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.
ppMessage Address of the pointer which will be set to the address of the message.
Timeout Maximum time in milliseconds until the requested message must be available.

Return value

= 0 No message available in queue.
> 0 Size of the message that was retrieved from the queue.

Sets the pointer ppMessage to the message that should be retrieved.

Additional information

If the queue is empty no message is retrieved, the task is suspended for the given timeout. The task continues execution according to the rules of the scheduler as soon as a message is available within the given timeout, or after the timeout value has expired. If no message is retrieved within the timeout ppMessage will not be set.

When the calling task is blocked by higher priority tasks for a period longer than the timeout value, it may happen that a message becomes available after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the message was not available within the requested time. In this case the state of the queue is not modified by OS_QUEUE_GetPtrTimed() and a pointer to the message is not delivered. As long as a message was retrieved and the message is not removed from the queue, the queue is marked “in use”.

Following calls of OS_QUEUE_Clear(), OS_QUEUE_Delete(), OS_QUEUE_GetPtr(), OS_QUEUE_GetPtrBlocked() and OS_QUEUE_GetPtrTimed() functions are not allowed until OS_QUEUE_Purge() is called.

OS_TIME_ConfigSysTimer() must have been called before calling OS_QUEUE_GetPtrTimed().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

143: OS_ERR_QUEUE_INUSE
145: OS_ERR_QUEUE_INVALID
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_QUEUE _MemoryQ;

static void _MemoryTask(void) {
  int   Len;
  void* pData;

  while (1) {
    Len = OS_QUEUE_GetPtrTimed(&_MemoryQ, &pData, 10);  // Check message
    if (Len > 0) {
      Memory_WritePacket(*(U32*)pData, Len);            // Process message
      OS_QUEUE_Purge(&_MemoryQ);                        // Delete message
    } else {                                            // Timeout
      DoSomethingElse();
    }
  }
}

OS_QUEUE_HasFreeSpace()

Description

Returns whether the message of size Size fits in the queue buffer.

Prototype

OS_BOOL OS_QUEUE_HasFreeSpace(OS_CONST_PTR OS_QUEUE *pQ,
                              OS_UINT      Size);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.
Size Message size.

Additional information

OS_QUEUE_HasFreeSpace() does not store any message in the queue.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

143: OS_ERR_QUEUE_INUSE
145: OS_ERR_QUEUE_INVALID
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void Task(OS_QUEUE* pQ) {
  OS_BOOL r;

  OS_INT_IncDI();
  r = OS_QUEUE_HasFreeSpace(pQ, 42)
  if (r == 1u) {
    OS_QUEUE_Put(pQ, pMessage, 42);
  }
  OS_INT_DecRI();
}

OS_QUEUE_IsInUse()

Description

Delivers information whether the specified message queue is currently in use.

Prototype

OS_BOOL OS_QUEUE_IsInUse(OS_CONST_PTR OS_QUEUE *pQ);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.

Return value

= 0 Queue is not in use.
≠ 0 Queue is in use and may not be deleted or cleared.

Additional information

A queue must not be cleared or deleted when it is in use. In use means a task or function currently accesses the queue and holds a pointer to a message in the queue.

OS_QUEUE_IsInUse() can be used to examine the state of the queue before it can be cleared or deleted, as these functions must not be performed as long as the queue is used.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

145: OS_ERR_QUEUE_INVALID
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void DeleteQ(OS_QUEUE* pQ) {
  OS_INT_IncDI();  // Avoid state change of the queue by task or interrupt
  //
  // Wait until queue is not used
  //
  while (OS_QUEUE_IsInUse(pQ) != 0) {
    OS_TASK_Delay_ms(1);
  }
  OS_QUEUE_Delete(pQ);
  OS_INT_DecRI();
}

OS_QUEUE_PeekPtr()

Description

Retrieve the pointer to a message from the specified message queue. The message must not be purged.

Prototype

int OS_QUEUE_PeekPtr(OS_CONST_PTR OS_QUEUE *pQ,
                     void**       ppMessage);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.
ppMessage Address of the pointer which will be set to the address of the message.

Return value

= 0 No message available.
≠ 0 Size of message in bytes.

Additional information

Sets the pointer ppMessage to the message that should be retrieved. If no message is available ppMessage will not be set.

Note

Ensure the queues state is not altered as long as a message is processed. That is the reason for calling OS_INT_IncDI() in the sample. Ensure no cooperative task switch is performed, as this may also alter the queue state and buffer.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

145: OS_ERR_QUEUE_INVALID
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_QUEUE _MemoryQ;
static void _MemoryTask(void) {
  int   Len;
  void* pData;

  while (1) {
    // Avoid state changes of the queue by task or interrupt
    OS_INT_IncDI();
    Len = OS_QUEUE_PeekPtr(&_MemoryQ, &pData);  // Get message
    if (Len > 0) {
      Memory_WritePacket(*(U32*)pData, Len);    // Process message
    }
    OS_INT_DecRI();
}

OS_QUEUE_Purge()

Description

Deletes the last retrieved message in the specified message queue.

Prototype

void OS_QUEUE_Purge(OS_QUEUE* pQ);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.

Additional information

This routine should be called by the task that retrieved the last message from the queue, after the message is processed.

Once a message was retrieved by a call of OS_QUEUE_GetPtrBlocked(), OS_QUEUE_GetPtr() or OS_QUEUE_GetPtrTimed(), the message must be removed from the queue by a call of OS_QUEUE_Purge() before a following message can be retrieved from the queue.

Consecutive calls of OS_QUEUE_Purge() or calling OS_QUEUE_Purge() without having retrieved a message from the queue are not allowed.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

143: OS_ERR_QUEUE_INUSE
145: OS_ERR_QUEUE_INVALID
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_QUEUE _MemoryQ;

static void _MemoryTask(void) {
  int   Len;
  void* pData;

  while (1) {
    Len = OS_QUEUE_GetPtrBlocked(&_MemoryQ, &pData);  // Get message
    Memory_WritePacket(*(U32*)pData, Len);            // Process message
    OS_QUEUE_Purge(&_MemoryQ);                        // Delete message
  }
}

OS_QUEUE_Put()

Description

Stores a new message of given size in the specified message queue.

Prototype

int OS_QUEUE_Put(OS_QUEUE*    pQ,
                 OS_CONST_PTR void *pMessage,
                 OS_UINT      Size);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.
pMessage Pointer to the message to store.
Size Size of the message to store. Valid values are:
1 ≤ Size ≤ 215 - 1 = 0x7FFF for 8/16-bit CPUs.
1 ≤ Size ≤ 231 - 1 = 0x7FFFFFFF for 32-bit CPUs.

Return value

= 0 Success, message stored.
≠ 0 Message could not be stored (queue is full).

Additional information

This routine never suspends the calling task and may therefore be called from an interrupt routine.
When the message is deposited into the queue, the entire message is copied into the queue buffer, not only the pointer to the data. Therefore the message content is protected and remains valid until it is retrieved and accessed by a task reading the message.

Note

The message is stored in the queue buffer with an additional message header. Additionally the message size will be round up to the next multiple of the size of an integer.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

145: OS_ERR_QUEUE_INVALID
149: OS_ERR_MESSAGE_SIZE_ZERO
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_QUEUE _MemoryQ;

int MEMORY_Write(const void* pData, OS_UINT Len) {
  return OS_QUEUE_Put(&_MemoryQ, pData, Len);
}

OS_QUEUE_PutEx()

Description

Stores a new message, of which the distinct parts are distributed in memory as indicated by a OS_QUEUE_SRCLIST structure, in the specified message queue.

Prototype

int OS_QUEUE_PutEx(OS_QUEUE*    pQ,
                   OS_CONST_PTR OS_QUEUE_SRCLIST *pMessageList,
                   OS_UINT      NumMessages);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.
pMessageList Pointer to an array of OS_QUEUE_SRCLIST structures which contain pointers to the data to store.
NumMessages Number of OS_QUEUE_SRCLIST structures at pMessageList.

Return value

= 0 Success, message stored.
≠ 0 Message could not be stored (queue is full).

Additional information

This routine never suspends the calling task and may therefore be called from main(), an interrupt routine or a software timer.
When the message is deposited into the queue, the entire message is copied into the queue buffer, not only the pointer(s) to the data. Therefore the message content is protected and remains valid until it is retrieved and accessed by a task reading the message.

The OS_QUEUE_SRCLIST structure consists of two elements:

Parameter Description
pSrc Pointer to a part of the message to store.
Size Size of the part of the message. Valid values are:
1 ≤ Size ≤ 215 - 1 = 0x7FFF for 8/16-bit CPUs.
1 ≤ Size ≤ 231 - 1 = 0x7FFFFFFF for 32-bit CPUs.

Note

The total size of all parts of the message must not exceed 0x7FFF on 8/16-bit CPUs, or 0x7FFFFFFF on 32-bit CPUs, respectively. The message is stored in the queue buffer with an additional message header. Additionally the message size will be round up to the next multiple of the size of an integer.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

145: OS_ERR_QUEUE_INVALID
149: OS_ERR_MESSAGE_SIZE_ZERO
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

OS_CONST_PTR OS_QUEUE_SRCLIST aDataList[] = { {"Hello ", 6},
                                              {"World!", 6}
                                            };
OS_QUEUE_PutEx(&_MemoryQ, aDataList, 2);

OS_QUEUE_PutBlocked()

Description

Stores a new message of given size in the specified message queue.

Prototype

void OS_QUEUE_PutBlocked(OS_QUEUE*    pQ,
                         OS_CONST_PTR void *pMessage,
                         OS_UINT      Size);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.
pMessage Pointer to the message to store.
Size Size of the message to store. Valid values are:
1 ≤ Size ≤ 215 - 1 = 0x7FFF for 8/16-bit CPUs.
1 ≤ Size ≤ 231 - 1 = 0x7FFFFFFF for 32-bit CPUs.

Additional information

If the queue is full, the calling task is suspended.
When the message is deposited into the queue, the entire message is copied into the queue buffer, not only the pointer(s) to the data. Therefore the message content is protected and remains valid until it is retrieved and accessed by a task reading the message.

Note

The message is stored in the queue buffer with an additional message header. Additionally the message size will be round up to the next multiple of the size of an integer.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

145: OS_ERR_QUEUE_INVALID
149: OS_ERR_MESSAGE_SIZE_ZERO
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

static OS_QUEUE _MemoryQ;

void StoreMessage(const void* pData, OS_UINT Len)
  OS_QUEUE_PutBlocked(&_MemoryQ, pData, Len);
}

OS_QUEUE_PutBlockedEx()

Description

Stores a new message, of which the distinct parts are distributed in memory as indicated by a OS_QUEUE_SRCLIST structure, in the specified message queue. Blocks the calling task when queue is full.

Prototype

void OS_QUEUE_PutBlockedEx(OS_QUEUE*    pQ,
                           OS_CONST_PTR OS_QUEUE_SRCLIST *pMessageList,
                           OS_UINT      NumMessages);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.
pMessageList Pointer to an array of OS_QUEUE_SRCLIST structures which contain pointers to the data to store.
NumMessages Number of OS_QUEUE_SRCLIST structures at pMessageList.

Additional information

If the queue is full, the calling task is suspended.
When the message is deposited into the queue, the entire message is copied into the queue buffer, not only the pointer(s) to the data. Therefore the message content is protected and remains valid until it is retrieved and accessed by a task reading the message.

The OS_QUEUE_SRCLIST structure consists of two elements:

Parameter Description
pSrc Pointer to a part of the message to store.
Size Size of the part of the message. Valid values are:
1 ≤ Size ≤ 215 - 1 = 0x7FFF for 8/16-bit CPUs.
1 ≤ Size ≤ 231 - 1 = 0x7FFFFFFF for 32-bit CPUs.

Note

The total size of all parts of the message must not exceed 0x7FFF on 8/16-bit CPUs, or 0x7FFFFFFF on 32-bit CPUs, respectively. The message is stored in the queue buffer with an additional message header. Additionally the message size will be round up to the next multiple of the size of an integer.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

145: OS_ERR_QUEUE_INVALID
149: OS_ERR_MESSAGE_SIZE_ZERO
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

OS_CONST_PTR OS_QUEUE_SRCLIST aDataList[] = { {"Hello ", 6},
                                              {"World!", 6}
                                            };
OS_QUEUE_PutEx(&_MemoryQ, aDataList, 2);

OS_QUEUE_PutTimed()

Description

Stores a new message of given size in the specified message queue if space is available within a given time.

Prototype

char OS_QUEUE_PutTimed(OS_QUEUE*    pQ,
                       OS_CONST_PTR void *pMessage,
                       OS_UINT      Size,
                       OS_U32       Timeout);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.
pMessage Pointer to the message to store.
Size Size of the message to store. Valid values are:
1 ≤ Size ≤ 215 - 1 = 0x7FFF for 8/16-bit CPUs.
1 ≤ Size ≤ 231 - 1 = 0x7FFFFFFF for 32-bit CPUs.
Timeout Maximum time in milliseconds until the given message must be stored.

Return value

= 0 Success, message stored.
≠ 0 Message could not be stored within the specified time (insufficient space).

Additional information

If the queue holds insufficient space, the calling task is suspended until space for the message is available, or the specified timeout time has expired. If the message could be deposited into the queue within the specified time, the function returns zero.
When the message is deposited into the queue, the entire message is copied into the queue buffer, not only the pointer(s) to the data. Therefore the message content is protected and remains valid until it is retrieved and accessed by a task reading the message.

Note

The message is stored in the queue buffer with an additional message header. Additionally the message size will be round up to the next multiple of the size of an integer.

OS_TIME_ConfigSysTimer() must have been called before calling OS_QUEUE_PutTimed().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

145: OS_ERR_QUEUE_INVALID
149: OS_ERR_MESSAGE_SIZE_ZERO
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_QUEUE _MemoryQ;

int MEMORY_WriteTimed(const void* pData, OS_UINT Len, OS_U32 Timeout) {
  return OS_QUEUE_PutTimed(&_MemoryQ, pData, Len, Timeout);
}

OS_QUEUE_PutTimedEx()

Description

Stores a new message, of which the distinct parts are distributed in memory as indicated by a OS_QUEUE_SRCLIST structure, in the specified message queue. Suspends the calling task for a given timeout when the queue is full.

Prototype

char OS_QUEUE_PutTimedEx(OS_QUEUE*    pQ,
                         OS_CONST_PTR OS_QUEUE_SRCLIST *pMessageList,
                         OS_UINT      NumMessages,
                         OS_U32       Timeout);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.
pMessageList Pointer to an array of OS_QUEUE_SRCLIST structures which contain pointers to the data to store.
NumMessages Number of OS_QUEUE_SRCLIST structures at pMessageList.
Timeout Maximum time in milliseconds until the given message must be stored.

Return value

= 0 Success, message stored.
≠ 0 Message could not be stored within the specified time (insufficient space).

Additional information

If the queue holds insufficient space, the calling task is suspended until space for the message is available or the specified timeout time has expired. If the message could be deposited into the queue within the specified time, the function returns zero.

When the message is deposited into the queue, the entire message is copied into the queue buffer, not only the pointer(s) to the data. Therefore the message content is protected and remains valid until it is retrieved and accessed by a task reading the message.

The OS_QUEUE_SRCLIST structure consists of two elements:

Parameter Description
pSrc Pointer to a part of the message to store.
Size Size of the part of the message. Valid values are:
1 ≤ Size ≤ 215 - 1 = 0x7FFF for 8/16-bit CPUs.
1 ≤ Size ≤ 231 - 1 = 0x7FFFFFFF for 32-bit CPUs.

Note

The total size of all parts of the message must not exceed 0x7FFF on 8/16-bit CPUs, or 0x7FFFFFFF on 32-bit CPUs, respectively. The message is stored in the queue buffer with an additional message header. Additionally the message size will be round up to the next multiple of the size of an integer.

OS_TIME_ConfigSysTimer() must have been called before calling OS_QUEUE_PutTimedEx().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

145: OS_ERR_QUEUE_INVALID
149: OS_ERR_MESSAGE_SIZE_ZERO
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

OS_CONST_PTR OS_QUEUE_SRCLIST aDataList[] = { {"Hello ", 6},
                                              {"World!", 6}
                                            };
OS_QUEUE_PutEx(&MemoryQ, aDataList, 2, 100);

Multi Object Wait

Introduction

In the preceding chapter, inter-task communication and synchronization with RTOS objects were described. With the described API a task can block for one specific RTOS object and condition only.

However, there could be the requirement to concurrently wait for multiple conditions to be fulfilled. For example, a task could need to wait at the same time for new data in a queue and an event to get signaled.

The Multi Object Wait feature allows to wait concurrently for one or more conditions to be fulfilled. The Multi Object Wait API returns as soon as one of the conditions it is waiting for is fulfilled. It is possible for more than one condition to be fulfilled when the Multi Object Wait API returns. The caller must look at the state of all RTOS objects to figure out which ones were fulfilled and what actions to take. The Multi Object Wait API does not e.g. retrieve data from the queue. That must be done subsequently by the application.

For each RTOS object and condition, an embOS condition routine can be defined.

Multi Object Wait can be used with:

Example

#include "RTOS.h"

#define OS_COUNT_OF(a)  (sizeof(a) / sizeof(a[0]))

static OS_STACKPTR int StackHP[128], StackLP[128];  // Task stacks
static OS_TASK         TCBHP, TCBLP;                // Task control blocks
static OS_QUEUE        MyQueue;                     // Queue control block
static char            MyQBuffer[30];               // Queue buffer
static OS_EVENT        MyEvent;                     // Event control block
//
// List of RTOS objects to simultaneously wait for
//
static const OS_MULTIOBJ_COND aMyMultiObjCond[] = {
  { &MyQueue, OS_MULTIOBJ_IsMessageInQueue, (void*)2    },
  { &MyEvent, OS_MULTIOBJ_IsEventSignaled,  (void*)NULL },
};
//
// Multiple object control blocks
//
static OS_MULTIOBJ aMyMultiObj[OS_COUNT_OF(aMyMultiObjCond)];

static void HPTask(void) {
  OS_INT  Index;
  char*   pData;
  int     MessageCnt;
  OS_BOOL Signaled;

  while (1) {
    Index = OS_MULTIOBJ_WaitBlocked(aMyMultiObj,
                                    aMyMultiObjCond,
                                    OS_COUNT_OF(aMyMultiObjCond));
    switch (Index) {
    case 0:
      MessageCnt = OS_QUEUE_GetMessageCnt(&MyQueue);
      if (MessageCnt == 2) {
        OS_QUEUE_GetPtr(&MyQueue, (void**)&pData);
        OS_COM_SendString(pData);
        OS_QUEUE_Purge(&MyQueue);
        OS_QUEUE_GetPtr(&MyQueue, (void**)&pData);
        OS_COM_SendString(pData);
        OS_QUEUE_Purge(&MyQueue);
      }
      break;
    case 1:
      Signaled = OS_EVENT_Get(&MyEvent);
      if (Signaled != 0u) {
         OS_COM_SendString("\nEvent received.");
         OS_EVENT_Reset(&MyEvent);
      }
      break;
    }

  }
}

static void LPTask(void) {
  while (1) {
    OS_QUEUE_Put(&MyQueue, "\nHello\0", 7);
    OS_QUEUE_Put(&MyQueue, "\nWorld !\0", 9);
    OS_EVENT_Set(&MyEvent);
    OS_TASK_Delay_ms(2);
  }
}

int main(void) {
  OS_Init();    // Initialize embOS
  OS_InitHW();  // Initialize required hardware
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_TASK_CREATE(&TCBLP, "LP Task",  50, LPTask, StackLP);
  OS_QUEUE_Create(&MyQueue, MyQBuffer, sizeof(MyQBuffer));
  OS_EVENT_CreateEx(&MyEvent, OS_EVENT_RESET_MODE_MANUAL);
  OS_Start();   // Start embOS
  return 0;
}

Condition routines

The Multi Object Wait API routines expect an array of OS_MULTIOBJ_COND entries. A OS_MULTIOBJ_COND structure contains the RTOS object address, the condition routine address and an optional parameter that is passed to the condition routine.

The application can choose for each RTOS object a different condition routine. The same condition routine can be used with different parameters. A condition routine returns true or false. If NULL is passed as the condition routine address, the return value is false.

Prototype

static OS_BOOL _IsCondition(OS_CONST_PTR void* pObj, void* pParam)

Example

static const OS_MULTIOBJ_COND aMyMultiObjCond[] = {
  { &MyQueue, OS_MULTIOBJ_IsMessageInQueue, (void*)2   },
  { &MyEvent, OS_MULTIOBJ_IsEventSignaled,  (void*)NULL},
};

API functions

Routine Description
OS_MULTIOBJ_IsEventSignaled() Returns whether the requested event object is in signaled state.
OS_MULTIOBJ_IsTokenInSema() Returns whether the requested semaphore contains available tokens.
OS_MULTIOBJ_IsMessageInMailbox() Returns whether the requested mailbox contains available messages.
OS_MULTIOBJ_IsSpaceInMailbox() Returns whether the requested mailbox has free space for additional messages.
OS_MULTIOBJ_IsMessageInQueue() Returns whether the requested queue contains available messages.
OS_MULTIOBJ_IsSpaceInQueue() Returns whether there is space for a message of size Size.
OS_MULTIOBJ_IsBlockInMemPool() Returns whether the requested Memory Pool contains available memory blocks.
OS_MULTIOBJ_IsEventSignaled()

Description

Returns whether the requested event object is in signaled state.

Prototype

OS_BOOL OS_MULTIOBJ_IsEventSignaled(OS_CONST_PTR void *pEvent,
                                    void*        pMask);

Parameters

Parameter Description
pEvent Pointer to an event object of type OS_EVENT.
pMask If pMask equals NULL, the function evaluates the entire event object bits. Therefore, it behaves like OS_EVENT_Get(), OS_EVENT_GetBlocked() and OS_EVENT_GetTimed() without an event mask and must be used with none mask event object API only. Otherwise, the bit mask indicates the event bits that shall be evaluated and must be used with mask event object API like OS_EVENT_SetMask() only.

Return value

= 0 Event object is not set to requested signal state.
≠ 0 Event object is set to requested signal state.

Additional information

The event bits are not consumed.

Note

OS_MULTIOBJ_IsEventSignaled() must be used with event object reset mode OS_EVENT_RESET_MODE_MANUAL only.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

220: OS_ERR_EVENT_INVALID

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example at the start of this sub-chapter.

OS_MULTIOBJ_IsTokenInSema()

Description

Returns whether the requested semaphore contains available tokens.

Prototype

OS_BOOL OS_MULTIOBJ_IsTokenInSema(OS_CONST_PTR void *pSemaphore,
                                  void*        pNumTokens);

Parameters

Parameter Description
pSemaphore Pointer to a semaphore object of type OS_SEMAPHORE.
pNumTokens If pNumTokens equals NULL, the function returns whether any token is available. Otherwise, the function returns whether the given amount of tokens is available.

Return value

= 0 Requested amount of semaphore tokens is not available.
≠ 0 Requested amount of semaphore tokens is available.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

132: OS_ERR_INV_SEMAPHORE

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example at the start of this sub-chapter.

OS_MULTIOBJ_IsMessageInMailbox()

Description

Returns whether the requested mailbox contains available messages.

Prototype

OS_BOOL OS_MULTIOBJ_IsMessageInMailbox(OS_CONST_PTR void *pMailbox,
                                       void*        pNumMessages);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pNumMessages If pNumMessages equals NULL, the function returns whether any message is available. Otherwise, the function returns whether the given number of messages is available.

Return value

= 0 Requested number of messages is not available.
≠ 0 Requested number of messages is available.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
147: OS_ERR_MAILBOX_INUSE

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example at the start of this sub-chapter.

OS_MULTIOBJ_IsSpaceInMailbox()

Description

Returns whether the requested mailbox has free space for additional messages.

Prototype

OS_BOOL OS_MULTIOBJ_IsSpaceInMailbox(OS_CONST_PTR void *pMailbox,
                                     void*        pNumMessages);

Parameters

Parameter Description
pMailbox Pointer to a mailbox object of type OS_MAILBOX.
pNumMessages If pNumMessages equals NULL, the function returns whether the mailbox has sufficient space for any message. Otherwise, the function returns whether the mailbox has sufficient space for the given number of messages.

Return value

= 0 Sufficient space for the requested number of messages is not available.
≠ 0 Sufficient space for the requested number of messages is available.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

130: OS_ERR_INV_MAILBOX
147: OS_ERR_MAILBOX_INUSE

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example at the start of this sub-chapter.

OS_MULTIOBJ_IsMessageInQueue()

Description

Returns whether the requested queue contains available messages.

Prototype

OS_BOOL OS_MULTIOBJ_IsMessageInQueue(OS_CONST_PTR void *pQueue,
                                     void*        pNumMessages);

Parameters

Parameter Description
pQueue Pointer to a queue object of type OS_QUEUE.
pNumMessages If pNumMessages equals NULL, the function returns whether any message is available. Otherwise, the function returns whether the given amount of messages is available.

Return value

= 0 Requested amount of messages is not available, or the queue is in use.
≠ 0 Requested amount of messages is available.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

143: OS_ERR_QUEUE_INUSE
145: OS_ERR_QUEUE_INVALID

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example at the start of this sub-chapter.

OS_MULTIOBJ_IsSpaceInQueue()

Description

Returns whether there is space for a message of size Size.

Prototype

OS_BOOL OS_MULTIOBJ_IsSpaceInQueue(OS_CONST_PTR void *pQueue,
                                   void*        pSize);

Parameters

Parameter Description
pQ Pointer to a queue object of type OS_QUEUE.
pSize Message size in bytes.

Return value

= 0 Not sufficient space for the requested message.
≠ 0 Sufficient space for the requested message.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

145: OS_ERR_QUEUE_INVALID

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example at the start of this sub-chapter.

OS_MULTIOBJ_IsBlockInMemPool()

Description

Returns whether the requested Memory Pool contains available memory blocks.

Prototype

OS_BOOL OS_MULTIOBJ_IsBlockInMemPool(OS_CONST_PTR void *pMEMF,
                                     void*        pNumBlocks);

Parameters

Parameter Description
pMEMF Pointer to a memory pool object of type OS_MEMPOOL.
pNumBlocks If pNumBlocks equals NULL, the function returns whether any memory block is available. Otherwise, the function returns whether the given amount of memory blocks is available.

Return value

= 0 Requested amount of memory blocks is not available.
≠ 0 Requested amount of memory blocks is available.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

190: OS_ERR_MEMF_INV

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example at the start of this sub-chapter.

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_MULTIOBJ_Wait() Returns whether one of the requested RTOS object conditions is true.
OS_MULTIOBJ_WaitBlocked() Waits until one of the requested RTOS object conditions is true.
OS_MULTIOBJ_WaitTimed() Returns whether one of the requested RTOS objects conditions is true.

OS_MULTIOBJ_Wait()

Description

Returns whether one of the requested RTOS object conditions is true.

Prototype

OS_INT OS_MULTIOBJ_Wait(OS_CONST_PTR OS_MULTIOBJ_COND *pMultiObjCond,
                        OS_UINT      NumObjects);

Parameters

Parameter Description
pMultiObjCond Pointer to an array of OS_MULTIOBJ_COND items.
NumObjects Number of OS_MULTIOBJ entries.

Return value

= -1 No RTOS object conditions is true.
≥ 0 Index of the first RTOS object conditions that is true.

Additional information

OS_MULTIOBJ_Wait() allows a task to wait concurrently for multiple RTOS objects. OS_MULTIOBJ_Wait() returns immediately and does not block the task.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

167: OS_ERR_CPU_STATE_ILLEGAL
265: OS_ERR_MULTIOBJ_INVALID_ROUTINE

For details, refer to the chapter Runtime application errors.

Example

#define OS_COUNT_OF(a)  (sizeof(a) / sizeof(a[0]))

static const OS_MULTIOBJ_COND aMyMultiObjCond[] = {
  { &MyQueue, OS_MULTIOBJ_IsMessageInQueue, (void*)2    },
  { &MyEvent, OS_MULTIOBJ_IsEventSignaled,  (void*)NULL },
};

static void HPTask(void) {
  OS_INT Index;

  while (1) {
    Index = OS_MULTIOBJ_Wait(aMyMultiObjCond, 2);
    ...
  }

OS_MULTIOBJ_WaitBlocked()

Description

Waits until one of the requested RTOS object conditions is true.

Prototype

OS_INT OS_MULTIOBJ_WaitBlocked(OS_MULTIOBJ* pMultiObj,
                               OS_CONST_PTR OS_MULTIOBJ_COND *pMultiObjCond,
                               OS_UINT      NumObjects);

Parameters

Parameter Description
pMultiObj Pointer to an array of OS_MULTIOBJ items.
pMultiObjCond Pointer to an array of OS_MULTIOBJ_COND items.
NumObjects Number of OS_MULTIOBJ entries.

Return value

Index of the first RTOS object conditions that is true.

Additional information

OS_MULTIOBJ_WaitBlocked() allows a task to wait concurrently for multiple RTOS objects. OS_MULTIOBJ_WaitBlocked() suspends the task until at least one condition is true.

Note

The pMultiObj and pMultiObjCond arrays must have the same number of items.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
265: OS_ERR_MULTIOBJ_INVALID_ROUTINE

For details, refer to the chapter Runtime application errors.

Example

#define OS_COUNT_OF(a)  (sizeof(a) / sizeof(a[0]))

static const OS_MULTIOBJ_COND aMyMultiObjCond[] = {
  { &MyQueue, OS_MULTIOBJ_IsMessageInQueue, (void*)2    },
  { &MyEvent, OS_MULTIOBJ_IsEventSignaled,  (void*)NULL },
};

static OS_MULTIOBJ aMyMultiObj[OS_COUNT_OF(aMyMultiObjCond)];

static void HPTask(void) {
  OS_INT Index;

  while (1) {
    Index = OS_MULTIOBJ_WaitBlocked(aMyMultiObMemj, aObjects, 2);
    ...
  }

OS_MULTIOBJ_WaitTimed()

Description

Returns whether one of the requested RTOS objects conditions is true.

Prototype

OS_INT OS_MULTIOBJ_WaitTimed(OS_MULTIOBJ* pMultiObj,
                             OS_CONST_PTR OS_MULTIOBJ_COND *pMultiObjCond,
                             OS_UINT      NumObjects,
                             OS_U32       Timeout);

Parameters

Parameter Description
pMultiObj Pointer to an array of OS_MULTIOBJ items.
pMultiObjCond Pointer to an array of OS_MULTIOBJ_COND items.
NumObjects Number of OS_MULTIOBJ entries.
Timeout Maximum time in system ticks until at least one condition must be true. The data type OS_TIME is defined as an integer, therefore valid values are:
1 ≤ Timeout ≤ 215 - 1 = 0x7FFF for 8/16-bit CPUs.
1 ≤ Timeout ≤ 231 - 1 = 0x7FFFFFFF for 32-bit CPUs.

Return value

= -1 No RTOS object conditions is true within the timeout.
≥ 0 Index of the first RTOS object conditions that is true.

Additional information

OS_MULTIOBJ_WaitTimed() allows a task to wait concurrently for multiple RTOS objects. OS_MULTIOBJ_WaitTimed() suspends the task until at least one condition is true or the timeout has expired.

OS_TIME_ConfigSysTimer() must have been called before calling OS_MULTIOBJ_WaitTimed().

Note

The pMultiObj and pMultiObjCond arrays must have the same number of items.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO
265: OS_ERR_MULTIOBJ_INVALID_ROUTINE

For details, refer to the chapter Runtime application errors.

Example

#define OS_COUNT_OF(a)  (sizeof(a) / sizeof(a[0]))

static const OS_MULTIOBJ_COND aMyMultiObjCond[] = {
  { &MyQueue, OS_MULTIOBJ_IsMessageInQueue, (void*)2    },
  { &MyEvent, OS_MULTIOBJ_IsEventSignaled,  (void*)NULL },
};

static OS_MULTIOBJ aMyMultiObj[OS_COUNT_OF(aMyMultiObjCond)];

static void HPTask(void) {
  OS_INT Index;

  while (1) {
    Index = OS_MULTIOBJ_WaitTimed(aMyMultiObMemj, aObjects, 2, 10);
    ...
  }

Watchdog

Introduction

A watchdog timer is a hardware timer that is used to reset a microcontroller after a specified amount of time. During normal operation, the microcontroller application periodically restarts (“triggers” or “feeds”) the watchdog timer to prevent it from timing out. In case of malfunction, however, the watchdog timer will eventually time out and subsequently reset the microcontroller. This allows to detect and recover from microcontroller malfunctions.

For example, in a system without an RTOS, the watchdog timer would be triggered periodically from a single point in the application. When the application does not run properly, the watchdog timer will not be triggered and thus the watchdog will cause a reset of the microcontroller.

In a system that includes an RTOS, on the other hand, multiple tasks run at the same time. It may happen that one or more of these tasks runs properly, while other tasks fail to run as intended. Hence it may be insufficient to trigger the watchdog from one of these tasks only. Therefore, embOS offers a watchdog support module that allows to automatically check if all tasks, software timers, or even interrupt routines are executing properly. The embOS watchdog support does not replace the hardware watchdog but makes it easier to use a hardware watchdog in an RTOS application.

Example

#include "RTOS.h"

static OS_STACKPTR int StackHP[128], StackLP[128];
static OS_TASK         TCBHP, TCBLP;
static OS_WD           WatchdogHP, WatchdogLP;
static OS_TIMER        Timer;

static void _TriggerWatchDog(void) {
  WD_REG = TRIGGER_WD;              // Trigger the hardware watchdog.
}

static void _Reset(OS_CONST_PTR OS_WD* pWD) {
  OS_USE_PARA(pWD);                 // Applications can use pWD to detect WD expiration cause.
  SYSTEM_CTRL_REG = PERFORM_RESET;  // Reboot microcontroller.
}

static void TimerCallback(void) {
  OS_WD_Check();
  OS_TIMER_Restart(&Timer);
}

static void HPTask(void) {
  OS_WD_Add(&WatchdogHP, 50);
  while (1) {
    OS_TASK_Delay_ms(50);
    OS_WD_Trigger(&WatchdogHP);
  }
}

static void LPTask(void) {
  OS_WD_Add(&WatchdogLP, 200);
  while (1) {
    OS_TASK_Delay_ms(200);
    OS_WD_Trigger(&WatchdogLP);
  }
}

int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_TASK_CREATE(&TCBLP, "LP Task",  50, LPTask, StackLP);
  OS_WD_Config(&_TriggerWatchDog, &_Reset);
  OS_TIMER_Create(&Timer, TimerCallback, 10);
  OS_TIMER_Start(&Timer);
  OS_Start();     // Start embOS
  return 0;
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_WD_Add() Adds a software watchdog timer to the watchdog list.
OS_WD_Check() Checks if a watchdog timer has expired.
OS_WD_Config() Sets the watchdog callback functions.
OS_WD_Remove() Removes a watchdog timer from the watchdog list.
OS_WD_Trigger() Triggers/Feeds a watchdog timer.

OS_WD_Add()

Description

Adds a software watchdog timer to the watchdog list.

Prototype

void OS_WD_Add(OS_WD* pWD,
               OS_U32 Timeout);

Parameters

Parameter Description
pWD Pointer to a watchdog object of type OS_WD.
Timeout Watchdog timer timeout in milliseconds.

Additional information

The watchdog timer will be checked by OS_WD_Check().

OS_TIME_ConfigSysTimer() must have been called before calling OS_WD_Add().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
179: OS_ERR_2USE_WATCHDOG
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_WD _myWD;

void HPTask(void) {
  OS_WD_Add(&_myWD, 50);
  while (1) {
    OS_WD_Trigger(&_myWD);
    OS_TASK_Delay_ms(50);
  }
}

OS_WD_Check()

Description

Checks if a watchdog timer has expired.

Prototype

void OS_WD_Check(void);

Additional information

If no watchdog timer has expired the hardware watchdog is triggered. If a watchdog timer has expired, the callback function is called. OS_WD_Check() must be called periodically. It is good practice to call it from the system tick handler.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void SysTick_Handler(void) {
  OS_INT_Enter();
  OS_Tick_Handle();
  OS_WD_Check();
  OS_INT_Leave();
}

OS_WD_Config()

Description

Sets the watchdog callback functions.

Prototype

void OS_WD_Config(OS_ROUTINE_VOID*   pfTrigger,
                  OS_ROUTINE_WD_PTR* pfReset);

Parameters

Parameter Description
pfTrigger Pointer to the function of type OS_ROUTINE_VOID which shall be called to trigger (fed) the hardware watchdog.
pfReset Pointer to the function of type OS_ROUTINE_WD_PTR which shall be called when an watchdog timer has expired.

Additional information

pfReset may be used to perform additional operations inside a callback routine prior to the reset of the microcontroller. For example, a message may be written to a log file. pfReset is optional and may be NULL. If pfReset is NULL, no callback routine gets executed, but the hardware watchdog will still cause a reset of the microcontroller.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static void _TriggerWatchDog(void) {
  WD_REG = TRIGGER_WD;              // Trigger the hardware watchdog
}

static void _Reset(OS_CONST_PTR OS_WD* pWD) {
  //
  // Store information about expired watchdog prior to reset.
  //
  _WriteLogMessage(pWD);
  //
  // Reboot microcontroller
  //
  SYSTEM_CTRL_REG = PERFORM_RESET;
}

int main(void) {
  ...
  OS_WD_Config(&_TriggerWatchDog, &_Reset);
  OS_Start();
  return 0;
}

OS_WD_Remove()

Description

Removes a watchdog timer from the watchdog list.

Prototype

void OS_WD_Remove(OS_CONST_PTR OS_WD *pWD);

Parameters

Parameter Description
pWD Pointer to a watchdog object of type OS_WD.

Additional information

A removed watchdog is no longer checked by OS_WD_Check().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

int main(void) {
  ...
  OS_WD_Add(&_myWD);
  OS_WD_Remove(&_myWD);
  return 0;
}

OS_WD_Trigger()

Description

Triggers/Feeds a watchdog timer.

Prototype

void OS_WD_Trigger(OS_WD* pWD);

Parameters

Parameter Description
pWD Pointer to a watchdog object of type OS_WD.

Additional information

Each software watchdog timer must be triggered (fed) periodically. If not, the timeout expires and OS_WD_Check() will no longer trigger the hardware watchdog timer, but will call the reset callback function (if any).

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

static OS_WD _myWD;

static void HPTask(void) {
  OS_WD_Add(&_myWD, 50);
  while (1) {
    OS_TASK_Delay_ms(50);
    OS_WD_Trigger(&_myWD);
  }
}

Multi-core Support

Introduction

embOS can be utilized on multi-core processors by running separate embOS instances on each individual core. For synchronization purposes and in order to exchange data between the cores, embOS includes a comprehensive spinlock API which can be used to control access to shared memory, peripherals, etc. This API is not available in embOS library mode OS_LIBMODE_SAFE.

Spinlocks

Spinlocks constitute a general purpose locking mechanism in which any process trying to acquire the lock is caused to actively wait until the lock becomes available. To do so, the process trying to acquire the lock remains active and repeatedly checks the availability of the lock in a loop. Effectively, the process will “spin” until it acquires the lock.

Once acquired by a process, spinlocks are usually held by that process until they are explicitly released. If held by one process for longer duration, spinlocks may severely impact the runtime behavior of other processes trying to acquire the same spinlock. Therefore, spinlocks should be held by one process for short periods of time only.

Usage of spinlocks with embOS

embOS spinlocks are intended for inter-core synchronization and communication. They are not intended for synchronization of individual tasks running on the same core, on which semaphores, queues and mailboxes should be used instead.

However, multitasking still has to be taken into consideration when using embOS spinlocks. Specifically, an embOS task holding a spinlock should not be preempted, for this would prevent that task from releasing the spinlock as fast as possible, which may in return impact the runtime behavior of other cores attempting to acquire the spinlock. Declaration of critical regions therefore is explicitly recommended while holding spinlocks.

embOS spinlocks are usually implemented using hardware instructions specific to one architecture, but a portable software implementation is provided in addition. If appropriate hardware instructions are unavailable for the specific architecture in use, the software implementation is provided exclusively.

Note

It is important to use matching implementations on each core of the multi-core processor that shall access the same spinlock.

For example, a core supporting a hardware implementation may use that implementation to access a spinlock that is shared with another core that supports the same hardware implementation. At the same time, that core may use the software implementation to access a different spinlock that is shared with a different core that does not support the same hardware implementation. However, in case all three cores in this example should share the same spinlock, each of them has to use the software implementation.

To know the spinlock’s location in memory, each core’s application must declare the appropriate OS_SPINLOCK variable (or OS_SPINLOCK_SW, respectively) at an identical memory address. Initialization of the spinlock, however, must be performed by one core only.

Example of using spinlocks

Two cores of a multi-core processor shall access an hardware peripheral, e.g. a LC display. To avoid situations in which both cores access the LCD simultaneously, access must be restricted through usage of a spinlock: Every time the LCD is used by one core, it must first claim the spinlock through the respective embOS API call. After the LCD has been written to, the spinlock is released by another embOS API call.

Data exchange between cores can be implemented analogously, e.g. through declaration of a buffer in shared memory: Here, every time a core shall write data to the buffer, it must acquire the spinlock first. After the data has been written to the buffer, the spinlock is released. This ensures that neither core can interfere with the writing of data by the other core.

Core 0:

#include "RTOS.h"

static OS_STACKPTR int Stack[128];    // Task stack
static OS_TASK         TCB;           // Task-control-block
static OS_SPINLOCK     MySpinlock @ ".shared_mem";

static void Task(void) {
  while (1) {
    OS_TASK_EnterRegion();            // Inhibit preemptive task switches
    OS_SPINLOCK_Lock(&MySpinlock);    // Acquire spinlock
    //
    // Perform critical operation
    //
    OS_SPINLOCK_Unlock(&MySpinlock);  // Release spinlock
    OS_TASK_LeaveRegion();            // Re-allow preemptive task switches
  }
}

int main(void) {
  OS_Init();                          // Initialize embOS
  OS_InitHW();                        // Initialize Hardware for OS
  OS_SPINLOCK_Create(&MySpinlock);    // Initialize Spinlock
  ReleaseCore(1);                     // Spinlock created, Core #1 can be released to start up
  OS_TASK_CREATE(&TCB, "Task", 100, Task, Stack);
  OS_Start();                         // Start multitasking
  return 0;
}

Core 1:

#include "RTOS.h"

static OS_STACKPTR int Stack[128];    // Task stack
static OS_TASK         TCB;           // Task-control-block
static OS_SPINLOCK     MySpinlock @ ".shared_mem";

static void Task(void) {
  while (1) {
    OS_TASK_EnterRegion();            // Inhibit preemptive task switches
    OS_SPINLOCK_Lock(&MySpinlock);    // Acquire spinlock
    //
    // Perform critical operation
    //
    OS_SPINLOCK_Unlock(&MySpinlock);  // Release spinlock
    OS_TASK_LeaveRegion();            // Re-allow preemptive task switches
  }
}

int main(void) {
  OS_Init();                          // Initialize embOS
  OS_InitHW();                        // Initialize Hardware for OS
  OS_TASK_CREATE(&TCB, "Task", 100, Task, Stack);
  OS_Start();                         // Start multitasking
  return 0;
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_SPINLOCK_Create() Creates a hardware-specific spinlock.
OS_SPINLOCK_Lock() Acquires a hardware-specific spinlock. Busy waiting until the spinlock becomes available. This function is unavailable for some architectures.
OS_SPINLOCK_Unlock() Releases a hardware-specific spinlock. This function is unavailable for architectures that do not support an appropriate instruction set.
OS_SPINLOCK_SW_Create() Creates a software-implementation spinlock.
OS_SPINLOCK_SW_Lock() Acquires the specified software-implementation spinlock.
OS_SPINLOCK_SW_Unlock() Releases the specified software-implementation spinlock.

OS_SPINLOCK_Create()

Description

Creates a hardware-specific spinlock.

Prototype

void OS_SPINLOCK_Create(OS_SPINLOCK* pSpinlock);

Parameters

Parameter Description
pSpinlock Pointer to a spinlock object of type OS_SPINLOCK. The variable must reside in shared memory.

Additional information

After creation, the spinlock is not locked.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

165: OS_ERR_INIT_NOT_CALLED
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example in the introduction of chapter Multi-core Support.

OS_SPINLOCK_Lock()

Description

OS_SPINLOCK_Lock() acquires a hardware-specific spinlock. If the spinlock is unavailable, the calling task will not be blocked, but will actively wait until the spinlock becomes available.
This function is unavailable for architectures that do not support an appropriate instruction set.

Prototype

void OS_SPINLOCK_Lock(OS_SPINLOCK* pSpinlock);

Parameters

Parameter Description
pSpinlock Pointer to a variable of type OS_SPINLOCK reserved for the management of the spinlock.

Additional information

A task that has acquired a spinlock must not call OS_SPINLOCK_Lock() for that spinlock again. The spinlock must first be released by a call to OS_SPINLOCK_Unlock().

The following diagram illustrates how OS_SPINLOCK_Lock() works:

Example

Please refer to the example in the introduction of chapter Multi-core Support.

OS_SPINLOCK_Unlock()

Description

Releases a hardware-specific spinlock. This function is unavailable for architectures that do not support an appropriate instruction set.

Prototype

void OS_SPINLOCK_Unlock(OS_SPINLOCK* pSpinlock);

Parameters

Parameter Description
pSpinlock Pointer to a variable of type OS_SPINLOCK reserved for the management of the spinlock.

Example

Please refer to the example in the introduction of chapter Multi-core Support.

OS_SPINLOCK_SW_Create()

Description

Creates a software-implementation spinlock.

Prototype

void OS_SPINLOCK_SW_Create(OS_SPINLOCK_SW* pSpinlock);

Parameters

Parameter Description
pSpinlock Pointer to a spinlock object of type OS_SPINLOCK_SW. The variable must reside in shared memory.

Additional information

After creation, the spinlock is not locked.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

165: OS_ERR_INIT_NOT_CALLED
160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example in the introduction of chapter Multi-core Support.

OS_SPINLOCK_SW_Lock()

Description

Acquires the specified software-implementation spinlock. If the spinlock is unavailable, the calling task will not be blocked, but will actively wait until the spinlock becomes available.

Prototype

void OS_SPINLOCK_SW_Lock(OS_SPINLOCK_SW* pSpinlock,
                         OS_UINT         Id);

Parameters

Parameter Description
pSpinlock Pointer to a spinlock object of type OS_SPINLOCK_SW.
Id Unique identifier to specify the core accessing the spinlock. Valid values are 0 ≤ Id < OS_SPINLOCK_MAX_CORES. By default, OS_SPINLOCK_MAX_CORES is defined to 4 and may be changed when using source code.

Additional information

A task that has acquired a spinlock must not call OS_SPINLOCK_SW_Lock() for that spinlock again. The spinlock must first be released by a call to OS_SPINLOCK_SW_Unlock().

OS_SPINLOCK_SW_Lock() implements Lamport’s bakery algorithm, published by Leslie Lamport in “Communications of the Association for Computing Machinery”, 1974, Volume 17, Number 8. An excerpt is publicly available at research.microsoft.com.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
185: OS_ERR_SPINLOCK_INV_CORE

For details, refer to the chapter Runtime application errors.

The following diagram illustrates how OS_SPINLOCK_SW_Lock() works:

Example

Please refer to the example in the introduction of chapter Multi-core Support.

OS_SPINLOCK_SW_Unlock()

Description

Releases the specified software-implementation spinlock.

Prototype

void OS_SPINLOCK_SW_Unlock(OS_SPINLOCK_SW* pSpinlock,
                           OS_UINT         Id);

Parameters

Parameter Description
pSpinlock Pointer to a spinlock object of type OS_SPINLOCK_SW.
Id Unique identifier to specify the core accessing the spinlock. Valid values are 0 ≤ Id < OS_SPINLOCK_MAX_CORES. By default, OS_SPINLOCK_MAX_CORES is defined to 4 and may be changed when using source code.

Additional information

OS_SPINLOCK_SW_Unlock() must called after OS_SPINLOCK_SW_Lock() only.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
185: OS_ERR_SPINLOCK_INV_CORE

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example in the introduction of chapter Multi-core Support.

Interrupts

What are interrupts?

This chapter explains how to use interrupt service routines (ISRs) in cooperation with embOS. Specific details for your CPU and compiler can be found in the CPU & Compiler Specifics manual of the embOS documentation.

Interrupts are interruptions of a program caused by hardware. When an interrupt occurs, the CPU saves its registers and executes a subroutine called an interrupt service routine, or ISR. After the ISR is completed, the program returns to the highest-priority task which is ready for execution. Normal interrupts are maskable. Maskable interrupts can occur at any time unless they are disabled. ISRs are also nestable -- they can be recognized and executed within other ISRs.

There are several good reasons for using interrupt routines. They can respond very quickly to external events such as the status change on an input, the expiration of a hardware timer, reception or completion of transmission of a character via serial interface, or other types of events. Interrupts effectively allow events to be processed as they occur.

Interrupt latency

Interrupt latency is the time between an interrupt request and the execution of the first instruction of the interrupt service routine. Every computer system has an interrupt latency. The latency depends on various factors and differs even on the same computer system. The value that one is typically interested in is the worst case interrupt latency. The interrupt latency is the sum of a number of individual smaller delays explained below.

Note

Interrupt latency caused by embOS can be avoided entirely when using zero latency interrupts, which are explained in chapter Zero interrupt latency.

Causes of interrupt latencies

Additional causes for interrupt latencies

There can be additional causes for interrupt latencies. These depend on the type of system used, but we list a few of them.

How to measure latency and detect its cause

It is sometimes desirable to detect the cause for high interrupt latency. High interrupt latency may occur if interrupts are disabled for extended periods of time, or if a low level interrupt handler is executed before the actual interrupt handler. In these regards, embOS related functions like OS_INT_Enter() add to interrupt latency as well.

To measure interrupt latency and detect its cause, a timer interrupt may be used. For example, if the hardware timer counts upwards starting from zero after each compare-match-interrupt, its current counter value may be read from within the interrupt service routine to evaluate how many timer cycles (and thus how much time) have lapsed between the interrupt’s occurrence and the actual execution of the interrupt handler:

static int Latency = 0;

void TimerIntHandler(void) {
  OS_INT_Enter();
  Latency = TIMER_CNT_VALUE;  // Get current timer value
  OS_INT_Leave();
}

If this measurement is repeated several times, different results will occur. This is for the reason that the interrupt will sometimes be asserted while interrupts have been disabled by the application, while at other times interrupts are enabled when this interrupt request occurs. Thus, an application may keep track of minimum and maximum latency as shown below:

static int Latency    = 0;
static int MaxLatency = 0;
static int MinLatency = 0xFFFFFFFF;

void TimerIntHandler(void) {
  OS_INT_Enter();
  Latency    = TIMER_CNT_VALUE;  // Get current timer value
  MinLatency = (Latency < MinLatency) ? Latency : MinLatency;
  MaxLatency = (Latency > MaxLatency) ? Latency : MaxLatency;
  OS_INT_Leave();
}

Using this method, MinLatency will hold the latency that was caused by hardware (and any low-level interrupt handler, if applicable). On the other hand, MaxLatency will hold the latency caused both by hardware and interrupt-masking in software. Therefore, by subtracting MaxLatency - MinLatency, it is possible to calculate the exact latency that was caused by interrupt-masking (typically performed by the operating system).

Based on this information, a threshold may be defined to detect the cause of high interrupt latency. E.g., a breakpoint may be set for when the current timer value exceeds a pre-defined threshold as shown below:

static int Latency = 0;

void TimerIntHandler(void) {
  OS_INT_Enter();
  Latency = TIMER_CNT_VALUE;  // Get current timer value
  if (Latency > LATENCY_THRESHOLD) {
    while (1);                // Set a breakpoint here
  }
  OS_INT_Leave();
}

If code trace information is available upon hitting the breakpoint, the exact cause for the latency may be checked through a trace log.

Note

If the hardware timer interrupt is the only interrupt in the system, its priority may be chosen arbitrarily. Otherwise, in case other interrupts occur during measurement as well, the timer interrupt should be configured to match the specific priority for which to measure latency. This is important, for other (possibly non-nestable) interrupts will influence the results depending on their priority relative to the timer interrupt’s priority, which may or may not be desired on a case-to-case basis.
Also, in order to provide meaningful results, the interrupt should occur quite frequently. Hence, the timer reload value typically is configured for small periods of time, but must ensure that interrupt execution will not consume the entire CPU time.

Zero interrupt latency

Zero interrupt latency in the strict sense is not possible as explained above. What we mean when we say “Zero interrupt latency” is that the latency of high priority interrupts is not affected by the RTOS; a system using embOS will have the same worst case interrupt latency for high priority interrupts as a system running without embOS.

Why is Zero latency important?

In some systems, a maximum interrupt response time or latency can be clearly defined. This maximum latency can arise from requirements such as maximum reaction time for a protocol or a software UART implementation that requires very precise timing.

For example a UART receiving at up to 800 kHz in software using ARM FIQ on a 48 MHz ARM7. This would be impossible to do if FIQ were disabled even for short periods of time.

In many embedded systems, the quality of the product depends on event reaction time and therefore latency. Typical examples would be systems which periodically read a value from an A/D converter at high speed, where the accuracy depends on accurate timing. Less jitter means a better product.

Why can a zero latency ISR not use the embOS API?

embOS disables embOS interrupts when embOS data structures are modified. During this time zero latency ISRs are enabled. If they would call an embOS function, which also modifies embOS data, the embOS data structures would be corrupted.

How can a zero latency ISR communicate with a task?

The most common way is to use global variables, e.g. a periodical read from an ADC and the result is stored in a global variable.

Another way is to assert an interrupt request for an embOS interrupt from within the zero latency ISR, which may then communicate or wake up one or more tasks. This is helpful if you want to receive high amounts of data in your zero latency ISR. The embOS ISR may then store the data bytes e.g. in a message queue or in a mailbox.

High / low priority interrupts

Most CPUs support interrupts with different priorities. Different priorities have two effects:

The number of interrupt levels depends on the CPU and the interrupt controller. Details are explained in the CPU/MCU/SoC manuals and the CPU & Compiler Specifics manual of embOS. embOS distinguishes two different levels of interrupts: High and low priority interrupts. High priority interrupts are named “Zero latency interrupts” and low priority interrupts are named “embOS interrupts”. The embOS port-specific documentations explain which interrupts are considered high and which are considered low priority for that specific port. In general, the differences between those two are as follows:

embOS interrupts

Zero latency interrupts

Example of different interrupt priority levels

Let’s assume we have a CPU which supports eight interrupt priority levels. With embOS, the interrupt levels are divided per default equal in low priority and high priority interrupt levels. The four highest priority levels are considered “Zero latency interrupts” and the four lowest priority interrupts are considered as “embOS interrupts”. For ARM CPUs, which support regular interrupts (IRQ) and fast interrupt (FIQ), FIQ is considered as “Zero latency interrupt” when using embOS.

For most implementations the high-priority threshold is adjustable. For details, refer to the processor specific embOS manual.

Using embOS API from zero latency interrupts

Zero latency interrupts are prohibited from using embOS functions. This is a consequence of embOS’s zero latency design, according to which embOS never disables zero latency interrupts. This means that zero latency interrupts can interrupt the operating system at any time, even in critical sections such as the modification of RTOS-maintained linked lists. This design decision has been made because zero interrupt latencies for zero latency interrupts usually are more important than the ability to call OS functions.

However, zero latency interrupts may use embOS functions in an indirect manner: The zero latency interrupt triggers an embOS interrupt by setting the appropriate interrupt request flag. Subsequently, that embOS interrupt may call the OS functions that the zero latency interrupt was not allowed to use.

The task 1 is interrupted by a high priority interrupt. This zero latency interrupt is not allowed to call an embOS API function directly. Therefore the zero latency interrupt triggers an embOS interrupt, which is allowed to call embOS API functions. The embOS interrupt calls an embOS API function to resume task 2. How the embOS interrupt gets triggered is device specific and cannot be explained here in general. But with most devices and interrupt controllers, it is possible to set a pending flag for an interrupt. This could for example be an unused peripheral interrupt like a hardware timer. Please refer to your core and/or device manual for more details.

Rules for interrupt handlers

General rules

There are some general rules for interrupt service routines (ISRs). These rules apply to both single-task programming as well as to multitask programming using embOS.

Additional rules for preemptive multitasking

A preemptive multitasking system like embOS needs to know if the code that is executing is part of the current task or an interrupt handler. This is necessary because embOS cannot perform a task switch during the execution but only at the end of an ISR.

If a task switch was to occur during the execution of an ISR, the ISR would continue as soon as the interrupted task became the current task again. This is not a problem for interrupt handlers that do not allow further interruptions (which do not enable interrupts) and that do not call any embOS functions.

This leads us to the following rule:

If a higher priority task is made ready by the ISR, the task switch may be performed in the routine OS_INT_Leave(). The end of the ISR is executed later on, when the interrupted task has been made ready again. Please consider this behavior if you debug an interrupt routine, this has proven to be the most efficient way of initiating a task switch from within an interrupt service routine.

Nesting interrupt routines

By default, interrupts are disabled in an ISR because most CPU disables interrupts with the execution of the interrupt handler. Re-enabling interrupts in an interrupt handler allows the execution of further interrupts with equal or higher priority than that of the current interrupt. These are known as nested interrupts, illustrated in the diagram below:

For applications requiring short interrupt latency, you may re-enable interrupts inside an ISR by using OS_INT_EnterNestable() and OS_INT_LeaveNestable() within the interrupt handler.

Nested interrupts can lead to problems that are difficult to debug; therefore it is not recommended to enable interrupts within an interrupt handler. As it is important that embOS keeps track of the status of the interrupt enable/disable flag, enabling and disabling of interrupts from within an ISR must be done using the functions that embOS offers for this purpose.

The routine OS_INT_EnterNestable() enables interrupts within an ISR and prevents further task switches; OS_INT_LeaveNestable() disables interrupts immediately before ending the interrupt routine, thus restoring the default condition. Re-enabling interrupts will make it possible for an embOS scheduler interrupt to interrupt this ISR. In this case, embOS needs to know that another ISR is still active and that it may not perform a task switch.

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_INT_Call() Entry function for use in an embOS interrupt handler.
OS_INT_CallNestable() Entry function for use in an embOS interrupt handler.
OS_INT_Enter() Informs embOS that interrupt code is executing.
OS_INT_EnterIntStack() Switches to another stack in interrupt routines.
OS_INT_EnterNestable() Informs embOS that interrupt code is executing and reenables interrupts.
OS_INT_InInterrupt() Checks if the calling function runs in an interrupt context.
OS_INT_Leave() Informs embOS that the end of the interrupt routine has been reached; executes task switching within ISR.
OS_INT_LeaveIntStack() Switches back to the interrupt stack.
OS_INT_LeaveNestable() Informs embOS that the end of the interrupt routine has been reached; executes task switching within ISR.
OS_INT_Call()

Description

Entry function for use in an embOS interrupt handler. Nestable interrupts are disabled.

Prototype

void OS_INT_Call(void ( *pfRoutine)());

Parameters

Parameter Description
pfRoutine Pointer to a routine that should run on interrupt.

Additional information

OS_INT_Call() can be used as an entry function in an embOS interrupt handler, when the corresponding interrupt should not be interrupted by another embOS interrupt.
OS_INT_Call() sets the interrupt priority of the CPU to the user definable ’fast’ interrupt priority level, thus locking any other embOS interrupt. Fast interrupts are not disabled.

Note

For some specific CPUs OS_INT_Call() must be used to call an interrupt handler because OS_INT_Enter()/OS_INT_Leave() may not be available.
OS_INT_Call() must not be used when OS_INT_Enter()/OS_INT_Leave() is available
Please refer to the CPU/compiler specific embOS manual.

Example

#pragma interrupt
void SysTick_Handler(void) {
  OS_INT_Call(_IsrTickHandler);
}
OS_INT_CallNestable()

Description

Entry function for use in an embOS interrupt handler. Nestable interrupts are enabled.

Prototype

void OS_INT_CallNestable(void ( *pfRoutine)());

Parameters

Parameter Description
pfRoutine Pointer to a routine that should run on interrupt.

Additional information

OS_INT_CallNestable() can be used as an entry function in an embOS interrupt handler, when interruption by higher prioritized embOS interrupts should be allowed.
OS_INT_CallNestable() does not alter the interrupt priority of the CPU, thus keeping all interrupts with higher priority enabled.

Note

For some specific CPUs OS_INT_CallNestable() must be used to call an interrupt handler because OS_INT_EnterNestable()/OS_INT_LeaveNestable() may not be available.
OS_INT_CallNestable() must not be used when OS_INT_EnterNestable()/OS_INT_LeaveNestable() is available
Please refer to the CPU/compiler specific embOS manual.

Example

#pragma interrupt
void SysTick_Handler(void) {
  OS_INT_CallNestable(_IsrTickHandler);
}
OS_INT_Enter()

Description

Informs embOS that interrupt code is executing.

Prototype

void OS_INT_Enter(void);

Additional information

Note

This function is not available in all ports.

If OS_INT_Enter() is used, it should be the first function to be called in the interrupt handler. It must be paired with OS_INT_Leave() as the last function called. The use of this function has the following effects:

Example

void ISR_Timer(void) {
  OS_INT_Enter();
  OS_TASKEVENT_Set(&Task, 1u);  // Any functionality could be here
  OS_INT_Leave();
}
OS_INT_EnterIntStack()

Description

OS_INT_EnterIntStack() and OS_INT_LeaveIntStack() can be used to switch the stack pointer to another stack during execution of the interrupt routine.

Prototype

void OS_INT_EnterIntStack(void);

Additional information

The actual implementation is core and compiler dependent. Therefore, OS_INT_EnterIntStack() and OS_INT_LeaveIntStack() are not implemented in all embOS ports. In that case OS_INT_EnterIntStack() is defined for compatibility reasons to nothing. That simplifies the porting of an existing embOS application to another embOS port.

Note

Please be aware any variables that are declared while using the initial stack, will no longer be accessible after switching to the interrupt stack.

void ISR_Timer(void) {
  //
  // Accessible only before OS_INT_EnterIntStack() is called,
  // and after OS_INT_LeaveIntStack() was called.
  //
  int localvar = 0;

  OS_INT_Enter();
  OS_INT_EnterIntStack();
  OS_TASKEVENT_Set(&Task, Event);
  OS_INT_LeaveIntStack();
  OS_INT_Leave();
}
OS_INT_EnterNestable()

Description

Re-enables interrupts and increments the embOS internal critical region counter, thus disabling further task switches.

Prototype

void OS_INT_EnterNestable(void);

Additional information

Note

This function is not available in all ports.

This function should be the first call inside an interrupt handler when nested interrupts are required. The function OS_INT_EnterNestable() is implemented as a macro and offers the same functionality as OS_INT_Enter() in combination with OS_INT_DecRI(), but is more efficient, resulting in smaller and faster code.

Example

_interrupt void ISR_Timer(void) {
  OS_INT_EnterNestable();
  OS_TASKEVENT_Set(&Task, 1);  // Any functionality could be here
  OS_INT_LeaveNestable();
}
OS_INT_InInterrupt()

Description

This function can be called to examine if the calling function is running in an interrupt context. For application code, it may be useful to know if it is called from interrupt or task, because some functions must not be called from an interrupt-handler.

Prototype

OS_BOOL OS_INT_InInterrupt(void);

Return value

= 0 Code is not executed in an interrupt handler.
≠ 0 Code is executed in an interrupt handler.

Additional information

Note

This function is not available in all ports.

The function delivers the interrupt state by checking the according CPU registers. It is only implemented for those CPUs where it is possible to read the interrupt state from CPU registers. In case of doubt please contact the embOS support.

Example

void foo(void) {
  if (OS_INT_InInterrupt() != 0) {
    // Do something within the ISR
  } else {
    printf("No interrupt context.\n")
  }
}
OS_INT_Leave()

Description

Informs embOS that the end of the interrupt routine has been reached; executes task switching within ISR.

Prototype

void OS_INT_Leave(void);

Additional information

Note

This function is not available in all ports.

If OS_INT_Leave() is used, it should be the last function to be called in the interrupt handler. If the interrupt has caused a task switch, that switch is performed immediately (unless the program which was interrupted was in a critical region).

Example

void ISR_Timer(void) {
  OS_INT_Enter();
  OS_TASKEVENT_Set(&Task, 1);  // Any functionality could be here
  OS_INT_Leave();
}
OS_INT_LeaveIntStack()

Description

OS_INT_EnterIntStack() and OS_INT_LeaveIntStack() can be used to switch the stack pointer to another stack during execution of the interrupt routine.

Prototype

void OS_INT_LeaveIntStack(void);

Additional information

The actual implementation is device and compiler dependent. Therefore OS_INT_EnterIntStack() and OS_INT_LeaveIntStack() are not implemented in all embOS ports. In that case OS_INT_EnterIntStack() is defined for compatibility reasons to nothing. That simplifies the porting of an existing embOS application to another embOS port.

Example

void ISR_Timer(void) {
  OS_INT_Enter();
  OS_INT_EnterIntStack();
  OS_TASKEVENT_Set(&Task, 1);
  OS_INT_LeaveIntStack();
  OS_INT_Leave();
}
OS_INT_LeaveNestable()

Description

Disables further interrupts, then decrements the embOS internal critical region count, thus re-enabling task switches if the counter has reached zero.

Prototype

void OS_INT_LeaveNestable(void);

Additional information

Note

This function is not available in all ports.

This function is the counterpart of OS_INT_EnterNestable(), and must be the last function call inside an interrupt handler when nested interrupts have been enabled by OS_INT_EnterNestable().

The function OS_INT_LeaveNestable() is implemented as a macro and offers the same functionality as OS_INT_Leave() in combination with OS_INT_IncDI(), but is more efficient, resulting in smaller and faster code.

Example

_interrupt void ISR_Timer(void) {
  OS_INT_EnterNestable();
  OS_TASKEVENT_Set(&Task, 1);  // Any functionality could be here
  OS_INT_LeaveNestable();
}

Interrupt control

Enabling / disabling interrupts

During the execution of a task, maskable interrupts are normally enabled. In certain sections of the program, however, it can be necessary to disable interrupts for short periods of time to make a section of the program an atomic operation that cannot be interrupted. We recommend disabling interrupts only for short periods of time, if possible (the longer interrupts are disabled, the higher is the interrupt latency).

An example would be the access to a global volatile variable of type long on an 8/16-bit CPU. To make sure that the value does not change between the two or more memory accesses that are needed, interrupts must be temporarily disabled:

Bad example:

volatile long lvar;

void IntHandler(void) {
  lvar++;
}

void Routine(void) {
  lvar++;
}

Good example:

volatile long lvar;

void IntHandler(void) {
  lvar++;
}

void Routine(void) {
  OS_INT_Disable();
  lvar++;
  OS_INT_Enable();
}

Nested interrupt disable and enable calls

OS_INT_Disable() does not use a counter on how often it was executed and OS_INT_Enable() does not evaluate any counter before enabling interrupts. The below sample fails when the application expects that interrupts are still disabled after the call to bar().

void bar(void) {
  OS_INT_Disable();
  DoSomething();
  OS_INT_Enable();
}

void foo(void) {
  OS_INT_Disable();
  bar();
  DoSomethingElse();
  OS_INT_Enable();
}

To avoid this bar() must not enable embOS interrupts unconditionally but use OS_INT_EnableConditional() instead and the routine foo() must call OS_INT_IncDI(). OS_INT_IncDI() does not disable embOS interrupts only but also increments the interrupt disable counter OS_Global.Counters.Cnt.DI. OS_INT_EnableConditional() enables embOS interrupts only when the interrupt disable counter OS_Global.Counters.Cnt.DI is zero.

void bar(void) {
  OS_INT_Disable();
  DoSomething();
  OS_INT_EnableConditional();
}

void foo(void) {
  OS_INT_IncDI();
  foo();
  DoSomethingElse();
  OS_INT_DecRI();
}

Assuming the interrupt disable counter was zero it will be incremented with OS_INT_IncDI() to one and embOS interrupts will be disabled. OS_INT_Disable() will again disable embOS interrupts. OS_INT_EnableConditional() evaluates the interrupt disable counter and since it is unequal to zero embOS interrupts will not be enabled. OS_INT_DecRI() decrements the interrupt disable counter which sets it to zero. It also evaluates the interrupt disable counter and since it is equal to zero embOS interrupts will be re-enabled.

OS_Global.Counters.Cnt.DI is saved during the context switch in the task context and is restored when the task is activated again. Therefore, the interrupt disable counter is task specific. Disabling embOS interrupts in one task does not disable embOS interrupts for other tasks or the kernel.

OS_INT_Disable() and OS_INT_Enable() can be used when no embOS API functions are called which could enable interrupts before the actual call to OS_INT_Enable() and the interrupt disable counter OS_Global.Counters.Cnt.DI is zero. OS_INT_Disable() / OS_INT_Enable() are slightly more efficient than OS_INT_IncDI() / OS_INT_DecRI(). OS_INT_EnableConditional() should be used when the interrupt disable counter value is unknown.

OS_INT_IncDI() / OS_INT_DecRI() can be used to avoid that embOS interrupts could be enabled unconditionally. This could e.g. the case when you call an embOS API function which internally disables and enables embOS interrupts. embOS API functions always enable embOS interrupts conditionally with OS_INT_EnableConditional().

void foo(void) {
  OS_INT_IncDI();
  OS_TASK_Delay(10);
  DoSomething()      // embOS interrupts are still disabled
  OS_INT_DecRI();
}

Zero latency interrupt disable / enable

The embOS interrupt enable and disable functions enable and disable embOS interrupts only. Zero latency interrupts are never implicitly enabled or disabled by embOS. However, embOS provides additional API functions to enable and disable embOS interrupts and zero latency interrupts.

In an application it may be required to disable and enable all interrupts. These API functions have the suffix All. These functions affect the state of the CPU unconditionally and should be used with care.

It is CPU specific whether zero latency interrupts are supported. If not, API functions with the suffix All (like e.g. OS_INT_DisableAll()) behave exactly the same as the API functions without this suffix.

Non-maskable interrupts (NMIs)

embOS performs atomic operations by disabling interrupts. However, a non-maskable interrupt (NMI) cannot be disabled, meaning it can interrupt these atomic operations. Therefore, NMIs should be used with great care and are prohibited from calling any embOS routines.

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer Idle
OS_INT_DecRI() Decrements the embOS interrupt disable counter and enables interrupts if the counter reaches 0.
OS_INT_Disable() Disables embOS interrupts. Does not change the interrupt disable counter.
OS_INT_DisableAll() Disables all (embOS and zero latency) interrupts.
OS_INT_Enable() Enables embOS interrupts unconditionally.
OS_INT_EnableAll() Enables all (embOS and zero latency) interrupts unconditionally.
OS_INT_EnableConditional() Enables embOS interrupts if the interrupt disable counter equals 0.
OS_INT_IncDI() Increments the embOS interrupt disable counter and disables embOS interrupts.
OS_INT_Preserve() Preserves the embOS interrupt state.
OS_INT_PreserveAll() Preserves the embOS and zero latency interrupt state.
OS_INT_PreserveAndDisable() Preserves the embOS interrupt state and then disables embOS interrupts.
OS_INT_PreserveAndDisableAll() Preserves the embOS and zero latency interrupt state and then disables all (embOS and zero latency) interrupts.
OS_INT_Restore() Restores the embOS interrupt state.
OS_INT_RestoreAll() Restores the embOS and zero latency interrupt state.
OS_INT_DecRI()

Description

OS_INT_DecRI() decrements the embOS interrupt disable counter OS_Global.Counters.Cnt.DI and enables embOS interrupts if the interrupt disable counter reaches zero.

Prototype

void OS_INT_DecRI(void);

Additional information

Short for Decrement and Restore Interrupts. It is important that OS_INT_IncDI() and OS_INT_DecRI() are used as a pair.

OS_INT_IncDI() increments the interrupt disable counter. Interrupts will not be switched on within the running task before the matching OS_INT_DecRI() is executed.

The interrupt disable counter OS_Global.Counters.Cnt.DI is task specific. A task switch may change the value, so if interrupts are disabled in one task they could be enabled in the next task and vice versa.

You can safely call embOS API between OS_INT_IncDI() and OS_INT_DecRI(). embOS API functions will not change the counter value.

Example

volatile long lvar;

void Routine(void) {
  OS_INT_IncDI();
  lvar++;
  OS_INT_DecRI();
}
OS_INT_Disable()

Description

OS_INT_Disable() disables embOS interrupts.

Prototype

void OS_INT_Disable(void);

Additional information

OS_INT_Disable() does not disable zero latency interrupts.

embOS interrupts can be re-enabled by calling OS_INT_Enable().

OS_INT_Disable() does not preserve the interrupt disable state. Please use OS_INT_Preserve() or OS_INT_PreserveAndDisable() instead when the interrupt disable state should be preserved.

OS_INT_Disable() does not increment the interrupt disable counter OS_Global.Counters.Cnt.DI. An embOS API function may re-enable embOS interrupts. Please use OS_INT_IncDI() and OS_INT_DecRI() instead.

void Task(void) {
  OS_INT_Disable();
  OS_TASK_Delay(10);
  DoSomething();  // embOS interrupts may be executed
}

Therefore, it is not recommend to call any embOS API function after OS_INT_Disable() except OS_INT_Enable().

Example

void Routine(void) {
  OS_INT_Disable();  // Disable embOS interrupts
  //
  // Execute any code that should be executed with interrupts disabled.
  // No embOS function should be called.
  //
  DoSomething();
  OS_INT_Enable();   // Re-enable embOS interrupts unconditionally.
}
OS_INT_DisableAll()

Description

OS_INT_DisableAll() disables embOS interrupts and zero latency interrupts.

Prototype

void OS_INT_DisableAll(void);

Additional information

embOS interrupts and zero latency interrupts can be re-enabled by calling OS_INT_EnableAll().

OS_INT_DisableAll() does not preserve the interrupt disable state. Please use OS_INT_PreserveAll() or OS_INT_PreserveAndDisableAll() instead when the interrupt disable state should be preserved.

OS_INT_DisableAll() does not increment the interrupt disable counter.

An embOS API function may re-enable embOS interrupts depending on the CPU. Please refer to the CPU and compiler specific manual for more details.

void Task(void) {
  OS_INT_DisableAll();
  OS_TASK_Delay(10);
  DoSomething();  // embOS interrupts may be executed
}

Therefore, it is not recommend to call any embOS API function after OS_INT_DisableAll() except OS_INT_EnableAll().

Example

void Routine(void) {
  OS_INT_DisableAll();  // Disable interrupts
  //
  // Execute any code that should be executed with interrupts disabled
  // No embOS function should be called.
  //
  DoSomething();
  OS_INT_EnableAll();  // Re-enable interrupts unconditionally
}
OS_INT_Enable()

Description

OS_INT_Enable() enables embOS interrupts.

Prototype

void OS_INT_Enable(void);

Additional information

OS_INT_Enable() does not enable zero latency interrupts.

OS_INT_Enable() does not decrement or check the interrupt disable counter OS_Global.Counters.Cnt.DI but enables interrupts unconditionally. If interrupts should be enabled only when the interrupt disable counter OS_Global.Counters.Cnt.DI is zero please use OS_INT_EnableConditional() instead.

Example

void Routine(void) {
  OS_INT_Disable();   // Disable embOS interrupts
  DoSomething();
  OS_INT_Enable();    // Re-enable embOS interrupts unconditionally
}
OS_INT_EnableAll()

Description

OS_INT_EnableAll() enables embOS interrupts and zero latency interrupts.

Prototype

void OS_INT_EnableAll(void);

Additional information

OS_INT_EnableAll() does not decrement or check the interrupt disable counter OS_Global.Counters.Cnt.DI but enables interrupts unconditionally.

Example

void Routine(void) {
  OS_INT_DisableAll();  // Disable interrupts
  DoSomething();
  OS_INT_EnableAll();   // Re-enable interrupts unconditionally
}
OS_INT_EnableConditional()

Description

OS_INT_EnableConditional() enables embOS interrupts conditionally depending on the interrupt disable counter OS_Global.Counters.Cnt.DI.

Prototype

void OS_INT_EnableConditional(void);

Additional information

OS_INT_EnableConditional() enables embOS interrupts only if the interrupt disable counter OS_Global.Counters.Cnt.DI is zero.

Example

void Routine (void) {
  OS_INT_Disable();
  DoSomething();
  OS_INT_EnableConditional();
}
OS_INT_IncDI()

Description

OS_INT_IncDI() disables embOS interrupts and increments the interrupt disable counter OS_Global.Counters.Cnt.DI.

Prototype

void OS_INT_IncDI(void);

Additional information

Short for Increment and Disable interrupts. OS_INT_IncDI() does not disable zero latency interrupts.

It is important that OS_INT_IncDI() and OS_INT_DecRI() are used as a pair. Interrupts will not be switched on within the running task before the matching OS_INT_DecRI() is executed.

The interrupt disable counter OS_Global.Counters.Cnt.DI is task specific. A task switch may change the value, so if interrupts are disabled they could be enabled in the next task and vice versa.

You can safely call embOS API between OS_INT_IncDI() and OS_INT_DecRI(). The embOS API will not enable interrupts.

Example

void Routine (void) {
  OS_INT_IncDI();
  DoSomething();
  OS_INT_DecRI();
}
OS_INT_Preserve()

Description

OS_INT_Preserve() preserves the current embOS interrupt disable state of the CPU.

Prototype

void OS_INT_Preserve(OS_U32* pState);

Parameters

Parameter Description
pState Pointer to an OS_U32 variable that receives the interrupt state.

Additional information

If the embOS interrupt disable state is not known and embOS interrupts should be disabled by a call of OS_INT_Disable(), the current embOS interrupt disable state can be preserved with OS_INT_Preserve() and restored later by a call of OS_INT_Restore().

OS_INT_Preserve() preserves the embOS interrupt disable state but not the zero latency interrupt state.

The pair of function calls OS_INT_Preserve() and OS_INT_Restore() can be nested, as long as the interrupt disable state is stored into an individual variable on each call of OS_INT_Preserve().

Example

void Sample(void) {
  OS_U32 IntState;

  OS_INT_Preserve(&IntState);  // Remember the interrupt disable state.
  OS_INT_Disable();            // Disable embOS interrupts
  //
  // Execute any code that should be executed with embOS interrupts disabled.
  //
  DoSomething();
  OS_INT_Restore(&IntState);   // Restore the interrupt disable state
}
OS_INT_PreserveAll()

Description

OS_INT_PreserveAll() preserves the current zero latency interrupt disable state of the CPU.

Prototype

void OS_INT_PreserveAll (OS_U32* pState);

Parameters

Parameter Description
pState Pointer to an OS_U32 variable that receives the interrupt state.

Additional information

If the zero latency interrupt disable state is not known and zero latency interrupts should be disabled by a call of OS_INT_DisableAll(), the current zero latency interrupt disable state can be preserved with with OS_INT_PreserveAll() and restored later by a call of OS_INT_RestoreAll().

OS_INT_PreserveAll() preserves the zero latency interrupt disable state but not the embOS interrupt disable state.

The pair of function calls OS_INT_PreserveAll() and OS_INT_RestoreAll() can be nested, as long as the interrupt disable state is stored into an individual variable on each call of OS_INT_Preserve().

Example

void Sample(void) {
  OS_U32 IntState;

  // Remember the interrupt disable state.
  OS_INT_PreserveAll(&IntState);
  OS_INT_DisableAll();  // Disable interrupts
  //
  // Execute any code that should be executed with interrupts disabled
  //
  DoSomething();
  OS_INT_RestoreAll(&IntState);  // Restore the interrupt disable state
}
OS_INT_PreserveAndDisable()

Description

OS_INT_PreserveAndDisable() preserves the current embOS interrupt disable state of the CPU and then disables embOS interrupts.

Prototype

void OS_INT_PreserveAndDisable (OS_U32* pState);

Parameters

Parameter Description
pState Pointer to an OS_U32 variable that receives the interrupt state.

Additional information

If the embOS interrupt disable state is not known and embOS interrupts should be disabled, the current embOS interrupt disable state can be preserved and embOS interrupts disabled with OS_INT_PreserveAndDisable() and restored later by a call of OS_INT_Restore().

OS_INT_PreserveAndDisable() preserves the embOS interrupt disable state but not the zero latency interrupt state.

The pair of function calls OS_INT_PreserveAndDisable() and OS_INT_Restore() can be nested, as long as the interrupt disable state is stored into an individual variable on each call of OS_INT_PreserveAndDisable().

Example

void Sample(void) {
  OS_U32 IntState;

  // Remember the interrupt disable state and disables interrupts.
  OS_INT_PreserveAndDisable(&IntState);
  //
  // Execute any code that should be executed with interrupts disabled
  //
  DoSomething();
  OS_INT_Restore(&IntState);  // Restore the interrupt disable state
}
OS_INT_PreserveAndDisableAll()

Description

OS_INT_PreserveAndDisableAll() preserves the current zero latency interrupt disable state of the CPU and disables embOS interrupts and zero latency interrupts.

Prototype

void OS_INT_PreserveAndDisableAll (OS_U32* pState);

Parameters

Parameter Description
pState Pointer to an OS_U32 variable that receives the interrupt state.

Additional information

If the zero latency interrupt disable state is not known and interrupts should be disabled by a call of OS_INT_DisableAll(), the current interrupt disable state can be preserved and interrupts disabled with with OS_INT_PreserveAll() and restored later by a call of OS_INT_RestoreAll().

OS_INT_PreserveAndDisableAll() preserves the zero latency interrupt disable state but not the embOS interrupt disable state.

An embOS API function may re-enable embOS interrupts depending on the CPU. Please refer to the CPU and compiler specific manual for more details.

The pair of function calls OS_INT_PreserveAndDisableAll() and OS_INT_RestoreAll() can be nested, as long as the interrupt disable state is stored into an individual variable on each call of OS_INT_PreserveAndDisableAll().

Example

void Sample(void) {
  OS_U32 IntState;

  // Remember the interrupt disable state and disables interrupts.
  OS_INT_PreserveAndDisableAll(&IntState);
  //
  // Execute any code that should be executed with interrupts disabled
  //
  DoSomething();
  OS_INT_RestoreAll(&IntState);  // Restore the interrupt disable state
}
OS_INT_Restore()

Description

OS_INT_Restore() restores the embOS interrupt disable state.

Prototype

void OS_INT_Restore (OS_U32* pState);

Parameters

Parameter Description
pState Pointer to an OS_U32 variable that holds the interrupt disable state.

Additional information

OS_INT_Restore() restores the embOS interrupt disable state of the CPU which was saved before by a call of OS_INT_Preserve() or OS_INT_PreserveAndDisable().

Example

void Sample(void) {
  OS_U32 IntState;

  OS_INT_Preserve(&IntState);  // Remember the interrupt disable state.
  OS_INT_Disable();            // Disable embOS interrupts
  //
  // Execute any code that should be executed with embOS interrupts disabled
  //
  DoSomething();
  OS_INT_Restore(&IntState);   // Restore the interrupt disable state
}
OS_INT_RestoreAll()

Description

OS_INT_RestoreAll() restores the zero latency interrupt disable state.

Prototype

void OS_INT_RestoreAll (OS_U32* pState);

Parameters

Parameter Description
pState Pointer to an OS_U32 variable that holds the interrupt disable state.

Additional information

OS_INT_RestoreAll() restores the zero latency interrupt disable state of the CPU which was saved before by a call of OS_INT_PreserveAll() or OS_INT_PreserveAndDisableAll().

Example

void Sample(void) {
  OS_U32 IntState;

  // Remember the interrupt disable state.
  OS_INT_PreserveAll(&IntState);
  OS_INT_DisableAll();  // Disable interrupts
  //
  // Execute any code that should be executed with interrupts disabled
  // No embOS function should be called
  //
  DoSomething();
  OS_INT_RestoreAll(&IntState);  // Restore the interrupt disable state
}

Critical Region

Introduction

Critical regions are program sections which should not be interrupted by another task. A critical region can be used anywhere during execution of a task. Depending on the application, it can be necessary for some critical program sections to disable preemptive task switches and execution of software timers or even interrupts.

It depends on the application whether disabling task switches is sufficient or interrupts need to be disabled as well. Disabling interrupts can mean to disable embOS interrupts or even to also disable zero latency interrupts. Cooperative task switches are never affected and will be executed in critical regions. Interrupts, too, may still occur in critical regions.

They may also be used in software timers and interrupts. However, since those are executed as critical regions anyways, critical regions do not have any effect on them.

Critical regions can be nested; they will then be effective until the outermost region is left. If a task switch becomes pending during the execution of a critical region, it will be performed immediately once the region is left.

A typical example for critical regions is the execution of time-critical hardware accesses (for example, writing multiple bytes into an EEPROM where the bytes must be written in a certain amount of time), or writing to global variables that are accessed by different tasks and therefore must ensure that data is consistent.

Example

void HPTask(void) {
  OS_TASK_EnterRegion();
  DoSomething();  // This code will not be interrupted by other tasks
  OS_TASK_LeaveRegion();
}

Note

Cooperative task switches are still executed, although preemptive task switches are disabled in critical sections.

void HPTask(void) {
  OS_TASK_EnterRegion();
  OS_TASK_Delay_ms(100);  // OS_TASK_Delay_ms() will cause a cooperative task switch
  OS_TASK_LeaveRegion();
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer Idle
OS_TASK_EnterRegion() Indicates the beginning of a critical region to embOS.
OS_TASK_LeaveRegion() Indicates to embOS the end of a critical region.

OS_TASK_EnterRegion()

Description

Indicates the beginning of a critical region to embOS.

Prototype

void OS_TASK_EnterRegion(void);

Additional information

The critical region counter (OS_Global.Counters.Cnt.Region) is zero by default. It gets incremented upon calling OS_TASK_EnterRegion() and decremented upon calling OS_TASK_LeaveRegion(). Critical regions can be nested: the critical region ends when this counter reaches zero again. The counter is specific for all tasks, its value is saved and restored on any task switch.

Interrupts are not disabled in a critical region. However, preemptive task switches are. If any interrupt triggers a task switch, the task switch stays pending until the final call of OS_TASK_LeaveRegion(). When the counter reaches zero, a pending task switch is executed.

Cooperative task switches are not affected and will be executed in critical regions. When a task is running in a critical region and calls any blocking embOS function, the task will be suspended. When the task is resumed, the critical region counter is restored, the task continues to run in a critical region until OS_TASK_LeaveRegion() is called.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

157: OS_ERR_REGIONCNT

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example in the introduction of chapter Critical Region.

OS_TASK_LeaveRegion()

Description

Indicates to embOS the end of a critical region. Decrements the critical region counter and checks if a task switch is pending if the counter reaches 0.

Prototype

void OS_TASK_LeaveRegion(void);

Additional information

A critical region counter (OS_Global.Counters.Cnt.Region), which is zero by default, is decremented. If this counter reaches zero, the critical region ends. A task switch which became pending during a critical region will be executed in OS_TASK_EnterRegion() when the counter reaches zero.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

151: OS_ERR_LEAVEREGION_BEFORE_ENTERREGION
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example in the introduction of chapter Critical Region.

Disabling context transitions

The following table shows which context transitions may occur after calling appropriate embOS API:

Cooperative task switch Preemptive task switch Software Timer embOS interrupt Zero latency interrupt
Regular execution
In critical region
With embOS interrupts disabled
With all interrupts disabled

Example

In the following example DoSomething() in the LPTask cannot be interrupt by the HPTask or the software timer SoftwareTimer. But it can be interrupted by the interrupt routines embOS_ISR and Zero_Latency_ISR.

void Zero_Latency_ISR(void) {
  DoSomething();
}

void embOS_ISR(void) {
  OS_INT_Enter();
  DoSomething();
  OS_INT_Leave();
}

void SoftwareTimer(void) {
  DoSomething();
  OS_TIMER_Restart(&Timer);
}

void HPTask(void) {
  while (1) {
    DoSomething();
    OS_TASK_Delay_ms(10);
  }
}

void LPTask(void) {
  while (1) {
    OS_TASK_EnterRegion();
    DoSomething();
    OS_TASK_LeaveRegion();
  }
}

In this example DoSomething() in the LPTask cannot be interrupt by the HPTask, the software timer SoftwareTimer or the embOS interrupt routine embOS_ISR. But it can be interrupted by the zero latency interrupt routine Zero_Latency_ISR.

void Zero_Latency_ISR(void) {
  DoSomething();
}

void embOS_ISR(void) {
  OS_INT_Enter();
  DoSomething();
  OS_INT_Leave();
}

void SoftwareTimer(void) {
  DoSomething();
  OS_TIMER_Restart(&Timer);
}

void HPTask(void) {
  while (1) {
    DoSomething();
    OS_TASK_Delay_ms(10);
  }
}

void LPTask(void) {
  while (1) {
    OS_INT_Disable();
    DoSomething();
    OS_INT_Enable();
  }
}

In this last example, DoSomething() in the LPTask cannot be interrupt by any other function.

void Zero_Latency_ISR(void) {
  DoSomething();
}

void embOS_ISR(void) {
  OS_INT_Enter();
  DoSomething();
  OS_INT_Leave();
}

void SoftwareTimer(void) {
  DoSomething();
  OS_TIMER_Restart(&Timer);
}

void HPTask(void) {
  while (1) {
    DoSomething();
    OS_TASK_Delay_ms(10);
  }
}

void LPTask(void) {
  while (1) {
    OS_INT_DisableAll();
    DoSomething();
    OS_INT_EnableAll();
  }
}

Time Measurement

Introduction

embOS-Ultra counts time in cycles and thus implicitly provides cycle-precise measurement functions. These functions can be used e.g. for calculating the execution time of any section of user code. The length of a timer cycle depends on the hardware counter clock frequency. For convenience, embOS-Ultra provides functions to convert back and forth between cycles and microseconds, milliseconds, or nanoseconds.

Note

The embOS time conversion functions use finite-precision arithmetic. Depending on the frequency of the used hardware counter, this may incur truncation errors (e.g. a maximum of one cycle when converting to cycles, a maximum of one microsecond when converting to microseconds, etc.).

Example

The following sample demonstrates the measurement to return the execution time of a section of code:

#include "RTOS.h"
#include <stdio.h>

static OS_STACKPTR int Stack[1000];  // Task stacks
static OS_TASK         TCB;          // Task-control-blocks
static volatile int    Dummy;

static void UserCode(void) {
  for (Dummy=0; Dummy < 11000; Dummy++);  // Burn some time
}

static void Task(void) {
  OS_U64 t0;
  OS_U64 t1;
  OS_U64 Cycles;
  OS_U64 Overhead;

  while (1) {
    //
    // Measure overhead
    //
    t0 = OS_TIME_Get_Cycles();
    t1 = OS_TIME_Get_Cycles();
    Overhead = t1 - t0;
    //
    // Measure user code
    //
    t0 = OS_TIME_Get_Cycles();
    UserCode();           // Execute the user code to be benchmarked
    t1 = OS_TIME_Get_Cycles();
    Cycles = (t1 - t0) - Overhead;
    //
    // Print results
    //
    printf("\n===== Measurement =====\n");
    printf("Timer Freq: %lu hertz\n", OS_INFO_GetTimerFreq());
    printf("%llu cycles\n", Cycles);
    printf("%llu nanoseconds\n", OS_TIME_ConvertCycles2ns(Cycles));
    printf("%llu microseconds\n", OS_TIME_ConvertCycles2us(Cycles));
    printf("%llu millisecones\n", OS_TIME_ConvertCycles2ms(Cycles));
  }
}

int main(void) {
  OS_Init();                   // Initialize embOS
  OS_InitHW();                 // Initialize hardware for embOS
  OS_TASK_CREATE(&TCB, "Task", 100, Task, Stack);
  OS_Start();                  // Start multitasking
  return 0;
}

The output of the sample is as follows:

 ...
===== Measurement =====
Timer Freq: 168000000 Hz
   121013 cycles
   720315 nanoseconds
      720 microseconds
        0 milliseconds
 ...

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_TIME_ConfigSysTimer() Configures the system time parameters for according timing functions, embOSView and profiling.
OS_TIME_ConvertCycles2ms() Converts counter cycles into milliseconds.
OS_TIME_ConvertCycles2ns() Converts counter cycles into nanoseconds.
OS_TIME_ConvertCycles2us() Converts counter cycles into microseconds.
OS_TIME_Convertms2Cycles() Converts milliseconds into counter cycles.
OS_TIME_Convertns2Cycles() Converts nanoseconds into counter cycles.
OS_TIME_Convertus2Cycles() Converts microseconds into counter cycles.
OS_TIME_Get_ms() Returns the current system time in milliseconds.
OS_TIME_Get_ns() Returns the current system time in nanoseconds.
OS_TIME_Get_us() Returns the current system time in microseconds.
OS_TIME_Get_Cycles() Returns the current system time in counter cycles.

OS_TIME_ConfigSysTimer()

Description

Configures the system time parameters for according timing functions, embOSView and profiling.

Prototype

void OS_TIME_ConfigSysTimer(OS_CONST_PTR OS_SYSTIMER_CONFIG *pConfig);

Parameters

Parameter Description
pConfig Pointer to a data structure of type OS_SYSTIMER_CONFIG.

Additional information

This function is usually called once from OS_InitHW() (implemented in RTOSInit.c). It must be called before calling OS_Start(), and before any time-related API function is called from main().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
167: OS_ERR_CPU_STATE_ILLEGAL
228: OS_ERR_ILLEGAL_AFTER_OSSTART

For details, refer to the chapter Runtime application errors.

The OS_SYSTIMER_CONFIG struct

OS_TIME_ConfigSysTimer() uses the struct OS_SYSTIMER_CONFIG:

Member Description
TimerFreq Counter frequency in Hz

Example

Please refer to the example in the chapter OS_InitHW().

OS_TIME_ConvertCycles2ms()

Description

Converts counter cycles into milliseconds.

Prototype

OS_U64 OS_TIME_ConvertCycles2ms(OS_U32 Cycles);

Parameters

Parameter Description
Cycles Counter cycles.

Return value

The converted value in milliseconds.

Additional information

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIME_ConvertCycles2ms().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Convert(void) {
  OS_U64 ms;

  ms = OS_TIME_ConvertCycles2ms(2000);
}

OS_TIME_ConvertCycles2ns()

Description

Converts counter cycles into nanoseconds.

Prototype

OS_U64 OS_TIME_ConvertCycles2ns(OS_U32 Cycles);

Parameters

Parameter Description
Cycles Counter cycles.

Return value

The converted value in nanoseconds.

Additional information

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIME_ConvertCycles2ns().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Convert(void) {
  OS_U64 ns;

  ns = OS_TIME_ConvertCycles2ns(2000);
}

OS_TIME_ConvertCycles2us()

Description

Converts counter cycles into microseconds.

Prototype

OS_U64 OS_TIME_ConvertCycles2us(OS_U32 Cycles);

Parameters

Parameter Description
Cycles Counter cycles.

Return value

The converted value in microseconds.

Additional information

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIME_ConvertCycles2us().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Convert(void) {
  OS_U64 us;

  us = OS_TIME_ConvertCycles2us(2000);
}

OS_TIME_Convertms2Cycles()

Description

Converts milliseconds into counter cycles.

Prototype

OS_U64 OS_TIME_Convertms2Cycles(OS_U32 ms);

Parameters

Parameter Description
ms Milliseconds.

Return value

The converted value in counter cycles.

Additional information

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIME_Convertms2Cycles().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Convert(void) {
  OS_U64 Cycles;

  Cycles = OS_TIME_Convertms2Cycles(100);
}

OS_TIME_Convertns2Cycles()

Description

Converts nanoseconds into counter cycles.

Prototype

OS_U64 OS_TIME_Convertns2Cycles(OS_U32 ns);

Parameters

Parameter Description
ns Nanoseconds.

Return value

The converted value in counter cycles.

Additional information

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIME_Convertns2Cycles().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Convert(void) {
  OS_U64 Cycles;

  Cycles = OS_TIME_Convertns2Cycles(100);
}

OS_TIME_Convertus2Cycles()

Description

Converts microseconds into counter cycles.

Prototype

OS_U64 OS_TIME_Convertus2Cycles(OS_U32 us);

Parameters

Parameter Description
us Microseconds.

Return value

The converted value in counter cycles.

Additional information

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIME_Convertus2Cycles().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Convert(void) {
  OS_U64 Cycles;

  Cycles = OS_TIME_Convertus2Cycles(100);
}

OS_TIME_Get_ms()

Description

Returns the current system time in milliseconds.

Prototype

OS_U64 OS_TIME_Get_ms(void);

Return value

The current system time in milliseconds.

Additional information

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIME_Get_ms().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Benchmark(void) {
  OS_U64 ms0, ms;

  ms0 = OS_TIME_Get_ms();
  DoSomeThing();
  ms = OS_TIME_Get_ms() - ms0;
}

OS_TIME_Get_ns()

Description

Returns the current system time in nanoseconds.

Prototype

OS_U64 OS_TIME_Get_ns(void);

Return value

The current system time in nanoseconds.

Additional information

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIME_Get_ns().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Benchmark(void) {
  OS_U64 ns0, ns;

  ns0 = OS_TIME_Get_ns();
  DoSomeThing();
  ns = OS_TIME_Get_ns() - ns0;
}

OS_TIME_Get_us()

Description

Returns the current system time in microseconds.

Prototype

OS_U64 OS_TIME_Get_us(void);

Return value

The current system time in microseconds.

Additional information

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIME_Get_us().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Benchmark(void) {
  OS_U64 us0, us;

  us0 = OS_TIME_Get_us();
  DoSomeThing();
  us = OS_TIME_Get_us() - us0;
}

OS_TIME_Get_Cycles()

Description

Returns the current system time in counter cycles.

Prototype

OS_U64 OS_TIME_Get_Cycles(void);

Return value

The current system time in counter cycles.

Additional information

OS_TIME_ConfigSysTimer() must have been called before calling OS_TIME_Get_Cycles().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

void Benchmark(void) {
  OS_U64 Cycles0, Cycles;

  Cycles0 = OS_TIME_Get_Cycles();
  DoSomeThing();
  Cycles = OS_TIME_Get_Cycles() - Cycles0;
}

Low Power Support

Introduction

embOS-Ultra provides several means to control the power consumption of your target hardware. These include:

Note

Since embOS-Ultra does not have a periodic system tick, the tickless support implemented with embOS-Classic is not included with embOS-Ultra

.

Starting power save modes in OS_Idle()

In case your controller supports some kind of power save mode, it is possible to use it with embOS. To enter that mode, you would usually implement the respective functionality in the function OS_Idle(), which is located inside the embOS source file RTOSInit.c.

OS_Idle() is executed whenever no task is ready for execution.

After entering OS_Idle(), the application is resumed only when an interrupt occurs. When that happens, it may be necessary to revert the initialized low power mode. To do so, embOS allows to register a callback routine that gets executed upon ISR entry. The callback function is then deleted as soon as it was executed (to avoid its execution when the application did not enter any low mode). It therefore must be registered in OS_Idle() by calling OS_POWER_SetISREntryCallback().

Note

The callback routine is executed with embOS interrupts only. It is not executed with zero-latency interrupts. Furthermore, interrupts might occur after the callback was set but before low power mode was entered, in which case the callback would need to be re-registered. If the architecture allows for this, we suggest disabling interrupts before entering low-power mode.

static void _Callback(void) {
  ...                      // Revert low power mode
}

void OS_Idle(void) {       // Idle loop: No task is ready to execute
  while (1) {
    OS_POWER_SetISREntryCallback(_Callback);
    _EnterLowPowerMode();  // Configure and enter device specific low power mode
  }
}

Note

Both the used hardware timer and the used hardware counter may be powered down during low-power modes. While the hardware timer could simply be swapped for a different timer upon entering OS_Idle() (and swapped back in by using the aforementioned callback), replacing the hardware counter with a different one will impact long-term stability and thus is strongly discouraged. Instead, when power-save modes should be utilized by the application, a counter that is never powered down shall be used both during regular exection and during power-saves modes.

For further information on OS_Idle(), refer to OS_Idle().

Peripheral power control

Introduction

The embOS peripheral power control is used to determine if a peripheral’s clock or its power supply can be switched off to save power.

It includes three functions: OS_POWER_GetMask(), OS_POWER_UsageInc() and OS_POWER_UsageDec(). These functions can be used to add peripheral power control to any embOS start project.

If a peripheral gets initialized a call to OS_POWER_UsageInc() increments a specific entry in the power management counter to signal that it is in use. When a peripheral is no longer in use, a call to OS_POWER_UsageDec() decrements this counter. Within OS_Idle() a call of OS_POWER_GetMask() generates a bit mask which describes which clock or power supply is in use, and which is not and may therefore be switched off.

This is an example for the peripheral power control. As it depends on the used hardware, its implementation is fictional: A, B and C are used to represent arbitrary peripherals.

#define OS_POWER_USE_A   (1 << 0)  // peripheral "A"
#define OS_POWER_USE_B   (1 << 1)  // peripheral "B"
#define OS_POWER_USE_C   (1 << 2)  // peripheral "C"
#define OS_POWER_USE_ALL (OS_POWER_USE_A | OS_POWER_USE_B | OS_POWER_USE_C)

In the following function the peripherals A and C have been initialized and were marked in-use by a call to OS_POWER_UsageInc():

void _InitAC(void) {
  ...
  OS_POWER_UsageInc(OS_POWER_USE_A); // Mark "A" as used
  OS_POWER_UsageInc(OS_POWER_USE_C); // Mark "C" as used
  ...
}

After some time, C will not be used any more and can therefore be marked as unused by a call to OS_POWER_UsageDec():

void _WorkDone(void) {
  ...
  OS_POWER_UsageDec(OS_POWER_USE_C); // Mark "C" as unused
  ...
}

While in OS_Idle(), a call to OS_POWER_GetMask() retrieves a bit mask from the power management counter. That bit mask subsequently is used to modify the corresponding bits of a control register, leaving only those bits set that represent a peripheral which is in-use.

void OS_Idle(void) {  // Idle loop: No task is ready to execute
  OS_UINT PowerMask;
  OS_U16  ClkControl;
  //
  // Initially disable interrupts
  //
  OS_INT_IncDI();
  //
  // Examine which peripherals may be switched off
  //
  PowerMask  = OS_POWER_GetMask();
  //
  //  Store the content of CTRLREG and clear all OS_POWER_USE related bits
  //
  ClkControl = CTRLREG & ~OS_POWER_USE_ALL;
  //
  //  Set only bits for used peripherals and write them to the specific register
  //  In this case only "A" is marked as used, so "C" gets switched off
  //
  CTRLREG    = ClkControl | PowerMask;
  //
  // Re-enable interrupts
  //
  OS_INT_DecRI();
  for (;;) {
    _do_nothing();
  };
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer Idle
OS_POWER_GetMask() Retrieves the power management counter.
OS_POWER_SetISREntryCallback() Sets a callback function to be executed on ISR entry.
OS_POWER_UsageDec() Decrements the power management counter(s).
OS_POWER_UsageInc() Increments the power management counter(s).
OS_POWER_GetMask()

Description

Retrieves the power management counter.

Prototype

OS_UINT OS_POWER_GetMask(void);

Return value

A bit mask which describes whether a peripheral is in use or not.

Additional information

This function generates a bit mask from the power management counter it retrieves. The bit mask describes which peripheral is in use and which one can be turned off. Switching off a peripheral can be done by writing this mask into the specific register. Please refer to the Example for additional information.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example in the introduction of chapter Peripheral power control.

OS_POWER_SetISREntryCallback()

Description

Sets a callback function to be executed on ISR entry.

Prototype

void OS_POWER_SetISREntryCallback(OS_ROUTINE_VOID* pfRoutine);

Parameters

Parameter Description
pfRoutine Pointer to an OS_ROUTINE_VOID function.

Additional information

The intended purpose for this callback is powering up the device after idle times / low power modes. For example, the device could be powered down in OS_Idle() after registering this callback. Subsequently, when an interrupt wakes the device from low power mode, this callback can perform clock initializations, etc. After execution the callback is deleted automatically to not interfere with regular application execution. It therefore needs to be registered in OS_Idle() again before entering low power mode again.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

167: OS_ERR_CPU_STATE_ILLEGAL
255: OS_ERR_INV_PARAMETER_VALUE

For details, refer to the chapter Runtime application errors.

Example

For an example, refer to Starting power save modes in OS_Idle();

OS_POWER_UsageDec()

Description

Decrements the power management counter(s).

Prototype

void OS_POWER_UsageDec(OS_UINT Index);

Parameters

Parameter Description
Index Contains a mask with bits set for those counters which should be updated. (Bit 0 => Counter 0) The debug version checks for underflow, overflow and undefined counter number.

Additional information

When a peripheral is no longer in use this function is called to mark the peripheral as unused and signal that it can be switched off.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

123: OS_ERR_POWER_UNDER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example in the introduction of chapter Peripheral power control.

OS_POWER_UsageInc()

Description

Increments the power management counter(s).

Prototype

void OS_POWER_UsageInc(OS_UINT Index);

Parameters

Parameter Description
Index Contains a mask with bits set for those counters which should be updated. (Bit 0 => Counter 0) The debug version checks for underflow, overflow and undefined counter number.

Additional information

When a peripheral is in use this function is called to mark the peripheral as in use.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

122: OS_ERR_POWER_OVER
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example in the introduction of chapter Peripheral power control.

Heap Type Memory Management

Introduction

ANSI C offers some basic dynamic memory management functions. These are e.g. malloc(), free(), and realloc(). Unfortunately, these routines are not thread-safe, unless a special thread-safe implementation exists in the compiler runtime libraries; they can only be used from one task or by multiple tasks if they are called sequentially. Therefore, embOS offer thread safe variants of these routines. These variants have the same names as their ANSI counterparts, but are prefixed OS_HEAP_; they are called OS_HEAP_malloc(), OS_HEAP_free(), OS_HEAP_realloc(). The thread-safe variants that embOS offers use the standard ANSI routines, but they guarantee that the calls are serialized using a mutex.

If heap memory management is not supported by the standard C libraries, embOS heap memory management is not implemented.

This API is not available in embOS library mode OS_LIBMODE_SAFE.

Note

Many modern toolchain standard libraries can be made thread-safe with hook functions which are implemented by embOS. With it functions like malloc(), free() and realloc() are thread-safe and is not necessary to use OS_HEAP_malloc(), OS_HEAP_free() and OS_HEAP_realloc(). Please have a look in the core/compiler specific embOS manual for more details.

Example

void HPTask(void) {
  OS_U32* p;

  while (1) {
    p = (OS_U32*)OS_HEAP_malloc(4);
    *p = 42;
    OS_HEAP_free(p);
  }
}

void LPTask(void) {
  OS_U16* p;

  while (1) {
    p = (OS_U16*)OS_HEAP_malloc(2);
    *p = 0;
    OS_HEAP_free(p);
  }
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_HEAP_free() Frees a block of memory previously allocated.
OS_HEAP_malloc() Allocates a block of memory on the heap.
OS_HEAP_realloc() Changes the allocation size.

OS_HEAP_free()

Description

Frees a block of memory previously allocated. This is the thread safe free() variant.

Prototype

void OS_HEAP_free(void* pMemBlock);

Parameters

Parameter Description
pMemBlock Pointer to a memory block previously allocated with OS_HEAP_malloc().

Additional information

OS_HEAP_free() calls free() from the standard library. An embOS mutex is used internally to make OS_HEAP_free() thread safe.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void UseHeapMem(void) {
  char* sText;

  sText = (char*)OS_HEAP_malloc(20);
  strcpy(sText, "Hello World");
  printf(sText);
  OS_HEAP_free(sText);
}

OS_HEAP_malloc()

Description

Allocates a block of memory on the heap. This is the thread safe malloc() variant.

Prototype

void *OS_HEAP_malloc(unsigned int Size);

Parameters

Parameter Description
Size Size of the requested memory block in bytes.

Return value

Upon successful completion with size not equal zero, OS_HEAP_malloc() returns a pointer to the allocated space. Otherwise, it returns a NULL pointer.

Additional information

OS_HEAP_malloc() calls malloc() from the standard library. An embOS mutex is used internally to make OS_HEAP_malloc() thread safe.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void UseHeapMem(void) {
  char* sText;

  sText = (char*)OS_HEAP_malloc(20);
  strcpy(sText, "Hello World");
  printf(sText);
  OS_HEAP_free(sText);
}

OS_HEAP_realloc()

Description

Changes the allocation size. This is the thread safe realloc() variant.

Prototype

void *OS_HEAP_realloc(void*        pMemBlock,
                      unsigned int Size);

Parameters

Parameter Description
pMemBlock Pointer to a memory block previously allocated with OS_HEAP_malloc().
Size New size for the memory block in bytes.

Return value

Upon successful completion, OS_HEAP_realloc() returns a pointer to the reallocated memory block. Otherwise, it returns a NULL pointer.

Additional information

OS_HEAP_realloc() calls realloc() from the standard library. An embOS mutex is used internally to make OS_HEAP_realloc() thread safe.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void UseHeapMem(void) {
  char* sText;

  sText = (char*)OS_HEAP_malloc(10);
  strcpy(sText, "Hello");
  printf(sText);
  sText = (char*)OS_HEAP_realloc(sText, 20);
  strcpy(sText, "Hello World");
  printf(sText);
  OS_HEAP_free(sText);
}

Fixed Block Size Memory Pool

Introduction

Fixed block size memory pools contain a specific number of fixed-size blocks of memory. The location in memory of the pool, the size of each block, and the number of blocks are set at runtime by the application via a call to the OS_MEMPOOL_Create() function. The advantage of fixed memory pools is that a block of memory can be allocated from within any task in a very short, determined period of time.

Example

#include "RTOS.h"
#include <string.h>
#include <stdio.h>

#define BLOCK_SIZE          (16)
#define NUM_BLOCKS          (16)
#define POOL_SIZE           (NUM_BLOCKS * BLOCK_SIZE)

static OS_STACKPTR int StackHP[128], StackLP[128];  // Task stacks
static OS_TASK         TCBHP, TCBLP;                // Task-control-blocks
static OS_MEMPOOL      MEMF;
static OS_U8           aPool[POOL_SIZE];

static void HPTask(void) {
  char* a;

  while (1) {
    //
    // Request one memory block
    //
    a = OS_MEMPOOL_AllocBlocked(&MEMF);
    //
    // Work with memory block
    //
    strcpy(a, "Hello World\n");
    printf(a);
    OS_MEMPOOL_FreeEx(&MEMF, a);  // Release memory block
    OS_TASK_Delay (10);
  }
}

static void LPTask(void) {
  char* b;

  while (1) {
    //
    // Request one memory block when available in max. next 10 milliseconds
    //
    b = OS_MEMPOOL_AllocTimed(&MEMF, 10);
    if (b != 0) {
      //
      // Work with memory block
      //
      b[0] = 0x12;
      b[1] = 0x34;
      //
      // Release memory block
      //
      OS_MEMPOOL_FreeEx(&MEMF, b);
    }
    OS_TASK_Delay (50);
  }
}

int main(void) {
  OS_Init();                       // Initialize embOS
  OS_InitHW();                     // Initialize hardware for embOS
  OS_TASK_CREATE(&TCBHP, "HP Task", 100, HPTask, StackHP);
  OS_TASK_CREATE(&TCBLP, "LP Task",  50, LPTask, StackLP);
  //
  // Create [NUM_BLOCKS] blocks with a size of [BLOCK_SIZE] each
  //
  OS_MEMPOOL_Create(&MEMF, aPool, NUM_BLOCKS, BLOCK_SIZE);
  OS_Start();                      // Start multitasking
  return 0;
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_MEMPOOL_Alloc() Allocates a memory block from the specified memory pool.
OS_MEMPOOL_AllocBlocked() Allocates a memory block from the specified memory pool.
OS_MEMPOOL_AllocTimed() Allocates a memory block from the specified memory pool.
OS_MEMPOOL_Create() Creates and initializes a fixed block size memory pool.
OS_MEMPOOL_Delete() Deletes the specified memory pool.
OS_MEMPOOL_Free() Releases the specified memory block.
OS_MEMPOOL_FreeEx() Releases the specified memory block.
OS_MEMPOOL_GetBlockSize() Returns the size of a single memory block in the specified memory pool.
OS_MEMPOOL_GetMaxUsed() Returns the maximum number of memory blocks in the specified pool that have been used simultaneously since creation of the pool.
OS_MEMPOOL_GetNumBlocks() Returns the total number of memory blocks in the specified memory pool.
OS_MEMPOOL_GetNumFreeBlocks() Returns the number of free memory blocks in the specified memory pool.
OS_MEMPOOL_IsInPool() Returns whether the specified memory block belongs to the specified memory pool.

OS_MEMPOOL_Alloc()

Description

Allocates a memory block from the specified memory pool.

Prototype

void *OS_MEMPOOL_Alloc(OS_MEMPOOL* pMEMF);

Parameters

Parameter Description
pMEMF Pointer to a memory pool object of type OS_MEMPOOL.

Return value

NULL Pointer to the allocated block.
= NULL If no block has been allocated.

Additional information

The calling task is never suspended by calling OS_MEMPOOL_Alloc(). The returned pointer must be passed as a parameter to OS_MEMPOOL_Free() or OS_MEMPOOL_FreeEx()to free the memory block. The pointer must not be modified.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
190: OS_ERR_MEMF_INV

For details, refer to the chapter Runtime application errors.

Example

static OS_MEMPOOL _MemPool;

void Task(void) {
  void* pData;

  pData = OS_MEMPOOL_Alloc(&_MemPool);
  if (pData != NULL) {
    // Success: Work with the allocated memory.
  } else {
    // Failed: Do something else.
  }
}

OS_MEMPOOL_AllocBlocked()

Description

Allocates a memory block from the specified memory pool.

Prototype

void *OS_MEMPOOL_AllocBlocked(OS_MEMPOOL* pMEMF);

Parameters

Parameter Description
pMEMF Pointer to a memory pool object of type OS_MEMPOOL.

Return value

Pointer to the allocated memory block.

Additional information

If there is no free memory block in the pool, the calling task is suspended until a memory block becomes available. The returned pointer must be passed as a parameter to OS_MEMPOOL_Free() or OS_MEMPOOL_FreeEx()to free the memory block. The pointer must not be modified.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
190: OS_ERR_MEMF_INV
226: OS_ERR_ILLEGAL_IN_MAIN

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example in the introduction of chapter Fixed Block Size Memory Pool.

OS_MEMPOOL_AllocTimed()

Description

Allocates a memory block from the specified memory pool.

Prototype

void *OS_MEMPOOL_AllocTimed(OS_MEMPOOL* pMEMF,
                            OS_U32      Timeout);

Parameters

Parameter Description
pMEMF Pointer to a memory pool object of type OS_MEMPOOL.
Timeout Maximum time in milliseconds until the memory block must be available.

Return value

= NULL No memory block could be allocated within the specified time.
NULL Pointer to the allocated memory block.

Additional information

If there is no free memory block in the pool, the calling task is suspended until a memory block becomes available or the timeout has expired. The returned pointer must be passed as a parameter to OS_MEMPOOL_Free() or OS_MEMPOOL_FreeEx()to free the memory block. The pointer must not be modified. When the calling task is blocked by higher priority tasks for a period longer than the timeout value, it may happen that the memory block becomes available after the timeout expired, but before the calling task is resumed. Anyhow, the function returns with timeout, because the memory block was not available within the requested time.

OS_TIME_ConfigSysTimer() must have been called before calling OS_MEMPOOL_AllocTimed().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
190: OS_ERR_MEMF_INV
226: OS_ERR_ILLEGAL_IN_MAIN
239: OS_ERR_COUNTER_FREQ_ZERO

For details, refer to the chapter Runtime application errors.

Example

static OS_MEMPOOL _MemPool;

void Task(void) {
  void* pData;

  pData = OS_MEMPOOL_AllocTimed(&_MemPool, 20);
  if (pData != NULL) {
    // Success: Work with the allocated memory.
  } else {
    // Failed: Do something else.
  }
}

OS_MEMPOOL_Create()

Description

Creates and initializes a fixed block size memory pool.

Prototype

void OS_MEMPOOL_Create(OS_MEMPOOL* pMEMF,
                       void*       pPool,
                       OS_UINT     NumBlocks,
                       OS_UINT     BlockSize);

Parameters

Parameter Description
pMEMF Pointer to a memory pool object of type OS_MEMPOOL.
pPool Pointer to memory to be used for the memory pool. Required size is: NumBlocks * BlockSize.
NumBlocks Number of blocks in the pool.
1 ≤ NumBlocks ≤ 215 - 1 = 0x7FFF for 8/16-bit CPUs
1 ≤ NumBlocks ≤ 231 - 1 = 0x7FFFFFFF for 32-bit CPUs
BlockSize Size in bytes of one block.
1 ≤ BlockSize ≤ 215 - 1 = 0x7FFF for 8/16-bit CPUs
1 ≤ BlockSize ≤ 231 - 1 = 0x7FFFFFFF for 32-bit CPUs

Additional information

The buffer must be big enough to hold the given number of memory blocks of the specified block size: NumBlocks * BlockSize bytes.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
165: OS_ERR_INIT_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
190: OS_ERR_MEMF_INV
194: OS_ERR_MEMF_POOLADDR
195: OS_ERR_MEMF_BLOCKSIZE

For details, refer to the chapter Runtime application errors.

Example

#define NUM_BLOCKS (16)
#define BLOCK_SIZE (16)
#define POOL_SIZE  (NUM_BLOCKS * BLOCK_SIZE)

static OS_U8      _aPool[POOL_SIZE];
static OS_MEMPOOL _MyMEMF;

void Init(void) {
  // Create 16 Blocks with size of 16 bytes
  OS_MEMPOOL_Create(&_MyMEMF, _aPool, NUM_BLOCKS, BLOCK_SIZE);
}

OS_MEMPOOL_Delete()

Description

Deletes the specified memory pool.

Prototype

void OS_MEMPOOL_Delete(OS_MEMPOOL* pMEMF);

Parameters

Parameter Description
pMEMF Pointer to a memory pool object of type OS_MEMPOOL.

Additional information

After deletion, the memory pool and memory blocks inside this pool can no longer be used. pMEMF must addresses a valid memory pool. Before deleting a memory pool, make sure that no task is waiting for it.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL
190: OS_ERR_MEMF_INV
196: OS_ERR_MEMF_DELETE

For details, refer to the chapter Runtime application errors.

Example

static OS_MEMPOOL MyMEMF;

int main(void) {
  ...
  //
  // Delete memory pool
  //
  OS_MEMPOOL_Delete(&MyMEMF);
  ...
  return 0;
}

OS_MEMPOOL_Free()

Description

Releases the specified memory block. The memory pool does not need to be denoted.

Prototype

void OS_MEMPOOL_Free(void* pMemBlock);

Parameters

Parameter Description
pMemBlock Pointer to the memory block.

Additional information

This function may be used instead of OS_MEMPOOL_FreeEx(). It has the advantage that only one parameter is needed since embOS will automatically determine the associated memory pool. The memory block becomes available for other tasks waiting for a memory block from the associated pool, which may cause a subsequent task switch.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
190: OS_ERR_MEMF_INV
191: OS_ERR_MEMF_INV_PTR

For details, refer to the chapter Runtime application errors.

Example

static OS_MEMPOOL _MemPool;

void Task(void) {
  void* pData;

  pData = OS_MEMPOOL_Alloc(&_MemPool);  // Allocate memory
  ...                                   // Work with allocated memory
  OS_MEMPOOL_Free(pData);               // Free allocated memory
}

OS_MEMPOOL_FreeEx()

Description

Releases the specified memory block.

Prototype

void OS_MEMPOOL_FreeEx(OS_MEMPOOL* pMEMF,
                       void*       pMemBlock);

Parameters

Parameter Description
pMEMF Pointer to a memory pool object of type OS_MEMPOOL.
pMemBlock Pointer to memory block to free.

Additional information

The memory block becomes available for other tasks waiting for a memory block from the associated pool, which may cause a subsequent task switch.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
190: OS_ERR_MEMF_INV
191: OS_ERR_MEMF_INV_PTR
192: OS_ERR_MEMF_PTR_FREE
193: OS_ERR_MEMF_RELEASE

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example in the introduction of chapter Fixed Block Size Memory Pool.

OS_MEMPOOL_GetBlockSize()

Description

Returns the size of a single memory block in the specified memory pool.

Prototype

int OS_MEMPOOL_GetBlockSize(OS_CONST_PTR OS_MEMPOOL *pMEMF);

Parameters

Parameter Description
pMEMF Pointer to a memory pool object of type OS_MEMPOOL.

Return value

Size in bytes of a single memory block in the specified memory pool.

Additional information

The return value is the value of the parameter when the memory pool was created.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
190: OS_ERR_MEMF_INV

For details, refer to the chapter Runtime application errors.

Example

static OS_MEMPOOL _MemPool;

void PrintBlockSize(void) {
  int Size;

  Size = OS_MEMPOOL_GetBlockSize(&_MemPool);
  printf("Block Size: %d\n", Size);
}

OS_MEMPOOL_GetMaxUsed()

Description

Returns the maximum number of memory blocks in the specified pool that have been used simultaneously since creation of the pool.

Prototype

int OS_MEMPOOL_GetMaxUsed(OS_CONST_PTR OS_MEMPOOL *pMEMF);

Parameters

Parameter Description
pMEMF Pointer to a memory pool object of type OS_MEMPOOL.

Return value

Maximum number of blocks in the specified memory pool that were used simultaneously since the pool was created.

Additional information

OS_MEMPOOL_GetMaxUsed() can be used during development to optimize the memory pool size which helps to save RAM.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
190: OS_ERR_MEMF_INV

For details, refer to the chapter Runtime application errors.

Example

static OS_MEMPOOL _MemPool;

void PrintMemoryUsagePeak(void) {
  int   BlockCnt, UsedBlocks;
  void* pData;

  pData = OS_MEMPOOL_AllocBlocked(&_MemPool);

  BlockCnt   = OS_MEMPOOL_GetNumBlocks(&_MemPool);
  UsedBlocks = OS_MEMPOOL_GetMaxUsed(&_MemPool);
  if (UsedBlocks != 0) {
    printf("Max used Memory: %d%%\n", (int)(((float)UsedBlocks / BlockCnt) * 100));
  } else {
    printf("Max used Memory: 0%%");
  }
}

OS_MEMPOOL_GetNumBlocks()

Description

Returns the total number of memory blocks in the specified memory pool.

Prototype

int OS_MEMPOOL_GetNumBlocks(OS_CONST_PTR OS_MEMPOOL *pMEMF);

Parameters

Parameter Description
pMEMF Pointer to a memory pool object of type OS_MEMPOOL.

Return value

Returns the number of blocks in the specified memory pool.

Additional information

The return value is the value that was given as parameter during creation of the memory pool.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
190: OS_ERR_MEMF_INV

For details, refer to the chapter Runtime application errors.

Example

Please refer to the example of OS_MEMPOOL_GetMaxUsed() or OS_MEMPOOL_GetNumFreeBlocks().

OS_MEMPOOL_GetNumFreeBlocks()

Description

Returns the number of free memory blocks in the specified memory pool.

Prototype

int OS_MEMPOOL_GetNumFreeBlocks(OS_CONST_PTR OS_MEMPOOL *pMEMF);

Parameters

Parameter Description
pMEMF Pointer to a memory pool object of type OS_MEMPOOL.

Return value

The number of free blocks currently available in the specified memory pool.

Additional information

If OS_MEMPOOL_GetNumFreeBlocks() returns the same as OS_MEMPOOL_GetNumBlocks(), no memory block is currently allocated.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
190: OS_ERR_MEMF_INV

For details, refer to the chapter Runtime application errors.

Example

static OS_MEMPOOL _MemPool;

void PrintMemoryUsage(void) {
  int   BlockCnt;
  int   UnusedBlocks;
  void* pData;

  pData = OS_MEMPOOL_AllocBlocked(&_MemPool);

  BlockCnt     = OS_MEMPOOL_GetNumBlocks(&_MemPool);
  UnusedBlocks = OS_MEMPOOL_GetNumFreeBlocks(&_MemPool);
  if (UnusedBlocks != 0) {
    printf("Used Memory: %d%%\n", 100 - (int)(((float)UnusedBlocks / BlockCnt) * 100));
  } else {
    printf("Used Memory: 0%%");
  }
}

OS_MEMPOOL_IsInPool()

Description

Returns whether the specified memory block belongs to the specified memory pool.

Prototype

OS_BOOL OS_MEMPOOL_IsInPool(OS_CONST_PTR OS_MEMPOOL *pMEMF,
                            OS_CONST_PTR void *pMemBlock);

Parameters

Parameter Description
pMEMF Pointer to a memory pool object of type OS_MEMPOOL.
pMemBlock Pointer to a memory block that should be checked.

Return value

= 0 Pointer does not belong to the specified memory pool.
≠ 0 Pointer belongs to the specified memory pool.

Additional information

OS_MEMPOOL_IsInPool() checks if the memory block is located in the range of the memory pool buffer.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
190: OS_ERR_MEMF_INV

For details, refer to the chapter Runtime application errors.

Example

static OS_MEMPOOL _MemPool;

void CheckPointerLocation(OS_MEMPOOL* pMEMF, void* Pointer) {
  if (OS_MEMPOOL_IsInPool(pMEMF, Pointer) == 0) {
    printf("Pointer doesn't belong to the specified memory pool.\n");
  } else {
    printf("Pointer belongs to the specified memory pool.\n");
  }
}

System Tick

Introduction

The embOS system tick is an interrupt that calls the embOS tick handler OS_TICK_Handle(). The latter triggers the scheduler when it needs to schedule a task or execute a software timer.

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_TICK_Handle() embOS-Ultra timer interrupt handler.

OS_TICK_Handle()

Description

embOS-Ultra timer interrupt handler.

Prototype

void OS_TICK_Handle(void);

Additional information

The embOS-Ultra timer interrupt handler must be called from the hardware timer interrupt handler only.

OS_TIME_ConfigSysTimer() must have been called before calling OS_TICK_Handle().

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

162: OS_ERR_ILLEGAL_OUT_ISR
164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL
239: OS_ERR_COUNTER_FREQ_ZERO

Example

void SysTick_Handler(void) {
  OS_INT_EnterNestable();
  OS_TICK_Handle();
  OS_INT_LeaveNestable();
}

Debugging

Runtime application errors

Many application errors can be detected during runtime.
These are for example:

Which runtime errors can be detected depends on how many checks are performed. Unfortunately, additional checks cost memory and performance (it is not that significant, but there is a difference). Not all embOS library modes include the debug and stack check code. For example OS_LIBMODE_DP includes the debug and stack check, whereas OS_LIBMODE_R does not contain any debug or stack check code.

Note

If an application error is detected and OS_Error() is called, do not switch to another embOS library mode which does not contain the debug checks. While doing so avoids calls to OS_Error() but it does not fix the original application error and subsequent behavior is unpredictable.

When embOS detects a runtime error, it calls the following routine:

void OS_Error(OS_STATUS ErrCode);

This routine is shipped as source code as part of the module OS_Error.c. Although this function is named OS_Error(), it does not show embOS errors but application errors. It is called with disabled preemptive task switches and, after re-enabling interrupts, loops forever as follows:

Example

void OS_Error(OS_STATUS ErrCode) {
  //
  // Disabling preemptive task switches avoids that other higher priority
  // tasks preempt OS_Error() which makes debugging easier.
  //
  OS_TASK_EnterRegion();
  //
  // Enable interrupts for embOSView communication.
  //
  OS_Global.Counters.Cnt.DI = 0u;
  OS_INT_Enable();
  //
  // OS_Global.Status will be shown in e.g. embOSView and IDE plugins.
  // It is available in debug and stack check builds only.
  //
#if (OS_DEBUG != 0) || (OS_SUPPORT_STACKCHECK != 0)
  OS_Global.Status = ErrCode;
#endif
  //
  // Endless loop may be left by setting ErrCode to OS_OK (0).
  //
  while (ErrCode != OS_OK) {
  }
}

If you are using embOSView, you can see the value and meaning of OS_Global.Status in the system variable window.

When using a debugger, you should set a breakpoint at the beginning of this routine or simply stop the program after a failure. The error code is passed to the function as a parameter. You should add OS_Global.Status to your watch window.

Your call stack window shows where the error occurred. If a call stack windows is not available you can (as described below) step back to the program sequence causing the problem.

You can modify the routine to accommodate to your own hardware; this could mean that your target hardware sets an error-indicating LED or shows a small message on the display.

Note

When modifying the OS_Error() routine, the last statement needs to be the infinite loop.

If you look at the OS_Error() routine, you will see that it is more complicated than necessary. The actual error code is passed to OS_Error() to the argument ErrCode. The program then waits for this variable to be reset. Simply reset this variable to 0 using your debugger, and you can easily step back to the program sequence causing the problem. Most of the time, looking at this part of the program will make the problem clear.

List of error codes

Value enum value Explanation
0 OS_OK No error, everything okay.
100 OS_ERR_ISR_INDEX Index value out of bounds during interrupt controller initialization or interrupt installation.
101 OS_ERR_ISR_VECTOR Default interrupt handler called, but interrupt vector not initialized.
102 OS_ERR_ISR_PRIO Wrong interrupt priority.
103 OS_ERR_WRONG_STACK Wrong stack used before main().
104 OS_ERR_ISR_NO_HANDLER No interrupt handler was defined for this interrupt.
105 OS_ERR_TLS_INIT OS_TLS_Init() called multiple times from one task.
106 OS_ERR_MB_BUFFER_SIZE For 16-bit CPUs, the maximum buffer size for a mailbox (65,535 bytes) exceeded.
115 OS_ERR_TASK_STACK_SIZE_INSUFFICIENT Task stack size too small.
116 OS_ERR_EXTEND_CONTEXT OS_TASK_SetContextExtension() called multiple times from one task.
119 OS_ERR_IDLE_RETURNS OS_Idle() must not return.
120 OS_ERR_TASK_STACK_OVERFLOW Task stack overflow.
121 OS_ERR_SEMAPHORE_OVERFLOW Semaphore value overflow.
122 OS_ERR_POWER_OVER Counter overflows when calling OS_POWER_UsageInc().
123 OS_ERR_POWER_UNDER Counter underflows when calling OS_POWER_UsageDec().
125 OS_ERR_SYSTEM_STACK_OVERFLOW System stack overflow.
126 OS_ERR_INTERRUPT_STACK_OVERFLOW Interrupt stack overflow.
128 OS_ERR_INV_TASK Task control block invalid, not initialized or overwritten.
129 OS_ERR_INV_TIMER Timer control block invalid, not initialized or overwritten.
130 OS_ERR_INV_MAILBOX Mailbox control block invalid, not initialized or overwritten.
132 OS_ERR_INV_SEMAPHORE Control block for semaphore invalid, not initialized or overwritten.
133 OS_ERR_INV_MUTEX Control block for mutex invalid, not initialized or overwritten.
135 OS_ERR_MAILBOX_NOT1 One of the following 1-byte mailbox functions has been used on a multi-byte mailbox: OS_MAILBOX_Get1(), OS_MAILBOX_GetBlocked1(), OS_MAILBOX_GetTimed1(), OS_MAILBOX_Put1(), OS_MAILBOX_PutBlocked1(), OS_MAILBOX_PutFront1(), OS_MAILBOX_PutFrontBlocked1() or OS_MAILBOX_PutTimed1().
136 OS_ERR_MAILBOX_DELETE OS_MAILBOX_Delete() was called on a mailbox with waiting tasks.
137 OS_ERR_SEMAPHORE_DELETE OS_SEMAPHORE_Delete() was called on a semaphore with waiting tasks.
138 OS_ERR_MUTEX_DELETE OS_MUTEX_Delete() was called on a mutex which is claimed by a task.
143 OS_ERR_QUEUE_INUSE Queue in use.
144 OS_ERR_QUEUE_NOT_INUSE Queue not in use.
145 OS_ERR_QUEUE_INVALID Queue invalid.
146 OS_ERR_QUEUE_DELETE A queue was deleted by a call of OS_QUEUE_Delete() while tasks are waiting at the queue.
147 OS_ERR_MAILBOX_INUSE Mailbox in use.
148 OS_ERR_MAILBOX_NOT_INUSE Mailbox not in use.
149 OS_ERR_MESSAGE_SIZE_ZERO Attempt to store a message with size of zero.
150 OS_ERR_UNUSE_BEFORE_USE OS_MUTEX_Unlock() has been called on a mutex that hasn’t been locked before.
151 OS_ERR_LEAVEREGION_BEFORE_ENTERREGION OS_TASK_LeaveRegion() has been called before OS_TASK_EnterRegion().
152 OS_ERR_LEAVEINT OS_INT_Leave()/OS_INT_LeaveNestable() called without OS_INT_Enter()/OS_INT_EnterNestable().
153 OS_ERR_DICNT_OVERFLOW The interrupt disable counter ( OS_Global.Counters.Cnt.DI ) is out of range (0-15). The counter is affected by the API calls OS_INT_IncDI(), OS_INT_DecRI(), OS_INT_Enter() and OS_INT_Leave().
154 OS_ERR_INTERRUPT_DISABLED OS_TASK_Delay() or OS_TASK_DelayUntil() called from inside a critical region with interrupts disabled.
155 OS_ERR_TASK_ENDS_WITHOUT_TERMINATE Task routine returns without OS_TASK_Terminate().
156 OS_ERR_MUTEX_OWNER OS_MUTEX_Unlock() has been called from a task which does not own the mutex.
157 OS_ERR_REGIONCNT The region counter overflows (>255).
158 OS_ERR_DELAYUS_INTERRUPT_DISABLED OS_TASK_Delay_us() called with interrupts disabled.
159 OS_ERR_MUTEX_OVERFLOW OS_MUTEX_Lock(), OS_MUTEX_LockBlocked() or OS_MUTEX_LockTimed() has been called too often from the same task.
160 OS_ERR_ILLEGAL_IN_ISR Illegal function call in an interrupt service routine: A routine that must not be called from within an ISR has been called from within an ISR.
161 OS_ERR_ILLEGAL_IN_TIMER Illegal function call in a software timer: A routine that must not be called from within a software timer has been called from within a timer.
162 OS_ERR_ILLEGAL_OUT_ISR Not a legal API outside interrupt.
163 OS_ERR_OS_INT_ENTER_CALLED OS_INT_Enter() has been called, but CPU is not in ISR state.
164 OS_ERR_OS_INT_ENTER_NOT_CALLED OS_INT_Enter() has not been called, but CPU is in ISR state.
165 OS_ERR_INIT_NOT_CALLED OS_Init() was not called.
166 OS_ERR_ISR_PRIORITY_INVALID embOS API called from ISR with an invalid priority.
167 OS_ERR_CPU_STATE_ILLEGAL CPU runs in illegal mode.
169 OS_ERR_TICKLESS_WITH_FRACTIONAL_TICK OS_TICKLESS_AdjustTime() was called despite OS_TICK_Config() has been called before.
170 OS_ERR_2USE_TASK Task control block has been initialized by calling a create function twice.
171 OS_ERR_2USE_TIMER Timer control block has been initialized by calling a create function twice.
172 OS_ERR_2USE_MAILBOX Mailbox control block has been initialized by calling a create function twice.
174 OS_ERR_2USE_SEMAPHORE Semaphore has been initialized by calling a create function twice.
175 OS_ERR_2USE_MUTEX Mutex has been initialized by calling a create function twice.
176 OS_ERR_2USE_MEMF Fixed size memory pool has been initialized by calling a create function twice.
177 OS_ERR_2USE_QUEUE Queue has been initialized by calling a create function twice.
178 OS_ERR_2USE_EVENT Event object has been initialized by calling a create function twice.
179 OS_ERR_2USE_WATCHDOG Watchdog has been initialized by calling a create function twice.
180 OS_ERR_NESTED_RX_INT OS_COM_OnRx() interrupt handler for embOSView is nested. Disable nestable interrupts.
181 OS_ERR_ISR_ENTRY_FUNC_INVALID Invalid function pointer for ISR entry callback.
185 OS_ERR_SPINLOCK_INV_CORE Invalid core ID specified for accessing a OS_SPINLOCK_SW struct.
190 OS_ERR_MEMF_INV Fixed size memory block control structure not created before use.
191 OS_ERR_MEMF_INV_PTR Pointer to memory block does not belong to memory pool on Release.
192 OS_ERR_MEMF_PTR_FREE Pointer to memory block is already free when calling OS_MEMPOOL_Free() or OS_MEMPOOL_FreeEx(). Possibly, same pointer was released twice.
193 OS_ERR_MEMF_RELEASE OS_MEMPOOL_Free() or OS_MEMPOOL_FreeEx() was called for a memory pool, that had no memory block allocated (all available blocks were already free before).
194 OS_ERR_MEMF_POOLADDR OS_MEMPOOL_Create() was called with a memory pool base address which is not located at a word aligned base address.
195 OS_ERR_MEMF_BLOCKSIZE OS_MEMPOOL_Create() was called with a data block size which is not a multiple of processors word size.
196 OS_ERR_MEMF_DELETE OS_MEMPOOL_Delete() was called on a memory pool with waiting tasks.
200 OS_ERR_SUSPEND_TOO_OFTEN Number of nested calls to OS_TASK_Suspend() exceeded 3.
201 OS_ERR_RESUME_BEFORE_SUSPEND OS_TASK_Resume() called on a task that was not suspended.
202 OS_ERR_TASK_PRIORITY OS_TASK_Create() was called with a task priority which is already assigned to another task. This error can only occur when embOS was compiled without round-robin support.
203 OS_ERR_TASK_PRIORITY_INVALID The value 0 was used as task priority.
205 OS_ERR_TIMER_PERIOD_INVALID The value 0 was used as timer period.
210 OS_ERR_EVENT_INVALID An OS_EVENT object was used before it was created.
212 OS_ERR_EVENT_DELETE An OS_EVENT object was deleted with waiting tasks.
213 OS_ERR_EVENTOBJ_RESETMODE OS_MULTIOBJ_IsEventSignaled() used with reset mode other than OS_EVENT_RESET_MODE_MANUAL.
220 OS_ERR_WAITLIST_RING This error should not occur. Please contact the support.
221 OS_ERR_WAITLIST_PREV This error should not occur. Please contact the support.
222 OS_ERR_WAITLIST_NEXT This error should not occur. Please contact the support.
223 OS_ERR_TICKHOOK_INVALID Invalid tick hook.
224 OS_ERR_TICKHOOK_FUNC_INVALID Invalid tick hook function.
225 OS_ERR_NOT_IN_REGION A function was called without declaring the necessary critical region.
226 OS_ERR_ILLEGAL_IN_MAIN Not a legal API call from main().
227 OS_ERR_ILLEGAL_IN_TASK Not a legal API after OS_Start().
228 OS_ERR_ILLEGAL_AFTER_OSSTART Not a legal API after OS_Start().
229 OS_ERR_ILLEGAL_IN_IDLE Not a legal API call from OS_Idle().
230 OS_ERR_NON_ALIGNED_INVALIDATE Cache invalidation needs to be cache line aligned.
234 OS_ERR_HW_NOT_AVAILABLE Hardware unit is not implemented or enabled.
235 OS_ERR_NON_TIMERCYCLES_FUNC OS_TIME_ConfigSysTimer() not called or called with NULL pointer for function to read timer counter value.
236 OS_ERR_NON_TIMERINTPENDING_FUNC OS_TIME_ConfigSysTimer() not called or called with NULL pointer for function to read timer interrupt pending.
237 OS_ERR_FRACTIONAL_TICK embOS API function called with fractional tick to interrupt ratio.
238 OS_ERR_ZERO_TIMER_INT_FREQ OS_TIME_ConfigSysTimer() not called or called with an interrupt frequency of 0.
239 OS_ERR_COUNTER_FREQ_ZERO OS_TIME_ConfigSysTimer() not called or called with a counter frequency of 0.
240 OS_ERR_MPU_NOT_PRESENT MPU unit not present in the device.
241 OS_ERR_MPU_INVALID_REGION Invalid MPU region index number.
242 OS_ERR_MPU_INVALID_SIZE Invalid MPU region size.
243 OS_ERR_MPU_INVALID_PERMISSION Invalid MPU region permission.
244 OS_ERR_MPU_INVALID_ALIGNMENT Invalid MPU region alignment.
245 OS_ERR_MPU_INVALID_OBJECT OS object is directly accessible from the task which is not allowed.
246 OS_ERR_MPU_PRIVSTATE_INVALID Invalid call from a privileged task.
247 OS_ERR_MPU_NOINIT OS_MPU_Init() not called.
248 OS_ERR_MPU_DEVICE_INDEX Invalid device driver index.
249 OS_ERR_MPU_INV_DEVICE_LIST Invalid device driver list.
250 OS_ERR_CONFIG_OSSTOP OS_Stop() is called without using OS_ConfigStop() before.
251 OS_ERR_OSSTOP_BUFFER Buffer is too small to hold a copy of the main() stack.
253 OS_ERR_VERSION_MISMATCH OS library and RTOS.h have different version numbers. Please ensure both are from the same embOS shipment.
254 OS_ERR_LIB_INCOMPATIBLE Incompatible OS library is used.
255 OS_ERR_INV_PARAMETER_VALUE An invalid value was passed to the called function (see call stack). Check the API description for valid values.
256 OS_ERR_TICKHANDLE_WITH_FRACTIONAL_TICK OS_TICK_Handle() or OS_TICK_HandleNoHook() was called after OS_TICK_Config() was used for an interrupt to tick ratio other than 1:1.
257 OS_ERR_RWLOCK_INVALID Readers-Writer Lock control block invalid, not initialized or overwritten.
258 OS_ERR_2USE_RWLOCK Readers-Writer Lock has been initialized by calling a create function twice.
260 OS_ERR_UNALIGNED_IRQ_STACK Unaligned IRQ stack.
261 OS_ERR_UNALIGNED_MAIN_STACK Unaligned main stack.
262 OS_ERR_FPU_NOT_ENABLED FPU was not enabled before embOS gets initialized.
263 OS_ERR_MPU_SANITY_BUFFER_NOT_SET MPU sanity check buffer not set with OS_MPU_SetSanityCheckBuffer().
264 OS_ERR_MPU_INVALID_ATTR_INDEX MPU Invalid index used with OS_ARMv8M_SetMPUAttribute().
265 OS_ERR_MULTIOBJ_INVALID_ROUTINE Invalid condition routine used with OS_MULTIOBJ_Wait(), OS_MULTIOBJ_WaitBlocked() or OS_MULTIOBJ_WaitTimed().

Application defined error codes

The embOS error codes begin at 100. The range 1 - 99 can be used for application defined error codes. With it you can call OS_Error() with your own defined error code from your application.

Example

#define OS_ERR_APPL  (0x02u)

void UserAppFunc(void) {
  int r;
  r = DoSomething()
  if (r == 0) {
    OS_Error(OS_ERR_APPL)
  }
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_DEBUG_GetError() Returns the system status.
OS_DEBUG_GetError()

Description

Returns the system status.

Prototype

OS_STATUS OS_DEBUG_GetError(void);

Return value

= 0 OS_OK, No application error occurred.
≠ 0 Application error occurred.

Additional information

The system status codes are described in the embOS manual in chapter List of error codes. OS_DEBUG_GetError() always returns OS_OK when no debug or stack check code is included.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

164: OS_ERR_OS_INT_ENTER_NOT_CALLED
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

void PrintOSStatus(void) {
  OS_STATUS s;

  s = OS_DEBUG_GetError();
  printf("embOS status: %u\n", s);
}

Human readable object identifiers

embOS objects like mailbox or semaphore are handled via separate control structures. Each OS object is identified by the address of the according control structure. For debugging purpose this address is displayed in external tools like embOSView or IDE RTOS plugins.

Tasks always have a human readable task name (except in embOS library mode OS_LIBMODE_XR). The task name is set at task creation. It can be helpful to have human readable identifiers for other OS objects, as well. With the following API functions human readable identifiers to an unlimited amount of OS objects can easily be added. Human readable object identifiers are not supported in embOS library mode OS_LIBMODE_XR.

Example

#include "RTOS.h"
#include <stdio.h>

static OS_STACKPTR int _Stack[128];
static OS_TASK         _TCB;
static OS_MAILBOX      _Mailbox;
static OS_OBJNAME      _MailboxName;
static char            _acBuffer[100];

static void _Task(void) {
  const char* s;
  s = OS_DEBUG_GetObjName(&_Mailbox);
  printf(s);
  //
  // Set another name for the mailbox
  //
  OS_DEBUG_RemoveObjName(&_MailboxName);
  OS_DEBUG_SetObjName(&_MailboxName, &_Mailbox, "My new Mailbox");
  while (1) {
    OS_TASK_Delay_ms(50);
  }
}

int main(void) {
  OS_Init();      // Initialize embOS
  OS_InitHW();    // Initialize required hardware
  OS_TASK_CREATE(&_TCB, "Task", 100, _Task, _Stack);
  OS_MAILBOX_Create(&_Mailbox, 10, 10, &_acBuffer);
  OS_DEBUG_SetObjName(&_MailboxName, &_Mailbox, "My Mailbox");
  OS_Start();     // Start embOS
  return 0;
}

API functions

Routine Description main Priv Task Unpriv Task ISR SW Timer
OS_DEBUG_GetObjName() Returns the name of an RTOS object.
OS_DEBUG_RemoveObjName() Removes an RTOS object name.
OS_DEBUG_SetObjName() Sets an RTOS object name.
OS_DEBUG_GetObjName()

Description

Returns the name of an RTOS object.

Prototype

char *OS_DEBUG_GetObjName(OS_CONST_PTR void *pOSObj);

Parameters

Parameter Description
pOSObj Pointer to the RTOS object.

Return value

= NULL Name was not set for this object.
NULL Pointer to the RTOS object name.

Additional information

OS_DEBUG_GetObjName() returns the object name which was set before with OS_DEBUG_SetObjName(). The return value is valid only when using an embOS build with object name support. When using an embOS build without object name support, OS_DEBUG_GetObjName() returns “n/a” in any case. The embOS OS_LIBMODE_XR library mode does not support object names.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please find an example at Human readable object identifiers.

OS_DEBUG_RemoveObjName()

Description

Removes an RTOS object name.

Prototype

void OS_DEBUG_RemoveObjName(OS_CONST_PTR OS_OBJNAME *pObjName);

Parameters

Parameter Description
pObjName Pointer to a OS_OBJNAME control structure.

Additional information

OS_DEBUG_RemoveObjName() removes the object name which was set before with OS_DEBUG_SetObjName(). When using an embOS build without object name support, OS_DEBUG_RemoveObjName() has no effect. The embOS OS_LIBMODE_XR library mode does not support object names.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please find an example at Human readable object identifiers.

OS_DEBUG_SetObjName()

Description

Sets an RTOS object name.

Prototype

void OS_DEBUG_SetObjName(OS_OBJNAME*  pObjName,
                         OS_CONST_PTR void *pOSObj,
                         OS_CONST_PTR char *sName);

Parameters

Parameter Description
pObjName Pointer to a OS_OBJNAME control structure.
pOSObj Pointer to the RTOS object.
sName Name of the RTOS object. embOS does not copy the RTOS object name, but uses the pointer exclusively.

Additional information

With OS_DEBUG_SetObjName() every RTOS object like mailbox can have a name. This name can be shown in debug tools like IDE RTOS plug-ins. Every object name needs a control structure of type OS_OBJNAME. When using an embOS build without object name support, OS_DEBUG_SetObjName() does not set an object name. The embOS OS_LIBMODE_XR library mode does not support object names.

Error codes

With embOS debug checks enabled erroneous calls to this function result in OS_Error() being called with one of the following application error IDs:

160: OS_ERR_ILLEGAL_IN_ISR
161: OS_ERR_ILLEGAL_IN_TIMER
167: OS_ERR_CPU_STATE_ILLEGAL

For details, refer to the chapter Runtime application errors.

Example

Please find an example at Human readable object identifiers.

embOS API trace

embOS supports API trace in two different ways:

To do so, the embOS API functions call specific routines which store trace events to a given memory location. With embOSView, these routines are called directly inside the embOS API functions. To enable the use of embOS API trace with other tools than embOSView, however, a structure containing various function pointers is used to store trace events in memory. That structure may be configured to point at specific routines for the desired tool via OS_TRACE_SetAPI(), which are then called from the embOS API functions when API trace is enabled. These specific routines must be provided as part of the application and are shipped for example with the SystemView target sources.

Example

void SEGGER_SYSVIEW_Conf(void) {
  ..
  //
  // Configure embOS to use SystemView
  //
  OS_TRACE_SetAPI(&embOS_TraceAPI_SYSVIEW);
  ..
}