diff --git a/QuickPID.cpp b/QuickPID.cpp index 9467214..16100c0 100644 --- a/QuickPID.cpp +++ b/QuickPID.cpp @@ -1,5 +1,5 @@ /********************************************************************************** - QuickPID Library for Arduino - Version 2.2.4 + QuickPID Library for Arduino - Version 2.2.5 by dlloydev https://github.com/Dlloydev/QuickPID Based on the Arduino PID Library, licensed under the MIT License **********************************************************************************/ diff --git a/QuickPID.h b/QuickPID.h index e5e4673..495814c 100644 --- a/QuickPID.h +++ b/QuickPID.h @@ -111,7 +111,7 @@ static const byte TRY_AUTOMATIC = 1; }; -#if defined(ESP32) +#if (defined(ESP32) || defined(ARDUINO_ARCH_ESP32)) #include "utility/analogWrite.h" #endif diff --git a/library.properties b/library.properties index 92c0589..56373be 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=QuickPID -version=2.2.4 +version=2.2.5 author=David Lloyd maintainer=David Lloyd sentence=A fast fixed/floating point PID controller with AutoTune and 9 tuning rules to choose from. diff --git a/utility/analogWrite.cpp b/utility/analogWrite.cpp index 7a323a6..6d4d20a 100644 --- a/utility/analogWrite.cpp +++ b/utility/analogWrite.cpp @@ -1,5 +1,5 @@ /********************************************************************************** - AnalogWrite Library for ESP32-ESP32S2 Arduino core - Version 1.1.0 + AnalogWrite Library for ESP32-ESP32S2 Arduino core - Version 2.0.6 by dlloydev https://github.com/Dlloydev/ESP32-ESP32S2-AnalogWrite This Library is licensed under the MIT License **********************************************************************************/ @@ -7,80 +7,56 @@ #include #include "analogWrite.h" +namespace aw { + #if (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3) pinStatus_t pinsStatus[8] = { - {0, -1, 5000, 13, 0 }, {2, -1, 5000, 13, 0 }, - {4, -1, 5000, 13, 0 }, {6, -1, 5000, 13, 0 }, - {1, -1, 5000, 13, 0 }, {3, -1, 5000, 13, 0 }, - {5, -1, 5000, 13, 0 }, {7, -1, 5000, 13, 0 } + {0, -1, 980, 8, 0, 0 }, {2, -1, 980, 8, 0, 0 }, + {4, -1, 980, 8, 0, 0 }, {6, -1, 980, 8, 0, 0 }, + {1, -1, 980, 8, 0, 0 }, {3, -1, 980, 8, 0, 0 }, + {5, -1, 980, 8, 0, 0 }, {7, -1, 980, 8, 0, 0 } }; const uint8_t chd = 1; #else //ESP32 pinStatus_t pinsStatus[8] = { - { 0, -1, 5000, 13, 0 }, { 2, -1, 5000, 13, 0 }, - { 4, -1, 5000, 13, 0 }, { 6, -1, 5000, 13, 0 }, - { 8, -1, 5000, 13, 0 }, {10, -1, 5000, 13, 0 }, - {12, -1, 5000, 13, 0 }, {14, -1, 5000, 13, 0 } + { 0, -1, 980, 8, 0, 0 }, { 2, -1, 980, 8, 0, 0 }, + { 4, -1, 980, 8, 0, 0 }, { 6, -1, 980, 8, 0, 0 }, + { 8, -1, 980, 8, 0, 0 }, {10, -1, 980, 8, 0, 0 }, + {12, -1, 980, 8, 0, 0 }, {14, -1, 980, 8, 0, 0 } }; const uint8_t chd = 2; #endif -void analogWrite(int8_t pin, int32_t value) { - if (pin == DAC1 || pin == DAC2) { //dac - if (value > 255) value = 255; - dacWrite(pin, value); - } else { //pwm - int8_t ch = getChannel(pin); - if (ch >= 0) { - if (value == -1) { //detach pin - pinsStatus[ch / chd].pin = -1; - pinsStatus[ch / chd].frequency = 5000; - pinsStatus[ch / chd].resolution = 13; - ledcDetachPin(pinsStatus[ch / chd].pin); - REG_SET_FIELD(GPIO_PIN_MUX_REG[pin], MCU_SEL, GPIO_MODE_DEF_DISABLE); - } else { // attached - int32_t valueMax = (pow(2, pinsStatus[ch / chd].resolution)) - 1; - if (value > valueMax) { // full ON - value = valueMax + 1; - ledcDetachPin(pin); - pinMode(pin, OUTPUT); - digitalWrite(pin, HIGH); - } else { // write PWM - ledcSetup(ch, pinsStatus[ch / chd].frequency, pinsStatus[ch / chd].resolution); - ledcWrite(ch, value); - } - pinsStatus[ch / chd].value = value; - } - } - } +float awLedcSetup(uint8_t ch, double frequency, uint8_t bits) { +#if (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3) + frequency *= 80; //workaround for issue 5050 + return ledcSetup(ch, frequency, bits) / 80; +#else //ESP32 + return ledcSetup(ch, frequency, bits); +#endif } -float analogWriteFrequency(int8_t pin, float frequency) { - int8_t ch = getChannel(pin); - if (ch >= 0) { - if ((pinsStatus[ch / chd].pin) > 47) return -1; - pinsStatus[ch / chd].pin = pin; - pinsStatus[ch / chd].frequency = frequency; - //ledcChangeFrequency(ch, frequency, pinsStatus[ch / chd].resolution); - ledcSetup(ch, frequency, pinsStatus[ch / chd].resolution); - ledcWrite(ch, pinsStatus[ch / chd].value); - } - return ledcReadFreq(ch); +void awDetachPin(uint8_t pin, uint8_t ch) { + pinsStatus[ch / chd].pin = -1; + pinsStatus[ch / chd].value = 0; + pinsStatus[ch / chd].frequency = 980; + pinsStatus[ch / chd].resolution = 8; + pinsStatus[ch / chd].phase = 0; + ledcWrite(ch / chd, 0); + ledcSetup(ch / chd, 0, 0); + ledcDetachPin(pinsStatus[ch / chd].pin); + REG_SET_FIELD(GPIO_PIN_MUX_REG[pin], MCU_SEL, GPIO_MODE_DEF_DISABLE); } -int32_t analogWriteResolution(int8_t pin, uint8_t resolution) { - int8_t ch = getChannel(pin); - if (ch >= 0) { - if ((pinsStatus[ch / chd].pin) > 47) return -1; - pinsStatus[ch / chd].pin = pin; - pinsStatus[ch / chd].resolution = resolution; - ledcSetup(ch, pinsStatus[ch / chd].frequency, resolution); - ledcWrite(ch, pinsStatus[ch / chd].value); - } - return pow(2, resolution); +float awLedcReadFreq(uint8_t ch) { +#if (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3) + return ledcReadFreq(ch) / 80; //workaround for issue 5050 +#else //ESP32 + return ledcReadFreq(ch); +#endif } -int8_t getChannel(int8_t pin) { +int8_t awGetChannel(int8_t pin) { if (!((pinMask >> pin) & 1)) return -1; //not pwm pin for (int8_t i = 0; i < 8; i++) { int8_t ch = pinsStatus[i].channel; @@ -95,6 +71,7 @@ int8_t getChannel(int8_t pin) { if (pinsStatus[ch / chd].pin == -1) { //free channel if ((ledcRead(ch) < 1) && (ledcReadFreq(ch) < 1)) { //free timer pinsStatus[ch / chd].pin = pin; + aw::awLedcSetup(ch, pinsStatus[ch / chd].frequency, pinsStatus[ch / chd].resolution); ledcAttachPin(pin, ch); return ch; break; @@ -112,10 +89,172 @@ int8_t getChannel(int8_t pin) { return -1; } +} //namespace aw + +float analogWrite(int8_t pin, int32_t value) { + if (pin == DAC1 || pin == DAC2) { //dac + if (value > 255) value = 255; + dacWrite(pin, value); + } else { + int8_t ch = aw::awGetChannel(pin); + if (ch >= 0) { + if (value == -1) aw::awDetachPin(pin, ch); + else { // write PWM + uint8_t bits = aw::pinsStatus[ch / aw::chd].resolution; + if (value > ((1 << bits) - 1)) value = (1 << bits); //constrain + if ((bits > 7) && (value == ((1 << bits) - 1))) value = (1 << bits); //keep PWM high + if (ledcRead(ch) != value) ledcWrite(ch, value); + aw::pinsStatus[ch / aw::chd].value = value; + } + } + return aw::awLedcReadFreq(ch); + } + return 0; +} + +float analogWrite(int8_t pin, int32_t value, float frequency) { + if (pin == DAC1 || pin == DAC2) { //dac + if (value > 255) value = 255; + dacWrite(pin, value); + } else { + int8_t ch = aw::awGetChannel(pin); + if (ch >= 0) { + if ((aw::pinsStatus[ch / aw::chd].pin) > 47) return -1; + if (value == -1) aw::awDetachPin(pin, ch); + else { // write PWM + uint8_t bits = aw::pinsStatus[ch / aw::chd].resolution; + if (value > ((1 << bits) - 1)) value = (1 << bits); //constrain + if ((bits > 7) && (value == ((1 << bits) - 1))) value = (1 << bits); //keep PWM high + if (aw::pinsStatus[ch / aw::chd].frequency != frequency) { + aw::awLedcSetup(ch, frequency, bits); + ledcWrite(ch, value); + aw::pinsStatus[ch / aw::chd].frequency = frequency; + } + if (aw::pinsStatus[ch / aw::chd].value != value) { + ledcWrite(ch, value); + aw::pinsStatus[ch / aw::chd].value = value; + } + } + } + return aw::awLedcReadFreq(ch); + } + return 0; +} + +float analogWrite(int8_t pin, int32_t value, float frequency, uint8_t resolution) { + if (pin == DAC1 || pin == DAC2) { //dac + if (value > 255) value = 255; + dacWrite(pin, value); + } else { + int8_t ch = aw::awGetChannel(pin); + if (ch >= 0) { + if ((aw::pinsStatus[ch / aw::chd].pin) > 47) return -1; + if (value == -1) aw::awDetachPin(pin, ch); + else { // write PWM + uint8_t bits = resolution & 0xF; + if (value > ((1 << bits) - 1)) value = (1 << bits); //constrain + if ((bits > 7) && (value == ((1 << bits) - 1))) value = (1 << bits); //keep PWM high + if ((aw::pinsStatus[ch / aw::chd].frequency != frequency) || (aw::pinsStatus[ch / aw::chd].resolution != bits)) { + aw::awLedcSetup(ch, frequency, bits); + ledcWrite(ch, value); + aw::pinsStatus[ch / aw::chd].frequency = frequency; + aw::pinsStatus[ch / aw::chd].resolution = bits; + } + if (aw::pinsStatus[ch / aw::chd].value != value) { + ledcWrite(ch, value); + aw::pinsStatus[ch / aw::chd].value = value; + } + } + } + return aw::awLedcReadFreq(ch); + } + return 0; +} + +float analogWrite(int8_t pin, int32_t value, float frequency, uint8_t resolution, uint32_t phase) { + if (pin == DAC1 || pin == DAC2) { //dac + if (value > 255) value = 255; + dacWrite(pin, value); + } else { + int8_t ch = aw::awGetChannel(pin); + if (ch >= 0) { + if ((aw::pinsStatus[ch / aw::chd].pin) > 47) return -1; + if (value == -1) aw::awDetachPin(pin, ch); + else { // write PWM + uint8_t bits = resolution & 0xF; + if (value > ((1 << bits) - 1)) value = (1 << bits); //constrain + if ((bits > 7) && (value == ((1 << bits) - 1))) value = (1 << bits); //keep PWM high + if ((aw::pinsStatus[ch / aw::chd].frequency != frequency) || (aw::pinsStatus[ch / aw::chd].resolution != bits)) { + aw::awLedcSetup(ch, frequency, bits); + ledcWrite(ch, value); + aw::pinsStatus[ch / aw::chd].frequency = frequency; + aw::pinsStatus[ch / aw::chd].resolution = bits; + } + if (aw::pinsStatus[ch / aw::chd].phase != phase) { + uint32_t group = (ch / 8), timer = ((ch / 2) % 4); + aw::ledc_channel_config_t ledc_channel { + (uint8_t)pin, + (aw::ledc_mode_t)group, + (aw::ledc_channel_t)ch, + aw::LEDC_INTR_DISABLE, + (aw::ledc_timer_t)timer, + (uint32_t)value, + (int)phase, + }; + ledc_channel_config(&ledc_channel); + ledc_set_duty_with_hpoint((aw::ledc_mode_t)group, (aw::ledc_channel_t)ch, value, phase); + aw::pinsStatus[ch / aw::chd].phase = phase; + } + if (aw::pinsStatus[ch / aw::chd].value != value) { + ledcWrite(ch, value); + aw::pinsStatus[ch / aw::chd].value = value; + } + } + } + return aw::awLedcReadFreq(ch); + } + return 0; +} + +float analogWriteFrequency(int8_t pin, float frequency) { + int8_t ch = aw::awGetChannel(pin); + if (ch >= 0) { + if ((aw::pinsStatus[ch / aw::chd].pin) > 47) return -1; + if (aw::pinsStatus[ch / aw::chd].frequency != frequency) { + aw::awLedcSetup(ch, frequency, aw::pinsStatus[ch / aw::chd].resolution); + ledcWrite(ch, aw::pinsStatus[ch / aw::chd].value); + aw::pinsStatus[ch / aw::chd].frequency = frequency; + } + } + return aw::awLedcReadFreq(ch); +} + +int32_t analogWriteResolution(int8_t pin, uint8_t resolution) { + int8_t ch = aw::awGetChannel(pin); + if (ch >= 0) { + if ((aw::pinsStatus[ch / aw::chd].pin) > 47) return -1; + if (aw::pinsStatus[ch / aw::chd].resolution != resolution) { + aw::awLedcSetup(ch, aw::pinsStatus[ch / aw::chd].frequency, resolution & 0xF); + ledcWrite(ch, aw::pinsStatus[ch / aw::chd].value); + aw::pinsStatus[ch / aw::chd].resolution = resolution & 0xF; + } + } + return 1 << resolution & 0xF; +} + +void setPinsStatusDefaults(int32_t value, float frequency, uint8_t resolution, uint32_t phase) { + for (int8_t i = 0; i < 8; i++) { + aw::pinsStatus[i].value = value; + aw::pinsStatus[i].frequency = frequency; + aw::pinsStatus[i].resolution = resolution; + aw::pinsStatus[i].phase = phase; + } +} + void printPinsStatus() { Serial.print("PWM pins: "); - for (int i = 0; i < muxSize; i++) { - if ((pinMask >> i) & 1) { + for (int i = 0; i < aw::muxSize; i++) { + if ((aw::pinMask >> i) & 1) { Serial.print(i); Serial.print(", "); } } @@ -123,27 +262,32 @@ void printPinsStatus() { Serial.println(); for (int i = 0; i < 8; i++) { - int ch = pinsStatus[i].channel; + int ch = aw::pinsStatus[i].channel; Serial.print("ch: "); if (ch < 10) Serial.print(" "); Serial.print(ch); Serial.print(" "); Serial.print("Pin: "); - if ((pinsStatus[ch / chd].pin >= 0) && (pinsStatus[ch / chd].pin < 10)) Serial.print(" "); - Serial.print(pinsStatus[ch / chd].pin); Serial.print(" "); + if ((aw::pinsStatus[ch / aw::chd].pin >= 0) && (aw::pinsStatus[ch / aw::chd].pin < 10)) Serial.print(" "); + Serial.print(aw::pinsStatus[ch / aw::chd].pin); Serial.print(" "); Serial.print("Hz: "); - if (ledcReadFreq(ch) < 10000) Serial.print(" "); - if (ledcReadFreq(ch) < 1000) Serial.print(" "); - if (ledcReadFreq(ch) < 100) Serial.print(" "); - if (ledcReadFreq(ch) < 10) Serial.print(" "); - Serial.print(ledcReadFreq(ch)); Serial.print(" "); + if (aw::awLedcReadFreq(ch) < 10000) Serial.print(" "); + if (aw::awLedcReadFreq(ch) < 1000) Serial.print(" "); + if (aw::awLedcReadFreq(ch) < 100) Serial.print(" "); + if (aw::awLedcReadFreq(ch) < 10) Serial.print(" "); + Serial.print(aw::awLedcReadFreq(ch)); Serial.print(" "); Serial.print("Bits: "); - if (pinsStatus[ch / chd].resolution < 10) Serial.print(" "); - Serial.print(pinsStatus[ch / chd].resolution); Serial.print(" "); + if (aw::pinsStatus[ch / aw::chd].resolution < 10) Serial.print(" "); + Serial.print(aw::pinsStatus[ch / aw::chd].resolution); Serial.print(" "); Serial.print("Duty: "); - if (pinsStatus[ch / chd].value < 10000) Serial.print(" "); - if (pinsStatus[ch / chd].value < 1000) Serial.print(" "); - if (pinsStatus[ch / chd].value < 100) Serial.print(" "); - if (pinsStatus[ch / chd].value < 10) Serial.print(" "); - Serial.print(pinsStatus[ch / chd].value); + if (aw::pinsStatus[ch / aw::chd].value < 10000) Serial.print(" "); + if (aw::pinsStatus[ch / aw::chd].value < 1000) Serial.print(" "); + if (aw::pinsStatus[ch / aw::chd].value < 100) Serial.print(" "); + if (aw::pinsStatus[ch / aw::chd].value < 10) Serial.print(" "); + Serial.print(aw::pinsStatus[ch / aw::chd].value); Serial.print(" "); + Serial.print("Ø: "); + if (aw::pinsStatus[ch / aw::chd].phase < 1000) Serial.print(" "); + if (aw::pinsStatus[ch / aw::chd].phase < 100) Serial.print(" "); + if (aw::pinsStatus[ch / aw::chd].phase < 10) Serial.print(" "); + Serial.print(aw::pinsStatus[ch / aw::chd].phase); Serial.println(); } } diff --git a/utility/analogWrite.h b/utility/analogWrite.h index f3bb8f0..e584060 100644 --- a/utility/analogWrite.h +++ b/utility/analogWrite.h @@ -5,13 +5,19 @@ #if (defined(ESP32) || defined(ARDUINO_ARCH_ESP32)) +namespace aw { + +#include "driver/ledc.h" + #if (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3) + #define NUM_OUTPUT_PINS 45 #define DAC1 17 #define DAC2 18 const uint8_t muxSize = 48; const uint64_t pinMask = 0x27FE00207FFE; //PWM -#else + +#else //ESP32 #define NUM_OUTPUT_PINS 34 #define DAC1 25 #define DAC2 26 @@ -25,12 +31,23 @@ typedef struct pinStatus { float frequency; uint8_t resolution; uint32_t value; + uint32_t phase; } pinStatus_t; -float analogWriteFrequency(int8_t pin, float frequency = 5000); -int32_t analogWriteResolution(int8_t pin, uint8_t resolution = 13); -void analogWrite(int8_t pin, int32_t value = 0); -int8_t getChannel(int8_t pin); +float awLedcSetup(uint8_t ch, double frequency, uint8_t bits); +void awDetachPin(uint8_t pin, uint8_t ch); +float awLedcReadFreq(uint8_t ch); +int8_t awGetChannel(int8_t pin); + +} //namespace aw + +float analogWriteFrequency(int8_t pin, float frequency = 980); +int32_t analogWriteResolution(int8_t pin, uint8_t resolution = 8); +float analogWrite(int8_t pin, int32_t value, float frequency, uint8_t resolution, uint32_t phase); +float analogWrite(int8_t pin, int32_t value, float frequency, uint8_t resolution); +float analogWrite(int8_t pin, int32_t value, float frequency); +float analogWrite(int8_t pin, int32_t value); +void setPinsStatusDefaults(int32_t value = 0, float frequency = 980, uint8_t resolution = 8, uint32_t phase = 0); void printPinsStatus(void); #endif //ESP32 or ARDUINO_ARCH_ESP32