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)
@@ -48,8 +49,25 @@ static bool fade_initialized = false;
4849
4950static bool ledcDetachBus (void * bus ) {
5051 ledc_channel_handle_t * handle = (ledc_channel_handle_t * )bus ;
51- ledc_handle .used_channels &= ~(1UL << handle -> channel );
52+ bool channel_found = false;
53+ // Check if more pins are attached to the same ledc channel
54+ for (uint8_t i = 0 ; i < SOC_GPIO_PIN_COUNT ; i ++ ) {
55+ if (!perimanPinIsValid (i )) {
56+ continue ; //invalid pin, skip
57+ }
58+ peripheral_bus_type_t type = perimanGetPinBusType (i );
59+ if (type == ESP32_BUS_TYPE_LEDC ) {
60+ ledc_channel_handle_t * bus_check = (ledc_channel_handle_t * )perimanGetPinBus (i , ESP32_BUS_TYPE_LEDC );
61+ if (bus_check -> channel == handle -> channel ) {
62+ channel_found = true;
63+ break ;
64+ }
65+ }
66+ }
5267 pinMatrixOutDetach (handle -> pin , false, false);
68+ if (!channel_found ) {
69+ ledc_handle .used_channels &= ~(1UL << handle -> channel );
70+ }
5371 free (handle );
5472 if (ledc_handle .used_channels == 0 ) {
5573 ledc_fade_func_uninstall ();
@@ -59,8 +77,8 @@ static bool ledcDetachBus(void *bus) {
5977}
6078
6179bool ledcAttachChannel (uint8_t pin , uint32_t freq , uint8_t resolution , uint8_t channel ) {
62- if (channel >= LEDC_CHANNELS || ledc_handle . used_channels & ( 1UL << channel ) ) {
63- log_e ("Channel %u is not available (maximum %u) or already used !" , channel , LEDC_CHANNELS );
80+ if (channel >= LEDC_CHANNELS ) {
81+ log_e ("Channel %u is not available (maximum %u)!" , channel , LEDC_CHANNELS );
6482 return false;
6583 }
6684 if (freq == 0 ) {
@@ -85,29 +103,45 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
85103 }
86104
87105 uint8_t group = (channel / 8 ), timer = ((channel / 2 ) % 4 );
106+ bool channel_used = ledc_handle .used_channels & (1UL << channel );
107+ if (channel_used ) {
108+ log_i ("Channel %u is already set up, given frequency and resolution will be ignored" , channel );
109+ if (ledc_set_pin (pin , group , channel % 8 ) != ESP_OK ) {
110+ log_e ("Attaching pin to already used channel failed!" );
111+ return false;
112+ }
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+ }
88119
89- ledc_timer_config_t ledc_timer = {.speed_mode = group , .timer_num = timer , .duty_resolution = resolution , .freq_hz = freq , .clk_cfg = LEDC_DEFAULT_CLK };
90- if (ledc_timer_config (& ledc_timer ) != ESP_OK ) {
91- log_e ("ledc setup failed!" );
92- return false;
93- }
94-
95- uint32_t duty = ledc_get_duty (group , (channel % 8 ));
120+ uint32_t duty = ledc_get_duty (group , (channel % 8 ));
96121
97- ledc_channel_config_t ledc_channel = {
98- .speed_mode = group , .channel = (channel % 8 ), .timer_sel = timer , .intr_type = LEDC_INTR_DISABLE , .gpio_num = pin , .duty = duty , .hpoint = 0
99- };
100- 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+ }
101127
102128 ledc_channel_handle_t * handle = (ledc_channel_handle_t * )malloc (sizeof (ledc_channel_handle_t ));
103-
104129 handle -> pin = pin ;
105130 handle -> channel = channel ;
106- handle -> channel_resolution = resolution ;
107131#ifndef SOC_LEDC_SUPPORT_FADE_STOP
108132 handle -> lock = NULL ;
109133#endif
110- 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+ log_i ("Channel %u frequency: %u, resolution: %u" , channel , ledc_get_freq (group , timer ), channel_resolution );
140+ handle -> channel_resolution = (uint8_t )channel_resolution ;
141+ } else {
142+ handle -> channel_resolution = resolution ;
143+ ledc_handle .used_channels |= 1UL << channel ;
144+ }
111145
112146 if (!perimanSetPinBus (pin , ESP32_BUS_TYPE_LEDC , (void * )handle , group , channel )) {
113147 ledcDetachBus ((void * )handle );
@@ -150,6 +184,30 @@ bool ledcWrite(uint8_t pin, uint32_t duty) {
150184 return false;
151185}
152186
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+
153211uint32_t ledcRead (uint8_t pin ) {
154212 ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
155213 if (bus != NULL ) {
0 commit comments