Skip to content

Commit

Permalink
feat(ledc): Add output invert option for LEDC pin + minor fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
P-R-O-C-H-Y committed Feb 16, 2024
1 parent bc769fd commit c15582b
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 29 deletions.
45 changes: 36 additions & 9 deletions cores/esp32/esp32-hal-ledc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;

Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion cores/esp32/esp32-hal-ledc.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ 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 ledcWrite(uint8_t pin, uint32_t duty);
Expand All @@ -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);
Expand Down
18 changes: 10 additions & 8 deletions cores/esp32/io_pin_remap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
30 changes: 21 additions & 9 deletions docs/en/api/ledc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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.

Expand Down Expand Up @@ -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
********

Expand Down
2 changes: 1 addition & 1 deletion libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit c15582b

Please sign in to comment.