I'm working with the ESP32_fastPWM library on an ESP32 DEVKIT V1 DOIT module. The project (simplified) has the ESP32 driving 10 LEDs at 1000 Hz where each has its own duty cycle (brightness). Each LED is driven by a PWM instance (defined in the library). After instantiating each PWM instance, I using the function setPWM_manual ( ) to change the duty cycle of the respective instances over time such that each LED has its own pattern.
I'm not getting what I expect and am probably doing something dumb. After much dinking around, I thought it time to ask for help. The code below was written to demonstrate what the issue is and the initial comment section gives detail about what I'm seeing with an o-scope and what I expected to see. I'm uploading the verbose compile output....and believe I'm using the required core ESP code and Arduino IDE. I've also uploaded 2 oscilloscope screen shots showing what I'm seeing.
Any help is much appreciated. If it turns out to be a library issue, any alternative library suggestions are welcome....looking for hardware based implementation capable of at least 10 different PWM outputs of the same frequency but different duty cycle. Many thanks.....jim
/* Name: PWM_set_manual.ino Created: 9/282024 2:58:38 PM Purpose: minimal code to demonstrate issues I'm having with ESP32_FastPWM library using setPWM_manual() on a ESP32 Dev Kit V1 module. In the example below, there are 2 PWMinstances. The main loop updates the duty cycles of the PWM instances at different rates. The duty cycle drives an LED to cycle according to sine wave. The 8 bit values for the sine wave are in a look-up table. There are 64 steps in the sine wave. The first instance should cycle 'fast' and the second instance should cycle 'slow'.....but that is not what I'm seeing. I'm using an o-scope to look at the PWM outputs of GPIO 16 and 17 (pins 6 & 7 on the module). The code below has two defines to turn on/off calls to setPWM_manual for the fast and slow cycle rate. Here is what I'm seeing....and what I expected to see. With #define ShowSlowRate commented out, I see both PWM instances cycling at the FAST rate.....however, what I expected was to see the fast rate at GPIO 16 and nothing at GPIO 17. With #define ShowFastRate commented out, I see both PWM instances cycling at the SLOW rate.....however, what I expected was to see was nothing at GPIO 16 and the slow rate at GPIO 17. With neither #defines commented out, I see both GPIO pins outputting the same jumbled output.....what I expected was to see the fast rate at GPIO 16 and the slow rate at GPIO 17. Any help here is much appreciated. I'm probably doing something dumb, but after much dinking around without making any progress, I figured it was time to ask for some help. Thx!!!....jim */ #include <ESP32_FastPWM.h> #define UseSerial // used to turn on/off setting up serial port #define ShowFastRate // shows fast PWM rate on GPIO 16, module pin 6 #define ShowSlowRate // shows slow PWM rate on GPIO 17, module pin 7 #define Debug2 // turns on digital outputs to test timeing with o-scope //----Defines and variables used to set rate of pattern change at LED strand level unsigned long OctalInterval; // microsec interval between changes in PWM for fastest LED strobe rate unsigned long LastOctalTic; // micros() of last time OctalInterval was met //----Defines and variables used for PWM drivers of LED strands (ESP32_FastPWM) #define NumOfPins 2 // Number of gpio pins used to drive strands of LEDS float PWMres = 8.0f; // Resolution 256 (8-bit) float Frequency = 1000.0f; // frequency of PWM waveform generation ESP32_FAST_PWM* PWMinstance[NumOfPins]; // array of pointers to the PWM drivers defined by ESP32_FastPWM library, one for each pin used to drive a LED // look up table for 8 bit sine wave containing 64 steps per wave cycle (TicsPerWave). Used to change duty cycle for PWM. const uint8_t SinLU[64] = { 137, 149, 161, 173, 184, 194, 205, 215, 223, 229, 236, 243, 246, 249, 251, 254, 253, 250, 248, 245, 239, 233, 226, 219, 210, 200, 189, 179, 167, 155, 143, 131, 119, 107, 95, 83, 72, 62, 51, 41, 33, 27, 20, 13, 10, 7, 5, 2, 3, 6, 8, 11, 17, 23, 30, 37, 46, 56, 67, 77, 89, 101, 113, 125 }; uint8_t Strand[NumOfPins] = { 16,17 }; #ifdef Debug2 // digital signals output to pins 25 and 26 used with o-scope to make sure we are getting into the timing cycles we expect. #define Rate4pin 25 #define Rate8pin 26 static bool tst4 = true, tst8 = true; // used to toggle test timing with o-scope #endif //--- void printPWMInfo(ESP32_FAST_PWM* PWM_Instance); // prints out info about the PWM instance /* ==================================================================== */ /* ==================== SETUP ========================================= */ /* ==================================================================== */ void setup() { #ifdef UseSerial Serial.begin(115200); while (!Serial && millis() < 5000); delay(100); Serial.print(F("\nStarting PWM_set_manual on ")); Serial.println(ARDUINO_BOARD); Serial.println(ESP32_FAST_PWM_VERSION); Serial.print("Number of pins= "); Serial.println(NumOfPins); #endif // Create a PWM instance for each pin, intialize with duty cycle of 0% which will make pin output low for (int x = 0; x < NumOfPins; x++) { PWMinstance[x] = new ESP32_FAST_PWM(Strand[x], Frequency, 0.0f, 0, PWMres); // instantiate PWM instance with duty cycle=0, channel 0, frequency 1k, and 256 resolution if (PWMinstance[x]) { // non-zero pointer means instance created ok PWMinstance[x]->setPWM(); printPWMInfo(PWMinstance[x]); } else { Serial.print(" failed to initialize PWM channel="); Serial.println(x); } } // set up timers and flags used to know when to change LED PWM output OctalInterval = 16741; // microsec interval between potential changes in PWM for fastest rate LastOctalTic = 0; // set timer for potential change of PWM rate for fastest BPM. Note, this drives all BPM rates (Beats::sing, dbl, quad, ocatal) #ifdef Debug2 // use digital output pins to see that timing of blocks of code for fast and slow PWM adjustment pinMode(Rate4pin, OUTPUT); digitalWrite(Rate4pin, 0); pinMode(Rate8pin, OUTPUT); digitalWrite(Rate8pin, 0); #endif } /* ==================================================================== */ /* ==================== MAIN LOOP ===================================== */ /* ==================================================================== */ void loop() { unsigned long Now; // value of micros() used for timing when to change PWM static bool tstSin = true; // boolean used to execute half time changes in PWM static uint8_t SinIdx=0, SinIdx1=0; // Check if it is time to change PWM rates Now = micros(); if (Now - LastOctalTic >= OctalInterval) { // interval for fastest BPM rate has elapsed LastOctalTic = Now; // set new interval #ifdef ShowFastRate // LED oscillation should be full speed digitalWrite(Rate8pin, tst8); tst8 = !tst8; PWMinstance[0]->setPWM_manual(Strand[0], SinLU[SinIdx % 64]); // SinIdx will loop from 0-->63 SinIdx++; #endif #ifdef ShowSlowRate // LED oscillation should be half speed if (tstSin==true) { digitalWrite(Rate4pin, tst4); tst4 = !tst4; PWMinstance[1]->setPWM_manual(Strand[1], SinLU[SinIdx1 % 64]); // SinIdx will loop from 0-->63 SinIdx1++; } tstSin = !tstSin; // skip updating low speed LED every other time through main loop #endif } } /* ==================================================================== */ /* ============================ functions ============================= */ /* ==================================================================== */ void printPWMInfo(ESP32_FAST_PWM* PWM_Instance) { Serial.println("============================================================================================"); Serial.print("Actual data: pin = "); Serial.print(PWM_Instance->getPin()); Serial.print(", PWM DutyCycle = "); Serial.print(PWM_Instance->getActualDutyCycle()); Serial.print(", PWMPeriod = "); Serial.print(PWM_Instance->getPWMPeriod()); Serial.print(", PWM Freq (Hz) = "); Serial.println(PWM_Instance->getActualFreq(), 4); Serial.println("============================================================================================"); } //-----------------------------
Verbose Compiling debug version of 'PWM_set.txt (86.1 KB)
Serial output.txt (679 Bytes)