PWM register-based LED dimming not updating duty cycle dynamically on nRF5340

Hi,
I’m trying to generate a PWM signal directly using the nRF5340’s PWM peripheral registers (not using Zephyr’s pwm_dt_spec or driver API).

The LED turns ON correctly, so the PWM peripheral is initialized and running, but the duty cycle doesn’t change dynamically — it stays at the first value even though I update the sequence buffer in code.

Here’s the simplified code I’m using:

#include <zephyr/kernel.h>
#include <hal/nrf_pwm.h>
#include <hal/nrf_gpio.h>

static NRF_PWM_Type *pwm = NRF_PWM0;
static uint16_t seq_values[2];
static uint16_t duty = 0;
static int dir = 200;

void pwm_init(void)
{
    pwm->ENABLE = 0;
    pwm->PSEL.OUT[0] = 25; // P0.25
    pwm->PSEL.OUT[1] = 26; // P0.26
    pwm->MODE = PWM_MODE_UPDOWN_Up;
    pwm->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_1;
    pwm->COUNTERTOP = 16000;
    pwm->LOOP = 0;
    pwm->DECODER = (PWM_DECODER_LOAD_Individual << PWM_DECODER_LOAD_Pos) |
                   (PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos);
    pwm->SEQ[0].PTR = (uint32_t)&seq_values[0];
    pwm->SEQ[0].CNT = 2;
    pwm->SEQ[0].REFRESH = 0;
    pwm->SEQ[0].ENDDELAY = 0;
    pwm->ENABLE = 1;
}

void pwm_update(uint16_t duty1, uint16_t duty2)
{
    seq_values[0] = duty1;
    seq_values[1] = duty2;
    pwm->TASKS_SEQSTART[0] = 1; // restart sequence
}

int main(void)
{
    pwm_init();

    while (1)
    {
        duty += dir;
        if (duty >= 16000) dir = -200;
        if (duty <= 0) dir = 200;
        pwm_update(duty, 16000 - duty);
        k_msleep(20);
    }
}

The LED stays ON continuously — it doesn’t fade in/out as expected.

I am using nRf5340 Audio DK and SDK version 2.9

Am I missing any register configuration (like SEQ[0].REFRESH or LOOP) for dynamic updates? 

Parents
  • Hello,

    I suspect your LEDs are on because the pins are disconnected. At least unless you did something in your devicetree/overlay files?

    Can you please zip and upload your entire application?

    Is there a particular reason why you want to use the PWM registers directly like this, instead of using the PWM drivers? 

    What is your end goal for the PWM? What are you controlling? 

    Best regards,

    Edvin

Reply
  • Hello,

    I suspect your LEDs are on because the pins are disconnected. At least unless you did something in your devicetree/overlay files?

    Can you please zip and upload your entire application?

    Is there a particular reason why you want to use the PWM registers directly like this, instead of using the PWM drivers? 

    What is your end goal for the PWM? What are you controlling? 

    Best regards,

    Edvin

Children
  • Hi,

    Actually, I don’t have any overlay file. The only setting I have in my prj.conf is:

    CONFIG_NRFX_PWM0=y

    The code snippet I shared is from a small test program I created.

    The reason I’m doing this is that in my main project, I need to update four GPIO pins simultaneously. Currently, I’m toggling them using a timer running at 8000 Hz. This works fine for a single GPIO pin, but when I add multiple pins, it starts producing glitches.

    To improve performance and eliminate those glitches, I’m exploring the use of PWM and direct register writes.

Related