We have built and run the code in examples->peripherals->timer in nRF5_SDK_12.3.0_d7731ad on 4 different Nordic DK nRF51 development boards. The timer period is 5 msec. We commented out the LED initialization and toggling. In the ISR, we toggle a GPIO pin and monitor the output on a logic analyzer. We find that the timer period varies from board to board, ranging from 4994 to 5025 msec. We replaced the nrf_drv_timer_xxx functions with direct programming of registers and get identical results. This is a problem because our nRF51 product needs a very accurate 5 msec "clock", and we don't want to have to hand calibrate the timer initialization with varying values for each board produced.
Can you confirm this problem and perhaps suggest a solution?
The accuracy of the timers is set by the clock source, which by default is the internal 16MHz RC oscillator. This oscillator has an accuracy of around +/- 5%, and as such your timer accuracy will be the same.
To get better accuracy for your timers you should start the external 16MHz crystal, which will have an accuracy of 50 ppm or better (depending on the crystal used).
The simplest way to start the external 16MHz crystal is to trigger the HFCLKSTART task, like this:
NRF_CLOCK->TASKS_HFCLKSTART = 1;
Although adding NRF_CLOCK->TASKS_HFCLKSTART = 1 improved the accuracy of the timer in the Nordic sample app (without softdevice), it caused our app -- which uses soft device S130 -- to fail. We embedded exactly the same timer code (using nrf_drv_timer_xxx calls), and they work OK, except we find again that the timer is again slightly off from 5000 microseconds, depending upon the board we're using.
We poked around and eventually added
before calling app_timer_create() for the one-second timer we use in the app.
That worked! The timer is now correct.
Thanks in advance for your help.
You can also try my timer driver here. Precision in usec even with low freq timer. Driver code in src. example in exemples folder.
I thought triggering the task should work if you did it before enabling the SoftDevice, but using the driver is probably a better idea ;)
Good to see you figured it out :)
Just getting back to this. Thanks for the answer and code!