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
7879bool 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+
170211uint32_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 ) {
0 commit comments