diff --git a/cores/esp32/esp32-hal-ledc.c b/cores/esp32/esp32-hal-ledc.c index 1847f6af839..b6327d7b966 100644 --- a/cores/esp32/esp32-hal-ledc.c +++ b/cores/esp32/esp32-hal-ledc.c @@ -330,13 +330,13 @@ bool ledcWrite(uint8_t pin, uint32_t duty) { ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC); if (bus != NULL) { - uint8_t group = (bus->channel / SOC_LEDC_CHANNEL_NUM), channel = (bus->channel % SOC_LEDC_CHANNEL_NUM); - //Fixing if all bits in resolution is set = LEDC FULL ON - uint32_t max_duty = (1 << bus->channel_resolution) - 1; + uint8_t group = (bus->channel / SOC_LEDC_CHANNEL_NUM), channel = (bus->channel % SOC_LEDC_CHANNEL_NUM); + uint32_t max_duty = (1 << bus->channel_resolution); // Max LEDC duty - if ((duty == max_duty) && (max_duty != 1)) { - duty = max_duty + 1; + if (duty > max_duty) { + log_w("Target duty %d was adjusted to the maximum duty %d", duty, max_duty); + duty = max_duty; } if (ledc_set_duty(group, channel, duty) != ESP_OK) { @@ -368,11 +368,11 @@ bool ledcWriteChannel(uint8_t channel, uint32_t duty) { //Fixing if all bits in resolution is set = LEDC FULL ON uint32_t resolution = 0; ledc_ll_get_duty_resolution(LEDC_LL_GET_HW(), group, timer, &resolution); + uint32_t max_duty = (1 << resolution); // Max LEDC duty - uint32_t max_duty = (1 << resolution) - 1; - - if ((duty == max_duty) && (max_duty != 1)) { - duty = max_duty + 1; + if (duty > max_duty) { + log_w("Target duty %d was adjusted to the maximum duty %d", duty, max_duty); + duty = max_duty; } if (ledc_set_duty(group, channel, duty) != ESP_OK) { @@ -435,15 +435,16 @@ uint32_t ledcWriteTone(uint8_t pin, uint32_t freq) { bus->channel_resolution = 10; uint32_t res_freq = ledc_get_freq(group, bus->timer_num); - ledcWrite(pin, 0x1FF); + ledcWrite(pin, 0x200); // LEDC 50% duty is 2^10 / 2 = 0x200 return res_freq; } return 0; } uint32_t ledcWriteNote(uint8_t pin, note_t note, uint8_t octave) { - const uint16_t noteFrequencyBase[12] = {// C C# D Eb E F F# G G# A Bb B - 4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902 + const uint16_t noteFrequencyBase[12] = { + // C C# D Eb E F F# G G# A Bb B + 4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902 }; if (octave > 8 || note >= NOTE_MAX) { @@ -557,6 +558,21 @@ static bool ledcFadeConfig(uint8_t pin, uint32_t start_duty, uint32_t target_dut #endif uint8_t group = (bus->channel / SOC_LEDC_CHANNEL_NUM), channel = (bus->channel % SOC_LEDC_CHANNEL_NUM); + uint32_t max_duty = (1 << bus->channel_resolution); // Max LEDC duty + + if (target_duty > max_duty) { + log_w("Final duty %d was adjusted to the maximum duty %d", target_duty, max_duty); + target_duty = max_duty; + } + if (start_duty > max_duty) { + log_w("Starting duty %d was adjusted to the maximum duty %d", start_duty, max_duty); + start_duty = max_duty; + } + if (start_duty >= target_duty) { + log_e("Starting duty must be lower than the final duty"); + return false; + } + // Initialize fade service. if (!fade_initialized) { ledc_fade_func_install(0); @@ -569,15 +585,6 @@ static bool ledcFadeConfig(uint8_t pin, uint32_t start_duty, uint32_t target_dut ledc_cbs_t callbacks = {.fade_cb = ledcFnWrapper}; ledc_cb_register(group, channel, &callbacks, (void *)bus); - //Fixing if all bits in resolution is set = LEDC FULL ON - uint32_t max_duty = (1 << bus->channel_resolution) - 1; - - if ((target_duty == max_duty) && (max_duty != 1)) { - target_duty = max_duty + 1; - } else if ((start_duty == max_duty) && (max_duty != 1)) { - start_duty = max_duty + 1; - } - #if SOC_LEDC_SUPPORT_FADE_STOP ledc_fade_stop(group, channel); #endif @@ -779,6 +786,17 @@ void analogWrite(uint8_t pin, int value) { return; } } + // Arduino API says that duty goes from 0 to (2^resolution) - 1 + // But LEDC works with duty from 0 to (2^resolution) + // Therefore, it will adjust Arduino MAX Duty to be the LEDC MAx Duty + uint32_t max_duty = (1 << bus->channel_resolution) - 1; + if (value < 0 || value > max_duty) { + log_e("Duty is out of range. Valid duty range for pin %d is 0 to %d", pin, max_duty); + return; + } + if (value == max_duty) { + value = max_duty + 1; + } ledcWrite(pin, value); } } diff --git a/docs/en/api/ledc.rst b/docs/en/api/ledc.rst index d3d6da1e0f6..a6e9d323d65 100644 --- a/docs/en/api/ledc.rst +++ b/docs/en/api/ledc.rst @@ -100,7 +100,7 @@ This function is used to set duty for the LEDC pin. bool ledcWrite(uint8_t pin, uint32_t duty); * ``pin`` select LEDC pin. -* ``duty`` select duty to be set for selected LEDC pin. +* ``duty`` select duty to be set for selected LEDC pin. Maximum value is 2 ^ ``resolution`` (number of bits). This function will return ``true`` if setting duty is successful. If ``false`` is returned, error occurs and duty was not set. @@ -115,7 +115,7 @@ This function is used to set duty for the LEDC channel. bool ledcWriteChannel(uint8_t channel, uint32_t duty); * ``channel`` select LEDC channel. -* ``duty`` select duty to be set for selected LEDC channel. +* ``duty`` select duty to be set for selected LEDC channel. Maximum value is 2 ^ ``resolution`` (number of bits). This function will return ``true`` if setting duty is successful. If ``false`` is returned, error occurs and duty was not set. @@ -240,8 +240,8 @@ This function is used to setup and start fade for the LEDC pin. bool ledcFade(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms); * ``pin`` select LEDC pin. -* ``start_duty`` select starting duty of fade. -* ``target_duty`` select target duty of fade. +* ``start_duty`` select starting duty of fade. Maximum value is 2 ^ ``resolution`` (number of bits). +* ``target_duty`` select target duty of fade. Maximum value is 2 ^ ``resolution`` (number of bits). * ``max_fade_time_ms`` select maximum time for fade. This function will return ``true`` if configuration is successful. @@ -257,8 +257,8 @@ This function is used to setup and start fade for the LEDC pin with interrupt. bool ledcFadeWithInterrupt(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, void (*userFunc)(void)); * ``pin`` select LEDC pin. -* ``start_duty`` select starting duty of fade. -* ``target_duty`` select target duty of fade. +* ``start_duty`` select starting duty of fade. Maximum value is 2 ^ ``resolution`` (number of bits). +* ``target_duty`` select target duty of fade. Maximum value is 2 ^ ``resolution`` (number of bits). * ``max_fade_time_ms`` select maximum time for fade. * ``userFunc`` function to be called when interrupt is triggered. @@ -275,8 +275,8 @@ This function is used to setup and start fade for the LEDC pin with interrupt us bool ledcFadeWithInterruptArg(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, void (*userFunc)(void*), void * arg); * ``pin`` select LEDC pin. -* ``start_duty`` select starting duty of fade. -* ``target_duty`` select target duty of fade. +* ``start_duty`` select starting duty of fade. Maximum value is 2 ^ ``resolution`` (number of bits). +* ``target_duty`` select target duty of fade. Maximum value is 2 ^ ``resolution`` (number of bits). * ``max_fade_time_ms`` select maximum time for fade. * ``userFunc`` function to be called when interrupt is triggered. * ``arg`` pointer to the interrupt arguments. diff --git a/libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino b/libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino index ea190e4f140..c37d9d081a0 100644 --- a/libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino +++ b/libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino @@ -17,7 +17,7 @@ // define starting duty, target duty and maximum fade time #define LEDC_START_DUTY (0) -#define LEDC_TARGET_DUTY (4095) +#define LEDC_TARGET_DUTY (4096) #define LEDC_FADE_TIME (3000) bool fade_ended = false; // status of LED fade diff --git a/libraries/ESP32/examples/AnalogOut/LEDCGammaFade/LEDCGammaFade.ino b/libraries/ESP32/examples/AnalogOut/LEDCGammaFade/LEDCGammaFade.ino index 4ca6c136ddf..2275bbb4eda 100644 --- a/libraries/ESP32/examples/AnalogOut/LEDCGammaFade/LEDCGammaFade.ino +++ b/libraries/ESP32/examples/AnalogOut/LEDCGammaFade/LEDCGammaFade.ino @@ -21,7 +21,7 @@ // define starting duty, target duty and maximum fade time #define LEDC_START_DUTY (0) -#define LEDC_TARGET_DUTY (4095) +#define LEDC_TARGET_DUTY (4096) #define LEDC_FADE_TIME (2000) // gamma factor for mathematical calculation diff --git a/libraries/ESP32/examples/AnalogOut/LEDCSingleChannel/LEDCSingleChannel.ino b/libraries/ESP32/examples/AnalogOut/LEDCSingleChannel/LEDCSingleChannel.ino index 2317e32a11a..3608a2e641c 100644 --- a/libraries/ESP32/examples/AnalogOut/LEDCSingleChannel/LEDCSingleChannel.ino +++ b/libraries/ESP32/examples/AnalogOut/LEDCSingleChannel/LEDCSingleChannel.ino @@ -26,7 +26,7 @@ #define LEDC_CHANNEL 0 int brightness = 0; // how bright the LED is -int fadeAmount = 5; // how many points to fade the LED by +int fadeAmount = 4; // how many points to fade the LED by void setup() { // Use single LEDC channel 0 for both pins @@ -42,7 +42,7 @@ void loop() { brightness = brightness + fadeAmount; // reverse the direction of the fading at the ends of the fade: - if (brightness <= 0 || brightness >= 255) { + if (brightness <= 0 || brightness >= 256) { fadeAmount = -fadeAmount; } // wait for 30 milliseconds to see the dimming effect diff --git a/libraries/ESP32/examples/AnalogOut/LEDCSoftwareFade/LEDCSoftwareFade.ino b/libraries/ESP32/examples/AnalogOut/LEDCSoftwareFade/LEDCSoftwareFade.ino index c605a89bc0b..4c88a7f534b 100644 --- a/libraries/ESP32/examples/AnalogOut/LEDCSoftwareFade/LEDCSoftwareFade.ino +++ b/libraries/ESP32/examples/AnalogOut/LEDCSoftwareFade/LEDCSoftwareFade.ino @@ -20,13 +20,13 @@ #define LED_PIN 5 int brightness = 0; // how bright the LED is -int fadeAmount = 5; // how many points to fade the LED by +int fadeAmount = 4; // how many points to fade the LED by // Arduino like analogWrite // value has to be between 0 and valueMax -void ledcAnalogWrite(uint8_t pin, uint32_t value, uint32_t valueMax = 255) { +void ledcAnalogWrite(uint8_t pin, uint32_t value, uint32_t valueMax = 256) { // calculate duty, 4095 from 2 ^ 12 - 1 - uint32_t duty = (4095 / valueMax) * min(value, valueMax); + uint32_t duty = (4096 / valueMax) * min(value, valueMax); // write duty to LEDC ledcWrite(pin, duty); @@ -45,7 +45,7 @@ void loop() { brightness = brightness + fadeAmount; // reverse the direction of the fading at the ends of the fade: - if (brightness <= 0 || brightness >= 255) { + if (brightness <= 0 || brightness >= 256) { fadeAmount = -fadeAmount; } // wait for 30 milliseconds to see the dimming effect diff --git a/libraries/ESP32/examples/AnalogOut/ledcWrite_RGB/ledcWrite_RGB.ino b/libraries/ESP32/examples/AnalogOut/ledcWrite_RGB/ledcWrite_RGB.ino index b7ea8943487..a3c8c06a5c9 100644 --- a/libraries/ESP32/examples/AnalogOut/ledcWrite_RGB/ledcWrite_RGB.ino +++ b/libraries/ESP32/examples/AnalogOut/ledcWrite_RGB/ledcWrite_RGB.ino @@ -17,7 +17,7 @@ const boolean invert = true; // set true if common anode, false if common catho uint8_t color = 0; // a value from 0 to 255 representing the hue uint32_t R, G, B; // the Red Green and Blue color components -uint8_t brightness = 255; // 255 is maximum brightness, but can be changed. Might need 256 for common anode to fully turn off. +uint8_t brightness = 255; // 255 is maximum brightness, but can be changed. Might need 256 for common anode to fully turn off. // the setup routine runs once when you press reset: void setup() { @@ -33,12 +33,12 @@ void setup() { // void loop runs over and over again void loop() { - Serial.println("Send all LEDs a 255 and wait 2 seconds."); + Serial.println("Send all LEDs a 256 and wait 2 seconds."); // If your RGB LED turns off instead of on here you should check if the LED is common anode or cathode. // If it doesn't fully turn off and is common anode try using 256. - ledcWrite(ledR, 255); - ledcWrite(ledG, 255); - ledcWrite(ledB, 255); + ledcWrite(ledR, 256); + ledcWrite(ledG, 256); + ledcWrite(ledB, 256); delay(2000); Serial.println("Send all LEDs a 0 and wait 2 seconds."); ledcWrite(ledR, 0);