Skip to content

Commit 3e43281

Browse files
committed
fix off-by-one PWM top issue
1 parent 766e79a commit 3e43281

File tree

3 files changed

+11
-11
lines changed

3 files changed

+11
-11
lines changed

ports/raspberrypi/common-hal/pwmio/PWMOut.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -164,19 +164,20 @@ void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t* self) {
164164

165165
extern void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t* self, uint16_t duty) {
166166
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);
168169
pwm_set_chan_level(self->slice, self->channel, actual_duty);
169170
}
170171

171172
uint16_t common_hal_pwmio_pwmout_get_duty_cycle(pwmio_pwmout_obj_t* self) {
172173
return self->duty_cycle;
173174
}
174175

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) {
176177
self->actual_frequency = common_hal_mcu_processor_get_frequency() / top;
177178
self->top = top;
178179
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);
180181
}
181182

182183
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
187188
target_slice_frequencies[self->slice] = frequency;
188189

189190
// 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))) {
191192
// Compute the divisor. It's an 8 bit integer and 4 bit fraction. Therefore,
192193
// we compute everything * 16 for the fractional part.
193194
// 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
202203
div16 = (1 << 12) - 1;
203204
}
204205
self->actual_frequency = frequency16 / div16;
205-
self->top = 1 << 16;
206+
self->top = (1 << 16) - 1;
206207
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);
208209
} else {
209210
uint32_t top = common_hal_mcu_processor_get_frequency() / frequency;
210211
self->actual_frequency = common_hal_mcu_processor_get_frequency() / top;
211-
self->top = top;
212+
self->top = MIN(UINT16_MAX, top - 1);
212213
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);
214215
}
215216
common_hal_pwmio_pwmout_set_duty_cycle(self, self->duty_cycle);
216217
}

ports/raspberrypi/common-hal/pwmio/PWMOut.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ typedef struct {
3939
bool variable_frequency;
4040
uint16_t duty_cycle;
4141
uint32_t actual_frequency;
42-
uint32_t top;
42+
uint16_t top;
4343
} pwmio_pwmout_obj_t;
4444

4545
void pwmout_reset(void);
4646
// Private API for AudioPWMOut.
47-
void pwmio_pwmout_set_top(pwmio_pwmout_obj_t* self, uint32_t top);
47+
void pwmio_pwmout_set_top(pwmio_pwmout_obj_t* self, uint16_t top);
4848

4949
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PWMIO_PWMOUT_H

shared-bindings/adafruit_bus_device/SPIDevice.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434

3535
#include "lib/utils/buffer_helper.h"
3636
#include "lib/utils/context_manager_helpers.h"
37-
#include "py/objproperty.h"
3837
#include "py/runtime.h"
3938
#include "supervisor/shared/translate.h"
4039

0 commit comments

Comments
 (0)