Accuracy issue between k_uptime_ticks() and hardware pwm outputs

Running into a slight issue where the timebase for system (reference time + uptime aka k_uptime_ticks()) drifts relative to sensor sampling rates.
Attempt to synchronize the timebases by using nRF53 pwm system to output clock for external sensors still drifts as the timebase for pwm appears to be HFCLK based of HF XTAL while system ticks come from LFCLK based of LF XTAL.

What is the recommended method to synchronize these while keeping power consumption low?
CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH may be an option but how will this impact power consumption, and will it prevent sleep?

  • The RTC (that runs off the LFCLK) appear to have a EVENTS_TICK for when counter is incremented. Could this serve as a source for PPI?

  • This would probably create an event only every tick which is once every clock cycle, and thus toggle would cause it to output at half frequency. I guess it could be possible to trigger a one shot timer based on same event and instead use SET task with the timer expiring and triggering a CLR task? The duty cycle would be close enough by using a fixed on time of approx half the cycle length.

    This is getting complicated but is it possible?

  • In case anyone else reads this with the same problem, yes it was possible!

    Using a GPIOTE task channel, and assigning it's SET task address together with a timers START task address in a DPPI channel (this is nrf5340 so DPPI not PPI) with the RTC TICK event address allows for setting a pin for every clock tick, and starting the timer at same time.

    Then connecting the timers COMPARE event to a second DPPI channel to the same GPIOTE task channel CLR task allows for clearing pin after a suitable half period that can be accurate enough for this use.

    Finally the SHORT in the timer must be set to RESET timer and STOP timer upon COMPARE.

    This all results in reproducing the LFCLK coming from the LF XTAL on a pin so external sensors can use this as reference and the internal RTC and systick now matches any external exactly. This completely eliminates clock drift between sensor and internal timekeeping in Zephyr.

  • One question... It appears my "hack" has a side effect of keeping Zephyr from sleeping.
    I believe Zephyr uses RTC1 for some of it's scheduling, and it appears to use the WFE instruction for sleeping.
    I have not found any way to avoid waking from the TICK event on RTC0 even though the reason for enabling it is only to generate events for the DPPI system. Is there no disabling this effect?

  • I think I have narrowed it down to the TIMER that is started by the event and stopped by it's own COMPARE. Configuring the timer appears to enable the interrupts for the timer by default in nrfx.

    Edit: After digging some more I found a stray nrfx_gpiote_trigger_enable() which basically meant enabling input trigger for the output pin. Every time it changed state this would wake the CPU leading to my excessive power draw!

Related