Skip to content

Commit 477527d

Browse files
committed
feat(ledc): Add ledcWriteChannel function
1 parent b68bfd8 commit 477527d

File tree

2 files changed

+65
-14
lines changed

2 files changed

+65
-14
lines changed

cores/esp32/esp32-hal-ledc.c

+55-14
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "esp32-hal-periman.h"
2222
#include "soc/gpio_sig_map.h"
2323
#include "esp_rom_gpio.h"
24+
#include "hal/ledc_ll.h"
2425

2526
#ifdef SOC_LEDC_SUPPORT_HS_MODE
2627
#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM << 1)
@@ -77,7 +78,7 @@ static bool ledcDetachBus(void *bus) {
7778

7879
bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t channel) {
7980
if (channel >= LEDC_CHANNELS) { //|| ledc_handle.used_channels & (1UL << channel)) {
80-
log_e("Channel %u is not available (maximum %u) TODO: delete (or already used)!", channel, LEDC_CHANNELS);
81+
log_e("Channel %u is not available (maximum %u)!", channel, LEDC_CHANNELS);
8182
return false;
8283
}
8384
if (freq == 0) {
@@ -102,29 +103,45 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
102103
}
103104

104105
uint8_t group = (channel / 8), timer = ((channel / 2) % 4);
105-
106-
ledc_timer_config_t ledc_timer = {.speed_mode = group, .timer_num = timer, .duty_resolution = resolution, .freq_hz = freq, .clk_cfg = LEDC_DEFAULT_CLK};
107-
if (ledc_timer_config(&ledc_timer) != ESP_OK) {
108-
log_e("ledc setup failed!");
109-
return false;
106+
bool channel_used = ledc_handle.used_channels & (1UL << channel);
107+
if (channel_used) {
108+
if (ledc_set_pin(pin, group, channel % 8) != ESP_OK) {
109+
log_e("Attaching pin to already used channel failed!");
110+
return false;
111+
}
110112
}
113+
else {
114+
ledc_timer_config_t ledc_timer = {.speed_mode = group, .timer_num = timer, .duty_resolution = resolution, .freq_hz = freq, .clk_cfg = LEDC_DEFAULT_CLK};
115+
if (ledc_timer_config(&ledc_timer) != ESP_OK) {
116+
log_e("ledc setup failed!");
117+
return false;
118+
}
111119

112-
uint32_t duty = ledc_get_duty(group, (channel % 8));
120+
uint32_t duty = ledc_get_duty(group, (channel % 8));
113121

114-
ledc_channel_config_t ledc_channel = {
115-
.speed_mode = group, .channel = (channel % 8), .timer_sel = timer, .intr_type = LEDC_INTR_DISABLE, .gpio_num = pin, .duty = duty, .hpoint = 0
116-
};
117-
ledc_channel_config(&ledc_channel);
122+
ledc_channel_config_t ledc_channel = {
123+
.speed_mode = group, .channel = (channel % 8), .timer_sel = timer, .intr_type = LEDC_INTR_DISABLE, .gpio_num = pin, .duty = duty, .hpoint = 0
124+
};
125+
ledc_channel_config(&ledc_channel);
126+
}
118127

119128
ledc_channel_handle_t *handle = (ledc_channel_handle_t *)malloc(sizeof(ledc_channel_handle_t));
120-
121129
handle->pin = pin;
122130
handle->channel = channel;
123-
handle->channel_resolution = resolution;
124131
#ifndef SOC_LEDC_SUPPORT_FADE_STOP
125132
handle->lock = NULL;
126133
#endif
127-
ledc_handle.used_channels |= 1UL << channel;
134+
135+
//get resolution of selected channel when used
136+
if (channel_used) {
137+
uint32_t channel_resolution = 0;
138+
ledc_ll_get_duty_resolution(LEDC_LL_GET_HW(), group, timer, &channel_resolution);
139+
handle->channel_resolution = (uint8_t)channel_resolution;
140+
}
141+
else {
142+
handle->channel_resolution = resolution;
143+
ledc_handle.used_channels |= 1UL << channel;
144+
}
128145

129146
if (!perimanSetPinBus(pin, ESP32_BUS_TYPE_LEDC, (void *)handle, group, channel)) {
130147
ledcDetachBus((void *)handle);
@@ -167,6 +184,30 @@ bool ledcWrite(uint8_t pin, uint32_t duty) {
167184
return false;
168185
}
169186

187+
bool ledcWriteChannel(uint8_t channel, uint32_t duty){
188+
//check if channel is valid and used
189+
if (channel >= LEDC_CHANNELS || !(ledc_handle.used_channels & (1UL << channel))) {
190+
log_e("Channel %u is not available (maximum %u) or not used!", channel, LEDC_CHANNELS);
191+
return false;
192+
}
193+
uint8_t group = (channel / 8), timer = ((channel / 2) % 4);
194+
195+
//Fixing if all bits in resolution is set = LEDC FULL ON
196+
uint32_t resolution = 0;
197+
ledc_ll_get_duty_resolution(LEDC_LL_GET_HW(), group, timer, &resolution);
198+
199+
uint32_t max_duty = (1 << resolution) - 1;
200+
201+
if ((duty == max_duty) && (max_duty != 1)) {
202+
duty = max_duty + 1;
203+
}
204+
205+
ledc_set_duty(group, channel, duty);
206+
ledc_update_duty(group, channel);
207+
208+
return true;
209+
}
210+
170211
uint32_t ledcRead(uint8_t pin) {
171212
ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC);
172213
if (bus != NULL) {

cores/esp32/esp32-hal-ledc.h

+10
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
9191
*/
9292
bool ledcWrite(uint8_t pin, uint32_t duty);
9393

94+
/**
95+
* @brief Set the duty cycle of a given channel.
96+
*
97+
* @param channel LEDC channel
98+
* @param duty duty cycle to set
99+
*
100+
* @return true if duty cycle was successfully set, false otherwise.
101+
*/
102+
bool ledcWriteChannel(uint8_t channel, uint32_t duty);
103+
94104
/**
95105
* @brief Sets the duty to 50 % PWM tone on selected frequency.
96106
*

0 commit comments

Comments
 (0)