Fix ESP32 PWM range

This commit is contained in:
Theo Arends 2020-08-03 11:52:25 +02:00
parent ff37beac6a
commit 1d990ad091
7 changed files with 65 additions and 56 deletions

View File

@ -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

View File

@ -29,28 +29,63 @@
#include <Esp.h>
/*********************************************************************************************\
* 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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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
}
}