fix off-by-one PWM top issue
This commit is contained in:
parent
766e79ad3d
commit
3e4328140c
|
@ -164,7 +164,8 @@ void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t* self) {
|
||||||
|
|
||||||
extern void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t* self, uint16_t duty) {
|
extern void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t* self, uint16_t duty) {
|
||||||
self->duty_cycle = duty;
|
self->duty_cycle = duty;
|
||||||
uint16_t actual_duty = duty * self->top / ((1 << 16) - 1);
|
// Do arithmetic in 32 bits to prevent overflow.
|
||||||
|
uint16_t actual_duty = (uint32_t) duty * self->top / ((1 << 16) - 1);
|
||||||
pwm_set_chan_level(self->slice, self->channel, actual_duty);
|
pwm_set_chan_level(self->slice, self->channel, actual_duty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,11 +173,11 @@ uint16_t common_hal_pwmio_pwmout_get_duty_cycle(pwmio_pwmout_obj_t* self) {
|
||||||
return self->duty_cycle;
|
return self->duty_cycle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pwmio_pwmout_set_top(pwmio_pwmout_obj_t* self, uint32_t top) {
|
void pwmio_pwmout_set_top(pwmio_pwmout_obj_t* self, uint16_t top) {
|
||||||
self->actual_frequency = common_hal_mcu_processor_get_frequency() / top;
|
self->actual_frequency = common_hal_mcu_processor_get_frequency() / top;
|
||||||
self->top = top;
|
self->top = top;
|
||||||
pwm_set_clkdiv_int_frac(self->slice, 1, 0);
|
pwm_set_clkdiv_int_frac(self->slice, 1, 0);
|
||||||
pwm_set_wrap(self->slice, self->top - 1);
|
pwm_set_wrap(self->slice, self->top);
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t* self, uint32_t frequency) {
|
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
|
||||||
target_slice_frequencies[self->slice] = frequency;
|
target_slice_frequencies[self->slice] = frequency;
|
||||||
|
|
||||||
// For low frequencies use the divider to give us full resolution duty_cycle.
|
// For low frequencies use the divider to give us full resolution duty_cycle.
|
||||||
if (frequency < (common_hal_mcu_processor_get_frequency() / (1 << 16))) {
|
if (frequency <= (common_hal_mcu_processor_get_frequency() / (1 << 16))) {
|
||||||
// Compute the divisor. It's an 8 bit integer and 4 bit fraction. Therefore,
|
// Compute the divisor. It's an 8 bit integer and 4 bit fraction. Therefore,
|
||||||
// we compute everything * 16 for the fractional part.
|
// we compute everything * 16 for the fractional part.
|
||||||
// This is 1 << 12 because 4 bits are the * 16.
|
// 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
|
||||||
div16 = (1 << 12) - 1;
|
div16 = (1 << 12) - 1;
|
||||||
}
|
}
|
||||||
self->actual_frequency = frequency16 / div16;
|
self->actual_frequency = frequency16 / div16;
|
||||||
self->top = 1 << 16;
|
self->top = (1 << 16) - 1;
|
||||||
pwm_set_clkdiv_int_frac(self->slice, div16 / 16, div16 % 16);
|
pwm_set_clkdiv_int_frac(self->slice, div16 / 16, div16 % 16);
|
||||||
pwm_set_wrap(self->slice, self->top - 1);
|
pwm_set_wrap(self->slice, self->top);
|
||||||
} else {
|
} else {
|
||||||
uint32_t top = common_hal_mcu_processor_get_frequency() / frequency;
|
uint32_t top = common_hal_mcu_processor_get_frequency() / frequency;
|
||||||
self->actual_frequency = common_hal_mcu_processor_get_frequency() / top;
|
self->actual_frequency = common_hal_mcu_processor_get_frequency() / top;
|
||||||
self->top = top;
|
self->top = MIN(UINT16_MAX, top - 1);
|
||||||
pwm_set_clkdiv_int_frac(self->slice, 1, 0);
|
pwm_set_clkdiv_int_frac(self->slice, 1, 0);
|
||||||
pwm_set_wrap(self->slice, self->top - 1);
|
pwm_set_wrap(self->slice, self->top);
|
||||||
}
|
}
|
||||||
common_hal_pwmio_pwmout_set_duty_cycle(self, self->duty_cycle);
|
common_hal_pwmio_pwmout_set_duty_cycle(self, self->duty_cycle);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,11 +39,11 @@ typedef struct {
|
||||||
bool variable_frequency;
|
bool variable_frequency;
|
||||||
uint16_t duty_cycle;
|
uint16_t duty_cycle;
|
||||||
uint32_t actual_frequency;
|
uint32_t actual_frequency;
|
||||||
uint32_t top;
|
uint16_t top;
|
||||||
} pwmio_pwmout_obj_t;
|
} pwmio_pwmout_obj_t;
|
||||||
|
|
||||||
void pwmout_reset(void);
|
void pwmout_reset(void);
|
||||||
// Private API for AudioPWMOut.
|
// Private API for AudioPWMOut.
|
||||||
void pwmio_pwmout_set_top(pwmio_pwmout_obj_t* self, uint32_t top);
|
void pwmio_pwmout_set_top(pwmio_pwmout_obj_t* self, uint16_t top);
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PWMIO_PWMOUT_H
|
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PWMIO_PWMOUT_H
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
|
|
||||||
#include "lib/utils/buffer_helper.h"
|
#include "lib/utils/buffer_helper.h"
|
||||||
#include "lib/utils/context_manager_helpers.h"
|
#include "lib/utils/context_manager_helpers.h"
|
||||||
#include "py/objproperty.h"
|
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "supervisor/shared/translate.h"
|
#include "supervisor/shared/translate.h"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue