之前用SAM4S的开发板,自带晶振是12M的,调用sysclk_init()函数初始化系统时钟,什么都不用修改,计时器可以按设定时间正常工作。新做的板子换了4M晶振,然后根据文章:SAM4S:抽丝剥茧大话时钟之用ASF设置时钟频率,修改了时钟频率设置,发现定时频率并不是我设想的1ms,而是3ms,刚好差了三倍,和外部晶振的差异相同!
按这个说明,改为内部12M晶振,倍频20倍,分频2的时候,计时又正常了!可以看出,之前MCU明显是把4M时钟当12M的使用了。所以,我们需要从初始设置系统时钟的地方修改起。
回头看看sysclk_init()函数,抛开前面的一堆宏定义,最后有个调用:
这个才是初始化系统时钟函数。进入函数,直接跳到PMC_MCKR_CSS_PLLA_CLK这一个选项,看到这里的判断PMC->CKGR_MOR,这是时钟模式选择,在pll_enable_source()函数中调用的(多层调用才可以看到)。一路追踪下去,可以判断这个条件是为真的,所以系统时钟 SystemCoreClock 这个关键值等于 CHIP_FREQ_XTAL!
再看CHIP_FREQ_XTAL的定义,如果没有定义CHIP_FREQ_XTAL,就默认是12M,一查,没有定义!所以,在晶振为4M的时候,MCU默认当成了12M,至此,问题才找到。修改有两种方法,定义CHIP_FREQ_XTAL为4M或者直接把CHIP_FREQ_XTAL_12M的值改为4000000UL。
但是,问题到这里还没完事。这只是把系统运行时间和SystemCoreClock这个全局变量的值修改的符合计算值,还有些地方需要修正。比如延时函数初始化,我用的是函数sysclk_get_cpu_hz()的返回值,一路查询下去,发现这个返回值返回的是BOARD_FREQ_MAINCK_XTAL:
同样,把这个12M改为4M即可。