Skip to content

Commit

Permalink
Update ESP32 Support
Browse files Browse the repository at this point in the history
  • Loading branch information
Dlloydev committed May 3, 2021
1 parent 099be92 commit f408d87
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 84 deletions.
2 changes: 1 addition & 1 deletion QuickPID.cpp
Original file line number Diff line number Diff line change
@@ -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
**********************************************************************************/
Expand Down
2 changes: 1 addition & 1 deletion QuickPID.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=QuickPID
version=2.2.4
version=2.2.5
author=David Lloyd
maintainer=David Lloyd <dlloydev@testcor.ca>
sentence=A fast fixed/floating point PID controller with AutoTune and 9 tuning rules to choose from.
Expand Down
296 changes: 220 additions & 76 deletions utility/analogWrite.cpp
Original file line number Diff line number Diff line change
@@ -1,86 +1,62 @@
/**********************************************************************************
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
**********************************************************************************/

#include <Arduino.h>
#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;
Expand All @@ -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;
Expand All @@ -112,38 +89,205 @@ 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(", ");
}
}
Serial.println();

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();
}
}
Loading

0 comments on commit f408d87

Please sign in to comment.