commit b767b3c5b9cd4313f89e2184955b28e877431f8c Author: Mohamed Salem Date: Mon Apr 13 03:51:41 2026 +0200 Initial: HAL_LED pixel buffer with intensity scaling over PIO diff --git a/cfg/HAL_LED_cfg.c b/cfg/HAL_LED_cfg.c new file mode 100644 index 0000000..2e90e93 --- /dev/null +++ b/cfg/HAL_LED_cfg.c @@ -0,0 +1,19 @@ +/****************************************************************************** + * File: HAL_LED_cfg.c + * Component: HAL_LED + * Description: Configuration array definition for the LED abstraction. + * + * Layer: HAL - configuration + *****************************************************************************/ + +#include "HAL_LED.h" +#include "HAL_LED_cfg.h" + +const HAL_LED_tstrConfig HAL_LED_astrConfig[HAL_LED_NUM_INSTANCES] = +{ + [HAL_LED_INSTANCE_ONBOARD] = + { + .u8NumLeds = HAL_LED_ONBOARD_NUM_LEDS, + .u8PioInstance = HAL_LED_ONBOARD_PIO_INSTANCE, + }, +}; \ No newline at end of file diff --git a/cfg/HAL_LED_cfg.h b/cfg/HAL_LED_cfg.h new file mode 100644 index 0000000..06b1b47 --- /dev/null +++ b/cfg/HAL_LED_cfg.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * File: HAL_LED_cfg.h + * Component: HAL_LED + * Description: Configuration header for the LED abstraction layer. + * Defines LED strip instances, maximum strip length, + * and per-instance settings. + * + * Layer: HAL - configuration + *****************************************************************************/ + +#ifndef HAL_LED_CFG_H +#define HAL_LED_CFG_H + +#include "STD_TYPES.h" + +/* ------------------------------------------------------------------------ */ +/* INSTANCE ENUMERATION */ +/* ------------------------------------------------------------------------ */ + +typedef enum +{ + HAL_LED_INSTANCE_ONBOARD = 0U, /**< Onboard WS2812B on RP2040-Zero */ + HAL_LED_NUM_INSTANCES +} HAL_LED_tenuInstance; + +/* ------------------------------------------------------------------------ */ +/* BUFFER SIZING */ +/* ------------------------------------------------------------------------ */ + +/** @brief Maximum number of LEDs any single instance can support. + * Determines the pixel buffer size in the control struct. + * Increase when adding longer strips. */ +#define HAL_LED_MAX_LEDS_PER_INSTANCE 1U + +/* ------------------------------------------------------------------------ */ +/* INSTANCE 0 (ONBOARD) CONFIGURATION */ +/* ------------------------------------------------------------------------ */ + +/** @brief Number of LEDs in the onboard strip (just 1 on the RP2040-Zero). */ +#define HAL_LED_ONBOARD_NUM_LEDS 1U + +/** @brief MCU_PIO instance index for the onboard LED. + * Maps to MCU_PIO_INSTANCE_WS2812 (defined in MCU_PIO_cfg.h). */ +#define HAL_LED_ONBOARD_PIO_INSTANCE 0U + +#endif /* HAL_LED_CFG_H */ \ No newline at end of file diff --git a/inc/HAL_LED.h b/inc/HAL_LED.h new file mode 100644 index 0000000..536194e --- /dev/null +++ b/inc/HAL_LED.h @@ -0,0 +1,70 @@ +/****************************************************************************** + * File: HAL_LED.h + * Component: HAL_LED + * Description: Public interface for the LED abstraction layer. + * Manages a pixel buffer for WS2812-style addressable LEDs + * and pushes color data through MCU_PIO. Supports indexed + * LED strips with per-pixel intensity scaling. + * + * SetColor sets one LED's color and immediately pushes the + * entire strip to the hardware — no separate Update call needed. + * + * Layer: HAL (hardware abstraction, one level above MCU drivers) + *****************************************************************************/ + +#ifndef HAL_LED_H +#define HAL_LED_H + +#include "STD_TYPES.h" + +/* ------------------------------------------------------------------------ */ +/* CONFIGURATION STRUCTURE */ +/* ------------------------------------------------------------------------ */ + +/** + * @brief Per-instance LED strip/array configuration. + * + * One entry per LED strip, stored in HAL_LED_astrConfig[]. + * The array index is the instance parameter in all public API calls. + */ +typedef struct +{ + u8 u8NumLeds; /**< Number of LEDs in this strip (1 for single LED) */ + u8 u8PioInstance; /**< MCU_PIO config index for the data output */ +} HAL_LED_tstrConfig; + +/* ------------------------------------------------------------------------ */ +/* PUBLIC API */ +/* ------------------------------------------------------------------------ */ + +/** + * @brief Initialize the LED abstraction layer. + * + * Clears the internal pixel buffer to all-off (black). Does NOT init + * MCU_PIO — SYS_ECU must call MCU_PIO_enuInit() before this. + * + * @return STD_OK on success. + */ +STD_tenuResult HAL_LED_enuInit(void); + +/** + * @brief Set the color of a single LED and push the entire strip. + * + * Scales each color channel by u8Intensity (0-255), stores the result + * in the internal pixel buffer, then immediately pushes all LEDs in + * this strip to the PIO state machine. + * + * @param u8Instance HAL_LED config instance. + * @param u8LedIndex LED position in the strip (0-based). + * @param u8Red Red intensity (0-255, before scaling). + * @param u8Green Green intensity (0-255, before scaling). + * @param u8Blue Blue intensity (0-255, before scaling). + * @param u8Intensity Global brightness scaler (0-255). 255 = full. + * @return STD_OK on success, + * STD_INDEX_OUT_OF_RANGE_ERROR if u8LedIndex >= u8NumLeds. + */ +STD_tenuResult HAL_LED_enuSetColor(u8 u8Instance, u8 u8LedIndex, + u8 u8Red, u8 u8Green, u8 u8Blue, + u8 u8Intensity); + +#endif /* HAL_LED_H */ \ No newline at end of file diff --git a/prg/HAL_LED_prg.c b/prg/HAL_LED_prg.c new file mode 100644 index 0000000..272911e --- /dev/null +++ b/prg/HAL_LED_prg.c @@ -0,0 +1,117 @@ +/****************************************************************************** + * File: HAL_LED_prg.c + * Component: HAL_LED + * Description: LED abstraction implementation. Manages a pixel buffer with + * intensity scaling and pushes color data to the hardware via + * MCU_PIO. SetColor updates one LED and immediately pushes the + * entire strip — no separate Update call needed. + * + * Layer: HAL + *****************************************************************************/ + +#include "HAL_LED.h" +#include "HAL_LED_priv.h" +#include "HAL_LED_cfg.h" + +#include "MCU_PIO.h" + +/* ------------------------------------------------------------------------ */ +/* RUNTIME STATE */ +/* ------------------------------------------------------------------------ */ + +static HAL_LED_tstrControl strControl; + +/* ------------------------------------------------------------------------ */ +/* INTERNAL HELPERS */ +/* ------------------------------------------------------------------------ */ + +/** + * @brief Push the entire pixel buffer for one instance to the PIO FIFO. + * + * Iterates through the pixel buffer, packs each pixel into a 32-bit + * GRB word (left-justified: G in [31:24], R in [23:16], B in [15:8], + * bits [7:0] unused), and sends it via MCU_PIO_vPutBlocking. + * + * @param u8Instance HAL_LED instance index. + */ +static void vPushStrip(u8 u8Instance) +{ + u8 u8PioInstLoc = HAL_LED_astrConfig[u8Instance].u8PioInstance; + u8 u8NumLedsLoc = HAL_LED_astrConfig[u8Instance].u8NumLeds; + u8 u8LedLoc; + + for (u8LedLoc = 0U; u8LedLoc < u8NumLedsLoc; u8LedLoc++) + { + HAL_LED_tstrPixel *pstrPixLoc = &strControl.astrPixels[u8Instance][u8LedLoc]; + + /* Pack RGB into bits [31:8] of the 32-bit word. + * The WS2812 variant on the RP2040-Zero uses RGB byte order + * (red first, green second, blue third) rather than the standard + * GRB. Bits [7:0] are padding (shifted out but ignored). */ + u32 u32RgbLoc = ((u32)pstrPixLoc->u8Red << 24U) + | ((u32)pstrPixLoc->u8Green << 16U) + | ((u32)pstrPixLoc->u8Blue << 8U); + + MCU_PIO_vPutBlocking(u8PioInstLoc, u32RgbLoc); + } +} + +/* ========================================================================= */ +/* INIT */ +/* ========================================================================= */ + +STD_tenuResult HAL_LED_enuInit(void) +{ + STD_tenuResult enuResultLoc = STD_OK; + u8 u8InstLoc; + u8 u8LedLoc; + + /* Clear all pixels to off (black) */ + for (u8InstLoc = 0U; u8InstLoc < (u8)HAL_LED_NUM_INSTANCES; u8InstLoc++) + { + for (u8LedLoc = 0U; u8LedLoc < HAL_LED_astrConfig[u8InstLoc].u8NumLeds; u8LedLoc++) + { + strControl.astrPixels[u8InstLoc][u8LedLoc].u8Green = 0U; + strControl.astrPixels[u8InstLoc][u8LedLoc].u8Red = 0U; + strControl.astrPixels[u8InstLoc][u8LedLoc].u8Blue = 0U; + } + } + + return enuResultLoc; +} + +/* ========================================================================= */ +/* SET COLOR */ +/* ========================================================================= */ + +STD_tenuResult HAL_LED_enuSetColor(u8 u8Instance, u8 u8LedIndex, + u8 u8Red, u8 u8Green, u8 u8Blue, + u8 u8Intensity) +{ + STD_tenuResult enuResultLoc = STD_OK; + u8 u8NumLedsLoc = HAL_LED_astrConfig[u8Instance].u8NumLeds; + + if (u8LedIndex >= u8NumLedsLoc) + { + enuResultLoc = STD_INDEX_OUT_OF_RANGE_ERROR; + } + else + { + /* Scale each channel by intensity: (channel * intensity) / 255. + * Use u16 intermediate to avoid overflow (255 * 255 = 65025, + * which fits in u16 but not u8). */ + u8 u8ScaledRLoc = (u8)(((u16)u8Red * (u16)u8Intensity) / 255U); + u8 u8ScaledGLoc = (u8)(((u16)u8Green * (u16)u8Intensity) / 255U); + u8 u8ScaledBLoc = (u8)(((u16)u8Blue * (u16)u8Intensity) / 255U); + + /* Store the scaled pixel in the buffer */ + strControl.astrPixels[u8Instance][u8LedIndex].u8Red = u8ScaledRLoc; + strControl.astrPixels[u8Instance][u8LedIndex].u8Green = u8ScaledGLoc; + strControl.astrPixels[u8Instance][u8LedIndex].u8Blue = u8ScaledBLoc; + + /* Immediately push the entire strip to the hardware */ + vPushStrip(u8Instance); + } + + return enuResultLoc; +} \ No newline at end of file diff --git a/prg/HAL_LED_priv.h b/prg/HAL_LED_priv.h new file mode 100644 index 0000000..169757e --- /dev/null +++ b/prg/HAL_LED_priv.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * File: HAL_LED_priv.h + * Component: HAL_LED + * Description: Private header — pixel struct, control struct with the + * pixel buffer, and extern config array declaration. + * + * Layer: HAL - internal use only + *****************************************************************************/ + +#ifndef HAL_LED_PRIV_H +#define HAL_LED_PRIV_H + +#include "HAL_LED.h" +#include "HAL_LED_cfg.h" + +extern const HAL_LED_tstrConfig HAL_LED_astrConfig[HAL_LED_NUM_INSTANCES]; + +/* ------------------------------------------------------------------------ */ +/* PIXEL STRUCTURE */ +/* ------------------------------------------------------------------------ */ + +/** + * @brief Per-LED color data in GRB order (matching WS2812 protocol). + * + * Stored after intensity scaling has been applied, so these values + * are the actual brightnesses sent to the hardware. + */ +typedef struct +{ + u8 u8Green; + u8 u8Red; + u8 u8Blue; +} HAL_LED_tstrPixel; + +/* ------------------------------------------------------------------------ */ +/* CONTROL STRUCTURE */ +/* ------------------------------------------------------------------------ */ + +/** + * @brief Internal runtime state for all HAL_LED instances. + * + * astrPixels is a 2D array: [instance][led_index]. Each pixel holds + * the intensity-scaled GRB values ready to be packed into 32-bit words + * for the PIO FIFO. + */ +typedef struct +{ + HAL_LED_tstrPixel astrPixels[HAL_LED_NUM_INSTANCES][HAL_LED_MAX_LEDS_PER_INSTANCE]; +} HAL_LED_tstrControl; + +#endif /* HAL_LED_PRIV_H */ \ No newline at end of file