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:
parent
2bc6279866
commit
ae91933c4a
12 changed files with 53 additions and 150 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
* @{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue