EmbLED (Embedded LED) is a lightweight, dependency-free, and RTOS-agnostic C library for LED control on embedded systems.
Designed for reliability, simplicity, and minimal resource usage.
It abstracts common patterns (ON/OFF, blinks), supports digital or PWM control, and lets you create dynamic profiles at runtime.
- Key Features
- Concepts & Execution Flow
- Resource Footprint
- Data Structures
- Public API
- Quick Start Code
- Limits & Configuration
- Examples
- License
- Contact
- ⚡ Lightweight for embedded systems
- 🧩 No dependencies or dynamic memory usage
- 🕒 Fixed-time tick engine
- 💡 Support for both GPIO and PWM control
- 🔄 Dynamic profiles created at runtime
- 🧠 RTOS and bare-metal compatible
-
Base cycle:
Set a periodic timer or RTOS task to callembled_task()everyEMBLED_CYCLE_TIME_MS(default 100 ms). -
Modes:
Each mode defines a sequence of ON/OFF states with durations expressed in ticks (multiples of the base cycle). -
Dynamic profiles:
Create new modes at runtime withembled_new_profile(), passing durations in milliseconds; the library converts them to ticks. -
Driver abstraction:
Each LED can use either a digital GPIO (ON/OFF) or a PWM driver (start/stop). -
Logic levels:
Supports both active-high and active-low outputs (EMBLED_ACTIVE_HIGH/EMBLED_ACTIVE_LOW).
| Resource | Typical Usage (per 4 LEDs, GCC -O0) |
|---|---|
| Flash | ≈ 2.2 KB |
| RAM | ≈ 540 B |
⚡ Built for very low memory usage and zero dynamic allocation.
embled_modes_t— available modes
| Mode | Description |
|---|---|
EMBLED_MODE_OFF |
LED remains off. |
EMBLED_MODE_ON |
LED remains on continuously. |
EMBLED_MODE_PULSE_FAST_ONCE |
Single short pulse — blinks once briefly, then turns off. |
EMBLED_MODE_PULSE_SLOW_ONCE |
Single long pulse — blinks once longer, then turns off. |
EMBLED_MODE_PULSE_FAST_DOUBLE_ONCE |
Two quick pulses, then turns off. |
EMBLED_MODE_PULSE_SINGLE |
Single short pulse repeated continuously. |
EMBLED_MODE_PULSE_DOUBLE |
Two short pulses repeated continuously. |
EMBLED_MODE_PULSE_TRIPLE |
Three short pulses repeated continuously. |
EMBLED_MODE_BLINK_SLOW |
Continuous slow blink (≈ 1 Hz). |
EMBLED_MODE_BLINK_MEDIUM |
Continuous medium-speed blink (≈ 2 Hz). |
EMBLED_MODE_BLINK_FAST |
Continuous fast blink (≈ 5 Hz). |
EMBLED_MODE_DYNAMIC_X |
Reserved for dynamic, user-defined profiles created at runtime. |
-
embled_levels_t— activation levelsEMBLED_ACTIVE_LOW: LED turns ON at low level (GND).EMBLED_ACTIVE_HIGH: LED turns ON at high level (VCC).
-
embled_driver_mode_t— pin control modeEMBLED_DRIVER_MODE_DIGITAL: Use GPIO peripheral driver control.EMBLED_DRIVER_MODE_PWM: Use PWM peripheral driver control.
-
embled_callbacks_t— MCU integrationwrite_gpio(pin, level): Write the GPIO level.read_gpio(pin): Read the current GPIO level.start_pwm(pin): Start the PWM channel.stop_pwm(pin): Stop the PWM channel.
Provide these callbacks once via
embled_init(). Callbacks may beNULLif not used.
void embled_init(embled_callbacks_t* cbks)Initializes the LED control service and registers the hardware driver callbacks.
Parameters:
cbks: Pointer to a structure containing function pointers for hardware-level control
(e.g.,write_gpio(),read_gpio(),start_pwm(),stop_pwm()).
Details:
- Must be called once before using any other
embled_*function. - If
cbksisNULL, the function performs no hardware operation.
void embled_task(void* argument)Main periodic service routine that executes the LED state machine.
Parameters:
argument: Optional user argument (not used internally; reserved for RTOS compatibility).
Details:
- Must be called periodically every
EMBLED_CYCLE_TIME_MS
(default: 100 ms) by:- A hardware timer interrupt, or
- A FreeRTOS task using
vTaskDelay()or a software timer.
- Responsible for:
- Applying pending shadow updates (
shadow.enabled). - Advancing LED state transitions according to their active profiles.
- Automatically restoring previous modes if
return_last_mode == true.
- Applying pending shadow updates (
bool embled_set_mode(uint16_t pin, embled_driver_mode_t driver_mode, embled_modes_t new_mode, embled_levels_t level, bool return_last_mode)Activates a new LED mode on the specified pin.
Parameters:
pin: Hardware pin identifier (application-defined).driver_mode: Output driver type (EMBLED_DRIVER_MODE_DIGITALorEMBLED_DRIVER_MODE_PWM).new_mode: One of the predefined modes fromembled_modes_t.level: Active logic level (EMBLED_ACTIVE_HIGHorEMBLED_ACTIVE_LOW).return_last_mode:- When
true, the current active mode is stored inbackup. - Once
new_modefinishes, the previous mode is automatically restored.
Useful for temporary actions like one-shot pulses or indications.
- When
Returns:
trueif the mode request was successfully queued.falseif:- No free LED slot is available.
- A shadow update is already pending for that pin.
- The driver mode differs from the one previously assigned to the same pin.
Thread Safety:
- Safe to call from any task context.
- Updates are atomic; no mutex or lock required.
int8_t embled_new_profile(uint8_t num_states, uint16_t num_repetitions, uint16_t* duration_ms)Creates a dynamic LED profile at runtime, allowing custom blink or pulse patterns.
Parameters:
num_states: Number of ON/OFF states in the sequence (1–EMBLED_MAX_STATES).num_repetitions:- Number of times the sequence repeats.
- Use
EMBLED_INFINITEfor continuous patterns.
duration_ms: Array ofnum_stateselements, each defining the duration (in milliseconds) of each state.
Returns:
- Index (
≥ 0) of the newly created mode (e.g.,EMBLED_MODE_DYNAMIC_1). -1if:num_statesexceedsEMBLED_MAX_STATES.- No free dynamic profile slot is available.
- Invalid parameter values.
Behavior:
- Dynamic profiles occupy one of the reserved slots (
EMBLED_MODE_DYNAMIC_1…_5). - Finite profiles are automatically cleared once the sequence completes, freeing the slot.
- Initialize embled and set a digital LED
#include "embled.h"
// Minimal callbacks (replace with your platform HAL). PWM omitted if not used.
static void cb_write(uint16_t pin, bool level) { (void)pin; (void)level; }
static bool cb_read(uint16_t pin) { (void)pin; return false; }
void app_setup(void) {
embled_callbacks_t cbks = {
.write_gpio = cb_write,
.read_gpio = cb_read,
.start_pwm = NULL,
.stop_pwm = NULL,
};
embled_init(&cbks);
// Configure a timer/RTOS to call embled_task() every 100 ms
// ...
// Turn ON LED on pin 5 (digital, active-high)
embled_set_mode(5, EMBLED_DRIVER_MODE_DIGITAL, EMBLED_MODE_ON, EMBLED_ACTIVE_HIGH, false);
}- Create a dynamic profile and activate it (200ms ON, 200ms OFF, 800ms ON, 400ms OFF)
// on/off/on/off in milliseconds
uint16_t pattern_ms[] = { 200, 200, 800, 400 };
int8_t mode_idx = embled_new_profile(4, EMBLED_INFINITE, pattern_ms);
if (mode_idx >= 0) {
embled_set_mode(5, EMBLED_DRIVER_MODE_DIGITAL, (embled_modes_t) mode_idx, EMBLED_ACTIVE_HIGH, false);
}- Temporary mode (blink once) and restore the previous state
// Start steady ON mode
embled_set_mode(5, EMBLED_DRIVER_MODE_DIGITAL, EMBLED_MODE_ON, EMBLED_ACTIVE_HIGH, false);
// Perform one fast blink, then return to ON automatically
embled_set_mode(5, EMBLED_DRIVER_MODE_DIGITAL, EMBLED_MODE_PULSE_FAST_ONCE, EMBLED_ACTIVE_HIGH, true);-
Static memory:
embleduses only static allocation, ensuring predictable memory usage and zero heap fragmentation. -
Number of supported LEDs — default: 4
EMBLED_NUM_LEDSdefines how many LEDs can be controlled simultaneously.
Adjust this value according to your hardware and memory constraints. -
Maximum profile states — default: 10
EMBLED_MAX_STATESdefines the maximum number of states per LED profile (e.g., ON/OFF transitions). -
Driver mode change:
Changing the driver type (e.g., from digital to PWM) of an already active pin is not allowed.
To reconfigure the driver, first set the LED toEMBLED_MODE_OFF. -
Update Limitations:
Ifembled_set_mode()is called multiple times within a period shorter thanEMBLED_CYCLE_TIME_MS,
only the first call will take effect; subsequent calls are ignored until the next update cycle. -
LED brightness control:
Brightness control via PWM duty cycle is supported in hardware but not yet implemented in the library API. -
Time base: — default: 100
EMBLED_CYCLE_TIME_MSdefines the base time to executeembled_task. All durations are stored in ticks, where1 tick = 100 ms. -
Timing precision:
The timing accuracy of LED profiles depends on your system architecture — including timer interrupt priority or RTOS task scheduling.
Some variations in blink timing may occur under heavy system load.
💡 Tip: Keep the 100 ms base unless you have strict timing requirements.
It offers a good balance between responsiveness and low CPU or RTOS overhead.
-
examples/embled_stm32— Demonstrates integration with STM32 HAL using both GPIO and PWM drivers.
Includes bare-metal and FreeRTOS variants.
Build with STM32CubeIDE
Licensed under the MIT License
See the LICENSE file at the repository root.
- Enhancements: please fork the repository and open a Pull Request.
- Bugs: open a new Issue with a minimal reproducible example when possible.
- Direct contact:
fabricio-lucasfbr@hotmail.com
marcelobarrosalmeida@gmail.com