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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy