Initial: HAL_LED pixel buffer with intensity scaling over PIO

This commit is contained in:
Mohamed Salem 2026-04-13 03:51:41 +02:00
commit b767b3c5b9
5 changed files with 303 additions and 0 deletions

19
cfg/HAL_LED_cfg.c Normal file
View File

@ -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,
},
};

46
cfg/HAL_LED_cfg.h Normal file
View File

@ -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 */

70
inc/HAL_LED.h Normal file
View File

@ -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 */

117
prg/HAL_LED_prg.c Normal file
View File

@ -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;
}

51
prg/HAL_LED_priv.h Normal file
View File

@ -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 */