From 1d990ad0919a9214b85566ed954df95eac577c2f Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 3 Aug 2020 11:52:25 +0200 Subject: [PATCH] Fix ESP32 PWM range --- RELEASENOTES.md | 3 + .../src/esp8266toEsp32.h | 80 ++++++++++--------- tasmota/CHANGELOG.md | 1 + tasmota/support_command.ino | 26 +++--- tasmota/support_tasmota.ino | 9 +-- tasmota/xdrv_04_light.ino | 1 - tasmota/xlgt_03_sm16716.ino | 1 - 7 files changed, 65 insertions(+), 56 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ae3820c55..5a0d46ab4 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -54,3 +54,6 @@ The following binary downloads have been compiled with ESP8266/Arduino library c ## Changelog ### Version 8.4.0.1 + +- Fix ESP32 PWM range +- Add Zigbee better support for IKEA Motion Sensor diff --git a/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h b/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h index b9876ac15..a301189a6 100644 --- a/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h +++ b/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h @@ -29,28 +29,63 @@ #include /*********************************************************************************************\ - * ESP32 analogWrite support + * ESP32 analogWrite emulation support \*********************************************************************************************/ #define PWM_SUPPORTED_CHANNELS 8 #define PWM_CHANNEL_OFFSET 2 // Webcam uses channel 0, so we offset standard PWM uint8_t _pwm_channel[PWM_SUPPORTED_CHANNELS] = { 99, 99, 99, 99, 99, 99, 99, 99 }; - -inline void analogWriteFreq(uint32_t freq) { -} -inline void analogWriteRange(uint32_t range) { -} +uint32_t _pwm_frequency = 977; // Default 977Hz +uint8_t _pwm_bit_num = 10; // Default 1023 inline uint32_t _analog_pin2chan(uint32_t pin) { - for (uint32_t cnt = 0; cnt < PWM_SUPPORTED_CHANNELS; cnt++) { - if ((_pwm_channel[cnt] < 99) && (_pwm_channel[cnt] == pin)) { - return cnt; + for (uint32_t channel = 0; channel < PWM_SUPPORTED_CHANNELS; channel++) { + if ((_pwm_channel[channel] < 99) && (_pwm_channel[channel] == pin)) { + return channel; } } return 0; } +inline void _analogWriteFreqRange(void) { + for (uint32_t channel = 0; channel < PWM_SUPPORTED_CHANNELS; channel++) { + if (_pwm_channel[channel] < 99) { +// uint32_t duty = ledcRead(channel + PWM_CHANNEL_OFFSET); + ledcSetup(channel + PWM_CHANNEL_OFFSET, _pwm_frequency, _pwm_bit_num); +// ledcWrite(channel + PWM_CHANNEL_OFFSET, duty); + } + } +// Serial.printf("freq - range %d - %d\n",freq,range); +} + +// input range is in full range, ledc needs bits +inline uint32_t _analogGetResolution(uint32_t x) { + uint32_t bits = 0; + while (x) { + bits++; + x >>= 1; + } + return bits; +} + +inline void analogWriteRange(uint32_t range) { + _pwm_bit_num = _analogGetResolution(range); + _analogWriteFreqRange(); +} + +inline void analogWriteFreq(uint32_t freq) { + _pwm_frequency = freq; + _analogWriteFreqRange(); +} + +inline void analogAttach(uint32_t pin, uint32_t channel) { + _pwm_channel[channel &7] = pin; + ledcAttachPin(pin, channel + PWM_CHANNEL_OFFSET); + ledcSetup(channel + PWM_CHANNEL_OFFSET, _pwm_frequency, _pwm_bit_num); +// Serial.printf("attach %d - %d\n", channel, pin); +} + inline void analogWrite(uint8_t pin, int val) { uint32_t channel = _analog_pin2chan(pin); @@ -58,33 +93,6 @@ inline void analogWrite(uint8_t pin, int val) // Serial.printf("write %d - %d\n",channel,val); } -inline void analogAttach(uint32_t pin, uint32_t channel) { - _pwm_channel[channel &7] = pin; - ledcAttachPin(pin, channel + PWM_CHANNEL_OFFSET); -// Serial.printf("attach %d - %d\n",channel,pin); -} - -inline uint32_t _analog_pow2(uint32_t x) { - uint32_t power = 1; - uint32_t bits = 0; - while (power < x) { - power *= 2; - bits++; - } - return bits; -} - -// input range is in full range, ledc needs bits -inline void analogWriteFreqRange(uint32_t channel, uint32_t freq, uint32_t irange) { - uint32_t range = _analog_pow2(irange); - for (uint32_t cnt = 0; cnt < PWM_SUPPORTED_CHANNELS; cnt++) { - if (_pwm_channel[cnt] < 99) { - ledcSetup(cnt + PWM_CHANNEL_OFFSET, freq, range); - } - } -// Serial.printf("freq - range %d - %d\n",freq,range); -} - /*********************************************************************************************/ #define INPUT_PULLDOWN_16 INPUT_PULLUP diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 237d131b3..7ceb6f7c1 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -2,6 +2,7 @@ ### 8.4.0.1 20200730 +- Fix ESP32 PWM range - Add Zigbee better support for IKEA Motion Sensor ### 8.4.0 20200730 diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index 0affcb83e..49f554b18 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -1236,29 +1236,31 @@ void CmndPwmfrequency(void) { if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload >= PWM_MIN) && (XdrvMailbox.payload <= PWM_MAX))) { Settings.pwm_frequency = (1 == XdrvMailbox.payload) ? PWM_FREQ : XdrvMailbox.payload; -#ifdef ESP8266 analogWriteFreq(Settings.pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c) -#else - analogWriteFreqRange(0,Settings.pwm_frequency,Settings.pwm_range); -#endif } ResponseCmndNumber(Settings.pwm_frequency); } -void CmndPwmrange(void) -{ +void CmndPwmrange(void) { + // Support only 8 (=255), 9 (=511) and 10 (=1023) bits resolution if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload > 254) && (XdrvMailbox.payload < 1024))) { - Settings.pwm_range = (1 == XdrvMailbox.payload) ? PWM_RANGE : XdrvMailbox.payload; + uint32_t pwm_range = XdrvMailbox.payload; + uint32_t pwm_resolution = 0; + while (pwm_range) { + pwm_resolution++; + pwm_range >>= 1; + } + pwm_range = (1 << pwm_resolution) - 1; + uint32_t old_pwm_range = Settings.pwm_range; + Settings.pwm_range = (1 == XdrvMailbox.payload) ? PWM_RANGE : pwm_range; for (uint32_t i = 0; i < MAX_PWMS; i++) { if (Settings.pwm_value[i] > Settings.pwm_range) { Settings.pwm_value[i] = Settings.pwm_range; } } -#ifdef ESP8266 - analogWriteRange(Settings.pwm_range); // Default is 1023 (Arduino.h) -#else - analogWriteFreqRange(0,Settings.pwm_frequency,Settings.pwm_range); -#endif + if (Settings.pwm_range != old_pwm_range) { // On ESP32 this prevents loss of duty state + analogWriteRange(Settings.pwm_range); // Default is 1023 (Arduino.h) + } } ResponseCmndNumber(Settings.pwm_range); } diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 6b0dd6f4e..db4ce592f 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -1564,12 +1564,12 @@ void GpioInit(void) // AddLogBufferSize(LOG_LEVEL_DEBUG, (uint8_t*)gpio_pin, ARRAY_SIZE(gpio_pin), sizeof(gpio_pin[0])); -#ifdef ESP8266 - if ((2 == Pin(GPIO_TXD)) || (H801 == my_module_type)) { Serial.set_tx(2); } - analogWriteRange(Settings.pwm_range); // Default is 1023 (Arduino.h) analogWriteFreq(Settings.pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c) +#ifdef ESP8266 + if ((2 == Pin(GPIO_TXD)) || (H801 == my_module_type)) { Serial.set_tx(2); } + #ifdef USE_SPI spi_flg = (((PinUsed(GPIO_SPI_CS) && (Pin(GPIO_SPI_CS) > 14)) || (Pin(GPIO_SPI_CS) < 12)) || ((PinUsed(GPIO_SPI_DC) && (Pin(GPIO_SPI_DC) > 14)) || (Pin(GPIO_SPI_DC) < 12))); if (spi_flg) { @@ -1584,8 +1584,6 @@ void GpioInit(void) soft_spi_flg = (PinUsed(GPIO_SSPI_CS) && PinUsed(GPIO_SSPI_SCLK) && (PinUsed(GPIO_SSPI_MOSI) || PinUsed(GPIO_SSPI_MISO))); #endif // USE_SPI #else // ESP32 - analogWriteFreqRange(0, Settings.pwm_frequency, Settings.pwm_range); - #ifdef USE_SPI if (PinUsed(GPIO_SPI_CS) || PinUsed(GPIO_SPI_DC)) { if ((15 == Pin(GPIO_SPI_CS)) && (!GetPin(12) && !GetPin(13) && !GetPin(14))) { // HSPI @@ -1690,7 +1688,6 @@ void GpioInit(void) pinMode(Pin(GPIO_PWM1, i), OUTPUT); #else // ESP32 analogAttach(Pin(GPIO_PWM1, i), i); - analogWriteFreqRange(i, Settings.pwm_frequency, Settings.pwm_range); #endif if (light_type) { // force PWM GPIOs to low or high mode, see #7165 diff --git a/tasmota/xdrv_04_light.ino b/tasmota/xdrv_04_light.ino index 97a09a806..908ec026e 100644 --- a/tasmota/xdrv_04_light.ino +++ b/tasmota/xdrv_04_light.ino @@ -1355,7 +1355,6 @@ void LightInit(void) pinMode(Pin(GPIO_PWM1, i), OUTPUT); #else // ESP32 analogAttach(Pin(GPIO_PWM1, i), i); - analogWriteFreqRange(i, Settings.pwm_frequency, Settings.pwm_range); #endif } } diff --git a/tasmota/xlgt_03_sm16716.ino b/tasmota/xlgt_03_sm16716.ino index 81e38996f..0c6866ada 100644 --- a/tasmota/xlgt_03_sm16716.ino +++ b/tasmota/xlgt_03_sm16716.ino @@ -152,7 +152,6 @@ void Sm16716ModuleSelected(void) pinMode(Pin(GPIO_PWM1, i), OUTPUT); #else // ESP32 analogAttach(Pin(GPIO_PWM1, i), i); - analogWriteFreqRange(i, Settings.pwm_frequency, Settings.pwm_range); #endif } }