1313// limitations under the License.
1414
1515#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"
2016#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"
2418
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)
4523#endif
4624
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
5029#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
5431#endif
5532
33+ #define LEDC_MAX_BIT_WIDTH SOC_LEDC_TIMER_BIT_WIDE_NUM
34+
5635/*
5736 * LEDC Chan to Group/Channel/Timer Mapping
5837** ledc: 0 => Group: 0, Channel: 0, Timer: 0
@@ -72,223 +51,89 @@ xSemaphoreHandle _ledc_sys_lock = NULL;
7251** ledc: 14 => Group: 1, Channel: 6, Timer: 3
7352** ledc: 15 => Group: 1, Channel: 7, Timer: 3
7453*/
75- #define LEDC_CHAN (g ,c ) LEDC.channel_group[(g)].channel[(c)]
76- #define LEDC_TIMER (g ,t ) LEDC.timer_group[(g)].timer[(t)]
7754
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 };
11256
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 )
15458{
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 ;
16862 }
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 ;
18063 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- }
19364
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 ;
21974
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 );
22876}
22977
23078void ledcWrite (uint8_t chan , uint32_t duty )
23179{
232- if (chan > LAST_CHAN ) {
80+ if (chan >= LEDC_CHANNELS ) {
23381 return ;
23482 }
23583 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 ;
26290 }
263- LEDC_MUTEX_UNLOCK ();
91+
92+ ledc_set_duty (group , channel , duty );
93+ ledc_update_duty (group , channel );
26494}
26595
26696uint32_t ledcRead (uint8_t chan )
26797{
268- if (chan > LAST_CHAN ) {
98+ if (chan >= LEDC_CHANNELS ) {
26999 return 0 ;
270100 }
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 );
272103}
273104
274105double ledcReadFreq (uint8_t chan )
275106{
276107 if (!ledcRead (chan )){
277108 return 0 ;
278109 }
279- return _ledcTimerRead (chan );
110+ uint8_t group = (chan /8 ), timer = ((chan /2 )%4 );
111+ return ledc_get_freq (group ,timer );
280112}
281113
282114double ledcWriteTone (uint8_t chan , double freq )
283115{
284- if (chan > LAST_CHAN ) {
116+ if (chan >= LEDC_CHANNELS ) {
285117 return 0 ;
286118 }
287- if (!freq ) {
119+ if (!freq ){
288120 ledcWrite (chan , 0 );
289121 return 0 ;
290122 }
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 );
292137 ledcWrite (chan , 0x1FF );
293138 return res_freq ;
294139}
@@ -308,15 +153,21 @@ double ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){
308153
309154void ledcAttachPin (uint8_t pin , uint8_t chan )
310155{
311- if (chan > LAST_CHAN ) {
156+ if (chan >= LEDC_CHANNELS ) {
312157 return ;
313158 }
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 );
320171}
321172
322173void ledcDetachPin (uint8_t pin )
@@ -326,21 +177,32 @@ void ledcDetachPin(uint8_t pin)
326177
327178double ledcChangeFrequency (uint8_t chan , double freq , uint8_t bit_num )
328179{
329- if (chan > 15 ) {
180+ if (chan >= LEDC_CHANNELS ) {
330181 return 0 ;
331182 }
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 );
334196}
335197
336198static 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 ;
338200void analogWrite (uint8_t pin , int value ) {
339201 // Use ledc hardware for internal pins
340202 if (pin < SOC_GPIO_PIN_COUNT ) {
341203 if (pin_to_channel [pin ] == 0 ) {
342204 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 );
344206 return ;
345207 }
346208 pin_to_channel [pin ] = cnt_channel -- ;
0 commit comments