nRF52840 PWM Jitter

I'm designing a product around the nRF52840 (PAN1780 module), and using the PWM to drive a piezo sounder (using 2 pins as Hbridge). When I start using BLE functions, I get about 1% jitter on the PWM drive, which doesn't sound good. Any idea why?

I though that a hardware timer-based PWM with direct pin control would be immune to whatever else the micro is doing, as it is not relying on any software interaction (interrupts etc). I've driven piezos from STM32F0 micros etc. with no jitter problems. So I'm wondering if I have a problem with the PWM config.

Below is the PWM setup code - if I run this on its own (just run init then sit in for(;;) loop, it is rock solid, but as soon as I start BLE advertising it gets the jitter.

Measured from the start of each cycle, there is jitter on both the rising edge (channel switch) and the falling edge (timer top), approx 1% of period.

I don't fully understand how the sequence code works - is it reloading the channel timers each time round? Could this be a cause of the problem? Is there a way to avoid using sequences and just have fixed channel counts? I just want a fixed frequency 50% PWM.

Here's my init code:-

static void pwm_init(void)
{
    nrf_drv_pwm_config_t const config0 =
    {
        .output_pins =
        {
            ARDUINO_0_PIN,
            ARDUINO_1_PIN, 
            NRFX_PWM_PIN_NOT_USED,
            NRFX_PWM_PIN_NOT_USED
        },
        .irq_priority = APP_IRQ_PRIORITY_LOWEST,
        .base_clock   = NRF_PWM_CLK_16MHz,
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = 4000,      //4kHz
        .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,  // I also tried NRF_PWM_LOAD_WAVE_FORM
        .step_mode    = NRF_PWM_STEP_AUTO
    };
    APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, demo1_handler));
    m_used |= USED_PWM(0);

    m_demo1_seq_values.channel_0 = 2000;
    m_demo1_seq_values.channel_1 = 2000 | 0x8000;  // MSB inverts output
    m_demo1_seq_values.channel_2 = 0;
    m_demo1_seq_values.channel_3 = 0;
    m_demo1_phase                = 0;

    (void)nrf_drv_pwm_simple_playback(&m_pwm0, &m_demo1_seq, 1, NRF_DRV_PWM_FLAG_LOOP);
}

Any suggestions gratefully received :-)

Related