226 lines
5.9 KiB
C++
226 lines
5.9 KiB
C++
|
|
////////////////////////////////////////////
|
|
// Addressable LEDs //
|
|
////////////////////////////////////////////
|
|
|
|
#include "Pixel.h"
|
|
|
|
////////////////////////////////////////////
|
|
// Single-Wire RGB/RGBW NeoPixels //
|
|
////////////////////////////////////////////
|
|
|
|
Pixel::Pixel(int pin, pixel_type_t pType){
|
|
|
|
rf=new RFControl(pin,false,false); // set clock to 1/80 usec, no default driver
|
|
if(!*rf)
|
|
return;
|
|
|
|
this->pType=pType;
|
|
|
|
setTiming(0.32, 0.88, 0.64, 0.56, 80.0); // set default timing parameters (suitable for most SK68 and WS28 RGB pixels)
|
|
|
|
rmt_isr_register(loadData,NULL,0,NULL); // set custom interrupt handler
|
|
|
|
rmt_set_tx_thr_intr_en(rf->getChannel(),false,8); // disable threshold interrupt
|
|
txThrMask=RMT.int_ena.val; // save interrupt enable vector
|
|
rmt_set_tx_thr_intr_en(rf->getChannel(),true,8); // enable threshold interrupt to trigger every 8 pulses
|
|
txThrMask^=RMT.int_ena.val; // find bit that flipped and save as threshold mask for this channel
|
|
|
|
rmt_set_tx_intr_en(rf->getChannel(),false); // disable end-of-transmission interrupt
|
|
txEndMask=RMT.int_ena.val; // save interrupt enable vector
|
|
rmt_set_tx_intr_en(rf->getChannel(),true); // enable end-of-transmission interrupt
|
|
txEndMask^=RMT.int_ena.val; // find bit that flipped and save as end-of-transmission mask for this channel
|
|
}
|
|
|
|
///////////////////
|
|
|
|
void Pixel::setTiming(float high0, float low0, float high1, float low1, uint32_t lowReset){
|
|
|
|
pattern[0]=RF_PULSE(high0*80+0.5,low0*80+0.5);
|
|
pattern[1]=RF_PULSE(high1*80+0.5,low1*80+0.5);
|
|
resetTime=lowReset;
|
|
}
|
|
|
|
///////////////////
|
|
|
|
void Pixel::setRGB(uint8_t r, uint8_t g, uint8_t b, uint8_t w, uint32_t nPixels){
|
|
|
|
if(!*rf || nPixels==0)
|
|
return;
|
|
|
|
uint32_t data=getColorRGB(r,g,b,w);
|
|
setColors(&data,nPixels,false);
|
|
}
|
|
|
|
///////////////////
|
|
|
|
void Pixel::setHSV(float h, float s, float v, double w, uint32_t nPixels){
|
|
float r,g,b;
|
|
LedPin::HSVtoRGB(h,s/100.0,v/100.0,&r,&g,&b);
|
|
setRGB(r*255,g*255,b*255,w*2.555,nPixels);
|
|
}
|
|
|
|
///////////////////
|
|
|
|
void Pixel::setColors(const uint32_t *data, uint32_t nPixels, boolean multiColor){
|
|
|
|
if(!*rf || nPixels==0)
|
|
return;
|
|
|
|
status.nPixels=nPixels;
|
|
status.data=data;
|
|
status.iMem=0;
|
|
status.iBit=32;
|
|
status.started=true;
|
|
status.px=this;
|
|
status.multiColor=multiColor;
|
|
|
|
loadData(this); // load first two bytes of data to get started
|
|
loadData(this);
|
|
|
|
rmt_tx_start(rf->getChannel(),true);
|
|
|
|
while(status.started); // wait for transmission to be complete
|
|
delayMicroseconds(resetTime); // end-of-marker delay
|
|
}
|
|
|
|
///////////////////
|
|
|
|
uint32_t Pixel::getColorRGB(uint8_t r, uint8_t g, uint8_t b, uint8_t w){
|
|
// return(g<<16 | r<<8 | b);
|
|
return(g<<24 | r<<16 | b<<8 | w);
|
|
}
|
|
|
|
///////////////////
|
|
|
|
uint32_t Pixel::getColorHSV(float h, float s, float v, double w){
|
|
float r,g,b;
|
|
LedPin::HSVtoRGB(h,s/100.0,v/100.0,&r,&g,&b);
|
|
return(getColorRGB(r*255,g*255,b*255,w*2.555));
|
|
}
|
|
|
|
///////////////////
|
|
|
|
void IRAM_ATTR Pixel::loadData(void *arg){
|
|
|
|
if(RMT.int_st.val & status.px->txEndMask){
|
|
RMT.int_clr.val=status.px->txEndMask;
|
|
status.started=false;
|
|
return;
|
|
}
|
|
|
|
RMT.int_clr.val=status.px->txThrMask; // if loadData() is called and it is NOT because of an END interrupt (above) then must either be a pre-load, or a threshold trigger
|
|
|
|
if(status.nPixels==0){
|
|
RMTMEM.chan[status.px->rf->getChannel()].data32[status.iMem].val=0;
|
|
return;
|
|
}
|
|
|
|
for(int i=0;i<8;i++)
|
|
RMTMEM.chan[status.px->rf->getChannel()].data32[status.iMem++].val=status.px->pattern[(*status.data>>(--status.iBit))&1];
|
|
|
|
if(status.iBit==status.px->pType){
|
|
status.iBit=32;
|
|
status.data+=status.multiColor;
|
|
status.nPixels--;
|
|
}
|
|
|
|
status.iMem%=status.px->memSize;
|
|
}
|
|
|
|
///////////////////
|
|
|
|
volatile Pixel::pixel_status_t Pixel::status;
|
|
|
|
////////////////////////////////////////////
|
|
// Two-Wire RGB DotStars //
|
|
////////////////////////////////////////////
|
|
|
|
Dot::Dot(uint8_t dataPin, uint8_t clockPin){
|
|
|
|
pinMode(dataPin,OUTPUT);
|
|
pinMode(clockPin,OUTPUT);
|
|
digitalWrite(dataPin,LOW);
|
|
digitalWrite(clockPin,LOW);
|
|
|
|
dataMask=1<<(dataPin%32);
|
|
clockMask=1<<(clockPin%32);
|
|
|
|
#ifdef CONFIG_IDF_TARGET_ESP32C3
|
|
dataSetReg=&GPIO.out_w1ts.val;
|
|
dataClearReg=&GPIO.out_w1tc.val;
|
|
clockSetReg=&GPIO.out_w1ts.val;
|
|
clockClearReg=&GPIO.out_w1tc.val;
|
|
#else
|
|
if(dataPin<32){
|
|
dataSetReg=&GPIO.out_w1ts;
|
|
dataClearReg=&GPIO.out_w1tc;
|
|
} else {
|
|
dataSetReg=&GPIO.out1_w1ts.val;
|
|
dataClearReg=&GPIO.out1_w1tc.val;
|
|
}
|
|
|
|
if(clockPin<32){
|
|
clockSetReg=&GPIO.out_w1ts;
|
|
clockClearReg=&GPIO.out_w1tc;
|
|
} else {
|
|
clockSetReg=&GPIO.out1_w1ts.val;
|
|
clockClearReg=&GPIO.out1_w1tc.val;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
///////////////////
|
|
|
|
void Dot::set(Color *c, int nPixels, boolean multiColor){
|
|
|
|
*dataClearReg=dataMask; // send all zeros
|
|
for(int j=0;j<31;j++){
|
|
*clockSetReg=clockMask;
|
|
*clockClearReg=clockMask;
|
|
}
|
|
|
|
for(int i=0;i<nPixels;i++){
|
|
for(int b=31;b>=0;b--){
|
|
if((c->val>>b)&1)
|
|
*dataSetReg=dataMask;
|
|
else
|
|
*dataClearReg=dataMask;
|
|
*clockSetReg=clockMask;
|
|
*clockClearReg=clockMask;
|
|
}
|
|
if(multiColor)
|
|
c++;
|
|
}
|
|
|
|
*dataClearReg=dataMask; // send all zeros
|
|
for(int j=0;j<31;j++){
|
|
*clockSetReg=clockMask;
|
|
*clockClearReg=clockMask;
|
|
}
|
|
}
|
|
|
|
///////////////////
|
|
|
|
Dot::Color Dot::RGB(uint8_t red, uint8_t green, uint8_t blue, uint8_t drive){
|
|
Color x;
|
|
x.red=red;
|
|
x.green=green;
|
|
x.blue=blue;
|
|
x.drive=drive;
|
|
x.flags=7;
|
|
return(x);
|
|
}
|
|
|
|
|
|
///////////////////
|
|
|
|
Dot::Color Dot::HSV(float h, float s, float v, float level){
|
|
float r,g,b;
|
|
LedPin::HSVtoRGB(h,s/100.0,v/100.0,&r,&g,&b);
|
|
return(RGB(r*255,g*255,b*255,level/100*31.5));
|
|
}
|
|
|
|
////////////////////////////////////////////
|