From 294b8d8d71453d32f22915940756c8d3818eeb11 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 28 Aug 2022 17:49:48 -0500 Subject: [PATCH] Complete re-write of Blinker Class Rather than use ESP32 timers, simply spawn a new task that turn on/off LED using simple delays. By avoiding the use of the ESP32 timer, we are no longer limited by the number of Blinkers possible. Also, Blinker relied on the timer interrupt, which crashed when it tried to call Pixel since Pixel in turn uses interrupts from the RMT. Switching to spawned tasks is much cleaner and does not consume more CPU time since the timer interrupts were driven by CPU anyway. Blinker class and generic LED class are now in extras.h. Blinkable Interface is also in extras.h. To Do: Incorporate new Blinker class into HomeSpan code --- src/extras/Blinker.cpp | 108 ++++++++++++----------------------------- src/extras/Blinker.h | 36 ++++---------- src/extras/Pixel.h | 5 +- src/extras/extras.ino | 42 ++++++---------- 4 files changed, 59 insertions(+), 132 deletions(-) diff --git a/src/extras/Blinker.cpp b/src/extras/Blinker.cpp index dad0ca2..9e65d48 100644 --- a/src/extras/Blinker.cpp +++ b/src/extras/Blinker.cpp @@ -31,76 +31,27 @@ // Blinker // //////////////////////////////// -Blinker::Blinker(Blinkable *led, int timerNum, uint16_t autoOffDuration){ - +Blinker::Blinker(Blinkable *led, uint16_t autoOffDuration){ this->led=led; - pauseDuration=autoOffDuration*1000; - -#if SOC_TIMER_GROUP_TIMERS_PER_GROUP>1 // ESP32 and ESP32-S2 contains two timers per timer group - group=((timerNum/2)%2==0)?TIMER_GROUP_0:TIMER_GROUP_1; - idx=(timerNum%2==0)?TIMER_0:TIMER_1; // ESP32-C3 only contains one timer per timer group -#else - group=(timerNum%2==0)?TIMER_GROUP_0:TIMER_GROUP_1; - idx=TIMER_0; -#endif - - timer_config_t conf; - conf.alarm_en=TIMER_ALARM_EN; - conf.counter_en=TIMER_PAUSE; - conf.intr_type=TIMER_INTR_LEVEL; - conf.counter_dir=TIMER_COUNT_UP; - conf.auto_reload=TIMER_AUTORELOAD_EN; - conf.divider=getApbFrequency()/10000; // set divider to yield 10 kHz clock (0.1 ms pulses) - -#ifdef SOC_TIMER_GROUP_SUPPORT_XTAL // set clock to APB (default is XTAL!) if clk_src is defined in conf structure - conf.clk_src=TIMER_SRC_CLK_APB; -#endif - - timer_init(group,idx,&conf); - timer_isr_register(group,idx,Blinker::isrTimer,(void *)this,0,NULL); - timer_enable_intr(group,idx); - } ////////////////////////////////////// -void Blinker::isrTimer(void *arg){ +void Blinker::blinkTask(void *arg){ Blinker *b=(Blinker *)arg; - -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) // use new method that is generic to ESP32, S2, and C3 - timer_group_clr_intr_status_in_isr(b->group,b->idx); -#else // use older method that is only for ESP32 - if(b->group){ - if(b->idx) - TIMERG1.int_clr_timers.t1=1; - else - TIMERG1.int_clr_timers.t0=1; - } else { - if(b->idx) - TIMERG0.int_clr_timers.t1=1; - else - TIMERG0.int_clr_timers.t0=1; - } -#endif - if(!(b->led->isOn())){ - b->led->on(); - timer_set_alarm_value(b->group,b->idx,b->onTime); - b->count--; - } else { - b->led->off(); - if(b->count){ - timer_set_alarm_value(b->group,b->idx,b->offTime); - } else { - timer_set_alarm_value(b->group,b->idx,b->delayTime); - b->count=b->nBlinks; + for(;;){ + for(int i=0;inBlinks;i++){ + b->led->on(); + delay(b->onTime); + b->led->off(); + delay(b->offTime); } + delay(b->delayTime); } - timer_set_alarm(b->group,b->idx,TIMER_ALARM_EN); - } ////////////////////////////////////// @@ -113,46 +64,48 @@ void Blinker::start(int period, float dutyCycle){ ////////////////////////////////////// void Blinker::start(int period, float dutyCycle, int nBlinks, int delayTime){ + + onTime=dutyCycle*period; + offTime=period-onTime; + this->delayTime=delayTime+offTime; + this->nBlinks=nBlinks; + + stop(); + Serial.printf("Starting Blink Task\n"); + xTaskCreate( blinkTask, "BlinkTask", 1024, (void *)this, 0, &blinkHandle ); pauseTime=millis(); isPaused=false; - - period*=10; - onTime=dutyCycle*period; - offTime=period-onTime; - this->delayTime=delayTime*10+offTime; - this->nBlinks=nBlinks; - count=nBlinks; - timer_set_counter_value(group,idx,0); - timer_set_alarm_value(group,idx,0); - timer_start(group,idx); } ////////////////////////////////////// void Blinker::stop(){ - timer_pause(group,idx); + if(blinkHandle!=NULL){ + Serial.printf("Deleting Blink Task\n"); + vTaskDelete(blinkHandle); + blinkHandle=NULL; + } + + isPaused=true; } ////////////////////////////////////// void Blinker::on(){ - pauseTime=millis(); - isPaused=false; - stop(); led->on(); + + pauseTime=millis(); + isPaused=false; } ////////////////////////////////////// void Blinker::off(){ - pauseTime=millis(); - isPaused=false; - stop(); led->off(); } @@ -164,9 +117,8 @@ void Blinker::check(){ if(pauseDuration==0 || isPaused || (millis()-pauseTime)off(); + Serial.print("Pausing LED\n"); + off(); } ////////////////////////////////////// diff --git a/src/extras/Blinker.h b/src/extras/Blinker.h index 9794d6b..16994ee 100644 --- a/src/extras/Blinker.h +++ b/src/extras/Blinker.h @@ -35,14 +35,11 @@ //////////////////////////////// class Blinkable { - protected: - boolean onState=false; - public: + virtual void on()=0; virtual void off()=0; virtual int getPin()=0; - boolean isOn() {return(onState);} }; //////////////////////////////// @@ -53,10 +50,10 @@ class LED : public Blinkable { int pin; public: - + LED(int pin) : pin{pin} {pinMode(pin,OUTPUT);digitalWrite(pin,0);} - void on() {digitalWrite(pin,HIGH);onState=true;} - void off() {digitalWrite(pin,LOW);onState=false;} + void on() {digitalWrite(pin,HIGH);} + void off() {digitalWrite(pin,LOW);} int getPin() {return(pin);} }; @@ -66,43 +63,28 @@ class LED : public Blinkable { class Blinker { - timer_group_t group; - timer_idx_t idx; - + TaskHandle_t blinkHandle = NULL; Blinkable *led; int nBlinks; int onTime; int offTime; int delayTime; - int count; unsigned long pauseDuration; unsigned long pauseTime; boolean isPaused=false; - static void isrTimer(void *arg); + static void blinkTask(void *arg); public: - Blinker(Blinkable *led, int timerNum=0, uint16_t autoOffDuration=0); + Blinker(Blinkable *led, uint16_t autoOffDuration=0); -// Creates a generic blinking LED on specified pin controlled -// in background via interrupts generated by an ESP32 Alarm Timer. -// -// In the first form, a Blinker is instantiated without specifying -// the pin. In this case the pin must be specified in a subsequent call -// to init() before the Blinker can be used. -// -// In the second form, a Blinker is instantiated and initialized with -// the specified pin, obviating the need for a separate call to init(). +// Creates a generic blinking LED in a separate task thread // // led: An initialized LED device that implements the Blinkable Interface -// -// timerNum: ESP32 Alarm Timer to use. -// For ESP32 and ESP32-S2: 0=Group0/Timer0, 1=Group0/Timer1, 2=Group1/Timer0, 3=Group1/Timer1 -// For ESP32-C3: 0=Group0/Timer0, 1=Group1/Timer0 -// +//// // autoOffDuration: If greater than zero, Blinker will automatically turn off after autoOffDuration (in seconds) has elapsed // Blinker will resume normal operation upon next call to start(), on(), or off() // Program must periodically call check() for auto-off functionality to work diff --git a/src/extras/Pixel.h b/src/extras/Pixel.h index 27d431c..facd92d 100644 --- a/src/extras/Pixel.h +++ b/src/extras/Pixel.h @@ -39,7 +39,7 @@ // Single-Wire RGB/RGBW NeoPixels // //////////////////////////////////////////// -class Pixel : Blinkable { +class Pixel : public Blinkable { public: struct Color { @@ -152,6 +152,9 @@ class Pixel : Blinkable { operator bool(){ // override boolean operator to return true/false if creation succeeded/failed return(*rf); } + + void on() {set(RGB(255,0,0));} + void off() {set(RGB(0,0,0));} }; //////////////////////////////////////////// diff --git a/src/extras/extras.ino b/src/extras/extras.ino index 8d47d19..3fd3fc5 100644 --- a/src/extras/extras.ino +++ b/src/extras/extras.ino @@ -1,13 +1,11 @@ // This is a placeholder .ino file that allows you to easily edit the contents of this files using the Arduino IDE, // as well as compile and test from this point. This file is ignored when the library is included in other sketches. +#include "Blinker.h" #include "Pixel.h" -//#define PixelType Pixel -#define PixelType Dot - -//Pixel p(8); -Dot p(0,1); +//Blinker p(new LED(26)); +Blinker p(new Pixel(27),20); void setup() { @@ -15,29 +13,21 @@ void setup() { Serial.flush(); delay(1000); // wait for interface to flush - Serial.println("\n\nHomeSpan Pixel Example\n"); + Serial.println("\n\nHomeSpan Blinker Example\n"); +// Serial.printf("Pins = %d %d\n",b.getPin(),p.getPin()); - PixelType::Color off=PixelType::RGB(0,0,0); - - p.set(PixelType::RGB(0,0,255),3); - delay(1000); - - p.set(off,3); - delay(1000); - - PixelType::Color c[]={p.HSV(120,100,30),p.HSV(0,0,0),p.HSV(0,0,0)}; - p.set(c,3); - delay(1000); - - c[0].HSV(0,0,0); - c[1].HSV(60,100,30); - p.set(c,3); - delay(1000); - - c[1].HSV(0,0,0); - c[2].HSV(0,100,30); - p.set(c,3); + p.on(); + delay(2000); + p.off(); + delay(2000); + p.start(300,0.25,4,1000); + delay(5000); + Serial.printf("New Pattern\n"); + p.start(200,0.2,2,200); + delay(3000); + p.off(); } void loop(){ + p.check(); }