Description
Board
ESP32-C3 dev module
Device Description
DevKitC
Hardware Configuration
tact switch and assignable RGB LED on GPIO9
Version
latest master
IDE Name
arduino IDE
Operating System
windows 10
Flash frequency
80M
PSRAM enabled
no
Upload speed
CDC
Description
in this use case IO9 is shared between assignable LED and tact switch, the RMT driver should take over IO9 only when sending datas to the LED and tact switch interrupt should be attached otherwise. This concept is long proven on other SoCs but it does not work on esp32c3 yet, due to RMT driver bug.
Actually there is two bugs, the first is minor and can be fixed easily with a check, for now by commenting during the test, the second is of unknown cause yet, nothing shows up in the log.
1 rmtDeinit throws an error when used in TX only mode, i suspect stopping the (non exsting) RX channel is the cause.
2 once rmtDeinit has been called the RMT driver cannot be re-init or used anymore, any subsequent call to rmtInit will just lock everything up until hard reset or power cycle.
It seems something has not been cleared somewhere when RMT driver is deInit.
Sketch
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "Arduino.h"
#include "freertos/timers.h"
#include "esp32-hal.h"
#define LED_IO 9
#define LED_QTY 1
#define LED_TICK 10
#define BITS 24*LED_QTY
#define TICK_CHK() if(millis()-ledfx.led_l_ts<LED_TICK)return
#define TICK_INC() ledfx.led_l_ts=millis()
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
enum {
SLOW_BREATH,
FAST_BREATH,
SLOW_SBLINK,
FAST_SBLINK,
SLOW_LBLINK,
FAST_LBLINK,
SLOW_FADIN,
FAST_FADIN,
SLOW_FADOUT,
FAST_FADOUT
}LED_MODE;
struct LED_FX{
uint32_t fade_in;
uint32_t hold;
uint32_t fade_out;
uint32_t wait;
uint8_t cycles;
uint32_t cycles_cnt;
float color;
float bright;
uint32_t hold_cnt;
uint32_t wait_cnt;
uint8_t state;
uint8_t fxmode;
bool polling_mode;
uint32_t led_ticker;
uint32_t led_l_ts;
float h;
float s;
float l;
};
typedef struct rgb{float r,g,b;}RGB;
typedef struct hsl{float h,s,l;}HSL;
rmt_data_t led_data[BITS];
rmt_obj_t* rmt_send=NULL;
TimerHandle_t ledTimer;
LED_FX ledfx;
volatile int tactFlag=0,irqInit=0;
void IRAM_ATTR tactIsr() {
tactFlag=1;
}
float hue2rgb(float p,float q,float t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1./6) return p + (q - p) * 6 * t;
if (t < 1./2) return q;
if (t < 2./3) return p + (q - p) * (2./3 - t) * 6;
return p;
}
HSL rgb2hsl(float r,float g,float b) {
HSL result;
r /= 255.0;
g /= 255.0;
b /= 255.0;
float max = MAX(MAX(r,g),b);
float min = MIN(MIN(r,g),b);
result.h = result.s = result.l = (max + min) / 2;
if (max == min) {
result.h = result.s = 0; // achromatic
}
else {
float d = max - min;
result.s = (result.l > 0.5) ? d / (2 - max - min) : d / (max + min);
if (max == r) { result.h = (g - b) / d + (g < b ? 6 : 0);}
else if (max == g) { result.h = (b - r) / d + 2; }
else if (max == b) { result.h = (r - g) / d + 4; }
result.h /= 6;
}
return result;
}
RGB hsl2rgb(float h,float s,float l) {
RGB result;
if(0 == s) {
result.r = result.g = result.b = l; // achromatic
}
else {
float q = l < 0.5 ? l * (1 + s) : l + s - l * s;
float p = 2 * l - q;
result.r = hue2rgb(p, q, h + 1./3) * 255;
result.g = hue2rgb(p, q, h) * 255;
result.b = hue2rgb(p, q, h - 1./3) * 255;
if(result.r<0)result.r=0;
if(result.g<0)result.g=0;
if(result.b<0)result.b=0;
}
return result;
}
void led_setbfr(int *color,int index) {
int led = index, col, bit, i = 0;
//Serial.printf("set %d %d %d\n",color[0],color[1],color[2]);
for (col = 0; col < 3; col++ ) {
for (bit = 0; bit < 8; bit++) {
if ( (color[col] & (1 << (7 - bit))) /*&& (led == led_index)*/ ) {
led_data[i].level0 = 1;
led_data[i].duration0 = 8;
led_data[i].level1 = 0;
led_data[i].duration1 = 4;
} else {
led_data[i].level0 = 1;
led_data[i].duration0 = 4;
led_data[i].level1 = 0;
led_data[i].duration1 = 8;
}
i++;
}
}
}
void led_setHSL(float h_,float s_,float l_,int index) {
RGB val=hsl2rgb(h_,s_,l_);
int col[]={val.r,val.g,val.b};
led_setbfr(col,index);
rmtWrite(rmt_send, led_data, BITS);
}
void set_timer(TimerHandle_t xTimer,unsigned int ms ) {
if(xTimerIsTimerActive( xTimer )!=pdFALSE){ xTimerDelete(xTimer,100); }
else{
if(xTimerChangePeriod( xTimer, pdMS_TO_TICKS(ms), 100 ) == pdPASS ) {}
else{Serial.println("timer set failed");}
}
}
void led_fxhandler(void){
if(ledfx.state==0) return;
if(ledfx.polling_mode)TICK_CHK();
switch(ledfx.state){
case 1: //----------- ramp up /on
ledfx.wait_cnt=0;
switch(ledfx.fxmode){
case SLOW_BREATH:
case FAST_BREATH:
case SLOW_SBLINK:
case FAST_SBLINK:
case SLOW_LBLINK:
case FAST_LBLINK:
led_setHSL(ledfx.h,ledfx.s,ledfx.l,0);
if(ledfx.l>=ledfx.bright)ledfx.state=2;
else ledfx.l+=(ledfx.bright/(ledfx.fade_in/LED_TICK));
break;
}
break;
case 2: //----------- hold
switch(ledfx.fxmode){
case SLOW_BREATH:
case FAST_BREATH:
case SLOW_SBLINK:
case FAST_SBLINK:
case SLOW_LBLINK:
case FAST_LBLINK:
if(ledfx.hold_cnt>=(ledfx.hold/LED_TICK))ledfx.state=3;
else ledfx.hold_cnt+=1;
break;
}
break;
case 3: //----------- ramp down / off
ledfx.hold_cnt=0;
switch(ledfx.fxmode){
case SLOW_BREATH:
case FAST_BREATH:
led_setHSL(ledfx.h,ledfx.s,ledfx.l,0);
if(ledfx.l<=0)ledfx.state=4;
else ledfx.l-=(ledfx.bright/(ledfx.fade_in/LED_TICK));
break;
case SLOW_SBLINK:
case FAST_SBLINK:
case SLOW_LBLINK:
case FAST_LBLINK:
led_setHSL(ledfx.h,ledfx.s,ledfx.l,0);
if(ledfx.l<=0)ledfx.state=4;
else ledfx.l-=(ledfx.bright/(ledfx.fade_out/LED_TICK));
break;
}
break;
case 4: //----------- wait
switch(ledfx.fxmode){
case SLOW_BREATH:
case FAST_BREATH:
case SLOW_SBLINK:
case FAST_SBLINK:
case SLOW_LBLINK:
case FAST_LBLINK:
if(ledfx.wait_cnt>=(ledfx.wait/LED_TICK)){
if(ledfx.cycles==255)ledfx.state=1;
else{
if(ledfx.cycles_cnt>=ledfx.cycles-1){
ledfx.state=0;
xTimerStop(ledTimer,0);
Serial.println("de-init rmt");
rmtDeinit(rmt_send);
//rmt_ll_stop_tx(s_rmt.regs, REF_CLOCK_RMT_CHANNEL);
//periph_module_disable(PERIPH_RMT_MODULE);
tact_init();
}
else{ledfx.cycles_cnt+=1; ledfx.state=1; }
}
}
else ledfx.wait_cnt+=1;
break;
}
break;
}
if(ledfx.polling_mode)TICK_INC();
}
void led_stop(int gracefully){
switch(ledfx.fxmode){
case 1:
if(gracefully)ledfx.cycles=1;
break;
}
}
void led_set(int fxmode,float color,float sat,float bright,int cnt){
Serial.println("led set");
ledfx.bright=bright; // brightness
ledfx.h=color;
ledfx.s=sat; // saturation
ledfx.fxmode=fxmode;
ledfx.cycles=cnt;
switch(ledfx.fxmode){
case SLOW_BREATH: ledfx.fade_in=800; ledfx.hold=100; ledfx.wait=1500; break;
case FAST_BREATH: ledfx.fade_in=30; ledfx.hold=10; ledfx.wait=300; break;
case SLOW_SBLINK: ledfx.fade_in=30; ledfx.hold=100; ledfx.fade_out=220; ledfx.wait=1500; break;
case FAST_SBLINK: ledfx.fade_in=20; ledfx.hold=20; ledfx.fade_out=60; ledfx.wait=250; break;
default: return;
}
Serial.println("detach tact irq");
if(irqInit) detachInterrupt(9);
Serial.println("init rmt");
led_init();
if(ledfx.polling_mode)TICK_INC();
ledfx.state=1;
xTimerStart(ledTimer,0);
}
void led_init(void){
if((rmt_send=rmtInit(LED_IO,true,RMT_MEM_64))==NULL)Serial.println("LED init failed\n");
float realTick = rmtSetTick(rmt_send, 100);
//Serial.printf("tick: %.02fns\n", realTick);
if(!ledfx.polling_mode && ledTimer==NULL) ledTimer = xTimerCreate("ledtimer", pdMS_TO_TICKS(LED_TICK), pdTRUE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(led_fxhandler));
}
void tact_init(){
pinMode(9, INPUT_PULLUP);
Serial.println("attach tact irq");
attachInterrupt(9,tactIsr, FALLING);
irqInit=1;
}
void setup(){
Serial.begin(115200);
while(!Serial);
delay(1500);
Serial.println("System ready");
led_set(FAST_SBLINK,0.628,0.75,0.10,3);
}
int ledFlag=0;
void loop(){
if(tactFlag){
Serial.println("tact handler");
tactFlag=0;
ledFlag=1;
}
if(ledFlag){
Serial.println("led blink handler");
led_set(FAST_SBLINK,0.628,0.75,0.10,2);
ledFlag=0;
}
}
Debug Message
none
Other Steps to Reproduce
No response
I have checked existing issues, online documentation and the Troubleshooting Guide
- I confirm I have checked existing issues, online documentation and Troubleshooting guide.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status