首先是 時鐘系統圖
整個系統框圖,本次要配置的是外部高速振蕩器(12Mhz)晶振,是以隻關注左上角部分的配置.
外部振蕩器配置位置
Xtal_in:高速振蕩器輸入 Xtal32_in: 低速32k振蕩器輸入
說一下配置流程(12M晶振為例):
A. XTAL_IN外接12M晶振, 系統選擇外部晶振,需要初始化外部晶振:
stc_clk_xtal_cfg_t stcXtalCfg; /* 高速外部振蕩器 */
/* 外部高速振蕩器初始化 */
MEM_ZERO_STRUCT(stcXtalCfg);
stcXtalCfg.enMode = ClkXtalModeOsc; /* 配置振蕩器 */
stcXtalCfg.enDrv = ClkXtalLowDrv; /* 12M晶振屬于低速驅動能力 */
stcXtalCfg.enFastStartup = Enable; /* 使能快速啟動 */
CLK_XtalConfig(&stcXtalCfg); /* 配置參數 */
CLK_XtalCmd(Enable); /* 使能振蕩器 */
B. 對于内部的sram也需要進行配置(主要參考手冊):
配置方式如下:
stc_sram_config_t stcSramConfig;/* sRam配置 */
/* sram */
stcSramConfig.u8SramIdx = Sram12Idx | Sram3Idx | SramHsIdx | SramRetIdx;
stcSramConfig.enSramRC = SramCycle2; /* 等待周期 參考上圖表8-1 */
stcSramConfig.enSramWC = SramCycle2;
/*
參考: 8.2.3 SRAM 校驗控制寄存器( SRAM_CKCR)
若1位錯誤,ECC糾錯, 産生1位錯誤标志,産生中斷/複位
若2位錯誤,ECC檢錯, 産生2位錯誤标志,産生中斷/複位
*/
stcSramConfig.enSramEccMode = EccMode3; /* 校驗模式選擇 */
stcSramConfig.enSramEccOp = SramNmi; /* ecc校驗失敗不産生NMI中斷*/
stcSramConfig.enSramPyOp = SramNmi; /*奇偶校驗出錯後不産生NMI中斷 */
SRAM_Init(&stcSramConfig); /* SRAM初始化 */
EFM_Unlock(); /* 解鎖flash配置寄存器 */
/* 配置延遲周期(參考表3),這個參數跟HCLK配置頻率有關系 */
EFM_SetLatency(EFM_LATENCY_5);
EFM_Lock(); /* 上鎖 */
C. 配置PLL(VCO倍頻後輸出)
計算方式:
1. 輸入晶振頻率/分頻系數 *倍頻系數 得到PLL時鐘源(VCO)
2. PLL再進行分頻
MPLL:用于cpu,io及外設i2c等
uPLL: 主要用于usb外設
PLL | qPLL | pPLL | rPLL |
MPLL | MqPLL | MpPLL | MrPLL |
UPLL | UqPLL | UpPLL | MrPLL |
計算12M晶振輸出:
計算公式:
PLL(VCO)= xtal(12)/ pllmDiv(3) * plln(100) = 400M
晶振輸入頻率12M先進行分頻,得到穩定的4M然後倍頻到400MHz,然後在進行分頻給p,q,r;
代碼配置如下:
stc_clk_mpll_cfg_t stcMpllCfg; /* MPLL 倍頻/分頻器 配置 */
/* MPLL config (XTAL / pllmDiv * plln / PllpDiv = 200M). */
/* 分頻系數 (12M)晶振頻率/(3)mdiv*(100)plln = MPLL頻率 400MHz */
stcMpllCfg.pllmDiv = 3ul;
stcMpllCfg.plln = 100ul; /* 倍頻系數 *100 = 400M */
/* MPLL_P 分頻系數 MPLL頻率/p = MPLL_P頻率 200MHz */
stcMpllCfg.PllpDiv = 2ul;
/* MPLL_Q 分頻系數 MPLL頻率/q = MPLL_Q頻率 200MHZ */
stcMpllCfg.PllqDiv = 2ul;
/* MPLL_R 分頻系數 MPLL頻率/r = MPLL_R頻率 200MHZ */
stcMpllCfg.PllrDiv = 2ul;
CLK_SetPllSource(ClkPllSrcXTAL); /* 配置時鐘源 外部高速振蕩器 */
CLK_MpllConfig(&stcMpllCfg); /* 配置MPLL參數 */
/* 使能MPLL. */
CLK_MpllCmd(Enable);
然後是配置系統時鐘源:
stc_clk_sysclk_cfg_t stcSysClkCfg; /* 系統時鐘 */
/* 系統時鐘配置 */
MEM_ZERO_STRUCT(stcSysClkCfg);
/* 12M/2 *100 = 400M(PLL) */
stcSysClkCfg.enHclkDiv = ClkSysclkDiv2; /* 200M ,max 200MHz */
stcSysClkCfg.enExclkDiv = ClkSysclkDiv4;/* 100M ,max 100MHz */
stcSysClkCfg.enPclk0Div = ClkSysclkDiv4;/* 100M ,max 100MHz */
stcSysClkCfg.enPclk1Div = ClkSysclkDiv8;/* 50M ,max 60MHz */
stcSysClkCfg.enPclk2Div = ClkSysclkDiv8;/* 50M ,max 50MHz */
stcSysClkCfg.enPclk3Div = ClkSysclkDiv4;/* 100M ,max 100MHz */
stcSysClkCfg.enPclk4Div = ClkSysclkDiv4;/* 100M ,max 100MHz */
CLK_SysClkConfig(&stcSysClkCfg);
配置要根據手冊進行配置 比例不對會出現 配置成功,燒錄後不可用!
關于總線時鐘配置參考文檔如下:
這裡是 pll(VCO)進行倍頻分頻相關參數設定:
a. 輸入晶振分頻系數: 1~24
b. 倍頻系數: 20~480
c. 倍頻後輸出頻率: 240M~480M之間 超範圍會異常
d. P,Q,R(pll)分頻系數:2~16
e. upll與mpll配置方式一樣
上面得到了所需最大頻率,實際還需要對系統時鐘進行配置具體的頻率:
參考上圖中關于 時鐘的最大頻率範圍 我們能得到自己所需的分頻系數:
enHclkDiv: HCLK時鐘 max 200MHZ
enExclkDiv:EXCLK時鐘 max100Mhz
enPclk0Div: EXCLK時鐘 max100Mhz
enPclk1Div: EXCLK時鐘 max50Mhz
enPclk2Div: EXCLK時鐘 max50Mhz
enPclk3Div: EXCLK時鐘 max100Mhz
enPclk4Div: EXCLK時鐘 max100Mh
在之前配置Mpll的時候 我們配置到了400Mhz
總線 | MPLL = 400MHz/分頻系數 | 分頻後頻率 |
HCLK | 2 | 200Mhz |
PCLK0 | 2 | 200Mhz |
PCLK1 | 4 | 100Mhz |
PCLK2 | 8 | 50Mhz |
PCLK3 | 8 | 50Mhz |
PCLK4 | 4 | 100Mhz |
EXCLK | 4 | 100Mhz |
這裡雖然配置好了 還需要注意文檔中關于頻率比例問題:
按照上述操作下來配置時鐘基本上沒有問題.注意一點就是PLL(VCO)倍頻以後需要在輸出範圍内.
EX:
下面舉個例子說明一下,自己的錯誤配置:
以下是錯誤示範,請勿直接使用代碼
12M外部輸入晶振
MPLL:
mPLL=12M/3* 42 = 168Mhz
MPLL 分頻參數: 3
MPLL 倍頻參數: 42
然後PQR使用2分頻 得到 84MHz
配置系統時鐘(錯誤配置示例):
總線 | MPLL = 168MHz/分頻系數 | 分頻後頻率 |
HCLK | 1 | 168Mhz |
PCLK0 | 1 | 168Mhz |
PCLK1 | 2 | 84Mhz |
PCLK2 | 4 | 42Mhz |
PCLK3 | 4 | 42Mhz |
PCLK4 | 2 | 100Mhz |
EXCLK | 2 | 84Mhz |
上述配置也是按照文檔中的要求系數配置但是實際中是不工作的.
最終發現配置出錯原因, PLL(VCO)輸出頻率不在輸出範圍内(240M-480M).
修正參數如下:
此處是修正代碼(可以正常使用)
12M外部輸入晶振
MPLL:
mPLL=12M/3* 84 = 338Mhz
MPLL 分頻參數: 3
MPLL 倍頻參數: 84
然後PQR使用2分頻 得到 168MHz
配置系統時鐘:
總線 | MPLL = 168MHz/分頻系數 | 分頻後頻率 |
HCLK | 2 | 168Mhz |
PCLK0 | 2 | 168Mhz |
PCLK1 | 4 | 84Mhz |
PCLK2 | 8 | 42Mhz |
PCLK3 | 8 | 42Mhz |
PCLK4 | 4 | 84Mhz |
EXCLK | 4 | 84Mhz |
此時系統正常跑起來了!
修改系統時鐘時需要對EFM做對應修改:
關于sram部分的修改這裡沒有繼續寫出,參考 sram延遲周期即可(根據運作頻率選擇對應等待周期即可)
EFM_Unlock();
EFM_SetLatency(EFM_LATENCY_4);/* 對應HCLK主頻 */
EFM_Lock();
這樣配置以後代碼跑起來沒什麼問題了.
續:
還沒完(這裡貼出三種配置時鐘方案):
方案一:
void system_clk_init(void) /* 12M晶振, 3分頻 84倍頻輸出 PLL(VCO)== 336M */
{
stc_clk_sysclk_cfg_t stcSysClkCfg; /* 系統時鐘 */
stc_clk_xtal_cfg_t stcXtalCfg; /* 高速外部振蕩器 */
stc_clk_xtal32_cfg_t stcXtal32Cfg; /* 外部低速振蕩器 */
stc_clk_mpll_cfg_t stcMpllCfg; /* MPLL 倍頻/分頻器 */
stc_sram_config_t stcSramConfig; /* sRam配置 */
/* 系統時鐘配置 HCLK 168M */
MEM_ZERO_STRUCT(stcSysClkCfg);
/* 12M/2 =6M *56 = 336M(PLL) */
stcSysClkCfg.enHclkDiv = ClkSysclkDiv2; /* 168M ,max 200MHz */
stcSysClkCfg.enExclkDiv = ClkSysclkDiv4;/* 84M ,max 100MHz */
stcSysClkCfg.enPclk0Div = ClkSysclkDiv2;/* 168M ,max 200MHz */
stcSysClkCfg.enPclk1Div = ClkSysclkDiv4;/* 84M ,max 100MHz */
stcSysClkCfg.enPclk2Div = ClkSysclkDiv8;/* 42M ,max 60MHz */
stcSysClkCfg.enPclk3Div = ClkSysclkDiv8;/* 42M ,max 50MHz */
stcSysClkCfg.enPclk4Div = ClkSysclkDiv4;/* 84M ,max 100MHz */
CLK_SysClkConfig(&stcSysClkCfg);
/* 外部高速振蕩器初始化 */
MEM_ZERO_STRUCT(stcXtalCfg);
stcXtalCfg.enMode = ClkXtalModeOsc; /* 配置振蕩器 */
stcXtalCfg.enDrv = ClkXtalLowDrv; /* 12M晶振屬于低速驅動能力 */
stcXtalCfg.enFastStartup = Enable; /* 使能快速啟動 */
CLK_XtalConfig(&stcXtalCfg); /* 配置參數 */
CLK_XtalCmd(Enable); /* 使能振蕩器 */
/* 外部低速振蕩器初始化 */
MEM_ZERO_STRUCT(stcXtal32Cfg);
stcXtal32Cfg.enDrv = ClkXtal32MidDrv;
stcXtal32Cfg.enFilterMode = ClkXtal32FilterModeFull;
CLK_Xtal32Config(&stcXtal32Cfg);
CLK_Xtal32Cmd(Disable); /* 未使用禁用掉 */
/* 配置sram及PLL */
MEM_ZERO_STRUCT(stcMpllCfg);
MEM_ZERO_STRUCT(stcSramConfig);
/* sram */
stcSramConfig.u8SramIdx = Sram12Idx | Sram3Idx | SramHsIdx | SramRetIdx;
stcSramConfig.enSramRC = SramCycle2;
stcSramConfig.enSramWC = SramCycle2;
/*
若1位錯誤,ECC糾錯, 産生1位錯誤标志,産生中斷/複位
若2位錯誤,ECC檢錯, 産生2位錯誤标志,産生中斷/複位
*/
stcSramConfig.enSramEccMode = EccMode3;
stcSramConfig.enSramEccOp = SramNmi;
stcSramConfig.enSramPyOp = SramNmi;
SRAM_Init(&stcSramConfig);
EFM_Unlock();
EFM_SetLatency(EFM_LATENCY_4);
EFM_Lock();
/* MPLL config (XTAL / pllmDiv * plln / PllpDiv = 168M). */
/* 分頻系數 (12M)晶振頻率/(3)mdiv*(84)plln = MPLL頻率 336MHz */
stcMpllCfg.pllmDiv = 3ul;
stcMpllCfg.plln = 84ul; /* 倍頻系數 *100 = 336M */
stcMpllCfg.PllpDiv = 2ul; /* MPLL_P 分頻系數 MPLL頻率/p = MPLL_P頻率 168MHz */
stcMpllCfg.PllqDiv = 2ul; /* MPLL_Q 分頻系數 MPLL頻率/q = MPLL_Q頻率 168MHZ */
stcMpllCfg.PllrDiv = 2ul; /* MPLL_R 分頻系數 MPLL頻率/r = MPLL_R頻率 168MHZ */
CLK_SetPllSource(ClkPllSrcXTAL); /* 配置時鐘源 外部高速振蕩器 */
CLK_MpllConfig(&stcMpllCfg); /* 配置MPLL參數 */
/* Enable MPLL. */
CLK_MpllCmd(Enable);
if(SystemCoreClock > CLK_HP_FREQ /* 168M */){
CLK_SetSysClkSource(CLKSysSrcMPLL);
}else if( SystemCoreClock < CLK_HS_FREQ /* 8M */){
PWC_LS2HP();
CLK_SetSysClkSource(CLKSysSrcMPLL);
}else{
PWC_HS2HP();
CLK_SetSysClkSource(CLKSysSrcMPLL);
}
}
方案二:
void system_clk_init(void) /* 12M晶振, 3分頻 100倍頻輸出 PLL(VCO)== 400M */
{
stc_clk_sysclk_cfg_t stcSysClkCfg; /* 系統時鐘 */
stc_clk_xtal_cfg_t stcXtalCfg; /* 高速外部振蕩器 */
stc_clk_xtal32_cfg_t stcXtal32Cfg; /* 外部低速振蕩器 */
stc_clk_mpll_cfg_t stcMpllCfg; /* MPLL 倍頻/分頻器 */
stc_sram_config_t stcSramConfig; /* sRam配置 */
/* 系統時鐘配置 HCLK 200M */
MEM_ZERO_STRUCT(stcSysClkCfg);
/* 12M/2 =6M *56 = 336M(PLL) */
stcSysClkCfg.enHclkDiv = ClkSysclkDiv2; /* 200M ,max 200MHz */
stcSysClkCfg.enExclkDiv = ClkSysclkDiv4;/* 100M ,max 100MHz */
stcSysClkCfg.enPclk0Div = ClkSysclkDiv2;/* 200M ,max 200MHz */
stcSysClkCfg.enPclk1Div = ClkSysclkDiv4;/* 100M ,max 100MHz */
stcSysClkCfg.enPclk2Div = ClkSysclkDiv8;/* 50M ,max 60MHz */
stcSysClkCfg.enPclk3Div = ClkSysclkDiv8;/* 50M ,max 50MHz */
stcSysClkCfg.enPclk4Div = ClkSysclkDiv4;/* 100M ,max 100MHz */
CLK_SysClkConfig(&stcSysClkCfg);
/* 外部高速振蕩器初始化 */
MEM_ZERO_STRUCT(stcXtalCfg);
stcXtalCfg.enMode = ClkXtalModeOsc; /* 配置振蕩器 */
stcXtalCfg.enDrv = ClkXtalLowDrv; /* 12M晶振屬于低速驅動能力 */
stcXtalCfg.enFastStartup = Enable; /* 使能快速啟動 */
CLK_XtalConfig(&stcXtalCfg); /* 配置參數 */
CLK_XtalCmd(Enable); /* 使能振蕩器 */
/* 外部低速振蕩器初始化 */
MEM_ZERO_STRUCT(stcXtal32Cfg);
stcXtal32Cfg.enDrv = ClkXtal32MidDrv;
stcXtal32Cfg.enFilterMode = ClkXtal32FilterModeFull;
CLK_Xtal32Config(&stcXtal32Cfg);
CLK_Xtal32Cmd(Disable); /* 未使用禁用掉 */
/* 配置sram及PLL */
MEM_ZERO_STRUCT(stcMpllCfg);
MEM_ZERO_STRUCT(stcSramConfig);
/* sram */
stcSramConfig.u8SramIdx = Sram12Idx | Sram3Idx | SramHsIdx | SramRetIdx;
stcSramConfig.enSramRC = SramCycle2;
stcSramConfig.enSramWC = SramCycle2;
/*
若1位錯誤,ECC糾錯, 産生1位錯誤标志,産生中斷/複位
若2位錯誤,ECC檢錯, 産生2位錯誤标志,産生中斷/複位
*/
stcSramConfig.enSramEccMode = EccMode3;
stcSramConfig.enSramEccOp = SramNmi;
stcSramConfig.enSramPyOp = SramNmi;
SRAM_Init(&stcSramConfig);
EFM_Unlock();
EFM_SetLatency(EFM_LATENCY_5);
EFM_Lock();
/* MPLL config (XTAL / pllmDiv * plln / PllpDiv = 200M). */
/* 分頻系數 (12M)晶振頻率/(3)mdiv*(100)plln = MPLL頻率 400MHz */
stcMpllCfg.pllmDiv = 3ul;
stcMpllCfg.plln = 100ul; /* 倍頻系數 *100 = 400M */
stcMpllCfg.PllpDiv = 2ul; /* MPLL_P 分頻系數 MPLL頻率/p = MPLL_P頻率 200MHz */
stcMpllCfg.PllqDiv = 2ul; /* MPLL_Q 分頻系數 MPLL頻率/q = MPLL_Q頻率 200MHZ */
stcMpllCfg.PllrDiv = 2ul; /* MPLL_R 分頻系數 MPLL頻率/r = MPLL_R頻率 200MHZ */
CLK_SetPllSource(ClkPllSrcXTAL); /* 配置時鐘源 外部高速振蕩器 */
CLK_MpllConfig(&stcMpllCfg); /* 配置MPLL參數 */
/* Enable MPLL. */
CLK_MpllCmd(Enable);
if(SystemCoreClock > CLK_HP_FREQ /* 168M */){
CLK_SetSysClkSource(CLKSysSrcMPLL);
}else if( SystemCoreClock < CLK_HS_FREQ /* 8M */){
PWC_LS2HP();
CLK_SetSysClkSource(CLKSysSrcMPLL);
}else{
PWC_HS2HP();
CLK_SetSysClkSource(CLKSysSrcMPLL);
}
}
方案三:
void system_clk_init(void)
{
stc_clk_sysclk_cfg_t stcSysClkCfg; /* 系統時鐘 */
stc_clk_xtal_cfg_t stcXtalCfg; /* 高速外部振蕩器 */
stc_clk_xtal32_cfg_t stcXtal32Cfg; /* 外部低速振蕩器 */
stc_clk_mpll_cfg_t stcMpllCfg; /* MPLL 倍頻/分頻器 */
stc_sram_config_t stcSramConfig;/* sRam配置 */
/* 系統時鐘配置 */
MEM_ZERO_STRUCT(stcSysClkCfg);
/* 12M/2 =6M *64 = 384M(PLL) */
stcSysClkCfg.enHclkDiv = ClkSysclkDiv2; /* 192M ,max 200MHz */
stcSysClkCfg.enExclkDiv = ClkSysclkDiv4;/* 96M , max 100MHz */
stcSysClkCfg.enPclk0Div = ClkSysclkDiv2;/* 192M , max 200MHz */
stcSysClkCfg.enPclk1Div = ClkSysclkDiv4;/* 96M , max 100MHz */
stcSysClkCfg.enPclk2Div = ClkSysclkDiv8;/* 48M , max 60MHz */
stcSysClkCfg.enPclk3Div = ClkSysclkDiv8;/* 48M , max 50MHz */
stcSysClkCfg.enPclk4Div = ClkSysclkDiv4;/* 96M , max 100MHz */
CLK_SysClkConfig(&stcSysClkCfg);
/* 外部高速振蕩器初始化 */
MEM_ZERO_STRUCT(stcXtalCfg);
stcXtalCfg.enMode = ClkXtalModeOsc; /* 配置振蕩器 */
stcXtalCfg.enDrv = ClkXtalLowDrv; /* 12M晶振屬于低速驅動能力 */
stcXtalCfg.enFastStartup = Enable; /* 使能快速啟動 */
CLK_XtalConfig(&stcXtalCfg); /* 配置參數 */
CLK_XtalCmd(Enable); /* 使能振蕩器 */
/* 外部低速振蕩器初始化 */
MEM_ZERO_STRUCT(stcXtal32Cfg);
stcXtal32Cfg.enDrv = ClkXtal32MidDrv;
stcXtal32Cfg.enFilterMode = ClkXtal32FilterModeFull;
CLK_Xtal32Config(&stcXtal32Cfg);
CLK_Xtal32Cmd(Disable); /* 未使用禁用掉 */
/* 配置sram及PLL */
MEM_ZERO_STRUCT(stcMpllCfg);
MEM_ZERO_STRUCT(stcSramConfig);
/* sram */
stcSramConfig.u8SramIdx = Sram12Idx | Sram3Idx | SramHsIdx | SramRetIdx;
stcSramConfig.enSramRC = SramCycle2;
stcSramConfig.enSramWC = SramCycle2;
/*
若1位錯誤,ECC糾錯, 産生1位錯誤标志,産生中斷/複位
若2位錯誤,ECC檢錯, 産生2位錯誤标志,産生中斷/複位
*/
stcSramConfig.enSramEccMode = EccMode3;
stcSramConfig.enSramEccOp = SramNmi;
stcSramConfig.enSramPyOp = SramNmi;
SRAM_Init(&stcSramConfig);
EFM_Unlock();
EFM_SetLatency(EFM_LATENCY_5);
EFM_Lock();
/* MPLL config (XTAL / pllmDiv * plln / PllpDiv = 200M). */
s tcMpllCfg.pllmDiv = 2ul; /* 分頻系數 (12M)晶振頻率/(2)mdiv*(64)plln = MPLL頻率 384MHz */
stcMpllCfg.plln = 64ul; /* 倍頻系數 *100 = 384M */
stcMpllCfg.PllpDiv = 2ul; /* MPLL_P 分頻系數 MPLL頻率/p = MPLL_P頻率 192MHz */
stcMpllCfg.PllqDiv = 2ul; /* MPLL_Q 分頻系數 MPLL頻率/q = MPLL_Q頻率 192MHZ */
stcMpllCfg.PllrDiv = 2ul; /* MPLL_R 分頻系數 MPLL頻率/r = MPLL_R頻率 192MHZ */
CLK_SetPllSource(ClkPllSrcXTAL); /* 配置時鐘源 外部高速振蕩器 */
CLK_MpllConfig(&stcMpllCfg); /* 配置MPLL參數 */
/* Enable MPLL. */
CLK_MpllCmd(Enable);
if(SystemCoreClock > CLK_HP_FREQ /* 168M */){
CLK_SetSysClkSource(CLKSysSrcMPLL);
}else if( SystemCoreClock < CLK_HS_FREQ /* 8M */){
PWC_LS2HP();
CLK_SetSysClkSource(CLKSysSrcMPLL);
}else{
PWC_HS2HP();
CLK_SetSysClkSource(CLKSysSrcMPLL);
}
}
修改晶振參數:
system_hc32f460keta.h中關于:
#if !defined (XTAL_VALUE)
#define XTAL_VALUE ((uint32_t)8000000) /*!< External high speed OSC freq. */
#endif
預設使用8M,我們定義一個12M晶振參數即可:
#define XTAL_VALUE ((uint32_t)12000000) /*!< External high speed OSC freq. */
#if !defined (XTAL_VALUE)
#define XTAL_VALUE ((uint32_t)8000000) /*!< External high speed OSC freq. */
#endif