mirror of https://github.com/arendst/Tasmota.git
Esp32 improve PWM inverted
This commit is contained in:
parent
3c1f30d3be
commit
a7577cfefc
|
@ -97,16 +97,33 @@ void analogWriteFreq(uint32_t freq) {
|
|||
_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
|
||||
// Find if pin is already attached
|
||||
int32_t channel = _analog_pin2chan(pin);
|
||||
if (channel >= 0) { return channel; }
|
||||
int32_t chan = _analog_pin2chan(pin);
|
||||
if (chan >= 0) { return chan; }
|
||||
// Find an empty channel
|
||||
for (channel = 0; channel < MAX_PWMS; channel++) {
|
||||
if (255 == pwm_channel[channel]) {
|
||||
pwm_channel[channel] = pin;
|
||||
ledcAttachPin(pin, channel);
|
||||
for (chan = 0; chan < MAX_PWMS; chan++) {
|
||||
if (255 == pwm_channel[chan]) {
|
||||
pwm_channel[chan] = pin;
|
||||
|
||||
// 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);
|
||||
// Serial.printf("PWM: New attach pin %d to channel %d\n", pin, channel);
|
||||
return channel;
|
||||
|
@ -153,6 +170,7 @@ void analogWritePhase(uint8_t pin, uint32_t duty, uint32_t phase)
|
|||
chan = analogAttach(pin);
|
||||
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 (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;
|
||||
phase = phase & max_duty;
|
||||
|
||||
ledc_set_duty_with_hpoint((ledc_mode_t)group, (ledc_channel_t)channel, duty, phase);
|
||||
ledc_update_duty((ledc_mode_t)group, (ledc_channel_t)channel);
|
||||
esp_err_t err1, err2;
|
||||
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
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
// input range is in full range, ledc needs bits
|
||||
void analogWriteRange(uint32_t range);
|
||||
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);
|
||||
|
||||
// Extended version that also allows to change phase
|
||||
|
|
|
@ -64,7 +64,8 @@ void PwmSaveToSettings(void) {
|
|||
// 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
|
||||
//
|
||||
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
|
||||
|
||||
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 (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
|
||||
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
|
||||
|
@ -86,17 +84,17 @@ void PwmApplyGPIO(void) {
|
|||
} else {
|
||||
// compute auto-phase
|
||||
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
|
||||
pwm_phase_accumulator = (pwm_phase + pwm_val) & Settings->pwm_range;
|
||||
}
|
||||
|
||||
// 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 ((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
|
||||
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_phase[i] = pwm_phase;
|
||||
}
|
||||
// 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[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[4],
|
||||
// Settings->pwm_range
|
||||
// );
|
||||
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[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[4],
|
||||
Settings->pwm_range
|
||||
);
|
||||
PwmSaveToSettings(); // copy to Settings
|
||||
PwmRearmChanges(); // reset expected changes
|
||||
}
|
||||
|
@ -120,7 +118,7 @@ void CmndPwm(void)
|
|||
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)) {
|
||||
TasmotaGlobal.pwm_value[XdrvMailbox.index - 1] = XdrvMailbox.payload;
|
||||
PwmApplyGPIO();
|
||||
PwmApplyGPIO(false);
|
||||
}
|
||||
Response_P(PSTR("{"));
|
||||
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
|
||||
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) {
|
||||
// force PWM GPIOs to black
|
||||
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
|
||||
TasmotaGlobal.pwm_value[i] = 0;
|
||||
}
|
||||
PwmApplyGPIO();
|
||||
PwmApplyGPIO(true);
|
||||
}
|
||||
|
||||
#else // now for ESP8266
|
||||
|
|
|
@ -2163,7 +2163,7 @@ void LightSetOutputs(const uint16_t *cur_col_10) {
|
|||
}
|
||||
}
|
||||
#ifdef ESP32
|
||||
PwmApplyGPIO();
|
||||
PwmApplyGPIO(false);
|
||||
#endif // ESP32
|
||||
|
||||
#ifdef USE_PWM_DIMMER
|
||||
|
|
Loading…
Reference in New Issue