首先是 时钟系统图
整个系统框图,本次要配置的是外部高速振荡器(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). */
stcMpllCfg.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