一 默認配置
在啟動文件中,已經對時鐘進行了初始化,默認按外部8M晶振,配置系統時鐘為48MHZ,APB為系統時鐘的2分頻,為24MHZ。在system_ac780x.c文件中,可以找到下面這個系統初始化函數,里面有SetSysClock()函數,對時鐘進行了初始化。
void SystemInit (void)
{
#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U)SCB->VTOR = (uint32_t) &__Vectors;
#endifSystemCoreClock = SYSTEM_CLOCK;SetEflashClock();SetSysClock();CKGEN_SetAPBClockDivider(APBCLK_DIV);//SPM_EnableLVD(DISABLE); //disable LVD if need
}
如果需要配置不一樣的時鐘,可以通過系統文件里的宏定義修改,但并不建議在系統文件上修改,可以自己寫配置函數。
二 時鐘模塊簡介
1.時鐘源:
高速內部時鐘(HSI):內部 RC 振蕩器提供 8MHz 時鐘源
外部高速時鐘(HSE):外部 OSC 提供 4MHZ ~30MHz 晶振
低速內部時鐘(LSI): 內部低速 RC OSC 提供 32KHz 時鐘源
系統時鐘 (SYSPLL): 提供高達 48MHz 的高速時鐘
2.系統時鐘框圖
手冊中的框圖可以幫助我們更好的理解時鐘的每個配置步驟。
輸入頻率:支持4~30MHZ
VCO = 輸入頻率 * FBKDIV / PREDIV
系統時鐘 = VCO / POSDIV / SYSCLKDIV
同時,手冊中也提供了典型的配置參數供參考。因為有些點的頻率值是有限制的,比如VCO的頻率范圍是0.5GHZ~1.5GHZ,那么直接參考典型配置參考表就肯定不會有問題,找到合適的參數即可。
三 自定義時鐘
以AC7801的開發板做測試,板子上外部晶振為8MHZ。這里以配置系統時鐘為48MHZ,APB時鐘為24MHZ為例。根據上面的參考表,可選擇PREDIV = 1,FBKDIV = 96,POSDIV=16,VOC = 8*96/16 =48M。相關寄存器如下圖,可知:SYSPLL1_PREDIV為0,SYSPLL1_POSDIV為8,SYSPLL1_FBKDIV為96。
為了直觀的測試時鐘的頻率,用一個定時器,定時產生中斷,在中斷中翻轉一個I/O電平,以此來測時鐘頻率。定時器初始化如下:定時器的時鐘源為APB時鐘24M,配置定時器裝載值為24000000,則1S產生一次中斷。
void TIMER_Config(void)
{TIMER_ConfigType config; memset(&config, 0, sizeof(config));config.periodValue = 24000000; /*!< TIMER channel period value */config.linkModeEn = DISABLE ; /*!< TIMER channel linkmode enable */config.interruptEn = ENABLE ; /*!< TIMER channel interrupt enable */config.callBack = TIM_CallBack; /*!< TIMER channel callback pointer */config.timerEn = ENABLE; /*!< TIMER channel enable/disable */TIMER_Init(TIMER_CHANNEL0, &config); //TIMER0初始化配置
}
1. 中斷處理
void TIM_CallBack(void *device, uint32_t wpara, uint32_t lpara)
{if (wpara & TIMER_CHANNEL_TF_T**_Msk){GPIOC->ODR ^= (1<<7);}
}
2.外部時鐘配置——庫函數
void SYS_CLOCK_HSE(void)
{/* check if xosc enable success? */if (SPM_EnableXOSC(ENABLE) == SUCCESS){CKGEN_SetPLLReference(PLL_REF_EXTERNAL_OSC);//PLL參考時鐘選擇外部振蕩器}else /* if xosc enable fail, */{}/* set system clock divider */CKGEN_SetSysclkDiv(0);//系統時鐘1分頻/* check if pll enable success? */if (SPM_EnablePLL(ENABLE) == SUCCESS)/使能SYSPLL{CKGEN_SetPllPrevDiv(0);//PREDIVCKGEN_SetPllPostDiv(8);//PLL_POSDIVCKGEN_SetPllFeedbackDiv(96);//PLL_FBKDIVCKGEN_SetSysclkSrc(SYSCLK_SRC_PLL_OUTPUT);//系統時鐘源選擇PLL時鐘}else /* pll enable fail */{}CKGEN_SetAPBClockDivider(APBCLK_DIVIDER_2);//APB時鐘為系統時鐘2分頻
}
3.外部時鐘配置——寄存器
外部時鐘的使能以及就緒標志,PLL使能以及就緒標志等,在第6章系統電源管理SPM模塊下的SPM_PWR_MGR_CFG1寄存器里。
配置過程比較常規,使能時鐘——>等待時鐘就緒——>PLL時鐘源選擇——>時鐘分頻及倍頻配置——>系統時鐘源選擇
void SYS_CLOCK_HSE_REG(void)
{SPM->PWR_MGR_CFG1 |= 1<<29;//外部高速時鐘XOSC使能while((SPM->PWR_MGR_CFG1 &(0X80000000))==0)//等待XOSC就緒{}SPM->PWR_MGR_CFG1 |= (1<<27);//SYSPLL使能while((SPM->PWR_MGR_CFG1 &(0X40000000))==0)//等待PLL時鐘就緒{}CKGEN->CTRL |= (1<<20);//PLL參考時鐘選擇外部振蕩器CKGEN->SYSPLL1_CFG0 = ((CKGEN->SYSPLL1_CFG0 & (~(uint32_t)(0x3<<30)))|(0<<30)); //PREDIVCKGEN->SYSPLL1_CFG0 = ((CKGEN->SYSPLL1_CFG0 & (~(uint32_t)(0x1f<<25)))|(8<<25)); //POSDIVCKGEN->SYSPLL1_CFG0 = ((CKGEN->SYSPLL1_CFG0 & (~(uint32_t)(0xff<<15)))|(96<<15)); //FBKDIVCKGEN->CTRL |= ((CKGEN->CTRL & (~(3<<4)))|(0<<4)); //系統時鐘分頻為1CKGEN->CTRL |= (1<<0);//系統時鐘源選擇PLL時鐘CKGEN->CTRL |= (1<<8);//APB為系統時鐘2分頻
}
4.內部時鐘配置——庫函數
采用內部高速8M時鐘源做配置
void SYS_CLOCK_HSI(void)
{CKGEN_SetPLLReference(PLL_REF_INTERAL_OSC);//PLL參考時鐘選擇內部振蕩器CKGEN_SetPllPrevDiv(0); //PREDIVCKGEN_SetPllPostDiv(8); //POSDIVCKGEN_SetPllFeedbackDiv(96); //FBKDIVCKGEN_SetSysclkDiv(0); //系統時鐘1分頻/* check if pll enable success? */if (SPM_EnablePLL(ENABLE) == SUCCESS){/* pll enable success,use pll output as system clock src */CKGEN_SetSysclkSrc(SYSCLK_SRC_PLL_OUTPUT);//系統時鐘源選擇PLL時鐘}else{/* pll enable fail */}CKGEN_SetAPBClockDivider(APBCLK_DIVIDER_2);//APB為系統時鐘2分頻
}
5.內部時鐘配置——寄存器
void SYS_CLOCK_HSI_REG(void)
{CKGEN->CTRL &= ~(1<<20);//PLL參考時鐘選擇內部振蕩器SPM->PWR_MGR_CFG1 |= (1<<27);//SYSPLL使能while((SPM->PWR_MGR_CFG1 &(0X40000000))==0)//等待PLL時鐘就緒{} CKGEN->SYSPLL1_CFG0 = ((CKGEN->SYSPLL1_CFG0 & (~(uint32_t)(0x3<<30)))|(0<<30)); //PREDIVCKGEN->SYSPLL1_CFG0 = ((CKGEN->SYSPLL1_CFG0 & (~(uint32_t)(0x1f<<25)))|(8<<25)); //POSDIVCKGEN->SYSPLL1_CFG0 = ((CKGEN->SYSPLL1_CFG0 & (~(uint32_t)(0xff<<15)))|(96<<15)); //FBKDIVCKGEN->CTRL |= ((CKGEN->CTRL & (~(3<<4)))|(0<<4)); //SYSCLK_DIV,系統時鐘1分頻CKGEN->CTRL |= (1<<0);//系統時鐘源選擇PLL時鐘CKGEN->CTRL |= (1<<8);//APB為系統時鐘2分頻
}
6.主函數
主函數中調用時鐘初始化函數,并對TIMER0配置,同時需要對使用到的I/O進行配置。
int main(void)
{//SYS_CLOCK_HSE();SYS_CLOCK_HSE_REG();//SYS_CLOCK_HSI();//SYS_CLOCK_HSI_REG();TIMER_Config();GPIO_SetFunc(GPIOC, GPIO_PIN7, GPIO_FUN0);/*功能復用選擇*/GPIO_SetDir(GPIOC, GPIO_PIN7, GPIO_OUT);GPIO_SetPinLevel(GPIOC, GPIO_PIN7, GPIO_LEVEL_HIGH);while(1){}
}