From 7a2f70165326609a856ac16d0e9011b623c8c6d2 Mon Sep 17 00:00:00 2001 From: Blitblank Date: Wed, 11 Feb 2026 20:57:15 -0600 Subject: [PATCH 1/4] add untested wsled drivers --- src/drivers/wsled.c | 118 ++++++++++++++++++++++++++++++++++++++++++++ src/drivers/wsled.h | 47 ++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 src/drivers/wsled.c create mode 100644 src/drivers/wsled.h diff --git a/src/drivers/wsled.c b/src/drivers/wsled.c new file mode 100644 index 0000000..82d3171 --- /dev/null +++ b/src/drivers/wsled.c @@ -0,0 +1,118 @@ + +#include "esp_ws28xx.h" + +uint16_t* dmaBuffer; +CRGB* wsledPixels; +static int ledCount, resetDelay, dmaBufferSize; +WsledType type; + +static spi_settings_t spiSettings = { + .host = SPI2_HOST, + .dma_chan = SPI_DMA_CH_AUTO, + .buscfg = + { + .miso_io_num = -1, + .sclk_io_num = -1, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + }, + .devcfg = + { + .clock_speed_hz = 3.2 * 1000 * 1000, // Clock out at 3.2 MHz + .mode = 0, // SPI mode 0 + .spics_io_num = -1, // CS pin + .queue_size = 1, + .command_bits = 0, + .address_bits = 0, + .flags = SPI_DEVICE_TXBIT_LSBFIRST, + }, +}; + +static const uint16_t timing_bits[16] = { + 0x1111, 0x7111, 0x1711, 0x7711, 0x1171, 0x7171, 0x1771, 0x7771, + 0x1117, 0x7117, 0x1717, 0x7717, 0x1177, 0x7177, 0x1777, 0x7777}; + +esp_err_t wsledInit(wsled_t* dev, CRGB** buffer) { + + type = dev->type; + ledCount = dev->numLeds; + resetDelay = (dev.wsledType == WS2812B) ? WSLED_12_RESET_TIME : WSLED_15_RESET_TIME; + + // 12 bytes for each led + bytes for initial zero and reset state + dmaBufferSize = dev->numLeds * 12 + (resetDelay + 1) * 2; + wsledPixels = malloc(sizeof(CRGB) * dev->numLeds); + if (wsledPixels == NULL) { + return ESP_ERR_NO_MEM; + } + *buffer = wsledPixels; + spi_settings.buscfg.mosi_io_num = pin; + spi_settings.buscfg.max_transfer_sz = dmaBufferSize; + + if (ESP_OK != spi_bus_initialize(spi_settings.host, &spi_settings.buscfg, spi_settings.dma_chan)) { + free(wsledPixels); + return -1; + } + + if (ESP_OK != spi_bus_add_device(spi_settings.host, &spi_settings.devcfg, &spi_settings.spi)) { + free(wsledPixels); + return -1; + } + + if (NULL == heap_caps_malloc(dmaBufferSize, MALLOC_CAP_DMA)) { + free(wsledPixels); + return -1; + } + return ESP_OK; +} + +void wsledFill(CRGB color) { + for (int i = 0; i < n_of_leds; i++) { + ws28xx_pixels[i] = color; + } +} + +esp_err_t wsledUpdate() { + + uint32_t n = 0; + + memset(dmaBuffer, 0, dmaBufferSize); + dmaBuffer[n++] = 0; + + for (int i = 0; i < ledCount; i++) { + + // Data you want to write to each LEDs + + CRGB currentPixel = wsledPixels[i]; + + uint32_t packedData; + if(type == WS2812B) { // different models have different color orders + packedData = currentPixel.g | ((uint32_t)currentPixel.r << 8) | ((uint32_t)currentPixel.b << 16) | ((uint32_t)(0x00) << 24); + } else { + packedData = currentPixel.r | ((uint32_t)currentPixel.g << 8) | ((uint32_t)currentPixel.b << 16) | ((uint32_t)(0x00) << 24); + } + + // Red + dmaBuffer[n++] = timing_bits[0x0f & (packedData >> 4)]; + dmaBuffer[n++] = timing_bits[0x0f & (packedData)]; + + // Green + dmaBuffer[n++] = timing_bits[0x0f & (packedData >> 12)]; + dmaBuffer[n++] = timing_bits[0x0f & (packedData) >> 8]; + + // Blue + dma_buffer[n++] = timing_bits[0x0f & (packedData >> 20)]; + dma_buffer[n++] = timing_bits[0x0f & (packedData) >> 16]; + + } + + // reset pulse + for (int i = 0; i < resetDelay; i++) { + dmaBuffer[n++] = 0; + } + + esp_err_t error = spi_device_transmit(spi_settings.spi, &(spi_transaction_t) { + .length = dmaBufferSize * 8, + .tx_buffer = dmaBuffer, + }); + return error; +} \ No newline at end of file diff --git a/src/drivers/wsled.h b/src/drivers/wsled.h new file mode 100644 index 0000000..217cdc9 --- /dev/null +++ b/src/drivers/wsled.h @@ -0,0 +1,47 @@ + +#pragma once + +#include "driver/gpio.h" +#include "driver/spi_master.h" +#include +#include + +#define WSLED_12_RESET_TIME 3 +#define WSLED_15_RESET_TIME 30 + +typedef struct { + uint8_t r; + uint8_t g; + uint8_t b; +} CRGB; + +typedef enum { + WS2812B = 0, + WS2815 +} WsledType; + +typedef struct { + spi_host_device_t host; + spi_device_handle_t spi; + int dma_chan; + spi_device_interface_config_t devcfg; + spi_bus_config_t buscfg; +} spi_settings_t; + +typedef enum { + WS2812B = 0, + WS2815, +} led_strip_model_t; + +typedef struct { + gpio_num_t pin; + WsledType type; + uint32_t numLeds; +} wsled_t; + +esp_err_t wsledInit(wsled_t* dev, CRGB** buffer); + +// test function +esp_err_t wsledFillAll(CRGB color); + +esp_err_t wsledUpdate(); From bb8dcd76b25dd7317916b994f80b5f9723b58749 Mon Sep 17 00:00:00 2001 From: Blitblank Date: Wed, 11 Feb 2026 22:31:03 -0600 Subject: [PATCH 2/4] fix wsled build --- src/CMakeLists.txt | 1 + src/drivers/wsled.c | 38 ++++++++++++++++++++------------------ src/drivers/wsled.h | 5 ----- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ff8896e..7cce900 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,5 +9,6 @@ idf_component_register( SRCS ${SRC_FILES} PRIV_REQUIRES spi_flash REQUIRES esp_driver_gpio + REQUIRES esp_driver_spi INCLUDE_DIRS "." ) diff --git a/src/drivers/wsled.c b/src/drivers/wsled.c index 82d3171..d996180 100644 --- a/src/drivers/wsled.c +++ b/src/drivers/wsled.c @@ -1,5 +1,7 @@ -#include "esp_ws28xx.h" +#include "wsled.h" + +#include "esp_heap_caps.h" uint16_t* dmaBuffer; CRGB* wsledPixels; @@ -28,7 +30,7 @@ static spi_settings_t spiSettings = { }, }; -static const uint16_t timing_bits[16] = { +static const uint16_t timingBits[16] = { 0x1111, 0x7111, 0x1711, 0x7711, 0x1171, 0x7171, 0x1771, 0x7771, 0x1117, 0x7117, 0x1717, 0x7717, 0x1177, 0x7177, 0x1777, 0x7777}; @@ -36,24 +38,24 @@ esp_err_t wsledInit(wsled_t* dev, CRGB** buffer) { type = dev->type; ledCount = dev->numLeds; - resetDelay = (dev.wsledType == WS2812B) ? WSLED_12_RESET_TIME : WSLED_15_RESET_TIME; + resetDelay = (dev->type == WS2812B) ? WSLED_12_RESET_TIME : WSLED_15_RESET_TIME; // 12 bytes for each led + bytes for initial zero and reset state - dmaBufferSize = dev->numLeds * 12 + (resetDelay + 1) * 2; - wsledPixels = malloc(sizeof(CRGB) * dev->numLeds); + dmaBufferSize = ledCount * 12 + (resetDelay + 1) * 2; + wsledPixels = malloc(sizeof(CRGB) * ledCount); if (wsledPixels == NULL) { return ESP_ERR_NO_MEM; } *buffer = wsledPixels; - spi_settings.buscfg.mosi_io_num = pin; - spi_settings.buscfg.max_transfer_sz = dmaBufferSize; + spiSettings.buscfg.mosi_io_num = dev->pin; + spiSettings.buscfg.max_transfer_sz = dmaBufferSize; - if (ESP_OK != spi_bus_initialize(spi_settings.host, &spi_settings.buscfg, spi_settings.dma_chan)) { + if (ESP_OK != spi_bus_initialize(spiSettings.host, &spiSettings.buscfg, spiSettings.dma_chan)) { free(wsledPixels); return -1; } - if (ESP_OK != spi_bus_add_device(spi_settings.host, &spi_settings.devcfg, &spi_settings.spi)) { + if (ESP_OK != spi_bus_add_device(spiSettings.host, &spiSettings.devcfg, &spiSettings.spi)) { free(wsledPixels); return -1; } @@ -66,8 +68,8 @@ esp_err_t wsledInit(wsled_t* dev, CRGB** buffer) { } void wsledFill(CRGB color) { - for (int i = 0; i < n_of_leds; i++) { - ws28xx_pixels[i] = color; + for (int i = 0; i < ledCount; i++) { + wsledPixels[i] = color; } } @@ -92,16 +94,16 @@ esp_err_t wsledUpdate() { } // Red - dmaBuffer[n++] = timing_bits[0x0f & (packedData >> 4)]; - dmaBuffer[n++] = timing_bits[0x0f & (packedData)]; + dmaBuffer[n++] = timingBits[0x0f & (packedData >> 4)]; + dmaBuffer[n++] = timingBits[0x0f & (packedData)]; // Green - dmaBuffer[n++] = timing_bits[0x0f & (packedData >> 12)]; - dmaBuffer[n++] = timing_bits[0x0f & (packedData) >> 8]; + dmaBuffer[n++] = timingBits[0x0f & (packedData >> 12)]; + dmaBuffer[n++] = timingBits[0x0f & (packedData) >> 8]; // Blue - dma_buffer[n++] = timing_bits[0x0f & (packedData >> 20)]; - dma_buffer[n++] = timing_bits[0x0f & (packedData) >> 16]; + dmaBuffer[n++] = timingBits[0x0f & (packedData >> 20)]; + dmaBuffer[n++] = timingBits[0x0f & (packedData) >> 16]; } @@ -110,7 +112,7 @@ esp_err_t wsledUpdate() { dmaBuffer[n++] = 0; } - esp_err_t error = spi_device_transmit(spi_settings.spi, &(spi_transaction_t) { + esp_err_t error = spi_device_transmit(spiSettings.spi, &(spi_transaction_t) { .length = dmaBufferSize * 8, .tx_buffer = dmaBuffer, }); diff --git a/src/drivers/wsled.h b/src/drivers/wsled.h index 217cdc9..bbedbe8 100644 --- a/src/drivers/wsled.h +++ b/src/drivers/wsled.h @@ -28,11 +28,6 @@ typedef struct { spi_bus_config_t buscfg; } spi_settings_t; -typedef enum { - WS2812B = 0, - WS2815, -} led_strip_model_t; - typedef struct { gpio_num_t pin; WsledType type; From 9f884b41e7909894d3212c7b79bfdcb06d14eb27 Mon Sep 17 00:00:00 2001 From: Blitblank Date: Fri, 13 Feb 2026 12:21:31 -0600 Subject: [PATCH 3/4] working wsled driver checkpoint --- scripts/build.sh | 1 + scripts/flash.sh | 1 + scripts/monitor.sh | 1 + src/DemoTask.cpp | 23 +++++++++++++++-- src/drivers/wsled.c | 61 +++++++++++++++++++++++++++++---------------- src/drivers/wsled.h | 12 +++++++-- 6 files changed, 74 insertions(+), 25 deletions(-) mode change 100644 => 100755 scripts/build.sh mode change 100644 => 100755 scripts/flash.sh mode change 100644 => 100755 scripts/monitor.sh diff --git a/scripts/build.sh b/scripts/build.sh old mode 100644 new mode 100755 index 89504eb..b4a3750 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -8,6 +8,7 @@ export IDF_PATH=${PWD}/lib/esp-idf export SDKCONFIG=${PWD}/config/sdkconfig export SDKCONFIG_DEFAULTS=${PWD}/config/sdkconfig.defaults +export IDF_PATH_FORCE=1 . ${IDF_PATH}/export.sh idf.py set-target esp32s3 diff --git a/scripts/flash.sh b/scripts/flash.sh old mode 100644 new mode 100755 index 3fa43aa..b8a5ce4 --- a/scripts/flash.sh +++ b/scripts/flash.sh @@ -8,6 +8,7 @@ export IDF_PATH=${PWD}/lib/esp-idf export SDKCONFIG=${PWD}/config/sdkconfig export SDKCONFIG_DEFAULTS=${PWD}/config/sdkconfig.defaults +export IDF_PATH_FORCE=1 . ${IDF_PATH}/export.sh idf.py fullclean diff --git a/scripts/monitor.sh b/scripts/monitor.sh old mode 100644 new mode 100755 index 4ce5a6d..b61b1a7 --- a/scripts/monitor.sh +++ b/scripts/monitor.sh @@ -5,6 +5,7 @@ set -e export IDF_TOOLS_PATH=${PWD}/lib/idf-tools export IDF_PATH=${PWD}/lib/esp-idf +export IDF_PATH_FORCE=1 . ${IDF_PATH}/export.sh idf.py -b 115200 monitor diff --git a/src/DemoTask.cpp b/src/DemoTask.cpp index a5bad7b..5be07ba 100644 --- a/src/DemoTask.cpp +++ b/src/DemoTask.cpp @@ -8,6 +8,7 @@ #include "SsdInterface.hpp" #include "pins.hpp" +#include "drivers/wsled.h" DemoTask::DemoTask() { @@ -17,8 +18,16 @@ void DemoTask::run() { ESP_LOGI(__FILE__, "Demo Task: run()"); - ssd_595_t dev = { gpio_ssd_data, gpio_ssd_clk, gpio_ssd_latch, true }; - SsdInterface ssd(&dev, ssdDigits); + // ssd device + ssd_595_t ssdDev = { gpio_ssd_data, gpio_ssd_clk, gpio_ssd_latch, true }; + SsdInterface ssd(&ssdDev, ssdDigits); + + // wsled device + size_t ledCount = 4; + wsled_t wsledDev = { gpio_ws2812b, WS2812B, ledCount}; + // TODO: wsled interface + CRGB ledBuffer[4]; + wsledInit(&wsledDev, (CRGB**)&ledBuffer); uint32_t delay = 500; // ms uint8_t digit = 0; @@ -28,6 +37,16 @@ void DemoTask::run() { digit++; if(digit >= 16) digit = 0; + //ledBuffer[0] = CRGB{100, 0, 80}; + wsledFill(CRGB{100, 20, 20}); + wsledUpdate(); + + vTaskDelay(delay / portTICK_PERIOD_MS); + + //ledBuffer[0] = CRGB{0, 0, 10}; + wsledFill(CRGB{20, 20, 100}); + wsledUpdate(); + vTaskDelay(delay / portTICK_PERIOD_MS); } diff --git a/src/drivers/wsled.c b/src/drivers/wsled.c index d996180..9b6282a 100644 --- a/src/drivers/wsled.c +++ b/src/drivers/wsled.c @@ -2,10 +2,17 @@ #include "wsled.h" #include "esp_heap_caps.h" +#include "esp_log.h" + +#ifdef __cplusplus +extern "C" { +#endif uint16_t* dmaBuffer; CRGB* wsledPixels; -static int ledCount, resetDelay, dmaBufferSize; +static uint32_t ledCount; +static uint32_t resetDelay; +static size_t dmaBufferSize; WsledType type; static spi_settings_t spiSettings = { @@ -26,7 +33,7 @@ static spi_settings_t spiSettings = { .queue_size = 1, .command_bits = 0, .address_bits = 0, - .flags = SPI_DEVICE_TXBIT_LSBFIRST, + //.flags = SPI_DEVICE_TXBIT_LSBFIRST, }, }; @@ -36,41 +43,54 @@ static const uint16_t timingBits[16] = { esp_err_t wsledInit(wsled_t* dev, CRGB** buffer) { + ESP_LOGI(__FILE__, "Initializing wsled device..."); + type = dev->type; ledCount = dev->numLeds; resetDelay = (dev->type == WS2812B) ? WSLED_12_RESET_TIME : WSLED_15_RESET_TIME; + ESP_LOGI(__FILE__, "mallocing the wsledPixel buffer with size %u bytes", sizeof(CRGB) * ledCount); + // 12 bytes for each led + bytes for initial zero and reset state dmaBufferSize = ledCount * 12 + (resetDelay + 1) * 2; wsledPixels = malloc(sizeof(CRGB) * ledCount); if (wsledPixels == NULL) { + ESP_LOGI(__FILE__, "Allocating memory failed"); return ESP_ERR_NO_MEM; } *buffer = wsledPixels; spiSettings.buscfg.mosi_io_num = dev->pin; spiSettings.buscfg.max_transfer_sz = dmaBufferSize; + ESP_LOGI(__FILE__, "Initializing spi interface..."); if (ESP_OK != spi_bus_initialize(spiSettings.host, &spiSettings.buscfg, spiSettings.dma_chan)) { free(wsledPixels); + ESP_LOGI(__FILE__, "SPI initialization failed"); return -1; } + ESP_LOGI(__FILE__, "Adding spi bus device..."); if (ESP_OK != spi_bus_add_device(spiSettings.host, &spiSettings.devcfg, &spiSettings.spi)) { free(wsledPixels); + ESP_LOGI(__FILE__, "Failed to add spi bus device"); return -1; } - if (NULL == heap_caps_malloc(dmaBufferSize, MALLOC_CAP_DMA)) { + ESP_LOGI(__FILE__, "heap_caps_malloc() with dmaBufferSize=%u...", dmaBufferSize); + dmaBuffer = heap_caps_malloc(dmaBufferSize, MALLOC_CAP_DMA); + if (NULL == dmaBuffer) { free(wsledPixels); + ESP_LOGI(__FILE__, "Failed to heap_caps_malloc"); return -1; } return ESP_OK; } -void wsledFill(CRGB color) { +esp_err_t wsledFill(CRGB color) { for (int i = 0; i < ledCount; i++) { wsledPixels[i] = color; } + return 0; } esp_err_t wsledUpdate() { @@ -82,28 +102,23 @@ esp_err_t wsledUpdate() { for (int i = 0; i < ledCount; i++) { - // Data you want to write to each LEDs - CRGB currentPixel = wsledPixels[i]; - uint32_t packedData; - if(type == WS2812B) { // different models have different color orders - packedData = currentPixel.g | ((uint32_t)currentPixel.r << 8) | ((uint32_t)currentPixel.b << 16) | ((uint32_t)(0x00) << 24); - } else { - packedData = currentPixel.r | ((uint32_t)currentPixel.g << 8) | ((uint32_t)currentPixel.b << 16) | ((uint32_t)(0x00) << 24); - } - - // Red - dmaBuffer[n++] = timingBits[0x0f & (packedData >> 4)]; - dmaBuffer[n++] = timingBits[0x0f & (packedData)]; + uint8_t b0 = (type == WS2812B) ? currentPixel.g : currentPixel.r; + uint8_t b1 = (type == WS2812B) ? currentPixel.r : currentPixel.g; + uint8_t b2 = currentPixel.b; // Green - dmaBuffer[n++] = timingBits[0x0f & (packedData >> 12)]; - dmaBuffer[n++] = timingBits[0x0f & (packedData) >> 8]; + dmaBuffer[n++] = timingBits[(b0 >> 4) & 0x0F]; + dmaBuffer[n++] = timingBits[b0 & 0x0F]; + + // Red + dmaBuffer[n++] = timingBits[(b1 >> 4) & 0x0F]; + dmaBuffer[n++] = timingBits[b1 & 0x0F]; // Blue - dmaBuffer[n++] = timingBits[0x0f & (packedData >> 20)]; - dmaBuffer[n++] = timingBits[0x0f & (packedData) >> 16]; + dmaBuffer[n++] = timingBits[(b2 >> 4) & 0x0F]; + dmaBuffer[n++] = timingBits[b2 & 0x0F]; } @@ -117,4 +132,8 @@ esp_err_t wsledUpdate() { .tx_buffer = dmaBuffer, }); return error; -} \ No newline at end of file +} + +#ifdef __cplusplus +} +#endif diff --git a/src/drivers/wsled.h b/src/drivers/wsled.h index bbedbe8..c331451 100644 --- a/src/drivers/wsled.h +++ b/src/drivers/wsled.h @@ -6,9 +6,13 @@ #include #include -#define WSLED_12_RESET_TIME 3 +#define WSLED_12_RESET_TIME 30 #define WSLED_15_RESET_TIME 30 +#ifdef __cplusplus +extern "C" { +#endif + typedef struct { uint8_t r; uint8_t g; @@ -37,6 +41,10 @@ typedef struct { esp_err_t wsledInit(wsled_t* dev, CRGB** buffer); // test function -esp_err_t wsledFillAll(CRGB color); +esp_err_t wsledFill(CRGB color); esp_err_t wsledUpdate(); + +#ifdef __cplusplus +} +#endif From 4f333435eaac5cd477eed330555c9ffccf0e28bd Mon Sep 17 00:00:00 2001 From: Blitblank Date: Fri, 13 Feb 2026 12:29:59 -0600 Subject: [PATCH 4/4] wsled interface skeleton --- src/WsledInterface.cpp | 21 +++++++++++++++++++++ src/WsledInterface.hpp | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 src/WsledInterface.cpp create mode 100644 src/WsledInterface.hpp diff --git a/src/WsledInterface.cpp b/src/WsledInterface.cpp new file mode 100644 index 0000000..18827b3 --- /dev/null +++ b/src/WsledInterface.cpp @@ -0,0 +1,21 @@ + +#include "WsledInterface.hpp" + +WsledInterface::WsledInterface(const wsled_t* device) { + +} + +STATUS WsledInterface::writePixel(CRGB pixel, size_t index) { + + return OKAY; +} + +STATUS WsledInterface::get(CRGB* pixel, size_t index) { + + return OKAY; +} + +STATUS WsledInterface::flush() { + + return OKAY; +} diff --git a/src/WsledInterface.hpp b/src/WsledInterface.hpp new file mode 100644 index 0000000..0e96fee --- /dev/null +++ b/src/WsledInterface.hpp @@ -0,0 +1,38 @@ + +#pragma once + +#include "stdint.h" + +#include "drivers/wsled.h" +#include "common.h" + +class WsledInterface { + +public: + + WsledInterface(const wsled_t* device); + ~WsledInterface() = default; + + // Sets a pixel in the leds buffer to a particular color + // index: the order in the strip of the pixel + // Returns: execution status + STATUS writePixel(CRGB pixel, size_t index); + + // Copies the color currently in a pixel to the pointer + // index: the order in the strip of the pixel + // Returns: execution status + STATUS get(CRGB* pixel, size_t index); + + // Writes all the data in the leds buffer to hardware + // Returns: execution status + STATUS flush(); + +private: + + const wsled_t* device_; + + static constexpr size_t numLeds_ = 4; + + CRGB leds_[numLeds_]; + +};