34
34
35
35
STATIC bool not_first_reset = false;
36
36
STATIC uint32_t reserved_timer_freq [LEDC_TIMER_MAX ];
37
+ STATIC bool varfreq_timers [LEDC_TIMER_MAX ];
37
38
STATIC uint8_t reserved_channels [LEDC_CHANNEL_MAX ];
38
39
STATIC bool never_reset_tim [LEDC_TIMER_MAX ];
39
40
STATIC bool never_reset_chan [LEDC_CHANNEL_MAX ];
40
41
42
+ STATIC uint32_t calculate_duty_cycle (uint32_t frequency ) {
43
+ uint32_t duty_bits = 0 ;
44
+ uint32_t interval = LEDC_APB_CLK_HZ / frequency ;
45
+ for (size_t i = 0 ; i < 32 ; i ++ ) {
46
+ if (!(interval >> i )) {
47
+ duty_bits = i - 1 ;
48
+ break ;
49
+ }
50
+ }
51
+ if (duty_bits >= LEDC_TIMER_14_BIT ) {
52
+ duty_bits = LEDC_TIMER_13_BIT ;
53
+ }
54
+ return duty_bits ;
55
+ }
56
+
41
57
void pwmout_reset (void ) {
42
58
for (size_t i = 0 ; i < LEDC_CHANNEL_MAX ; i ++ ) {
43
59
if (reserved_channels [i ] != INDEX_EMPTY && not_first_reset ) {
@@ -53,6 +69,7 @@ void pwmout_reset(void) {
53
69
}
54
70
if (!never_reset_tim [i ]) {
55
71
reserved_timer_freq [i ] = 0 ;
72
+ varfreq_timers [i ] = false;
56
73
}
57
74
}
58
75
not_first_reset = true;
@@ -70,25 +87,17 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
70
87
}
71
88
72
89
// Calculate duty cycle
73
- uint32_t duty_bits = 0 ;
74
- uint32_t interval = LEDC_APB_CLK_HZ / frequency ;
75
- for (size_t i = 0 ; i < 32 ; i ++ ) {
76
- if (!(interval >> i )) {
77
- duty_bits = i - 1 ;
78
- break ;
79
- }
80
- }
81
- if (duty_bits < 1 ) {
82
- mp_raise_ValueError (translate ("Invalid frequency" ));
83
- } else if (duty_bits >= LEDC_TIMER_14_BIT ) {
84
- duty_bits = LEDC_TIMER_13_BIT ;
90
+ uint32_t duty_bits = calculate_duty_cycle (frequency );
91
+ if (duty_bits == 0 ) {
92
+ return PWMOUT_INVALID_FREQUENCY ;
85
93
}
86
94
87
95
// Find a viable timer
88
96
size_t timer_index = INDEX_EMPTY ;
89
97
size_t channel_index = INDEX_EMPTY ;
90
98
for (size_t i = 0 ; i < LEDC_TIMER_MAX ; i ++ ) {
91
- if ((reserved_timer_freq [i ] == frequency ) && !variable_frequency ) {
99
+ // accept matching freq timers unless this instance is varfreq or a prior one was
100
+ if ((reserved_timer_freq [i ] == frequency ) && !variable_frequency && !varfreq_timers [i ]) {
92
101
// prioritize matched frequencies so we don't needlessly take slots
93
102
timer_index = i ;
94
103
break ;
@@ -139,6 +148,9 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
139
148
reserved_timer_freq [timer_index ] = frequency ;
140
149
reserved_channels [channel_index ] = timer_index ;
141
150
151
+ if (variable_frequency ) {
152
+ varfreq_timers [timer_index ] = true;
153
+ }
142
154
self -> variable_frequency = variable_frequency ;
143
155
self -> pin_number = pin -> number ;
144
156
self -> deinited = false;
@@ -175,6 +187,7 @@ void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t *self) {
175
187
if (reserved_channels [self -> chan_handle .channel ] != INDEX_EMPTY ) {
176
188
ledc_stop (LEDC_LOW_SPEED_MODE , self -> chan_handle .channel , 0 );
177
189
}
190
+ reserved_channels [self -> chan_handle .channel ] = INDEX_EMPTY ;
178
191
// Search if any other channel is using the timer
179
192
bool taken = false;
180
193
for (size_t i = 0 ; i < LEDC_CHANNEL_MAX ; i ++ ) {
@@ -184,13 +197,12 @@ void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t *self) {
184
197
}
185
198
// Variable frequency means there's only one channel on the timer
186
199
if (!taken || self -> variable_frequency ) {
187
- if (reserved_timer_freq [self -> tim_handle .timer_num ] != 0 ) {
188
- ledc_timer_rst (LEDC_LOW_SPEED_MODE , self -> tim_handle .timer_num );
189
- }
200
+ ledc_timer_rst (LEDC_LOW_SPEED_MODE , self -> tim_handle .timer_num );
190
201
reserved_timer_freq [self -> tim_handle .timer_num ] = 0 ;
202
+ // if timer isn't varfreq this will be off aleady
203
+ varfreq_timers [self -> tim_handle .timer_num ] = false;
191
204
}
192
205
reset_pin_number (self -> pin_number );
193
- reserved_channels [self -> chan_handle .channel ] = INDEX_EMPTY ;
194
206
self -> deinited = true;
195
207
}
196
208
@@ -204,6 +216,12 @@ uint16_t common_hal_pwmio_pwmout_get_duty_cycle(pwmio_pwmout_obj_t *self) {
204
216
}
205
217
206
218
void common_hal_pwmio_pwmout_set_frequency (pwmio_pwmout_obj_t * self , uint32_t frequency ) {
219
+ // Calculate duty cycle
220
+ uint32_t duty_bits = calculate_duty_cycle (frequency );
221
+ if (duty_bits == 0 ) {
222
+ mp_raise_ValueError (translate ("Invalid PWM frequency" ));
223
+ }
224
+ self -> duty_resolution = duty_bits ;
207
225
ledc_set_freq (LEDC_LOW_SPEED_MODE , self -> tim_handle .timer_num , frequency );
208
226
}
209
227
0 commit comments