diff --git a/cores/esp32/esp32-hal-ledc.c b/cores/esp32/esp32-hal-ledc.c index 76d522c2313..f030821e109 100644 --- a/cores/esp32/esp32-hal-ledc.c +++ b/cores/esp32/esp32-hal-ledc.c @@ -19,6 +19,8 @@ #include "esp32-hal-ledc.h" #include "driver/ledc.h" #include "esp32-hal-periman.h" +#include "soc/gpio_sig_map.h" +#include "esp_rom_gpio.h" #ifdef SOC_LEDC_SUPPORT_HS_MODE #define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM<<1) @@ -40,7 +42,7 @@ typedef struct { int used_channels : LEDC_CHANNELS; // Used channels as a bits } ledc_periph_t; -ledc_periph_t ledc_handle; +ledc_periph_t ledc_handle = {0}; static bool fade_initialized = false; @@ -58,15 +60,25 @@ static bool ledcDetachBus(void * bus){ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t channel) { - if (channel >= LEDC_CHANNELS || resolution > LEDC_MAX_BIT_WIDTH) - { - log_e("Channel %u is not available! (maximum %u) or bit width too big (maximum %u)", channel, LEDC_CHANNELS, LEDC_MAX_BIT_WIDTH); + if(channel >= LEDC_CHANNELS || ledc_handle.used_channels & (1UL << channel)){ + log_e("Channel %u is not available (maximum %u) or already used!", channel, LEDC_CHANNELS); + return false; + } + + if (resolution > LEDC_MAX_BIT_WIDTH){ + log_e("LEDC resolution too big (maximum %u)", LEDC_MAX_BIT_WIDTH); return false; } perimanSetBusDeinit(ESP32_BUS_TYPE_LEDC, ledcDetachBus); ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC); - if(bus != NULL && !perimanClearPinBus(pin)){ + if(bus != NULL){ + log_e("Pin %u is already attached to LEDC (channel %u, resolution %u)", pin, bus->channel, bus->channel_resolution); + return false; + } + + if(!perimanClearPinBus(pin)){ + log_e("Pin %u is already attached to another bus and failed to detach", pin); return false; } @@ -120,11 +132,11 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution) { uint8_t free_channel = ~ledc_handle.used_channels & (ledc_handle.used_channels+1); - if (free_channel == 0 || resolution > LEDC_MAX_BIT_WIDTH){ - log_e("No more LEDC channels available! (maximum %u) or bit width too big (maximum %u)", LEDC_CHANNELS, LEDC_MAX_BIT_WIDTH); + if (free_channel == 0){ + log_e("No more LEDC channels available! (maximum is %u channels)", LEDC_CHANNELS); return false; } - int channel = log2(free_channel & -free_channel); + uint8_t channel = log2(free_channel & -free_channel); return ledcAttachChannel(pin, freq, resolution, channel); } @@ -265,6 +277,21 @@ uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution) return 0; } +bool ledcOutputInvert(uint8_t pin, bool out_invert) +{ + ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC); + if(bus != NULL){ + gpio_set_level(pin, out_invert); + #ifdef SOC_LEDC_SUPPORT_HS_MODE + esp_rom_gpio_connect_out_signal(pin, ((bus->channel/8 == 0) ? LEDC_HS_SIG_OUT0_IDX : LEDC_LS_SIG_OUT0_IDX) + ((bus->channel)%8), out_invert, 0); + #else + esp_rom_gpio_connect_out_signal(pin, LEDC_LS_SIG_OUT0_IDX + ((bus->channel)%8), out_invert, 0); + #endif + return true; + } + return false; +} + static IRAM_ATTR bool ledcFnWrapper(const ledc_cb_param_t *param, void *user_arg) { if (param->event == LEDC_FADE_END_EVT) { @@ -373,7 +400,7 @@ void analogWrite(uint8_t pin, int value) { if (pin < SOC_GPIO_PIN_COUNT) { ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC); if(bus == NULL && perimanClearPinBus(pin)){ - if(ledcAttach(pin, analog_frequency, analog_resolution) == 0){ + if(ledcAttach(pin, analog_frequency, analog_resolution, LEDC_CHANNEL_AUTO) == 0){ log_e("analogWrite setup failed (freq = %u, resolution = %u). Try setting different resolution or frequency"); return; } diff --git a/cores/esp32/esp32-hal-ledc.h b/cores/esp32/esp32-hal-ledc.h index 2d2c42e9369..08cfea9f30e 100644 --- a/cores/esp32/esp32-hal-ledc.h +++ b/cores/esp32/esp32-hal-ledc.h @@ -45,9 +45,8 @@ typedef struct { #endif } ledc_channel_handle_t; -//channel 0-15 resolution 1-16bits freq limits depend on resolution bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution); -bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t channel); +bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t channel); bool ledcWrite(uint8_t pin, uint32_t duty); uint32_t ledcWriteTone(uint8_t pin, uint32_t freq); uint32_t ledcWriteNote(uint8_t pin, note_t note, uint8_t octave); @@ -55,6 +54,7 @@ uint32_t ledcRead(uint8_t pin); uint32_t ledcReadFreq(uint8_t pin); bool ledcDetach(uint8_t pin); uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution); +bool ledcOutputInvert(uint8_t pin, bool out_invert); //Fade functions bool ledcFade(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms); diff --git a/cores/esp32/io_pin_remap.h b/cores/esp32/io_pin_remap.h index 63fb16cefd0..049da110740 100644 --- a/cores/esp32/io_pin_remap.h +++ b/cores/esp32/io_pin_remap.h @@ -53,14 +53,16 @@ int8_t gpioNumberToDigitalPin(int8_t gpioNumber); #define i2cSlaveInit(num, sda, scl, slaveID, frequency, rx_len, tx_len) i2cSlaveInit(num, digitalPinToGPIONumber(sda), digitalPinToGPIONumber(scl), slaveID, frequency, rx_len, tx_len) // cores/esp32/esp32-hal-ledc.h -#define ledcAttach(pin, freq, resolution) ledcAttach(digitalPinToGPIONumber(pin), freq, resolution) -#define ledcWrite(pin, duty) ledcWrite(digitalPinToGPIONumber(pin), duty) -#define ledcWriteTone(pin, freq) ledcWriteTone(digitalPinToGPIONumber(pin), freq) -#define ledcWriteNote(pin, note, octave) ledcWriteNote(digitalPinToGPIONumber(pin), note, octave) -#define ledcRead(pin) ledcRead(digitalPinToGPIONumber(pin)) -#define ledcReadFreq(pin) ledcReadFreq(digitalPinToGPIONumber(pin)) -#define ledcDetach(pin) ledcDetach(digitalPinToGPIONumber(pin)) -#define ledcChangeFrequency(pin, freq, resolution) ledcChangeFrequency(digitalPinToGPIONumber(pin), freq, resolution) +#define ledcAttach(pin, freq, resolution) ledcAttach(digitalPinToGPIONumber(pin), freq, resolution) +#define ledcAttachChannel(pin, freq, resolution, channel) ledcAttachChannel(digitalPinToGPIONumber(pin), freq, resolution, channel) +#define ledcWrite(pin, duty) ledcWrite(digitalPinToGPIONumber(pin), duty) +#define ledcWriteTone(pin, freq) ledcWriteTone(digitalPinToGPIONumber(pin), freq) +#define ledcWriteNote(pin, note, octave) ledcWriteNote(digitalPinToGPIONumber(pin), note, octave) +#define ledcRead(pin) ledcRead(digitalPinToGPIONumber(pin)) +#define ledcReadFreq(pin) ledcReadFreq(digitalPinToGPIONumber(pin)) +#define ledcDetach(pin) ledcDetach(digitalPinToGPIONumber(pin)) +#define ledcChangeFrequency(pin, freq, resolution) ledcChangeFrequency(digitalPinToGPIONumber(pin), freq, resolution) +#define ledcOutputInvert(pin, out_invert) ledcOutputInvert(digitalPinToGPIONumber(pin), out_invert) #define ledcFade(pin, start_duty, target_duty, max_fade_time_ms) ledcFade(digitalPinToGPIONumber(pin), start_duty, target_duty, max_fade_time_ms) #define ledcFadeWithInterrupt(pin, start_duty, target_duty, max_fade_time_ms, userFunc) ledcFadeWithInterrupt(digitalPinToGPIONumber(pin), start_duty, target_duty, max_fade_time_ms, userFunc) diff --git a/docs/en/api/ledc.rst b/docs/en/api/ledc.rst index 1abeea2f6ee..08912d880dd 100644 --- a/docs/en/api/ledc.rst +++ b/docs/en/api/ledc.rst @@ -26,19 +26,17 @@ Arduino-ESP32 LEDC API ledcAttach ********** -This function is used to setup LEDC pin with given frequency and resolution. -LEDC channel will be selected automatically. +This function is used to setup LEDC pin with given frequency and resolution. LEDC channel will be selected automatically. .. code-block:: arduino - bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution); + bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution, int8_t channel); * ``pin`` select LEDC pin. * ``freq`` select frequency of pwm. * ``resolution`` select resolution for LEDC channel. - * range is 1-14 bits (1-20 bits for ESP32). - + This function will return ``true`` if configuration is successful. If ``false`` is returned, error occurs and LEDC channel was not configured. @@ -49,15 +47,14 @@ This function is used to setup LEDC pin with given frequency, resolution and cha .. code-block:: arduino - bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t channel); + bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution, int8_t channel); * ``pin`` select LEDC pin. * ``freq`` select frequency of pwm. * ``resolution`` select resolution for LEDC channel. -* ``channel`` select LEDC channel. - * range is 1-14 bits (1-20 bits for ESP32). - +* ``channel`` select LEDC channel. + This function will return ``true`` if configuration is successful. If ``false`` is returned, error occurs and LEDC channel was not configured. @@ -171,6 +168,21 @@ This function is used to set frequency for the LEDC pin. This function will return ``frequency`` configured for the LEDC channel. If ``0`` is returned, error occurs and the LEDC channel frequency was not set. +ledcOutputInvert +**************** + +This function is used to set inverting output for the LEDC pin. + +.. code-block:: arduino + + bool ledcOutputInvert(uint8_t pin, bool out_invert); + +* ``pin`` select LEDC pin. +* ``out_invert`` select, if output should be inverted (1 = inverting output). + +This function returns ``true`` if setting inverting output was successful. +If ``false`` is returned, an error occurred and the inverting output was not set. + ledcFade ******** diff --git a/libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino b/libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino index 002df746014..19c2be3428d 100644 --- a/libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino +++ b/libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino @@ -33,7 +33,7 @@ void setup() { Serial.begin(115200); while(!Serial) delay(10); - // Setup timer and attach timer to a led pins + // Setup timer with given frequency, resolution and attach it to a led pin with auto-selected channel ledcAttach(LED_PIN, LEDC_BASE_FREQ, LEDC_TIMER_12_BIT); // Setup and start fade on led (duty from 0 to 4095) diff --git a/libraries/ESP32/examples/AnalogOut/ledcWrite_RGB/ledcWrite_RGB.ino b/libraries/ESP32/examples/AnalogOut/ledcWrite_RGB/ledcWrite_RGB.ino index 1104a6b4c63..0135ab1d0c1 100644 --- a/libraries/ESP32/examples/AnalogOut/ledcWrite_RGB/ledcWrite_RGB.ino +++ b/libraries/ESP32/examples/AnalogOut/ledcWrite_RGB/ledcWrite_RGB.ino @@ -26,7 +26,7 @@ void setup() delay(10); // Initialize pins as LEDC channels - // resolution 1-16 bits, freq limits depend on resolution + // resolution 1-16 bits, freq limits depend on resolution, channel is automatically selected ledcAttach(ledR, 12000, 8); // 12 kHz PWM, 8-bit resolution ledcAttach(ledG, 12000, 8); ledcAttach(ledB, 12000, 8);