mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-21 17:56:31 +00:00
Esp32 improve PWM inverted
This commit is contained in:
parent
3c1f30d3be
commit
a7577cfefc
@ -97,16 +97,33 @@ void analogWriteFreq(uint32_t freq) {
|
|||||||
_analogWriteFreqRange();
|
_analogWriteFreqRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t analogAttach(uint32_t pin) { // returns ledc channel used, or -1 if failed
|
int32_t analogAttach(uint32_t pin, bool output_invert) { // returns ledc channel used, or -1 if failed
|
||||||
_analogInit(); // make sure the mapping array is initialized
|
_analogInit(); // make sure the mapping array is initialized
|
||||||
// Find if pin is already attached
|
// Find if pin is already attached
|
||||||
int32_t channel = _analog_pin2chan(pin);
|
int32_t chan = _analog_pin2chan(pin);
|
||||||
if (channel >= 0) { return channel; }
|
if (chan >= 0) { return chan; }
|
||||||
// Find an empty channel
|
// Find an empty channel
|
||||||
for (channel = 0; channel < MAX_PWMS; channel++) {
|
for (chan = 0; chan < MAX_PWMS; chan++) {
|
||||||
if (255 == pwm_channel[channel]) {
|
if (255 == pwm_channel[chan]) {
|
||||||
pwm_channel[channel] = pin;
|
pwm_channel[chan] = pin;
|
||||||
ledcAttachPin(pin, channel);
|
|
||||||
|
// ledcAttachPin(pin, channel); -- replicating here because we want the default duty
|
||||||
|
uint8_t group=(chan/8), channel=(chan%8), timer=((chan/2)%4);
|
||||||
|
|
||||||
|
// AddLog(LOG_LEVEL_INFO, "PWM: ledc_channel pin=%i out_invert=%i", pin, output_invert);
|
||||||
|
ledc_channel_config_t ledc_channel = {
|
||||||
|
(int)pin, // gpio
|
||||||
|
(ledc_mode_t)group, // speed-mode
|
||||||
|
(ledc_channel_t)channel, // channel
|
||||||
|
(ledc_intr_type_t)LEDC_INTR_DISABLE, // intr_type
|
||||||
|
(ledc_timer_t)timer, // timer_sel
|
||||||
|
0, // duty
|
||||||
|
0, // hpoint
|
||||||
|
{ output_invert ? 1u : 0u },// output_invert
|
||||||
|
};
|
||||||
|
ledc_channel_config(&ledc_channel);
|
||||||
|
|
||||||
|
|
||||||
ledcSetup(channel, pwm_frequency, pwm_bit_num);
|
ledcSetup(channel, pwm_frequency, pwm_bit_num);
|
||||||
// Serial.printf("PWM: New attach pin %d to channel %d\n", pin, channel);
|
// Serial.printf("PWM: New attach pin %d to channel %d\n", pin, channel);
|
||||||
return channel;
|
return channel;
|
||||||
@ -153,6 +170,7 @@ void analogWritePhase(uint8_t pin, uint32_t duty, uint32_t phase)
|
|||||||
chan = analogAttach(pin);
|
chan = analogAttach(pin);
|
||||||
if (chan < 0) { return; } // failed
|
if (chan < 0) { return; } // failed
|
||||||
}
|
}
|
||||||
|
// AddLog(LOG_LEVEL_INFO, "PWM: analogWritePhase pin=%i chan=%i duty=%03X phase=%03X", pin, chan, duty, phase);
|
||||||
|
|
||||||
if (duty >> (pwm_bit_num-1) ) ++duty; // input is 0..1023 but PWM takes 0..1024 - so we skip at mid-range. It creates a small non-linearity
|
if (duty >> (pwm_bit_num-1) ) ++duty; // input is 0..1023 but PWM takes 0..1024 - so we skip at mid-range. It creates a small non-linearity
|
||||||
if (phase >> (pwm_bit_num-1) ) ++phase;
|
if (phase >> (pwm_bit_num-1) ) ++phase;
|
||||||
@ -163,8 +181,10 @@ void analogWritePhase(uint8_t pin, uint32_t duty, uint32_t phase)
|
|||||||
uint32_t max_duty = (1 << channels_resolution[chan]) - 1;
|
uint32_t max_duty = (1 << channels_resolution[chan]) - 1;
|
||||||
phase = phase & max_duty;
|
phase = phase & max_duty;
|
||||||
|
|
||||||
ledc_set_duty_with_hpoint((ledc_mode_t)group, (ledc_channel_t)channel, duty, phase);
|
esp_err_t err1, err2;
|
||||||
ledc_update_duty((ledc_mode_t)group, (ledc_channel_t)channel);
|
err1 = ledc_set_duty_with_hpoint((ledc_mode_t)group, (ledc_channel_t)channel, duty, phase);
|
||||||
|
err2 = ledc_update_duty((ledc_mode_t)group, (ledc_channel_t)channel);
|
||||||
|
// AddLog(LOG_LEVEL_INFO, "PWM: err1=%i err2=%i", err1, err2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ESP32
|
#endif // ESP32
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
// input range is in full range, ledc needs bits
|
// input range is in full range, ledc needs bits
|
||||||
void analogWriteRange(uint32_t range);
|
void analogWriteRange(uint32_t range);
|
||||||
void analogWriteFreq(uint32_t freq);
|
void analogWriteFreq(uint32_t freq);
|
||||||
int32_t analogAttach(uint32_t pin); // returns the ledc channel, or -1 if failed. This is implicitly called by analogWrite if the channel was not already allocated
|
int32_t analogAttach(uint32_t pin, bool output_invert = false); // returns the ledc channel, or -1 if failed. This is implicitly called by analogWrite if the channel was not already allocated
|
||||||
void analogWrite(uint8_t pin, int val);
|
void analogWrite(uint8_t pin, int val);
|
||||||
|
|
||||||
// Extended version that also allows to change phase
|
// Extended version that also allows to change phase
|
||||||
|
@ -64,7 +64,8 @@ void PwmSaveToSettings(void) {
|
|||||||
// or `-1` if no change.
|
// or `-1` if no change.
|
||||||
// Auto-phasing is recomputed, and changes are applied to GPIO if there is a physical GPIO configured and an actual change needed
|
// Auto-phasing is recomputed, and changes are applied to GPIO if there is a physical GPIO configured and an actual change needed
|
||||||
//
|
//
|
||||||
void PwmApplyGPIO(void) {
|
// force_update_all: force applying the PWM values even if the value didn't change (necessary at initialization)
|
||||||
|
void PwmApplyGPIO(bool force_update_all) {
|
||||||
uint32_t pwm_phase_accumulator = 0; // dephase each PWM channel with the value of the previous
|
uint32_t pwm_phase_accumulator = 0; // dephase each PWM channel with the value of the previous
|
||||||
|
|
||||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||||
@ -73,9 +74,6 @@ void PwmApplyGPIO(void) {
|
|||||||
if (TasmotaGlobal.pwm_value[i] >= 0) { pwm_val = TasmotaGlobal.pwm_value[i]; } // new value explicitly specified
|
if (TasmotaGlobal.pwm_value[i] >= 0) { pwm_val = TasmotaGlobal.pwm_value[i]; } // new value explicitly specified
|
||||||
if (pwm_val > Settings->pwm_range) { pwm_val = Settings->pwm_range; } // prevent overflow
|
if (pwm_val > Settings->pwm_range) { pwm_val = Settings->pwm_range; } // prevent overflow
|
||||||
|
|
||||||
// gpio_val : actual value of GPIO, taking into account inversion
|
|
||||||
uint32_t gpio_val = bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - pwm_val : pwm_val;
|
|
||||||
|
|
||||||
// compute phase
|
// compute phase
|
||||||
uint32_t pwm_phase = TasmotaGlobal.pwm_cur_phase[i]; // pwm_phase is the logical phase of the active pulse, ignoring inverted
|
uint32_t pwm_phase = TasmotaGlobal.pwm_cur_phase[i]; // pwm_phase is the logical phase of the active pulse, ignoring inverted
|
||||||
uint32_t gpio_phase = pwm_phase; // gpio is the physical phase taking into account inverted
|
uint32_t gpio_phase = pwm_phase; // gpio is the physical phase taking into account inverted
|
||||||
@ -86,17 +84,17 @@ void PwmApplyGPIO(void) {
|
|||||||
} else {
|
} else {
|
||||||
// compute auto-phase
|
// compute auto-phase
|
||||||
pwm_phase = pwm_phase_accumulator;
|
pwm_phase = pwm_phase_accumulator;
|
||||||
uint32_t pwm_phase_invert = bitRead(TasmotaGlobal.pwm_inverted, i) ? pwm_val : 0; // move phase if inverted
|
|
||||||
gpio_phase = (pwm_phase + pwm_phase_invert) & Settings->pwm_range;
|
|
||||||
// accumulate phase for next GPIO
|
// accumulate phase for next GPIO
|
||||||
pwm_phase_accumulator = (pwm_phase + pwm_val) & Settings->pwm_range;
|
pwm_phase_accumulator = (pwm_phase + pwm_val) & Settings->pwm_range;
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply new values to GPIO if GPIO is set
|
// apply new values to GPIO if GPIO is set
|
||||||
|
// AddLog(LOG_LEVEL_INFO, "PWM: i=%i used=%i pwm_val=%03X vs %03X pwm_phase=%03X vs %03X", i, PinUsed(GPIO_PWM1, i), pwm_val, TasmotaGlobal.pwm_cur_value[i], pwm_phase, TasmotaGlobal.pwm_cur_phase[i]);
|
||||||
if (PinUsed(GPIO_PWM1, i)) {
|
if (PinUsed(GPIO_PWM1, i)) {
|
||||||
if ((pwm_val != TasmotaGlobal.pwm_cur_value[i]) || (pwm_phase != TasmotaGlobal.pwm_cur_phase[i])) {
|
if (force_update_all || (pwm_val != TasmotaGlobal.pwm_cur_value[i]) || (pwm_phase != TasmotaGlobal.pwm_cur_phase[i])) {
|
||||||
// GPIO has PWM and there is a chnage to apply, apply it
|
// GPIO has PWM and there is a chnage to apply, apply it
|
||||||
analogWritePhase(Pin(GPIO_PWM1, i), gpio_val, gpio_phase);
|
analogWritePhase(Pin(GPIO_PWM1, i), pwm_val, pwm_phase);
|
||||||
|
// AddLog(LOG_LEVEL_INFO, "PWM: analogWritePhase i=%i val=%03X phase=%03X", i, pwm_val, pwm_phase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,13 +102,13 @@ void PwmApplyGPIO(void) {
|
|||||||
TasmotaGlobal.pwm_cur_value[i] = pwm_val;
|
TasmotaGlobal.pwm_cur_value[i] = pwm_val;
|
||||||
TasmotaGlobal.pwm_cur_phase[i] = pwm_phase;
|
TasmotaGlobal.pwm_cur_phase[i] = pwm_phase;
|
||||||
}
|
}
|
||||||
// AddLog(LOG_LEVEL_INFO, "PWM: Val=%03X-%03X-%03X-%03X-%03X Phase=%03X-%03X-%03X-%03X-%03X Range=%03X",
|
AddLog(LOG_LEVEL_INFO, "PWM: Val=%03X-%03X-%03X-%03X-%03X Phase=%03X-%03X-%03X-%03X-%03X Range=%03X",
|
||||||
// TasmotaGlobal.pwm_cur_value[0], TasmotaGlobal.pwm_cur_value[1], TasmotaGlobal.pwm_cur_value[2], TasmotaGlobal.pwm_cur_value[3],
|
TasmotaGlobal.pwm_cur_value[0], TasmotaGlobal.pwm_cur_value[1], TasmotaGlobal.pwm_cur_value[2], TasmotaGlobal.pwm_cur_value[3],
|
||||||
// TasmotaGlobal.pwm_cur_value[4],
|
TasmotaGlobal.pwm_cur_value[4],
|
||||||
// TasmotaGlobal.pwm_cur_phase[0], TasmotaGlobal.pwm_cur_phase[1], TasmotaGlobal.pwm_cur_phase[2], TasmotaGlobal.pwm_cur_phase[3],
|
TasmotaGlobal.pwm_cur_phase[0], TasmotaGlobal.pwm_cur_phase[1], TasmotaGlobal.pwm_cur_phase[2], TasmotaGlobal.pwm_cur_phase[3],
|
||||||
// TasmotaGlobal.pwm_cur_phase[4],
|
TasmotaGlobal.pwm_cur_phase[4],
|
||||||
// Settings->pwm_range
|
Settings->pwm_range
|
||||||
// );
|
);
|
||||||
PwmSaveToSettings(); // copy to Settings
|
PwmSaveToSettings(); // copy to Settings
|
||||||
PwmRearmChanges(); // reset expected changes
|
PwmRearmChanges(); // reset expected changes
|
||||||
}
|
}
|
||||||
@ -120,7 +118,7 @@ void CmndPwm(void)
|
|||||||
if (TasmotaGlobal.pwm_present && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_PWMS)) {
|
if (TasmotaGlobal.pwm_present && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_PWMS)) {
|
||||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= Settings->pwm_range) && PinUsed(GPIO_PWM1, XdrvMailbox.index -1)) {
|
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= Settings->pwm_range) && PinUsed(GPIO_PWM1, XdrvMailbox.index -1)) {
|
||||||
TasmotaGlobal.pwm_value[XdrvMailbox.index - 1] = XdrvMailbox.payload;
|
TasmotaGlobal.pwm_value[XdrvMailbox.index - 1] = XdrvMailbox.payload;
|
||||||
PwmApplyGPIO();
|
PwmApplyGPIO(false);
|
||||||
}
|
}
|
||||||
Response_P(PSTR("{"));
|
Response_P(PSTR("{"));
|
||||||
MqttShowPWMState(); // Render the PWM status to MQTT
|
MqttShowPWMState(); // Render the PWM status to MQTT
|
||||||
@ -133,7 +131,7 @@ void GpioInitPwm(void) {
|
|||||||
|
|
||||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||||
if (PinUsed(GPIO_PWM1, i)) {
|
if (PinUsed(GPIO_PWM1, i)) {
|
||||||
analogAttach(Pin(GPIO_PWM1, i));
|
analogAttach(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i));
|
||||||
if (i < TasmotaGlobal.light_type) {
|
if (i < TasmotaGlobal.light_type) {
|
||||||
// force PWM GPIOs to black
|
// force PWM GPIOs to black
|
||||||
TasmotaGlobal.pwm_value[i] = 0;
|
TasmotaGlobal.pwm_value[i] = 0;
|
||||||
@ -147,7 +145,7 @@ void GpioInitPwm(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PwmApplyGPIO(); // apply all changes
|
PwmApplyGPIO(true); // apply all changes
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************************************/
|
/********************************************************************************************/
|
||||||
@ -157,7 +155,7 @@ void ResetPwm(void)
|
|||||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||||
TasmotaGlobal.pwm_value[i] = 0;
|
TasmotaGlobal.pwm_value[i] = 0;
|
||||||
}
|
}
|
||||||
PwmApplyGPIO();
|
PwmApplyGPIO(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // now for ESP8266
|
#else // now for ESP8266
|
||||||
|
@ -2163,7 +2163,7 @@ void LightSetOutputs(const uint16_t *cur_col_10) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
PwmApplyGPIO();
|
PwmApplyGPIO(false);
|
||||||
#endif // ESP32
|
#endif // ESP32
|
||||||
|
|
||||||
#ifdef USE_PWM_DIMMER
|
#ifdef USE_PWM_DIMMER
|
||||||
|
Loading…
x
Reference in New Issue
Block a user