drivers: pwm: nrfx: Add option to glitch free 100% duty cycle

IDLEOUT presence in PWM means that there are 3 sources from which
PWM pin can be driven:
- GPIO setting when PWM peripheral is disabled.
- IDLEOUT setting when PWM is enabled.
- PWM Sequence when it is in use.

IDLEOUT setting cannot be changed after enabling PWM so it is
configured to the initial state of the pin. It means that if duty
cycle is 100%, GPIO output is set to 1 but initial pin state was 0
(IDLEOUT setting) there will be a glitch between disabling a PWM
sequence and disabling a PWM peripheral.

By default, PWM driver tries to disable PWM peripheral if all channels
are 0% or 100% duty cycle to safe power. When IDLEOUT feature is
present there will be a short glitch on channels with 100% duty cycle.

In order to avoid that CONFIG_PWM_NRFX_NO_GLITCH_DUTY_100 option is
added (enabled by default). When option is enabled 100% duty cycle
is achieved by PWM sequence and not by driving a GPIO pin. It will
consume more power in cases where all channels are 0% or 100% with
at least one channel set to 100% duty cycle.

Signed-off-by: Krzysztof Chruściński <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruściński 2025-05-29 08:25:32 +02:00 committed by Daniel DeGrasse
commit 0261d7d96d
2 changed files with 15 additions and 14 deletions

View file

@ -20,3 +20,13 @@ config PWM_NRFX
select PINCTRL
help
Enable support for nrfx Hardware PWM driver for nRF52 MCU series.
config PWM_NRFX_NO_GLITCH_DUTY_100
bool "No glitches when using 100% duty"
depends on $(dt_compat_any_has_prop,$(DT_COMPAT_NORDIC_NRF_PWM),idleout-supported,True)
default y
help
Due to how IDLEOUT feature in PWM works it is possible to see a glitch on a channel
with 100% duty cycle when all other channels switches to 0% or 100%. Enabling this
option ensures that there are no glitches but it also means that 100% duty cycle
on any channels requires PWM peripheral to be active.

View file

@ -240,6 +240,9 @@ static int pwm_nrfx_set_cycles(const struct device *dev, uint32_t channel,
/* Constantly active (duty 100%). */
/* This value is always greater than or equal to COUNTERTOP. */
compare_value = PWM_NRFX_CH_COMPARE_MASK;
needs_pwm = pwm_is_fast(config) ||
(IS_ENABLED(NRF_PWM_HAS_IDLEOUT) &&
IS_ENABLED(CONFIG_PWM_NRFX_NO_GLITCH_DUTY_100));
} else {
/* PWM generation needed. Check if the requested period matches
* the one that is currently set, or the PWM peripheral can be
@ -279,20 +282,8 @@ static int pwm_nrfx_set_cycles(const struct device *dev, uint32_t channel,
if (inverted) {
out_level ^= 1;
}
/* Output of fast PWM instance is directly connected to GPIO pads,
* thus it cannot controlled by GPIO. Use regular 0%/100% duty cycle
* playback instead.
*/
#ifdef PWM_NRFX_FAST_PRESENT
if (pwm_is_fast(config)) {
nrfx_pwm_simple_playback(&config->pwm, &config->seq, 1,
NRFX_PWM_FLAG_NO_EVT_FINISHED);
} else {
#else
{
#endif
nrf_gpio_pin_write(psel, out_level);
}
nrf_gpio_pin_write(psel, out_level);
}
data->pwm_needed &= ~BIT(channel);