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 Reply Children
No Data
Related