Just started building a RC car. I want to add led strips in it. And of course WLED is the best way to drive leds. But unfortunately WLED doesn’t have PWM input, so I guess a usermod needs to be created.
Currently I can read the PWM output from my RC receiver and run code when one of my two channels goes above 1750 (pulse width) or under 1250.
So, this is what I have now:
#pragma once
#include "wled.h"
//This is an empty v2 usermod template. Please see the file usermod_v2_example.h in the EXAMPLE_v2 usermod folder for documentation on the functions you can use!
class PWMInput : public Usermod {
private:
#define RCPinChan1 2
#define RCPinChan2 4
volatile long StartTimeChan1 = 0;
volatile long CurrentTimeChan1 = 0;
volatile long PulsesChan1 = 0;
int PulseWidthChan1 = 0;
int PulseOptionChan1 = 0;
volatile long StartTimeChan2 = 0;
volatile long CurrentTimeChan2 = 0;
volatile long PulsesChan2 = 0;
int PulseWidthChan2 = 0;
int PulseOptionChan2 = 0;
public:
void setup() {
Serial.begin(9600);
pinMode(RCPinChan1, INPUT_PULLUP);
pinMode(RCPinChan2, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(RCPinChan1),PulseTimerChan1,CHANGE);
attachInterrupt(digitalPinToInterrupt(RCPinChan2),PulseTimerChan2,CHANGE);
}
void PulseTimerChan1(){
CurrentTimeChan1 = micros();
if (CurrentTimeChan1 > StartTimeChan1){
PulsesChan1 = CurrentTimeChan1 - StartTimeChan1;
StartTimeChan1 = CurrentTimeChan1;
}
}
void PulseTimerChan2(){
CurrentTimeChan2 = micros();
if (CurrentTimeChan2 > StartTimeChan2){
PulsesChan2 = CurrentTimeChan2 - StartTimeChan2;
StartTimeChan2 = CurrentTimeChan2;
}
}
void loop() {
if (PulsesChan1 < 2100){
PulseWidthChan1 = PulsesChan1;
}
if ((PulseWidthChan1 < 2100) && (PulseWidthChan1 > 1750) && (PulseOptionChan1 != 3)) {
Serial.println("Hoog 1");
Serial.println(PulseWidthChan1);
PulseOptionChan1 = 3;
}
if ((PulseWidthChan1 < 1250) && (PulseWidthChan1 > 900) && (PulseOptionChan1 != 2)) {
Serial.println("Laag 1");
Serial.println(PulseWidthChan1);
PulseOptionChan1 = 2;
}
if (PulsesChan2 < 2100){
PulseWidthChan2 = PulsesChan2;
}
if ((PulseWidthChan2 < 2100) && (PulseWidthChan2 > 1750) && (PulseOptionChan2 != 3)) {
Serial.println("Hoog 2");
Serial.println(PulseWidthChan2);
PulseOptionChan2 = 3;
}
if ((PulseWidthChan2 < 1250) && (PulseWidthChan2 > 900) && (PulseOptionChan2 != 2)) {
Serial.println("Laag 2");
Serial.println(PulseWidthChan2);
PulseOptionChan2 = 2;
}
}
};
So, if I for instance want to cycle through presets, will that be possible by adding a command (instead of the prinln’s)?
Ok, I managed to get to this code and compile it succesfully:
#pragma once
#include "wled.h"
class PWM_input : public Usermod {
private:
static volatile long StartTimeChan1;
static volatile long CurrentTimeChan1;
static volatile long PulsesChan1;
static int PulseWidthChan1;
static int PulseOptionChan1;
static volatile long StartTimeChan2;
static volatile long CurrentTimeChan2;
static volatile long PulsesChan2;
static int PulseWidthChan2;
static int PulseOptionChan2;
public:
#define RCPinChan1 5
#define RCPinChan2 4
void setup() override {
Serial.begin(9600);
pinMode(RCPinChan1, INPUT_PULLUP);
pinMode(RCPinChan2, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(RCPinChan1), PulseTimerChan1, CHANGE);
attachInterrupt(digitalPinToInterrupt(RCPinChan2), PulseTimerChan2, CHANGE);
}
void loop() override {
if (PulsesChan1 < 2100){
PulseWidthChan1 = PulsesChan1;
}
if ((PulseWidthChan1 < 2100) && (PulseWidthChan1 > 1750) && (PulseOptionChan1 != 3)) {
Serial.println("Hoog 1");
Serial.println(PulseWidthChan1);
PulseOptionChan1 = 3;
}
if ((PulseWidthChan1 < 1250) && (PulseWidthChan1 > 900) && (PulseOptionChan1 != 2)) {
Serial.println("Laag 1");
Serial.println(PulseWidthChan1);
PulseOptionChan1 = 2;
}
if (PulsesChan2 < 2100){
PulseWidthChan2 = PulsesChan2;
}
if ((PulseWidthChan2 < 2100) && (PulseWidthChan2 > 1750) && (PulseOptionChan2 != 3)) {
Serial.println("Hoog 2");
Serial.println(PulseWidthChan2);
PulseOptionChan2 = 3;
}
if ((PulseWidthChan2 < 1250) && (PulseWidthChan2 > 900) && (PulseOptionChan2 != 2)) {
Serial.println("Laag 2");
Serial.println(PulseWidthChan2);
PulseOptionChan2 = 2;
}
}
static void PulseTimerChan1() {
CurrentTimeChan1 = micros();
if (CurrentTimeChan1 > StartTimeChan1){
PulsesChan1 = CurrentTimeChan1 - StartTimeChan1;
StartTimeChan1 = CurrentTimeChan1;
}
}
static void PulseTimerChan2() {
CurrentTimeChan2 = micros();
if (CurrentTimeChan2 > StartTimeChan2){
PulsesChan2 = CurrentTimeChan2 - StartTimeChan2;
StartTimeChan2 = CurrentTimeChan2;
}
}
};
// Initialize static variables
volatile long PWM_input::StartTimeChan1 = 0;
volatile long PWM_input::StartTimeChan2 = 0;
volatile long PWM_input::CurrentTimeChan1 = 0;
volatile long PWM_input::CurrentTimeChan2 = 0;
volatile long PWM_input::PulsesChan1 = 0;
volatile long PWM_input::PulsesChan2 = 0;
int PWM_input::PulseWidthChan1 = 0;
int PWM_input::PulseWidthChan2 = 0;
int PWM_input::PulseOptionChan1 = 0;
int PWM_input::PulseOptionChan2 = 0;
This seems to work. WLED works and in the Arduino Serial Monitor I see the serial output as expected when I give certain PWM input through the RC receiver. So far so good.
But… when I add
applyPreset(1, true);
to the code, the ESP32 gets a panic attack on PWM input. So apparently something is wrong with the applyPreset?
Guru Meditation Error: Core 1 panic'ed (Cache disabled but cached memory region accessed)
Core 1 register dump:
PC : 0x4010f064 PS : 0x00060034 A0 : 0x40085140 A1 : 0x3ffbffe0
A2 : 0x00000004 A3 : 0x3ffc93b8 A4 : 0x00000000 A5 : 0x00000010
A6 : 0x000420bc A7 : 0x3ffb8798 A8 : 0x800819a4 A9 : 0x00000001
A10 : 0x00000000 A11 : 0x00000000 A12 : 0x8009048d A13 : 0x3ffb18e0
A14 : 0x00000000 A15 : 0x3ffb191c SAR : 0x0000001a EXCCAUSE: 0x00000007
EXCVADDR: 0x00000000 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0xffffffff
Core 1 was running in ISR context:
EPC1 : 0x4009055a EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x4010f064
ELF file SHA256: 0000000000000000
Backtrace: 0x4010f061:0x3ffbffe0 0x4008513d:0x3ffc0000 0x40090557:0x3ffb1940 0x40090ce9:0x3ffb1960 0x40088cfc:0x3ffb1980 0x4019fb76:0x3ffb19f
Immediately at
applyPreset(1, true);
For clarity I added those below PulseOptionChan, so:
#pragma once
#include "wled.h"
class PWM_input : public Usermod {
private:
static volatile long StartTimeChan1;
static volatile long CurrentTimeChan1;
static volatile long PulsesChan1;
static int PulseWidthChan1;
static int PulseOptionChan1;
static volatile long StartTimeChan2;
static volatile long CurrentTimeChan2;
static volatile long PulsesChan2;
static int PulseWidthChan2;
static int PulseOptionChan2;
public:
#define RCPinChan1 5
#define RCPinChan2 4
void setup() override {
Serial.begin(9600);
pinMode(RCPinChan1, INPUT_PULLUP);
pinMode(RCPinChan2, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(RCPinChan1), PulseTimerChan1, CHANGE);
attachInterrupt(digitalPinToInterrupt(RCPinChan2), PulseTimerChan2, CHANGE);
}
void loop() override {
if (PulsesChan1 < 2100){
PulseWidthChan1 = PulsesChan1;
}
if ((PulseWidthChan1 < 2100) && (PulseWidthChan1 > 1750) && (PulseOptionChan1 != 3)) {
Serial.println("Hoog 1");
Serial.println(PulseWidthChan1);
PulseOptionChan1 = 3;
applyPreset(1, true);
}
if ((PulseWidthChan1 < 1250) && (PulseWidthChan1 > 900) && (PulseOptionChan1 != 2)) {
Serial.println("Laag 1");
Serial.println(PulseWidthChan1);
PulseOptionChan1 = 2;
applyPreset(2, true);
}
if (PulsesChan2 < 2100){
PulseWidthChan2 = PulsesChan2;
}
if ((PulseWidthChan2 < 2100) && (PulseWidthChan2 > 1750) && (PulseOptionChan2 != 3)) {
Serial.println("Hoog 2");
Serial.println(PulseWidthChan2);
PulseOptionChan2 = 3;
applyPreset(3, true);
}
if ((PulseWidthChan2 < 1250) && (PulseWidthChan2 > 900) && (PulseOptionChan2 != 2)) {
Serial.println("Laag 2");
Serial.println(PulseWidthChan2);
PulseOptionChan2 = 2;
applyPreset(4, true);
}
}
static void PulseTimerChan1() {
CurrentTimeChan1 = micros();
if (CurrentTimeChan1 > StartTimeChan1){
PulsesChan1 = CurrentTimeChan1 - StartTimeChan1;
StartTimeChan1 = CurrentTimeChan1;
}
}
static void PulseTimerChan2() {
CurrentTimeChan2 = micros();
if (CurrentTimeChan2 > StartTimeChan2){
PulsesChan2 = CurrentTimeChan2 - StartTimeChan2;
StartTimeChan2 = CurrentTimeChan2;
}
}
};
// Initialize static variables
volatile long PWM_input::StartTimeChan1 = 0;
volatile long PWM_input::StartTimeChan2 = 0;
volatile long PWM_input::CurrentTimeChan1 = 0;
volatile long PWM_input::CurrentTimeChan2 = 0;
volatile long PWM_input::PulsesChan1 = 0;
volatile long PWM_input::PulsesChan2 = 0;
int PWM_input::PulseWidthChan1 = 0;
int PWM_input::PulseWidthChan2 = 0;
int PWM_input::PulseOptionChan1 = 0;
int PWM_input::PulseOptionChan2 = 0;