8000 rp2/PWM: Add duty_xx() checks and return 0 if PWM is not started. · micropython/micropython@37ef0c1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 37ef0c1

Browse files
committed
rp2/PWM: Add duty_xx() checks and return 0 if PWM is not started.
- Limit duty_u16() to 65535 and duty_ns() to the period duration. - Return 0 for pwm.freq() if the frequency has not been set yet. - Return 0 for pwm.duty_us16() and duty_ns() unless both frequency and duty cycle have been set.
1 parent 1059265 commit 37ef0c1

File tree

1 file changed

+45
-17
lines changed

1 file changed

+45
-17
lines changed

ports/rp2/machine_pwm.c

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args
150150
mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
151151
mp_machine_pwm_init_helper(self, n_args - 1, all_args + 1, &kw_args);
152152

153+
// Select PWM function for given GPIO.
154+
gpio_set_function(gpio, GPIO_FUNC_PWM);
155+
153156
return MP_OBJ_FROM_PTR(self);
154157
}
155158

@@ -158,7 +161,15 @@ void machine_pwm_deinit_all(void) {
158161
for (int i = 0; i < 8; i++) {
159162
slice_freq_set[i] = false;
160163
pwm_set_enabled(machine_pwm_obj[i].slice, false);
164+
// pwm_set_chan_level(i, 0, 0);
165+
// pwm_set_chan_level(i, 1, 0);
161166
}
167+
// Clean out the table
168+
// for (int i = 0; i < 16; i++) {
169+
// machine_pwm_obj[i].invert = 0;
170+
// machine_pwm_obj[i].duty = 0;
171+
// machine_pwm_obj[i].duty_type = DUTY_NOT_SET;
172+
// }
162173
}
163174

164175
STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) {
@@ -189,10 +200,14 @@ uint32_t get_slice_hz_ceil(uint32_t div16) {
189200
}
190201

191202
STATIC mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) {
192-
uint32_t div16 = pwm_hw->slice[self->slice].div;
193-
uint32_t top = pwm_hw->slice[self->slice].top;
194-
uint32_t pwm_freq = get_slice_hz_round(div16 * (top + 1));
195-
return MP_OBJ_NEW_SMALL_INT(pwm_freq);
203+
if (slice_freq_set[self->slice] == true) {
204+
uint32_t div16 = pwm_hw->slice[self->slice].div;
205+
uint32_t top = pwm_hw->slice[self->slice].top;
206+
uint32_t pwm_freq = get_slice_hz_round(div16 * (top + 1));
207+
return MP_OBJ_NEW_SMALL_INT(pwm_freq);
208+
} else {
209+
return MP_OBJ_NEW_SMALL_INT(0);
210+
}
196211
}
197212

198213
STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
@@ -245,19 +260,27 @@ STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
245260
}
246261

247262
STATIC mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self) {
248-
uint32_t top = pwm_hw->slice[self->slice].top;
249-
uint32_t cc = pwm_hw->slice[self->slice].cc;
250-
cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff;
251-
252-
// Use rounding (instead of flooring) here to give as accurate an
253-
// estimate as possible.
254-
return MP_OBJ_NEW_SMALL_INT((cc * 65535 + (top + 1) / 2) / (top + 1));
263+
if (self->duty_type != DUTY_NOT_SET && slice_freq_set[self->slice] == true) {
264+
uint32_t top = pwm_hw->slice[self->slice].top;
265+
uint32_t cc = pwm_hw->slice[self->slice].cc;
266+
cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff;
267+
268+
// Use rounding (instead of flooring) here to give as accurate an
269+
// estimate as possible.
270+
return MP_OBJ_NEW_SMALL_INT((cc * 65535 + (top + 1) / 2) / (top + 1));
271+
} else {
272+
return MP_OBJ_NEW_SMALL_INT(0);
273+
}
255274
}
256275

257276
STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16) {
258277
uint32_t top = pwm_hw->slice[self->slice].top;
259278

279+
// Limit duty_u16 to 65535
260280
// Use rounding here to set it as accurately as possible.
281+
if (duty_u16 > 65535) {
282+
duty_u16 = 65535;
283+
}
261284
uint32_t cc = (duty_u16 * (top + 1) + 65535 / 2) / 65535;
262285
pwm_set_chan_level(self->slice, self->channel, cc);
263286
self->duty = duty_u16;
@@ -266,17 +289,22 @@ STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u
266289
}
267290

268291
STATIC mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self) {
269-
uint32_t slice_hz = get_slice_hz_round(pwm_hw->slice[self->slice].div);
270-
uint32_t cc = pwm_hw->slice[self->slice].cc;
271-
cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff;
272-
return MP_OBJ_NEW_SMALL_INT(((uint64_t)cc * 1000000000ULL + slice_hz / 2) / slice_hz);
292+
if (self->duty_type != DUTY_NOT_SET && slice_freq_set[self->slice] == true) {
293+
uint32_t slice_hz = get_slice_hz_round(pwm_hw->slice[self->slice].div);
294+
uint32_t cc = pwm_hw->slice[self->slice].cc;
295+
cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff;
296+
return MP_OBJ_NEW_SMALL_INT(((uint64_t)cc * 1000000000ULL + slice_hz / 2) / slice_hz);
297+
} else {
298+
return MP_OBJ_NEW_SMALL_INT(0);
299+
}
273300
}
274301

275302
STATIC void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns) {
276303
uint32_t slice_hz = get_slice_hz_round(pwm_hw->slice[self->slice].div);
277304
uint32_t cc = ((uint64_t)duty_ns * slice_hz + 500000000ULL) / 1000000000ULL;
278-
if (cc > 65535) {
279-
mp_raise_ValueError(MP_ERROR_TEXT("duty larger than period"));
305+
uint32_t top = pwm_hw->slice[self->slice].top;
306+
if (cc > (top + 1)) {
307+
cc = top + 1;
280308
}
281309
pwm_set_chan_level(self->slice, self->channel, cc);
282310
self->duty = duty_ns;

0 commit comments

Comments
 (0)
0