Description
I think found a minor issue in producing the 48Mhz clock from 32.768Khz in startup.c
Leading to a small offset of the nominal 48Mhz towards 47.972Mhz (546ppm off). This is probably not important in most cases, but it is to me in a timing critical application.
I think there is an easy fix which brings the frequency to 48.005Mhz (136ppm) which is already a factor 4 better. I measured it with a 5 digit frequency meter and the above seems confirmed in practice.
I think the culprit is the following line of code in startup.c
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP( 31 ) | // Coarse step is 31, half of the max value SYSCTRL_DFLLMUL_FSTEP( 511 ) | // Fine step is 511, half of the max value SYSCTRL_DFLLMUL_MUL( (VARIANT_MCK/VARIANT_MAINOSC) ) ; // External 32KHz is the reference }
The multiplier is loaded with (VARIANT_MCK/VARIANT_MAINOSC) which is a division of 2 unsigned longs being 48000000/32768=1464 (I assume)
A floating division should give 1464.8 which should then get rounded to 1465.
I am not entirely sure what it is the best syntax to get this in a nice way...I am thinking along something like
uint(double(VARIANT_MCK)/double(VARIANT_MAINOSC)) but need to check the correct syntax to get it.
Note that the error can be much more significant for lower frequencies and is on average 0.5/MUL, so fixing this seemingly minor issue could be very helpful for others working at much lower frequencies and requiring accuracy of the main clock.(after all, we have a nice accurate crystal, so lets not downgrade it in software)
An even more accurate solution would be to divide the XOSC32K by 4 and then using the same corrected rounding leading to an accuracy of 68ppm, or dividing by 8 gives 21 ppm accuracy which starts to be on the same size of the accuracy of the 32.768Khz crystal itself (similar crystals state between 10-100 ppm, don't have exact datasheet for the one mounted on the M0 pro board). But this might have more side-effects?
Note that including correct rounding leads to a 48.005 Mhz frequency which is slightly above the maximum allowed 48Mhz and strictly speaking brings us out of spec. As the deviation in in the few 100ppm range I really don't expect issues, but one never knows if you built a life-supporting application (you probably aren't using Arduino in the first place then).