Industrial manufacturing
Industrial Internet of Things | Industrial materials | Equipment Maintenance and Repair | Industrial programming |
home  MfgRobots >> Industrial manufacturing >  >> Industrial Internet of Things >> Embedded

Semaphores in Nucleus SE: Overview, Configuration, and API Essentials

Semaphores in Nucleus SE: Overview, Configuration, and API Essentials
View the RTOS Revealed series

Semaphores are a foundational mechanism for synchronizing access to shared resources in embedded systems. They allow tasks to safely obtain and release control over a resource without conflicts.

Using Semaphores

In Nucleus SE, semaphore support is enabled during the build process. A single application can configure up to 16 semaphores. If you opt not to use any semaphores, the related data structures and API code are excluded from the final binary, reducing footprint.

A semaphore is simply an 8‑bit counter whose value is protected so that multiple tasks can manipulate it safely. Tasks call Obtain to decrement the counter and Release to increment it. If a task attempts to obtain a semaphore whose counter is zero, the outcome depends on the API options and the system configuration: the call may return an error or suspend the task until the semaphore becomes available.

Configuring Semaphores

Number of Semaphores

Semaphores are defined via #define statements in nuse_config.h. The key macro is NUSE_SEMAPHORE_NUMBER, which specifies how many semaphore slots the application will use. The default value is 0, meaning no semaphore support. Valid values range from 0 to 16. An invalid value triggers a compile‑time error generated by nuse_config_check.h (included through nuse_config.c).

Setting NUSE_SEMAPHORE_NUMBER to a non‑zero value activates the semaphore subsystem: data structures are sized accordingly, and API enabling symbols are processed.

API Enables

Each Nucleus SE API call is guarded by a dedicated enabling macro in nuse_config.h. For semaphores, the relevant symbols are:

By default, all these macros are set to FALSE, which disables the corresponding service calls and excludes their implementation from the build. To enable a particular API, set its macro to TRUE.

Below is a snippet from the default nuse_config.h file:

#define NUSE_SEMAPHORE_NUMBER              0                      /* Number of semaphores in the system – 0‑16 */
#define NUSE_SEMAPHORE_OBTAIN              FALSE                   /* Service call enabler */
#define NUSE_SEMAPHORE_RELEASE             FALSE                   /* Service call enabler */
#define NUSE_SEMAPHORE_RESET               FALSE                   /* Service call enabler */
#define NUSE_SEMAPHORE_INFORMATION         FALSE                   /* Service call enabler */
#define NUSE_SEMAPHORE_COUNT               FALSE                   /* Service call enabler */

Enabling an API call without configuring any semaphores (except NUSE_Semaphore_Count(), which is always available) results in a compile‑time error. If you call an API that has not been enabled, a link‑time error occurs because the implementation was omitted.

Semaphore Service Calls

Nucleus SE offers eight semaphore‑related service calls. The first five are fully implemented; the remaining three are placeholders for future extensions.

Obtain and Release Operations

The core semaphore operations are obtaining (decrementing) and releasing (incrementing). Nucleus RTOS provides a flexible obtain API with optional suspension and timeouts. Nucleus SE mirrors this behavior, though task suspension is optional and timeouts are not supported.

Nucleus RTOS Obtain API

Prototype:

STATUS NU_Obtain_Semaphore(NU_SEMAPHORE *semaphore, UNSIGNED suspend);

Parameters:

semaphore – pointer to the semaphore control block.

suspend – can be NU_NO_SUSPEND, NU_SUSPEND, or a timeout value.

Return values:

NU_SUCCESS – operation succeeded.

NU_UNAVAILABLE – semaphore value was zero.

NU_INVALID_SEMAPHORE – invalid semaphore pointer.

NU_INVALID_SUSPEND – suspend attempted from a non‑task context.

NU_SEMAPHORE_WAS_RESET – semaphore reset while task was suspended.

Nucleus SE Obtain API

Prototype:

STATUS NUSE_Semaphore_Obtain(NUSE_SEMAPHORE semaphore, U8 suspend);

Parameters:

semaphore – the semaphore index.

suspend – can be NUSE_NO_SUSPEND or NUSE_SUSPEND.

Return values:

NUSE_SUCCESS – operation succeeded.

NUSE_UNAVAILABLE – semaphore value was zero.

NUSE_INVALID_SEMAPHORE – invalid semaphore index.

NUSE_INVALID_SUSPEND – suspend attempted from non‑task or blocking APIs disabled.

NUSE_SEMAPHORE_WAS_RESET – semaphore reset during suspension.

Implementation Highlights

When blocking is disabled, the implementation simply checks if the counter is non‑zero, decrements it, and returns NUSE_SUCCESS. If the counter is zero, it returns NUSE_UNAVAILABLE.

if (NUSE_Semaphore_Counter[semaphore] != 0) {
    NUSE_Semaphore_Counter[semaphore]--;
    return_value = NUSE_SUCCESS;
} else {
    return_value = NUSE_UNAVAILABLE;
}
When blocking is enabled, the routine enters a do…while loop that attempts to acquire the semaphore. If the counter is zero and suspend is NUSE_SUSPEND, the task is blocked. Upon release, the first waiting task is woken and the loop retries the acquisition.
do {
    if (NUSE_Semaphore_Counter[semaphore] != 0) {
        NUSE_Semaphore_Counter[semaphore]--;
        return_value = NUSE_SUCCESS;
        suspend = NUSE_NO_SUSPEND;
    } else {
        if (suspend == NUSE_NO_SUSPEND) {
            return_value = NUSE_UNAVAILABLE;
        } else {
            NUSE_Semaphore_Blocking_Count[semaphore]++;
            NUSE_Suspend_Task(NUSE_Task_Active, semaphore << 4 | NUSE_SEMAPHORE_SUSPEND);
            return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active];
            if (return_value != NUSE_SUCCESS) {
                suspend = NUSE_NO_SUSPEND;
            }
        }
    }
} while (suspend == NUSE_SUSPEND);

Nucleus RTOS Release API

Prototype:

STATUS NU_Release_Semaphore(NU_SEMAPHORE *semaphore);

Parameters:

semaphore – pointer to the semaphore control block.

Return values:

NU_SUCCESS – operation succeeded.

NU_INVALID_SEMAPHORE – invalid semaphore pointer.

Nucleus SE Release API

Prototype:

STATUS NUSE_Semaphore_Release(NUSE_SEMAPHORE semaphore);

Parameters:

semaphore – the semaphore index.

Return values:

NUSE_SUCCESS – operation succeeded.

NUSE_INVALID_SEMAPHORE – invalid semaphore index.

NUSE_UNAVAILABLE – counter already at 255; cannot increment.

Implementation Highlights

The release routine first checks that the counter is below its maximum (255). If so, it increments the counter. If blocking is enabled and there are tasks waiting on this semaphore, the first one is awakened.

NUSE_CS_Enter();
if (NUSE_Semaphore_Counter[semaphore] < 255) {
    NUSE_Semaphore_Counter[semaphore]++;
    return_value = NUSE_SUCCESS;
    #if NUSE_BLOCKING_ENABLE
    if (NUSE_Semaphore_Blocking_Count[semaphore] != 0) {
        NUSE_Semaphore_Blocking_Count[semaphore]--;
        for (U8 index = 0; index < NUSE_TASK_NUMBER; index++) {
            if ((LONIB(NUSE_Task_Status[index]) == NUSE_SEMAPHORE_SUSPEND) &&
                (HINIB(NUSE_Task_Status[index]) == semaphore)) {
                NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS;
                NUSE_Wake_Task(index);
                break;
            }
        }
    }
    #endif
} else {
    return_value = NUSE_UNAVAILABLE;
}
NUSE_CS_Exit();
return return_value;

When tasks are suspended on a semaphore, releasing it wakes the first waiting task, allowing it to continue execution.

The next article will explore event flag groups and their related data structures.


Colin Walls has over thirty years of experience in the electronics industry, primarily focused on embedded software. He frequently presents at conferences, writes technical articles, and authored two books on embedded software. Colin is an embedded software technologist with Mentor Embedded (the Mentor Graphics Embedded Software Division) and is based in the UK. His blog is at https://blogs.mentor.com/colinwalls. Reach him by email at colin_walls@mentor.com.


Embedded

  1. Stainless Steel Explained: Composition, Production, and Global Impact
  2. Diodes and Rectifiers: Fundamentals, Operation, and Key Parameters
  3. Understanding Conductors and Insulators: From Quantum Mechanics to Practical Applications
  4. C# Fundamentals: Input and Output Essentials
  5. Mailboxes in Nucleus SE: A Practical Guide to Configuration and Usage
  6. Semaphores in Nucleus RTOS: Utility Services & Data Structures
  7. Event Flag Groups in Nucleus SE: An Introductory Guide to Configuration and API Usage
  8. Partition Memory in Nucleus RTOS/SE: Utility Services and Data Structures
  9. Partition Memory in Nucleus SE: Configuration, APIs, and Best Practices
  10. Queues in Nucleus SE: Introduction and Core Service Calls