@@ -164,19 +164,20 @@ void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t* self) {
164
164
165
165
extern void common_hal_pwmio_pwmout_set_duty_cycle (pwmio_pwmout_obj_t * self , uint16_t duty ) {
166
166
self -> duty_cycle = duty ;
167
- uint16_t actual_duty = duty * self -> top / ((1 << 16 ) - 1 );
167
+ // Do arithmetic in 32 bits to prevent overflow.
168
+ uint16_t actual_duty = (uint32_t ) duty * self -> top / ((1 << 16 ) - 1 );
168
169
pwm_set_chan_level (self -> slice , self -> channel , actual_duty );
169
170
}
170
171
171
172
uint16_t common_hal_pwmio_pwmout_get_duty_cycle (pwmio_pwmout_obj_t * self ) {
172
173
return self -> duty_cycle ;
173
174
}
174
175
175
- void pwmio_pwmout_set_top (pwmio_pwmout_obj_t * self , uint32_t top ) {
176
+ void pwmio_pwmout_set_top (pwmio_pwmout_obj_t * self , uint16_t top ) {
176
177
self -> actual_frequency = common_hal_mcu_processor_get_frequency () / top ;
177
178
self -> top = top ;
178
179
pwm_set_clkdiv_int_frac (self -> slice , 1 , 0 );
179
- pwm_set_wrap (self -> slice , self -> top - 1 );
180
+ pwm_set_wrap (self -> slice , self -> top );
180
181
}
181
182
182
183
void common_hal_pwmio_pwmout_set_frequency (pwmio_pwmout_obj_t * self , uint32_t frequency ) {
@@ -187,7 +188,7 @@ void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t* self, uint32_t fr
187
188
target_slice_frequencies [self -> slice ] = frequency ;
188
189
189
190
// For low frequencies use the divider to give us full resolution duty_cycle.
190
- if (frequency < (common_hal_mcu_processor_get_frequency () / (1 << 16 ))) {
191
+ if (frequency <= (common_hal_mcu_processor_get_frequency () / (1 << 16 ))) {
191
192
// Compute the divisor. It's an 8 bit integer and 4 bit fraction. Therefore,
192
193
// we compute everything * 16 for the fractional part.
193
194
// This is 1 << 12 because 4 bits are the * 16.
@@ -202,15 +203,15 @@ void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t* self, uint32_t fr
202
203
div16 = (1 << 12 ) - 1 ;
203
204
}
204
205
self -> actual_frequency = frequency16 / div16 ;
205
- self -> top = 1 << 16 ;
206
+ self -> top = ( 1 << 16 ) - 1 ;
206
207
pwm_set_clkdiv_int_frac (self -> slice , div16 / 16 , div16 % 16 );
207
- pwm_set_wrap (self -> slice , self -> top - 1 );
208
+ pwm_set_wrap (self -> slice , self -> top );
208
209
} else {
209
210
uint32_t top = common_hal_mcu_processor_get_frequency () / frequency ;
210
211
self -> actual_frequency = common_hal_mcu_processor_get_frequency () / top ;
211
- self -> top = top ;
212
+ self -> top = MIN ( UINT16_MAX , top - 1 ) ;
212
213
pwm_set_clkdiv_int_frac (self -> slice , 1 , 0 );
213
- pwm_set_wrap (self -> slice , self -> top - 1 );
214
+ pwm_set_wrap (self -> slice , self -> top );
214
215
}
215
216
common_hal_pwmio_pwmout_set_duty_cycle (self , self -> duty_cycle );
216
217
}
0 commit comments