Skip to content

Commit c4b55bb

Browse files
P-R-O-C-H-YSuGliderlucasssvaz
authored
feature(ledc): Add output invert option for LEDC pin + minor fixes (espressif#9257)
* feat(ledc): Add output invert option for LEDC pin + minor fixes * docs(ledc): Document LEDC functions in header file * feat(ledc): Replace log2 with __builtin_ctz * fix(ledc): Fixing free_channel for > 8 supported channels * fix(ledc): Apply suggestions from code review Co-authored-by: Rodrigo Garcia <rodrigo.garcia@espressif.com> * fix(ledc): Added freq check to ledcChangeFrequency * docs(ledc): Fix ledc documentation formatting * docs(migration): Add new functions to the migration guide * docs(ledc): Fix functions name and parameters --------- Co-authored-by: Rodrigo Garcia <rodrigo.garcia@espressif.com> Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com>
1 parent 05e2abc commit c4b55bb

File tree

7 files changed

+226
-44
lines changed

7 files changed

+226
-44
lines changed

cores/esp32/esp32-hal-ledc.c

+45-12
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "esp32-hal-ledc.h"
2020
#include "driver/ledc.h"
2121
#include "esp32-hal-periman.h"
22+
#include "soc/gpio_sig_map.h"
23+
#include "esp_rom_gpio.h"
2224

2325
#ifdef SOC_LEDC_SUPPORT_HS_MODE
2426
#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM<<1)
@@ -40,7 +42,7 @@ typedef struct {
4042
int used_channels : LEDC_CHANNELS; // Used channels as a bits
4143
} ledc_periph_t;
4244

43-
ledc_periph_t ledc_handle;
45+
ledc_periph_t ledc_handle = {0};
4446

4547
static bool fade_initialized = false;
4648

@@ -58,15 +60,28 @@ static bool ledcDetachBus(void * bus){
5860

5961
bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t channel)
6062
{
61-
if (channel >= LEDC_CHANNELS || resolution > LEDC_MAX_BIT_WIDTH)
62-
{
63-
log_e("Channel %u is not available! (maximum %u) or bit width too big (maximum %u)", channel, LEDC_CHANNELS, LEDC_MAX_BIT_WIDTH);
63+
if(channel >= LEDC_CHANNELS || ledc_handle.used_channels & (1UL << channel)){
64+
log_e("Channel %u is not available (maximum %u) or already used!", channel, LEDC_CHANNELS);
65+
return false;
66+
}
67+
if (freq == 0) {
68+
log_e("LEDC pin %u - frequency can't be zero.", pin);
69+
return false;
70+
}
71+
if (resolution == 0 || resolution > LEDC_MAX_BIT_WIDTH){
72+
log_e("LEDC pin %u - resolution is zero or it is too big (maximum %u)", pin, LEDC_MAX_BIT_WIDTH);
6473
return false;
6574
}
6675

6776
perimanSetBusDeinit(ESP32_BUS_TYPE_LEDC, ledcDetachBus);
6877
ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC);
69-
if(bus != NULL && !perimanClearPinBus(pin)){
78+
if(bus != NULL){
79+
log_e("Pin %u is already attached to LEDC (channel %u, resolution %u)", pin, bus->channel, bus->channel_resolution);
80+
return false;
81+
}
82+
83+
if(!perimanClearPinBus(pin)){
84+
log_e("Pin %u is already attached to another bus and failed to detach", pin);
7085
return false;
7186
}
7287

@@ -119,12 +134,12 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
119134

120135
bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution)
121136
{
122-
uint8_t free_channel = ~ledc_handle.used_channels & (ledc_handle.used_channels+1);
123-
if (free_channel == 0 || resolution > LEDC_MAX_BIT_WIDTH){
124-
log_e("No more LEDC channels available! (maximum %u) or bit width too big (maximum %u)", LEDC_CHANNELS, LEDC_MAX_BIT_WIDTH);
137+
int free_channel = ~ledc_handle.used_channels & (ledc_handle.used_channels+1);
138+
if (free_channel == 0){
139+
log_e("No more LEDC channels available! (maximum is %u channels)", LEDC_CHANNELS);
125140
return false;
126141
}
127-
int channel = log2(free_channel & -free_channel);
142+
uint8_t channel = __builtin_ctz(free_channel); // Convert the free_channel bit to channel number
128143

129144
return ledcAttachChannel(pin, freq, resolution, channel);
130145
}
@@ -239,9 +254,12 @@ uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution)
239254
{
240255
ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC);
241256
if(bus != NULL){
242-
243-
if(resolution > LEDC_MAX_BIT_WIDTH){
244-
log_e("LEDC resolution too big (maximum %u)", LEDC_MAX_BIT_WIDTH);
257+
if (freq == 0) {
258+
log_e("LEDC pin %u - frequency can't be zero.", pin);
259+
return 0;
260+
}
261+
if (resolution == 0 || resolution > LEDC_MAX_BIT_WIDTH){
262+
log_e("LEDC pin %u - resolution is zero or it is too big (maximum %u)", pin, LEDC_MAX_BIT_WIDTH);
245263
return 0;
246264
}
247265
uint8_t group=(bus->channel/8), timer=((bus->channel/2)%4);
@@ -265,6 +283,21 @@ uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution)
265283
return 0;
266284
}
267285

286+
bool ledcOutputInvert(uint8_t pin, bool out_invert)
287+
{
288+
ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC);
289+
if(bus != NULL){
290+
gpio_set_level(pin, out_invert);
291+
#ifdef SOC_LEDC_SUPPORT_HS_MODE
292+
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);
293+
#else
294+
esp_rom_gpio_connect_out_signal(pin, LEDC_LS_SIG_OUT0_IDX + ((bus->channel)%8), out_invert, 0);
295+
#endif
296+
return true;
297+
}
298+
return false;
299+
}
300+
268301
static IRAM_ATTR bool ledcFnWrapper(const ledc_cb_param_t *param, void *user_arg)
269302
{
270303
if (param->event == LEDC_FADE_END_EVT) {

cores/esp32/esp32-hal-ledc.h

+140-10
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,150 @@ typedef struct {
4545
#endif
4646
} ledc_channel_handle_t;
4747

48-
//channel 0-15 resolution 1-16bits freq limits depend on resolution
49-
bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution);
50-
bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t channel);
51-
bool ledcWrite(uint8_t pin, uint32_t duty);
52-
uint32_t ledcWriteTone(uint8_t pin, uint32_t freq);
53-
uint32_t ledcWriteNote(uint8_t pin, note_t note, uint8_t octave);
54-
uint32_t ledcRead(uint8_t pin);
55-
uint32_t ledcReadFreq(uint8_t pin);
56-
bool ledcDetach(uint8_t pin);
57-
uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution);
48+
/**
49+
* @brief Attach a pin to the LEDC driver, with a given frequency and resolution.
50+
* Channel is automatically assigned.
51+
*
52+
* @param pin GPIO pin
53+
* @param freq frequency of PWM signal
54+
* @param resolution resolution for LEDC pin
55+
*
56+
* @return true if configuration is successful and pin was successfully attached, false otherwise.
57+
*/
58+
bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution);
59+
60+
/**
61+
* @brief Attach a pin to the LEDC driver, with a given frequency, resolution and channel.
62+
*
63+
* @param pin GPIO pin
64+
* @param freq frequency of PWM signal
65+
* @param resolution resolution for LEDC pin
66+
* @param channel LEDC channel to attach to
67+
*
68+
* @return true if configuration is successful and pin was successfully attached, false otherwise.
69+
*/
70+
bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t channel);
71+
72+
/**
73+
* @brief Set the duty cycle of a given pin.
74+
*
75+
* @param pin GPIO pin
76+
* @param duty duty cycle to set
77+
*
78+
* @return true if duty cycle was successfully set, false otherwise.
79+
*/
80+
bool ledcWrite(uint8_t pin, uint32_t duty);
81+
82+
/**
83+
* @brief Sets the duty to 50 % PWM tone on selected frequency.
84+
*
85+
* @param pin GPIO pin
86+
* @param freq select frequency of pwm signal. If frequency is 0, duty will be set to 0.
87+
*
88+
* @return frequency if tone was successfully set.
89+
* If ``0`` is returned, error occurs and LEDC pin was not configured.
90+
*/
91+
uint32_t ledcWriteTone(uint8_t pin, uint32_t freq);
92+
93+
/**
94+
* @brief Sets the LEDC pin to specific note.
95+
*
96+
* @param pin GPIO pin
97+
* @param note select note to be set (NOTE_C, NOTE_Cs, NOTE_D, NOTE_Eb, NOTE_E, NOTE_F, NOTE_Fs, NOTE_G, NOTE_Gs, NOTE_A, NOTE_Bb, NOTE_B).
98+
* @param octave select octave for note.
99+
*
100+
* @return frequency if note was successfully set.
101+
* If ``0`` is returned, error occurs and LEDC pin was not configured.
102+
*/
103+
uint32_t ledcWriteNote(uint8_t pin, note_t note, uint8_t octave);
104+
105+
/**
106+
* @brief Read the duty cycle of a given LEDC pin.
107+
*
108+
* @param pin GPIO pin
109+
*
110+
* @return duty cycle of selected LEDC pin.
111+
*/
112+
uint32_t ledcRead(uint8_t pin);
113+
114+
/**
115+
* @brief Read the frequency of a given LEDC pin.
116+
*
117+
* @param pin GPIO pin
118+
*
119+
* @return frequency of selected LEDC pin.
120+
*/
121+
uint32_t ledcReadFreq(uint8_t pin);
122+
123+
/**
124+
* @brief Detach a pin from the LEDC driver.
125+
*
126+
* @param pin GPIO pin
127+
*
128+
* @return true if pin was successfully detached, false otherwise.
129+
*/
130+
bool ledcDetach(uint8_t pin);
131+
132+
/**
133+
* @brief Change the frequency and resolution of a given LEDC pin.
134+
*
135+
* @param pin GPIO pin
136+
* @param freq frequency of PWM signal
137+
* @param resolution resolution for LEDC pin
138+
*
139+
* @return frequency configured for the LEDC channel.
140+
* If ``0`` is returned, error occurs and LEDC pin was not configured.
141+
*/
142+
uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution);
143+
144+
/**
145+
* @brief Sets inverting of the output signal for a given LEDC pin.
146+
*
147+
* @param pin GPIO pin
148+
* @param out_invert select, if output should be inverted (true = inverting output).
149+
*
150+
* @return true if output inverting was successfully set, false otherwise.
151+
*/
152+
bool ledcOutputInvert(uint8_t pin, bool out_invert);
58153

59154
//Fade functions
155+
/**
156+
* @brief Setup and start a fade on a given LEDC pin.
157+
*
158+
* @param pin GPIO pin
159+
* @param start_duty initial duty cycle of the fade
160+
* @param target_duty target duty cycle of the fade
161+
* @param max_fade_time_ms maximum fade time in milliseconds
162+
*
163+
* @return true if fade was successfully set and started, false otherwise.
164+
*/
60165
bool ledcFade(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms);
166+
167+
/**
168+
* @brief Setup and start a fade on a given LEDC pin with a callback function.
169+
*
170+
* @param pin GPIO pin
171+
* @param start_duty initial duty cycle of the fade
172+
* @param target_duty target duty cycle of the fade
173+
* @param max_fade_time_ms maximum fade time in milliseconds
174+
* @param userFunc callback function to be called after fade is finished
175+
*
176+
* @return true if fade was successfully set and started, false otherwise.
177+
*/
61178
bool ledcFadeWithInterrupt(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, void (*userFunc)(void));
179+
180+
/**
181+
* @brief Setup and start a fade on a given LEDC pin with a callback function and argument.
182+
*
183+
* @param pin GPIO pin
184+
* @param start_duty initial duty cycle of the fade
185+
* @param target_duty target duty cycle of the fade
186+
* @param max_fade_time_ms maximum fade time in milliseconds
187+
* @param userFunc callback function to be called after fade is finished
188+
* @param arg argument to be passed to the callback function
189+
*
190+
* @return true if fade was successfully set and started, false otherwise.
191+
*/
62192
bool ledcFadeWithInterruptArg(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, void (*userFunc)(void*), void * arg);
63193

64194
#ifdef __cplusplus

cores/esp32/io_pin_remap.h

+10-8
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,16 @@ int8_t gpioNumberToDigitalPin(int8_t gpioNumber);
5353
#define i2cSlaveInit(num, sda, scl, slaveID, frequency, rx_len, tx_len) i2cSlaveInit(num, digitalPinToGPIONumber(sda), digitalPinToGPIONumber(scl), slaveID, frequency, rx_len, tx_len)
5454

5555
// cores/esp32/esp32-hal-ledc.h
56-
#define ledcAttach(pin, freq, resolution) ledcAttach(digitalPinToGPIONumber(pin), freq, resolution)
57-
#define ledcWrite(pin, duty) ledcWrite(digitalPinToGPIONumber(pin), duty)
58-
#define ledcWriteTone(pin, freq) ledcWriteTone(digitalPinToGPIONumber(pin), freq)
59-
#define ledcWriteNote(pin, note, octave) ledcWriteNote(digitalPinToGPIONumber(pin), note, octave)
60-
#define ledcRead(pin) ledcRead(digitalPinToGPIONumber(pin))
61-
#define ledcReadFreq(pin) ledcReadFreq(digitalPinToGPIONumber(pin))
62-
#define ledcDetach(pin) ledcDetach(digitalPinToGPIONumber(pin))
63-
#define ledcChangeFrequency(pin, freq, resolution) ledcChangeFrequency(digitalPinToGPIONumber(pin), freq, resolution)
56+
#define ledcAttach(pin, freq, resolution) ledcAttach(digitalPinToGPIONumber(pin), freq, resolution)
57+
#define ledcAttachChannel(pin, freq, resolution, channel) ledcAttachChannel(digitalPinToGPIONumber(pin), freq, resolution, channel)
58+
#define ledcWrite(pin, duty) ledcWrite(digitalPinToGPIONumber(pin), duty)
59+
#define ledcWriteTone(pin, freq) ledcWriteTone(digitalPinToGPIONumber(pin), freq)
60+
#define ledcWriteNote(pin, note, octave) ledcWriteNote(digitalPinToGPIONumber(pin), note, octave)
61+
#define ledcRead(pin) ledcRead(digitalPinToGPIONumber(pin))
62+
#define ledcReadFreq(pin) ledcReadFreq(digitalPinToGPIONumber(pin))
63+
#define ledcDetach(pin) ledcDetach(digitalPinToGPIONumber(pin))
64+
#define ledcChangeFrequency(pin, freq, resolution) ledcChangeFrequency(digitalPinToGPIONumber(pin), freq, resolution)
65+
#define ledcOutputInvert(pin, out_invert) ledcOutputInvert(digitalPinToGPIONumber(pin), out_invert)
6466

6567
#define ledcFade(pin, start_duty, target_duty, max_fade_time_ms) ledcFade(digitalPinToGPIONumber(pin), start_duty, target_duty, max_fade_time_ms)
6668
#define ledcFadeWithInterrupt(pin, start_duty, target_duty, max_fade_time_ms, userFunc) ledcFadeWithInterrupt(digitalPinToGPIONumber(pin), start_duty, target_duty, max_fade_time_ms, userFunc)

docs/en/api/ledc.rst

+25-10
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,18 @@ Arduino-ESP32 LEDC API
2626
ledcAttach
2727
**********
2828

29-
This function is used to setup LEDC pin with given frequency and resolution.
30-
LEDC channel will be selected automatically.
29+
This function is used to setup LEDC pin with given frequency and resolution. LEDC channel will be selected automatically.
3130

3231
.. code-block:: arduino
3332
3433
bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution);
3534
3635
* ``pin`` select LEDC pin.
3736
* ``freq`` select frequency of pwm.
38-
* ``resolution`` select resolution for LEDC channel.
39-
37+
* ``resolution`` select resolution for LEDC channel.
38+
4039
* range is 1-14 bits (1-20 bits for ESP32).
41-
40+
4241
This function will return ``true`` if configuration is successful.
4342
If ``false`` is returned, error occurs and LEDC channel was not configured.
4443

@@ -49,15 +48,16 @@ This function is used to setup LEDC pin with given frequency, resolution and cha
4948

5049
.. code-block:: arduino
5150
52-
bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t channel);
51+
bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, int8_t channel);
5352
5453
* ``pin`` select LEDC pin.
5554
* ``freq`` select frequency of pwm.
56-
* ``resolution`` select resolution for LEDC channel.
57-
* ``channel`` select LEDC channel.
58-
55+
* ``resolution`` select resolution for LEDC channel.
56+
5957
* range is 1-14 bits (1-20 bits for ESP32).
60-
58+
59+
* ``channel`` select LEDC channel.
60+
6161
This function will return ``true`` if configuration is successful.
6262
If ``false`` is returned, error occurs and LEDC channel was not configured.
6363

@@ -171,6 +171,21 @@ This function is used to set frequency for the LEDC pin.
171171
This function will return ``frequency`` configured for the LEDC channel.
172172
If ``0`` is returned, error occurs and the LEDC channel frequency was not set.
173173

174+
ledcOutputInvert
175+
****************
176+
177+
This function is used to set inverting output for the LEDC pin.
178+
179+
.. code-block:: arduino
180+
181+
bool ledcOutputInvert(uint8_t pin, bool out_invert);
182+
183+
* ``pin`` select LEDC pin.
184+
* ``out_invert`` select, if output should be inverted (true = inverting output).
185+
186+
This function returns ``true`` if setting inverting output was successful.
187+
If ``false`` is returned, an error occurred and the inverting output was not set.
188+
174189
ledcFade
175190
********
176191

docs/en/migration_guides/2.x_to_3.0.rst

+4-2
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,10 @@ New APIs
6363
********
6464

6565
* ``ledcAttach`` used to set up the LEDC pin (merged ``ledcSetup`` and ``ledcAttachPin`` functions).
66-
* ``timerGetFrequency`` used to get the actual frequency of the timer.
67-
* ``timerAttachInterruptArg`` used to attach the interrupt to a timer using arguments.
66+
* ``ledcOutputInvert`` used to attach the interrupt to a timer using arguments.
67+
* ``ledcFade`` used to set up and start a fade on a given LEDC pin.
68+
* ``ledcFadeWithInterrupt`` used to set up and start a fade on a given LEDC pin with an interrupt.
69+
* ``ledcFadeWithInterruptArg`` used to set up and start a fade on a given LEDC pin with an interrupt using arguments.
6870

6971
Changes in APIs
7072
***************

libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ void setup() {
3333
Serial.begin(115200);
3434
while(!Serial) delay(10);
3535

36-
// Setup timer and attach timer to a led pins
36+
// Setup timer with given frequency, resolution and attach it to a led pin with auto-selected channel
3737
ledcAttach(LED_PIN, LEDC_BASE_FREQ, LEDC_TIMER_12_BIT);
3838

3939
// Setup and start fade on led (duty from 0 to 4095)

libraries/ESP32/examples/AnalogOut/ledcWrite_RGB/ledcWrite_RGB.ino

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ void setup()
2626
delay(10);
2727

2828
// Initialize pins as LEDC channels
29-
// resolution 1-16 bits, freq limits depend on resolution
29+
// resolution 1-16 bits, freq limits depend on resolution, channel is automatically selected
3030
ledcAttach(ledR, 12000, 8); // 12 kHz PWM, 8-bit resolution
3131
ledcAttach(ledG, 12000, 8);
3232
ledcAttach(ledB, 12000, 8);

0 commit comments

Comments
 (0)