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

Skip to content

Commit c76aab0

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. ------------- - Initialize the pin to PWM at the end of the constructor.
1 parent 1059265 commit c76aab0

File tree

1 file changed

+45
-20
lines changed

1 file changed

+45
-20
lines changed

ports/rp2/machine_pwm.c

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,14 @@ STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args
142142
self->invert = 0;
143143
self->duty_type = DUTY_NOT_SET;
144144

145-
// Select PWM function for given GPIO.
146-
gpio_set_function(gpio, GPIO_FUNC_PWM);
147-
148145
// Process the remaining parameters.
149146
mp_map_t kw_args;
150147
mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
151148
mp_machine_pwm_init_helper(self, n_args - 1, all_args + 1, &kw_args);
152149

150+
// Select PWM function for given GPIO.
151+
gpio_set_function(gpio, GPIO_FUNC_PWM);
152+
153153
return MP_OBJ_FROM_PTR(self);
154154
}
155155

@@ -158,7 +158,15 @@ void machine_pwm_deinit_all(void) {
158158
for (int i = 0; i < 8; i++) {
159159
slice_freq_set[i] = false;
160160
pwm_set_enabled(machine_pwm_obj[i].slice, false);
161+
// pwm_set_chan_level(i, 0, 0);
162+
// pwm_set_chan_level(i, 1, 0);
161163
}
164+
// Clean out the table
165+
// for (int i = 0; i < 16; i++) {
166+
// machine_pwm_obj[i].invert = 0;
167+
// machine_pwm_obj[i].duty = 0;
168+
// machine_pwm_obj[i].duty_type = DUTY_NOT_SET;
169+
// }
162170
}
163171

164172
STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) {
@@ -189,10 +197,14 @@ uint32_t get_slice_hz_ceil(uint32_t div16) {
189197
}
190198

191199
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);
200+
if (slice_freq_set[self->slice] == true) {
201+
uint32_t div16 = pwm_hw->slice[self->slice].div;
202+
uint32_t top = pwm_hw->slice[self->slice].top;
203+
uint32_t pwm_freq = get_slice_hz_round(div16 * (top + 1));
204+
return MP_OBJ_NEW_SMALL_INT(pwm_freq);
205+
} else {
206+
return MP_OBJ_NEW_SMALL_INT(0);
207+
}
196208
}
197209

198210
STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
@@ -245,19 +257,27 @@ STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
245257
}
246258

247259
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));
260+
if (self->duty_type != DUTY_NOT_SET && slice_freq_set[self->slice] == true) {
261+
uint32_t top = pwm_hw->slice[self->slice].top;
262+
uint32_t cc = pwm_hw->slice[self->slice].cc;
263+
cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff;
264+
265+
// Use rounding (instead of flooring) here to give as accurate an
266+
// estimate as possible.
267+
return MP_OBJ_NEW_SMALL_INT((cc * 65535 + (top + 1) / 2) / (top + 1));
268+
} else {
269+
return MP_OBJ_NEW_SMALL_INT(0);
270+
}
255271
}
256272

257273
STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16) {
258274
uint32_t top = pwm_hw->slice[self->slice].top;
259275

276+
// Limit duty_u16 to 65535
260277
// Use rounding here to set it as accurately as possible.
278+
if (duty_u16 > 65535) {
279+
duty_u16 = 65535;
280+
}
261281
uint32_t cc = (duty_u16 * (top + 1) + 65535 / 2) / 65535;
262282
pwm_set_chan_level(self->slice, self->channel, cc);
263283
self->duty = duty_u16;
@@ -266,17 +286,22 @@ STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u
266286
}
267287

268288
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);
289+
if (self->duty_type != DUTY_NOT_SET && slice_freq_set[self->slice] == true) {
290+
uint32_t slice_hz = get_slice_hz_round(pwm_hw->slice[self->slice].div);
291+
uint32_t cc = pwm_hw->slice[self->slice].cc;
292+
cc = (cc >> (self->channel ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB)) & 0xffff;
293+
return MP_OBJ_NEW_SMALL_INT(((uint64_t)cc * 1000000000ULL + slice_hz / 2) / slice_hz);
294+
} else {
295+
return MP_OBJ_NEW_SMALL_INT(0);
296+
}
273297
}
274298

275299
STATIC void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns) {
276300
uint32_t slice_hz = get_slice_hz_round(pwm_hw->slice[self->slice].div);
277301
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"));
302+
uint32_t top = pwm_hw->slice[self->slice].top;
303+
if (cc > (top + 1)) {
304+
cc = top + 1;
280305
}
281306
pwm_set_chan_level(self->slice, self->channel, cc);
282307
self->duty = duty_ns;

0 commit comments

Comments
 (0)
0