21
21
#include "esp32-hal-periman.h"
22
22
#include "soc/gpio_sig_map.h"
23
23
#include "esp_rom_gpio.h"
24
+ #include "hal/ledc_ll.h"
24
25
25
26
#ifdef SOC_LEDC_SUPPORT_HS_MODE
26
27
#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM << 1)
@@ -48,8 +49,25 @@ static bool fade_initialized = false;
48
49
49
50
static bool ledcDetachBus (void * bus ) {
50
51
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
+ }
52
67
pinMatrixOutDetach (handle -> pin , false, false);
68
+ if (!channel_found ) {
69
+ ledc_handle .used_channels &= ~(1UL << handle -> channel );
70
+ }
53
71
free (handle );
54
72
if (ledc_handle .used_channels == 0 ) {
55
73
ledc_fade_func_uninstall ();
@@ -59,8 +77,8 @@ static bool ledcDetachBus(void *bus) {
59
77
}
60
78
61
79
bool 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 );
64
82
return false;
65
83
}
66
84
if (freq == 0 ) {
@@ -85,29 +103,45 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
85
103
}
86
104
87
105
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
+ }
88
119
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 ));
96
121
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
+ }
101
127
102
128
ledc_channel_handle_t * handle = (ledc_channel_handle_t * )malloc (sizeof (ledc_channel_handle_t ));
103
-
104
129
handle -> pin = pin ;
105
130
handle -> channel = channel ;
106
- handle -> channel_resolution = resolution ;
107
131
#ifndef SOC_LEDC_SUPPORT_FADE_STOP
108
132
handle -> lock = NULL ;
109
133
#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
+ }
111
145
112
146
if (!perimanSetPinBus (pin , ESP32_BUS_TYPE_LEDC , (void * )handle , group , channel )) {
113
147
ledcDetachBus ((void * )handle );
@@ -150,6 +184,30 @@ bool ledcWrite(uint8_t pin, uint32_t duty) {
150
184
return false;
151
185
}
152
186
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
+
153
211
uint32_t ledcRead (uint8_t pin ) {
154
212
ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
155
213
if (bus != NULL ) {
0 commit comments