13
13
// limitations under the License.
14
14
15
15
#include "esp32-hal.h"
16
- #include "freertos/FreeRTOS.h"
17
- #include "freertos/task.h"
18
- #include "freertos/semphr.h"
19
- #include "esp32-hal-matrix.h"
20
16
#include "soc/soc_caps.h"
21
- #include "soc/ledc_reg.h"
22
- #include "soc/ledc_struct.h"
23
- #include "driver/periph_ctrl.h"
17
+ #include "driver/ledc.h"
24
18
25
- #include "esp_system.h"
26
- #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
27
- #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
28
- #include "soc/dport_reg.h"
29
- #include "esp32/rom/ets_sys.h"
30
- #define LAST_CHAN (15)
31
- #elif CONFIG_IDF_TARGET_ESP32S2
32
- #include "soc/dport_reg.h"
33
- #include "esp32s2/rom/ets_sys.h"
34
- #define LAST_CHAN (7)
35
- #define LEDC_DIV_NUM_HSTIMER0_V LEDC_CLK_DIV_LSTIMER0_V
36
- #elif CONFIG_IDF_TARGET_ESP32C3
37
- #include "esp32c3/rom/ets_sys.h"
38
- #define LAST_CHAN (7)
39
- #define LEDC_DIV_NUM_HSTIMER0_V LEDC_CLK_DIV_LSTIMER0_V
40
- #else
41
- #error Target CONFIG_IDF_TARGET is not supported
42
- #endif
43
- #else // ESP32 Before IDF 4.0
44
- #include "rom/ets_sys.h"
19
+ #ifdef SOC_LEDC_SUPPORT_HS_MODE
20
+ #define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM<<1)
21
+ #else
22
+ #define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM)
45
23
#endif
46
24
47
- #if CONFIG_DISABLE_HAL_LOCKS
48
- #define LEDC_MUTEX_LOCK ()
49
- #define LEDC_MUTEX_UNLOCK ()
25
+ //Use XTAL clock if possible to avoid timer frequency error when setting APB clock < 80 Mhz
26
+ //Need to be fixed in ESP-IDF
27
+ #ifdef SOC_LEDC_SUPPORT_XTAL_CLOCK
28
+ #define LEDC_DEFAULT_CLK LEDC_USE_XTAL_CLK
50
29
#else
51
- #define LEDC_MUTEX_LOCK () do {} while (xSemaphoreTake(_ledc_sys_lock, portMAX_DELAY) != pdPASS)
52
- #define LEDC_MUTEX_UNLOCK () xSemaphoreGive(_ledc_sys_lock)
53
- xSemaphoreHandle _ledc_sys_lock = NULL ;
30
+ #define LEDC_DEFAULT_CLK LEDC_AUTO_CLK
54
31
#endif
55
32
33
+ #define LEDC_MAX_BIT_WIDTH SOC_LEDC_TIMER_BIT_WIDE_NUM
34
+
56
35
/*
57
36
* LEDC Chan to Group/Channel/Timer Mapping
58
37
** ledc: 0 => Group: 0, Channel: 0, Timer: 0
@@ -72,223 +51,89 @@ xSemaphoreHandle _ledc_sys_lock = NULL;
72
51
** ledc: 14 => Group: 1, Channel: 6, Timer: 3
73
52
** ledc: 15 => Group: 1, Channel: 7, Timer: 3
74
53
*/
75
- #define LEDC_CHAN (g ,c ) LEDC.channel_group[(g)].channel[(c)]
76
- #define LEDC_TIMER (g ,t ) LEDC.timer_group[(g)].timer[(t)]
77
54
78
- static void _on_apb_change (void * arg , apb_change_ev_t ev_type , uint32_t old_apb , uint32_t new_apb ){
79
- if (ev_type == APB_AFTER_CHANGE && old_apb != new_apb ){
80
- uint16_t iarg = * (uint16_t * )arg ;
81
- uint8_t chan = 0 ;
82
- old_apb /= 1000000 ;
83
- new_apb /= 1000000 ;
84
- while (iarg ){ // run though all active channels, adjusting timing configurations
85
- if (iarg & 1 ) {// this channel is active
86
- uint8_t group = (chan /8 ), timer = ((chan /2 )%4 );
87
- if (LEDC_TIMER (group , timer ).conf .tick_sel ){
88
- LEDC_MUTEX_LOCK ();
89
- uint32_t old_div = LEDC_TIMER (group , timer ).conf .clock_divider ;
90
- uint32_t div_num = (new_apb * old_div ) / old_apb ;
91
- if (div_num > LEDC_DIV_NUM_HSTIMER0_V ){
92
- div_num = ((REF_CLK_FREQ /1000000 ) * old_div ) / old_apb ;
93
- if (div_num > LEDC_DIV_NUM_HSTIMER0_V ) {
94
- div_num = LEDC_DIV_NUM_HSTIMER0_V ;//lowest clock possible
95
- }
96
- LEDC_TIMER (group , timer ).conf .tick_sel = 0 ;
97
- } else if (div_num < 256 ) {
98
- div_num = 256 ;//highest clock possible
99
- }
100
- LEDC_TIMER (group , timer ).conf .clock_divider = div_num ;
101
- LEDC_MUTEX_UNLOCK ();
102
- }
103
- else {
104
- log_d ("using REF_CLK chan=%d" ,chan );
105
- }
106
- }
107
- iarg = iarg >> 1 ;
108
- chan ++ ;
109
- }
110
- }
111
- }
55
+ uint8_t channels_resolution [LEDC_CHANNELS ] = {0 };
112
56
113
- //uint32_t frequency = (80MHz or 1MHz)/((div_num / 256.0)*(1 << bit_num));
114
- static void _ledcSetupTimer (uint8_t chan , uint32_t div_num , uint8_t bit_num , bool apb_clk )
115
- {
116
- uint8_t group = (chan /8 ), timer = ((chan /2 )%4 );
117
- static bool tHasStarted = false;
118
- static uint16_t _activeChannels = 0 ;
119
- #if CONFIG_IDF_TARGET_ESP32S2
120
- // ESP32-S2 TRM v1.0 on Page 789 -> BIT LEDC_TICK_SEL_TIMERx is 0 for LEDC_PWM_CLK and 1 for REF_TICK
121
- apb_clk = 0 ;
122
- #endif
123
- if (!tHasStarted ) {
124
- tHasStarted = true;
125
- periph_module_enable (PERIPH_LEDC_MODULE );
126
- LEDC .conf .apb_clk_sel = 1 ;//LS use apb clock
127
- addApbChangeCallback ((void * )& _activeChannels , _on_apb_change );
128
-
129
- #if !CONFIG_DISABLE_HAL_LOCKS
130
- _ledc_sys_lock = xSemaphoreCreateMutex ();
131
- #endif
132
- }
133
- LEDC_MUTEX_LOCK ();
134
- LEDC_TIMER (group , timer ).conf .clock_divider = div_num ;//18 bit (10.8) This register is used to configure parameter for divider in timer the least significant eight bits represent the decimal part.
135
- LEDC_TIMER (group , timer ).conf .duty_resolution = bit_num ;//5 bit This register controls the range of the counter in timer. the counter range is [0 2**bit_num] the max bit width for counter is 20.
136
- LEDC_TIMER (group , timer ).conf .tick_sel = apb_clk ;//apb clock
137
- #if CONFIG_IDF_TARGET_ESP32
138
- if (group ) {
139
- #endif
140
- LEDC_TIMER (group , timer ).conf .low_speed_update = 1 ;//This bit is only useful for low speed timer channels, reserved for high speed timers
141
- #if CONFIG_IDF_TARGET_ESP32
142
- }
143
- #endif
144
- LEDC_TIMER (group , timer ).conf .pause = 0 ;
145
- LEDC_TIMER (group , timer ).conf .rst = 1 ;//This bit is used to reset timer the counter will be 0 after reset.
146
- LEDC_TIMER (group , timer ).conf .rst = 0 ;
147
- LEDC_MUTEX_UNLOCK ();
148
- _activeChannels |= (1 << chan ); // mark as active for APB callback
149
- }
150
-
151
- //max div_num 0x3FFFF (262143)
152
- //max bit_num 0x1F (31)
153
- static double _ledcSetupTimerFreq (uint8_t chan , double freq , uint8_t bit_num )
57
+ double ledcSetup (uint8_t chan , double freq , uint8_t bit_num )
154
58
{
155
- uint64_t clk_freq = getApbFrequency ();
156
- clk_freq <<= 8 ;//div_num is 8 bit decimal
157
- uint32_t div_num = (clk_freq >> bit_num ) / freq ;
158
- bool apb_clk = true;
159
- if (div_num > LEDC_DIV_NUM_HSTIMER0_V ) {
160
- clk_freq /= 80 ;
161
- div_num = (clk_freq >> bit_num ) / freq ;
162
- if (div_num > LEDC_DIV_NUM_HSTIMER0_V ) {
163
- div_num = LEDC_DIV_NUM_HSTIMER0_V ;//lowest clock possible
164
- }
165
- apb_clk = false;
166
- } else if (div_num < 256 ) {
167
- div_num = 256 ;//highest clock possible
59
+ if (chan >= LEDC_CHANNELS ){
60
+ log_e ("No more LEDC channels available! You can have maximum %u" , LEDC_CHANNELS );
61
+ return 0 ;
168
62
}
169
- _ledcSetupTimer (chan , div_num , bit_num , apb_clk );
170
- //log_i("Fin: %f, Fclk: %uMhz, bits: %u, DIV: %u, Fout: %f",
171
- // freq, apb_clk?80:1, bit_num, div_num, (clk_freq >> bit_num) / (double)div_num);
172
- return (clk_freq >> bit_num ) / (double )div_num ;
173
- }
174
-
175
- static double _ledcTimerRead (uint8_t chan )
176
- {
177
- uint32_t div_num ;
178
- uint8_t bit_num ;
179
- bool apb_clk ;
180
63
uint8_t group = (chan /8 ), timer = ((chan /2 )%4 );
181
- LEDC_MUTEX_LOCK ();
182
- div_num = LEDC_TIMER (group , timer ).conf .clock_divider ;//18 bit (10.8) This register is used to configure parameter for divider in timer the least significant eight bits represent the decimal part.
183
- bit_num = LEDC_TIMER (group , timer ).conf .duty_resolution ;//5 bit This register controls the range of the counter in timer. the counter range is [0 2**bit_num] the max bit width for counter is 20.
184
- apb_clk = LEDC_TIMER (group , timer ).conf .tick_sel ;//apb clock
185
- LEDC_MUTEX_UNLOCK ();
186
- uint64_t clk_freq = 1000000 ;
187
- if (apb_clk ) {
188
- clk_freq = getApbFrequency ();
189
- }
190
- clk_freq <<= 8 ;//div_num is 8 bit decimal
191
- return (clk_freq >> bit_num ) / (double )div_num ;
192
- }
193
64
194
- static void _ledcSetupChannel (uint8_t chan , uint8_t idle_level )
195
- {
196
- uint8_t group = (chan /8 ), channel = (chan %8 ), timer = ((chan /2 )%4 );
197
- LEDC_MUTEX_LOCK ();
198
- LEDC_CHAN (group , channel ).conf0 .timer_sel = timer ;//2 bit Selects the timer to attach 0-3
199
- LEDC_CHAN (group , channel ).conf0 .idle_lv = idle_level ;//1 bit This bit is used to control the output value when channel is off.
200
- LEDC_CHAN (group , channel ).hpoint .hpoint = 0 ;//20 bit The output value changes to high when timer selected by channel has reached hpoint
201
- LEDC_CHAN (group , channel ).conf1 .duty_inc = 1 ;//1 bit This register is used to increase the duty of output signal or decrease the duty of output signal for high speed channel
202
- LEDC_CHAN (group , channel ).conf1 .duty_num = 1 ;//10 bit This register is used to control the number of increased or decreased times for channel
203
- LEDC_CHAN (group , channel ).conf1 .duty_cycle = 1 ;//10 bit This register is used to increase or decrease the duty every duty_cycle cycles for channel
204
- LEDC_CHAN (group , channel ).conf1 .duty_scale = 0 ;//10 bit This register controls the increase or decrease step scale for channel.
205
- LEDC_CHAN (group , channel ).duty .duty = 0 ;
206
- LEDC_CHAN (group , channel ).conf0 .sig_out_en = 0 ;//This is the output enable control bit for channel
207
- LEDC_CHAN (group , channel ).conf1 .duty_start = 0 ;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware.
208
- #if CONFIG_IDF_TARGET_ESP32
209
- if (group ) {
210
- #endif
211
- LEDC_CHAN (group , channel ).conf0 .low_speed_update = 1 ;
212
- #if CONFIG_IDF_TARGET_ESP32
213
- } else {
214
- LEDC_CHAN (group , channel ).conf0 .clk_en = 0 ;
215
- }
216
- #endif
217
- LEDC_MUTEX_UNLOCK ();
218
- }
65
+ ledc_timer_config_t ledc_timer = {
66
+ .speed_mode = group ,
67
+ .timer_num = timer ,
68
+ .duty_resolution = bit_num ,
69
+ .freq_hz = freq ,
70
+ .clk_cfg = LEDC_DEFAULT_CLK
71
+ };
72
+ ledc_timer_config (& ledc_timer );
73
+ channels_resolution [chan ] = bit_num ;
219
74
220
- double ledcSetup (uint8_t chan , double freq , uint8_t bit_num )
221
- {
222
- if (chan > LAST_CHAN ) {
223
- return 0 ;
224
- }
225
- double res_freq = _ledcSetupTimerFreq (chan , freq , bit_num );
226
- _ledcSetupChannel (chan , LOW );
227
- return res_freq ;
75
+ return ledc_get_freq (group ,timer );
228
76
}
229
77
230
78
void ledcWrite (uint8_t chan , uint32_t duty )
231
79
{
232
- if (chan > LAST_CHAN ) {
80
+ if (chan >= LEDC_CHANNELS ) {
233
81
return ;
234
82
}
235
83
uint8_t group = (chan /8 ), channel = (chan %8 );
236
- LEDC_MUTEX_LOCK ();
237
- LEDC_CHAN (group , channel ).duty .duty = duty << 4 ;//25 bit (21.4)
238
- if (duty ) {
239
- LEDC_CHAN (group , channel ).conf0 .sig_out_en = 1 ;//This is the output enable control bit for channel
240
- LEDC_CHAN (group , channel ).conf1 .duty_start = 1 ;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware.
241
- #if CONFIG_IDF_TARGET_ESP32
242
- if (group ) {
243
- #endif
244
- LEDC_CHAN (group , channel ).conf0 .low_speed_update = 1 ;
245
- #if CONFIG_IDF_TARGET_ESP32
246
- } else {
247
- LEDC_CHAN (group , channel ).conf0 .clk_en = 1 ;
248
- }
249
- #endif
250
- } else {
251
- LEDC_CHAN (group , channel ).conf0 .sig_out_en = 0 ;//This is the output enable control bit for channel
252
- LEDC_CHAN (group , channel ).conf1 .duty_start = 0 ;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware.
253
- #if CONFIG_IDF_TARGET_ESP32
254
- if (group ) {
255
- #endif
256
- LEDC_CHAN (group , channel ).conf0 .low_speed_update = 1 ;
257
- #if CONFIG_IDF_TARGET_ESP32
258
- } else {
259
- LEDC_CHAN (group , channel ).conf0 .clk_en = 0 ;
260
- }
261
- #endif
84
+
85
+ //Fixing if all bits in resolution is set = LEDC FULL ON
86
+ uint32_t max_duty = (1 << channels_resolution [chan ]) - 1 ;
87
+
88
+ if (duty == max_duty ){
89
+ duty = max_duty + 1 ;
262
90
}
263
- LEDC_MUTEX_UNLOCK ();
91
+
92
+ ledc_set_duty (group , channel , duty );
93
+ ledc_update_duty (group , channel );
264
94
}
265
95
266
96
uint32_t ledcRead (uint8_t chan )
267
97
{
268
- if (chan > LAST_CHAN ) {
98
+ if (chan >= LEDC_CHANNELS ) {
269
99
return 0 ;
270
100
}
271
- return LEDC .channel_group [chan /8 ].channel [chan %8 ].duty .duty >> 4 ;
101
+ uint8_t group = (chan /8 ), channel = (chan %8 );
102
+ return ledc_get_duty (group ,channel );
272
103
}
273
104
274
105
double ledcReadFreq (uint8_t chan )
275
106
{
276
107
if (!ledcRead (chan )){
277
108
return 0 ;
278
109
}
279
- return _ledcTimerRead (chan );
110
+ uint8_t group = (chan /8 ), timer = ((chan /2 )%4 );
111
+ return ledc_get_freq (group ,timer );
280
112
}
281
113
282
114
double ledcWriteTone (uint8_t chan , double freq )
283
115
{
284
- if (chan > LAST_CHAN ) {
116
+ if (chan >= LEDC_CHANNELS ) {
285
117
return 0 ;
286
118
}
287
- if (!freq ) {
119
+ if (!freq ){
288
120
ledcWrite (chan , 0 );
289
121
return 0 ;
290
122
}
291
- double res_freq = _ledcSetupTimerFreq (chan , freq , 10 );
123
+
124
+ uint8_t group = (chan /8 ), timer = ((chan /2 )%4 );
125
+
126
+ ledc_timer_config_t ledc_timer = {
127
+ .speed_mode = group ,
128
+ .timer_num = timer ,
129
+ .duty_resolution = 10 ,
130
+ .freq_hz = freq ,
131
+ .clk_cfg = LEDC_DEFAULT_CLK
132
+ };
133
+ ledc_timer_config (& ledc_timer );
134
+ channels_resolution [chan ] = 10 ;
135
+
136
+ double res_freq = ledc_get_freq (group ,timer );
292
137
ledcWrite (chan , 0x1FF );
293
138
return res_freq ;
294
139
}
@@ -308,15 +153,21 @@ double ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){
308
153
309
154
void ledcAttachPin (uint8_t pin , uint8_t chan )
310
155
{
311
- if (chan > LAST_CHAN ) {
156
+ if (chan >= LEDC_CHANNELS ) {
312
157
return ;
313
158
}
314
- pinMode (pin , OUTPUT );
315
- #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
316
- pinMatrixOutAttach (pin , LEDC_LS_SIG_OUT0_IDX + chan , false, false);
317
- #else
318
- pinMatrixOutAttach (pin , ((chan /8 )?LEDC_LS_SIG_OUT0_IDX :LEDC_HS_SIG_OUT0_IDX ) + (chan %8 ), false, false);
319
- #endif
159
+ uint8_t group = (chan /8 ), channel = (chan %8 ), timer = ((chan /2 )%4 );
160
+
161
+ ledc_channel_config_t ledc_channel = {
162
+ .speed_mode = group ,
163
+ .channel = channel ,
164
+ .timer_sel = timer ,
165
+ .intr_type = LEDC_INTR_DISABLE ,
166
+ .gpio_num = pin ,
167
+ .duty = 0 ,
168
+ .hpoint = 0
169
+ };
170
+ ledc_channel_config (& ledc_channel );
320
171
}
321
172
322
173
void ledcDetachPin (uint8_t pin )
@@ -326,21 +177,32 @@ void ledcDetachPin(uint8_t pin)
326
177
327
178
double ledcChangeFrequency (uint8_t chan , double freq , uint8_t bit_num )
328
179
{
329
- if (chan > 15 ) {
180
+ if (chan >= LEDC_CHANNELS ) {
330
181
return 0 ;
331
182
}
332
- double res_freq = _ledcSetupTimerFreq (chan , freq , bit_num );
333
- return res_freq ;
183
+ uint8_t group = (chan /8 ), timer = ((chan /2 )%4 );
184
+
185
+ ledc_timer_config_t ledc_timer = {
186
+ .speed_mode = group ,
187
+ .timer_num = timer ,
188
+ .duty_resolution = bit_num ,
189
+ .freq_hz = freq ,
190
+ .clk_cfg = LEDC_DEFAULT_CLK
191
+ };
192
+ ledc_timer_config (& ledc_timer );
193
+ channels_resolution [chan ] = bit_num ;
194
+
195
+ return ledc_get_freq (group ,timer );
334
196
}
335
197
336
198
static int8_t pin_to_channel [SOC_GPIO_PIN_COUNT ] = { 0 };
337
- static int cnt_channel = SOC_LEDC_CHANNEL_NUM ;
199
+ static int cnt_channel = LEDC_CHANNELS ;
338
200
void analogWrite (uint8_t pin , int value ) {
339
201
// Use ledc hardware for internal pins
340
202
if (pin < SOC_GPIO_PIN_COUNT ) {
341
203
if (pin_to_channel [pin ] == 0 ) {
342
204
if (!cnt_channel ) {
343
- log_e ("No more analogWrite channels available! You can have maximum %u" , SOC_LEDC_CHANNEL_NUM );
205
+ log_e ("No more analogWrite channels available! You can have maximum %u" , LEDC_CHANNELS );
344
206
return ;
345
207
}
346
208
pin_to_channel [pin ] = cnt_channel -- ;
0 commit comments