This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

High frequency PWM shifts phase when radio is active

image description

When setting up a 1Mhz square wave using NRF_PWM on the NRF52 or GPIOTE on the NRF51 while BLE is advertising, the PWM stops when the radio is active. The problem doesn't happen when the frequency is below 6khz. No PWM interrupt is enabled. Is this an unavoidable limitation with high PWM frequencies?

  • Setting the old Rigol to "long memory" mode got the sample rate up to 20 Megsamples, which revealed there may still be a phase shift when the radio turns on, but it's small enough to be within spec. The spec probably isn't stable enough to drive a high precision LCR meter.

    June 6 update:

    It's a clock frequency shift that happens when the NRF switches between the 32khz & 16Mhz crystals. The 32khz is 1% faster. This can be reproduced by initializing a program with

    SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, NULL);

    or

    SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_SYNTH_250_PPM, NULL);

    Toggling a GPIO & viewing the frequency on a frequency counter. Unfortunately, the nrf_drv_clock_hfclk_request doesn't do anything after advertising is enabled, the current usage is too high to have it always on, so a clock that jitters 1% is what you get if you want to use the radio.

  • image description image description

    I'm also experiencing this on my nrf52. I can see the advertising events causing the artifacts in the pwm output.

    1. Advertising interval = 125x 0.625 ms = 78 ms
    2. Advertising interval = 250 x 0.625 ms = 156 ms

    This might be caused by the BLE-event requesting a clock change from RC to XTAL.

    sd_clock_hfclk_request() did the trick in my case.

  • Did you solve it then? Using that function? Where did you place it?

  • I call the function before I do ble_advertising_start(). I just tested this to see if the artifact disappared in my pwm output (I'm playing a 38khz sine), and it did.

    This was just for test purposes, so I never release the HFCLK after that.

    Whether this a solution or just a workaround I'll let the Nordic folks answer :)

     uint32_t p_is_running = 0;
    	sd_clock_hfclk_request();
    	while(! p_is_running) {  							//wait for the hfclk to be available
    		sd_clock_hfclk_is_running((&p_is_running));
    	}
    
        err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
    
Related