Skip to content

Commit

Permalink
1st trial with ledspitask
Browse files Browse the repository at this point in the history
  • Loading branch information
andreas committed Sep 7, 2024
1 parent e29e8eb commit 92baf20
Show file tree
Hide file tree
Showing 3 changed files with 260 additions and 0 deletions.
237 changes: 237 additions & 0 deletions lib/ledspitask/GwLedSpiTask.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
#include "GwLedSpiTask.h"
#include "GwHardware.h"
#include "GwApi.h"
#include <driver/spi_master.h>

/*
controlling some WS2812 using SPI
https://controllerstech.com/ws2812-leds-using-spi/
*/

typedef enum {
LED_OFF,
LED_GREEN,
LED_BLUE,
LED_RED,
LED_WHITE
} GwLedMode;

typedef struct{
uint8_t r;
uint8_t g;
uint8_t b;
} Color;

static Color COLOR_GREEN={
.r=0,
.g=255,
.b=0
};
static Color COLOR_RED={
.r=255,
.g=0,
.b=0
};
static Color COLOR_BLUE={
.r=0,
.g=0,
.b=255
};
static Color COLOR_WHITE={
.r=255,
.g=255,
.b=255
};
static Color COLOR_BLACK={
.r=0,
.g=0,
.b=0
};

static uint8_t mulcolor(uint8_t f1, uint8_t f2){
uint16_t rt=f1;
rt*=(uint16_t)f2;
return rt >> 8;
}

static Color setBrightness(const Color &color,uint8_t brightness){
//very simple for now
Color rt=color;
rt.g=mulcolor(rt.g,brightness);
rt.b=mulcolor(rt.b,brightness);
rt.r=mulcolor(rt.r,brightness);
return rt;
}

static Color colorFromMode(GwLedMode cmode){
switch(cmode){
case LED_BLUE:
return COLOR_BLUE;
case LED_GREEN:
return COLOR_GREEN;
case LED_RED:
return COLOR_RED;
case LED_WHITE:
return COLOR_WHITE;
default:
return COLOR_BLACK;
}
}



static void colorCompTo3Byte(uint8_t comp,uint8_t *buffer){
//test: we assume comp to be 0x7f
//meaning 1 0 bit (100) and 7 1 bits (110)
/*
*buffer= 0b10011011;
*(buffer+1)=0b01101101;
*(buffer+2)=0b10110110;
*/
*buffer= 0b10010010;
*(buffer+1)=0b01001001;
*(buffer+2)=0b10110110;
}

static size_t ledsToBuffer(int numLeds,const Color *leds,uint8_t *buffer){
uint8_t *p=buffer;
for (int i=0;i<numLeds;i++){
colorCompTo3Byte(leds[i].g,p);
p+=3;
colorCompTo3Byte(leds[i].r,p);
p+=3;
colorCompTo3Byte(leds[i].b,p);
p+=3;
}
return p-buffer;
}

#define EXIT_TASK delay(50);vTaskDelete(NULL);return;
void handleSpiLeds(GwApi *api){
GwLog *logger=api->getLogger();
spi_host_device_t bus;
bool spiValid=false;
#ifndef GWLED_SPI
LOG_DEBUG(GwLog::LOG,"no SPI LEDs defined");
EXIT_TASK;
#else
#ifndef GWLED_PIN
#error "GWLED_PIN not defined"
#endif
#if GWLED_SPI == 1
#ifdef GWSPI1_CLK
#error "GWLED_SPI is 1 but SPI bus one is used by GWSPI1_CLK"
#endif
bus=SPI2_HOST;
spiValid=true;
#endif
#if GWLED_SPI == 2
#ifdef GWSPI2_CLK
#error "GWLED_SPI is 2 but SPI bus two is used by GWSPI2_CLK"
#endif
bus=SPI3_HOST;
spiValid=true;
#endif
if (! spiValid){
LOG_DEBUG(GwLog::ERROR,"invalid SPI bus defined for SPI leds %s",GWSTRINGIFY(GWLED_SPI))
EXIT_TASK;
}
LOG_DEBUG(GwLog::ERROR,"SpiLed task started");
uint8_t ledPin=GWLED_PIN;
spi_bus_config_t buscfg = {
.mosi_io_num = ledPin,
.miso_io_num = -1,
.sclk_io_num = -1,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 0
};
esp_err_t err=spi_bus_initialize(bus,&buscfg,SPI_DMA_CH_AUTO);
if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to initialize SPI bus %d,mosi=%d, error=%d",
(int)bus,ledPin,(int)err);
EXIT_TASK;
}
spi_device_interface_config_t devcfg = {
.command_bits = 0,
.address_bits = 0,
.dummy_bits = 0,
.mode = 0,
.duty_cycle_pos = 128,
.cs_ena_pretrans = 0,
.cs_ena_posttrans =0,
.clock_speed_hz = 2500000, //2.5 Mhz
.input_delay_ns =0,
.spics_io_num = -1, //CS pin
.queue_size = 1 //see https://github.com/espressif/esp-idf/issues/9450
};
spi_device_handle_t device;
err=spi_bus_add_device(bus,&devcfg,&device);
if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to add device to SPI bus %d,mosi=%d, error=%d",
(int)bus,ledPin,(int)err);
EXIT_TASK;
}
const int NUMLEDS=1;
Color leds[NUMLEDS];
size_t bufferSize=NUMLEDS*3*3;
uint8_t *outbuffer=(uint8_t*) heap_caps_malloc(bufferSize,MALLOC_CAP_DMA);
if (! outbuffer){
LOG_DEBUG(GwLog::ERROR,"unable to allocate %d bytes of DMA buffer",(int)bufferSize);
EXIT_TASK;
}
uint8_t brightness=api->getConfig()->getInt(GwConfigDefinitions::ledBrightness,128);
GwLedMode currentMode=LED_GREEN;
bool first=true;
int apiResult=0;
while (true)
{
delay(50);
GwLedMode newMode = currentMode;
IButtonTask buttonState = api->taskInterfaces()->get<IButtonTask>(apiResult);
if (apiResult >= 0)
{
switch (buttonState.state)
{
case IButtonTask::PRESSED_5:
newMode = LED_BLUE;
break;
case IButtonTask::PRESSED_10:
newMode = LED_RED;
break;
default:
newMode = LED_GREEN;
break;
}
}
else
{
newMode = LED_WHITE;
}
if (newMode != currentMode || first)
{
first=false;
leds[0] = setBrightness(colorFromMode(newMode),brightness);
ledsToBuffer(NUMLEDS,leds,outbuffer);
struct spi_transaction_t ta = {
.flags = 0,
.cmd = 0,
.addr = 0,
.length = bufferSize*8,
.rxlength = 0,
.tx_buffer = outbuffer
};
esp_err_t ret = spi_device_transmit(device, &ta);
if (ret != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to send led data: %d",(int)ret);
}
else{
LOG_DEBUG(GwLog::DEBUG,"successfully send led data for %d leds",NUMLEDS);
}
currentMode = newMode;
}
}
vTaskDelete(NULL);
#endif
}
8 changes: 8 additions & 0 deletions lib/ledspitask/GwLedSpiTask.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef _GWSPILEDS_H
#define _GWSPILEDS_H
#include "GwApi.h"
//task function
void handleSpiLeds(GwApi *param);

DECLARE_USERTASK(handleSpiLeds);
#endif
15 changes: 15 additions & 0 deletions lib/ledspitask/platformio.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[platformio]
#if you want a pio run to only build
#your special environments you can set this here
#by uncommenting the next line
#default_envs = testboard
[env:nodemcu_spiled]
board = nodemcu-32s
lib_deps = ${env.lib_deps}
build_flags =
-D BOARD_HOMBERGER
-D GWLED_SPI=1
-D GWLED_PIN=33
${env.build_flags}
upload_port = /dev/esp32
upload_protocol = esptool

0 comments on commit 92baf20

Please sign in to comment.