drivers: pwm: always use nanoseconds for set

In order to be consistent with what is possible in Devicetree, always
take a period in nanoseconds. Other scales or units may be specified by
using, e.g., the PWM_MSEC() macros (all of them converting down to
nanoseconds). This change then deletes the "_nsec" and "_usec" versions
of the pwm_set call.

Note that this change limits the period to UINT32_MAX nanoseconds,
~4.3s. PWM is, in generali, used with periods below the second so it
should not be a problem.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
This commit is contained in:
Gerard Marull-Paretas 2022-04-27 13:02:27 +02:00 committed by Carles Cufí
commit ae91933c4a
12 changed files with 53 additions and 150 deletions

View file

@ -49,7 +49,7 @@ static int led_pwm_blink(const struct device *dev, uint32_t led,
dt_led = &config->led[led];
return pwm_set_usec_dt(dt_led, period_usec, pulse_usec);
return pwm_set_dt(dt_led, PWM_USEC(period_usec), PWM_USEC(pulse_usec));
}
static int led_pwm_set_brightness(const struct device *dev,
@ -64,7 +64,7 @@ static int led_pwm_set_brightness(const struct device *dev,
dt_led = &config->led[led];
return pwm_set_nsec_pulse_dt(&config->led[led],
return pwm_set_pulse_dt(&config->led[led],
dt_led->period * value / 100);
}

View file

@ -417,100 +417,12 @@ static inline int z_impl_pwm_get_cycles_per_sec(const struct device *dev,
return api->get_cycles_per_sec(dev, channel, cycles);
}
/**
* @brief Set the period and pulse width in microseconds for a single PWM
* output.
*
* @param[in] dev PWM device instance.
* @param channel PWM channel.
* @param period Period (in microseconds) set to the PWM.
* @param pulse Pulse width (in microseconds) set to the PWM.
* @param flags Flags for pin configuration (polarity).
*
* @retval 0 If successful.
* @retval -ENOTSUP If requested period or pulse cycles are not supported.
* @retval -errno Other negative errno code on failure.
*/
static inline int pwm_set_usec(const struct device *dev, uint32_t channel,
uint32_t period, uint32_t pulse,
pwm_flags_t flags)
{
int err;
uint64_t pulse_cycles;
uint64_t period_cycles;
uint64_t cycles_per_sec;
err = pwm_get_cycles_per_sec(dev, channel, &cycles_per_sec);
if (err < 0) {
return err;
}
period_cycles = (period * cycles_per_sec) / USEC_PER_SEC;
if (period_cycles > UINT32_MAX) {
return -ENOTSUP;
}
pulse_cycles = (pulse * cycles_per_sec) / USEC_PER_SEC;
if (pulse_cycles > UINT32_MAX) {
return -ENOTSUP;
}
return pwm_set_cycles(dev, channel, (uint32_t)period_cycles,
(uint32_t)pulse_cycles, flags);
}
/**
* @brief Set the period and pulse width in microseconds from a struct
* pwm_dt_spec (with custom period).
*
* This is equivalent to:
*
* pwm_set_usec(spec->dev, spec->channel, period, pulse, spec->flags)
*
* The period specified in @p spec is ignored. This API call can be used when
* the period specified in Devicetree needs to be changed at runtime.
*
* @param[in] spec PWM specification from devicetree.
* @param period Period (in microseconds) set to the PWM.
* @param pulse Pulse width (in microseconds) set to the PWM.
*
* @return A value from pwm_set_usec().
*
* @see pwm_set_usec_pulse_dt()
*/
static inline int pwm_set_usec_dt(const struct pwm_dt_spec *spec,
uint32_t period, uint32_t pulse)
{
return pwm_set_usec(spec->dev, spec->channel, period, pulse,
spec->flags);
}
/**
* @brief Set the period and pulse width in microseconds from a struct
* pwm_dt_spec.
*
* This is equivalent to:
*
* pwm_set_usec(spec->dev, spec->channel, spec->period / NSEC_PER_USEC,
* pulse, spec->flags)
*
* @param[in] spec PWM specification from devicetree.
* @param pulse Pulse width (in microseconds) set to the PWM.
*
* @return A value from pwm_set_usec().
*
* @see pwm_set_usec_dt()
*/
static inline int pwm_set_usec_pulse_dt(const struct pwm_dt_spec *spec,
uint32_t pulse)
{
return pwm_set_usec(spec->dev, spec->channel,
spec->period / NSEC_PER_USEC, pulse, spec->flags);
}
/**
* @brief Set the period and pulse width in nanoseconds for a single PWM output.
*
* @note Utility macros such as PWM_MSEC() can be used to convert from other
* scales or units to nanoseconds, the units used by this function.
*
* @param[in] dev PWM device instance.
* @param channel PWM channel.
* @param period Period (in nanoseconds) set to the PWM.
@ -521,9 +433,8 @@ static inline int pwm_set_usec_pulse_dt(const struct pwm_dt_spec *spec,
* @retval -ENOTSUP If requested period or pulse cycles are not supported.
* @retval -errno Other negative errno code on failure.
*/
static inline int pwm_set_nsec(const struct device *dev, uint32_t channel,
uint32_t period, uint32_t pulse,
pwm_flags_t flags)
static inline int pwm_set(const struct device *dev, uint32_t channel,
uint32_t period, uint32_t pulse, pwm_flags_t flags)
{
int err;
uint64_t pulse_cycles;
@ -555,7 +466,7 @@ static inline int pwm_set_nsec(const struct device *dev, uint32_t channel,
*
* This is equivalent to:
*
* pwm_set_nsec(spec->dev, spec->channel, period, pulse, spec->flags)
* pwm_set(spec->dev, spec->channel, period, pulse, spec->flags)
*
* The period specified in @p spec is ignored. This API call can be used when
* the period specified in Devicetree needs to be changed at runtime.
@ -564,15 +475,14 @@ static inline int pwm_set_nsec(const struct device *dev, uint32_t channel,
* @param period Period (in nanoseconds) set to the PWM.
* @param pulse Pulse width (in nanoseconds) set to the PWM.
*
* @return A value from pwm_set_nsec().
* @return A value from pwm_set().
*
* @see pwm_set_nsec_pulse_dt()
* @see pwm_set_pulse_dt()
*/
static inline int pwm_set_nsec_dt(const struct pwm_dt_spec *spec,
uint32_t period, uint32_t pulse)
static inline int pwm_set_dt(const struct pwm_dt_spec *spec, uint32_t period,
uint32_t pulse)
{
return pwm_set_nsec(spec->dev, spec->channel, period, pulse,
spec->flags);
return pwm_set(spec->dev, spec->channel, period, pulse, spec->flags);
}
/**
@ -581,19 +491,19 @@ static inline int pwm_set_nsec_dt(const struct pwm_dt_spec *spec,
*
* This is equivalent to:
*
* pwm_set_nsec(spec->dev, spec->channel, spec->period, pulse, spec->flags)
* pwm_set(spec->dev, spec->channel, spec->period, pulse, spec->flags)
*
* @param[in] spec PWM specification from devicetree.
* @param pulse Pulse width (in nanoseconds) set to the PWM.
*
* @return A value from pwm_set_nsec().
* @return A value from pwm_set().
*
* @see pwm_set_nsec_pulse_dt()
* @see pwm_set_pulse_dt()
*/
static inline int pwm_set_nsec_pulse_dt(const struct pwm_dt_spec *spec,
static inline int pwm_set_pulse_dt(const struct pwm_dt_spec *spec,
uint32_t pulse)
{
return pwm_set_nsec(spec->dev, spec->channel, spec->period, pulse,
return pwm_set(spec->dev, spec->channel, spec->period, pulse,
spec->flags);
}
@ -934,26 +844,27 @@ pwm_pin_set_cycles(const struct device *dev, uint32_t channel, uint32_t period,
/**
* @brief Set the period and pulse width for a single PWM output.
* @deprecated Use pwm_set_usec() instead.
* @deprecated Use pwm_set() with PWM_USEC() instead.
*/
__deprecated static inline int pwm_pin_set_usec(const struct device *dev,
uint32_t channel,
uint32_t period, uint32_t pulse,
pwm_flags_t flags)
{
return pwm_set_usec(dev, channel, period, pulse, flags);
return pwm_set(dev, channel, period * NSEC_PER_USEC,
pulse * NSEC_PER_USEC, flags);
}
/**
* @brief Set the period and pulse width for a single PWM output.
* @deprecated Use pwm_set_nsec() instead.
* @deprecated Use pwm_set() instead.
*/
__deprecated static inline int pwm_pin_set_nsec(const struct device *dev,
uint32_t channel,
uint32_t period, uint32_t pulse,
pwm_flags_t flags)
{
return pwm_set_nsec(dev, channel, period, pulse, flags);
return pwm_set(dev, channel, period, pulse, flags);
}
/**

View file

@ -30,9 +30,8 @@
/**
* @name PWM polarity flags
* The `PWM_POLARITY_*` flags are used with pwm_set_cycles(), pwm_set_usec(),
* pwm_set_nsec() or pwm_configure_capture() to specify the polarity of a PWM
* channel.
* The `PWM_POLARITY_*` flags are used with pwm_set_cycles(), pwm_set()
* or pwm_configure_capture() to specify the polarity of a PWM channel.
*
* The flags are on the lower 8bits of the pwm_flags_t
* @{

View file

@ -43,7 +43,7 @@ void main(void)
*/
printk("Calibrating for channel %d...\n", pwm_led0.channel);
max_period = MAX_PERIOD;
while (pwm_set_nsec_dt(&pwm_led0, max_period, max_period / 2U)) {
while (pwm_set_dt(&pwm_led0, max_period, max_period / 2U)) {
max_period /= 2U;
if (max_period < (4U * MIN_PERIOD)) {
printk("Error: PWM device "
@ -58,7 +58,7 @@ void main(void)
period = max_period;
while (1) {
ret = pwm_set_nsec_dt(&pwm_led0, period, period / 2U);
ret = pwm_set_dt(&pwm_led0, period, period / 2U);
if (ret) {
printk("Error %d: failed to set pulse width\n", ret);
return;

View file

@ -35,7 +35,7 @@ void main(void)
}
while (1) {
ret = pwm_set_nsec_pulse_dt(&pwm_led0, pulse_width);
ret = pwm_set_pulse_dt(&pwm_led0, pulse_width);
if (ret) {
printk("Error %d: failed to set pulse width\n", ret);
return;

View file

@ -39,7 +39,7 @@ void main(void)
while (1) {
for (pulse_red = 0U; pulse_red <= red_pwm_led.period;
pulse_red += STEP_SIZE) {
ret = pwm_set_nsec_pulse_dt(&red_pwm_led, pulse_red);
ret = pwm_set_pulse_dt(&red_pwm_led, pulse_red);
if (ret != 0) {
printk("Error %d: red write failed\n", ret);
return;
@ -48,7 +48,7 @@ void main(void)
for (pulse_green = 0U;
pulse_green <= green_pwm_led.period;
pulse_green += STEP_SIZE) {
ret = pwm_set_nsec_pulse_dt(&green_pwm_led,
ret = pwm_set_pulse_dt(&green_pwm_led,
pulse_green);
if (ret != 0) {
printk("Error %d: green write failed\n",
@ -59,8 +59,8 @@ void main(void)
for (pulse_blue = 0U;
pulse_blue <= blue_pwm_led.period;
pulse_blue += STEP_SIZE) {
ret = pwm_set_nsec_pulse_dt(
&blue_pwm_led, pulse_blue);
ret = pwm_set_pulse_dt(&blue_pwm_led,
pulse_blue);
if (ret != 0) {
printk("Error %d: "
"blue write failed\n",

View file

@ -38,7 +38,7 @@ void main(void)
}
while (1) {
ret = pwm_set_nsec_pulse_dt(&servo, pulse_width);
ret = pwm_set_pulse_dt(&servo, pulse_width);
if (ret < 0) {
printk("Error %d: failed to set pulse width\n", ret);
return;

View file

@ -129,13 +129,14 @@ void board_play_tune(const char *str)
}
if (period) {
pwm_set_usec(pwm, BUZZER_PWM_CHANNEL, period, period / 2U, 0);
pwm_set(pwm, BUZZER_PWM_CHANNEL, PWM_USEC(period),
PWM_USEC(period) / 2U, 0);
}
k_sleep(K_MSEC(duration));
/* Disable the PWM */
pwm_set_usec(pwm, BUZZER_PWM_CHANNEL, 0, 0, 0);
pwm_set(pwm, BUZZER_PWM_CHANNEL, 0, 0, 0);
}
}

View file

@ -120,7 +120,7 @@ static enum sound_state {
static inline void beep(int period)
{
pwm_set_usec(pwm, SOUND_PWM_CHANNEL, period, period / 2, 0);
pwm_set(pwm, SOUND_PWM_CHANNEL, PWM_USEC(period), PWM_USEC(period) / 2, 0);
}
static void sound_set(enum sound_state state)

View file

@ -33,11 +33,11 @@ static void beep(struct k_work *work)
/* The "period / 2" pulse duration gives 50% duty cycle, which
* should result in the maximum sound volume.
*/
pwm_set_usec(pwm, BUZZER_PWM_CHANNEL, period, period / 2U, 0);
pwm_set(pwm, BUZZER_PWM_CHANNEL, PWM_USEC(period), PWM_USEC(period) / 2U, 0);
k_sleep(BEEP_DURATION);
/* Disable the PWM */
pwm_set_usec(pwm, BUZZER_PWM_CHANNEL, 0, 0, 0);
pwm_set(pwm, BUZZER_PWM_CHANNEL, 0, 0, 0);
/* Ensure there's a clear silent period between two tones */
k_sleep(K_MSEC(50));

View file

@ -12,8 +12,7 @@
* @details
* - Test Steps
* -# Bind PWM_0 port 0.
* -# Set PWM period and pulse using pwm_set_cycles(),
* pwm_set_usec(), or pwm_set_nsec().
* -# Set PWM period and pulse using pwm_set_cycles() or pwm_set().
* -# Use multimeter or other instruments to measure the output
* from PWM_OUT_0.
* - Expected Results
@ -121,15 +120,9 @@ static int test_task(uint32_t port, uint32_t period, uint32_t pulse, uint8_t uni
TC_PRINT("Fail to set the period and pulse width\n");
return TC_FAIL;
}
} else if (unit == UNIT_USECS) {
/* Verify pwm_set_usec() */
if (pwm_set_usec(pwm_dev, port, period, pulse, 0)) {
TC_PRINT("Fail to set the period and pulse width\n");
return TC_FAIL;
}
} else { /* unit == UNIT_NSECS */
/* Verify pwm_set_nsec() */
if (pwm_set_nsec(pwm_dev, port, period, pulse, 0)) {
/* Verify pwm_set() */
if (pwm_set(pwm_dev, port, period, pulse, 0)) {
TC_PRINT("Fail to set the period and pulse width\n");
return TC_FAIL;
}

View file

@ -50,16 +50,15 @@ void test_capture(uint32_t period, uint32_t pulse, enum test_pwm_unit unit,
case TEST_PWM_UNIT_NSEC:
TC_PRINT("Testing PWM capture @ %u/%u nsec\n",
pulse, period);
err = pwm_set_nsec(out.dev, out.pwm, period,
pulse, out.flags ^=
err = pwm_set(out.dev, out.pwm, period, pulse, out.flags ^=
(flags & PWM_POLARITY_MASK));
break;
case TEST_PWM_UNIT_USEC:
TC_PRINT("Testing PWM capture @ %u/%u usec\n",
pulse, period);
err = pwm_set_usec(out.dev, out.pwm, period,
pulse, out.flags ^=
err = pwm_set(out.dev, out.pwm, PWM_USEC(period),
PWM_USEC(pulse), out.flags ^=
(flags & PWM_POLARITY_MASK));
break;
@ -235,8 +234,8 @@ void test_continuous_capture(void)
memset(buffer, 0, sizeof(buffer));
k_sem_init(&data.sem, 0, 1);
err = pwm_set_usec(out.dev, out.pwm, period_usec, pulse_usec,
out.flags);
err = pwm_set(out.dev, out.pwm, PWM_USEC(period_usec),
PWM_USEC(pulse_usec), out.flags);
zassert_equal(err, 0, "failed to set pwm output (err %d)", err);
err = pwm_configure_capture(in.dev, in.pwm,