-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
andreas
committed
Sep 7, 2024
1 parent
e29e8eb
commit 92baf20
Showing
3 changed files
with
260 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |