1.时钟参数
1.1 宏定义时钟注释
//宏定义外接时钟,设置时钟很重要
#define EXTAL_IN_XT1_HZ ( 32768)
#define EXTAL_IN_XT2_HZ (4000000)
//宏定义内部REFO,VLO时钟频率
#define VLOCLK_FREQUENCY ( 10000)
#define REFOCLK_FREQUENCY ( 32768)
1.2 时钟来源
switch(clk)
{
case CLOCK_XT1 :g_sClock.CLK.nHZ = EXTAL_IN_XT1_HZ;break;
case CLOCK_VLO :g_sClock.CLK.nHZ = VLOCLK_FREQUENCY;break;
case CLOCK_REFO :g_sClock.CLK.nHZ = REFOCLK_FREQUENCY;break;
case CLOCK_DCO :g_sClock.CLK.nHZ = g_sClock.DCO_FLL_Frequency;break;
case CLOCK_DCO_DIV:g_sClock.CLK.nHZ = g_sClock.DCO_FLL_Frequency;break;
case CLOCK_XT2 :g_sClock.CLK.nHZ = EXTAL_IN_XT2_HZ;break;
default :return;
}
1.3 时钟参数介绍
typedef enum
{
CLOCK_XT1, //XT1
CLOCK_VLO, //内部10K
CLOCK_REFO, //内部32768
CLOCK_DCO, //内部DCO,如果使用内部DCO作为时钟的话,需要先调用DCO_PLLConfig设置DCO频率
CLOCK_DCO_DIV, //DCO分频(分频为1且不允许修改,与DCO同频)
CLOCK_XT2, //XT2
}CLOCK_Source; //时钟源
1.4 时钟分表
时钟源 时钟频率(HZ) 时钟源 时钟频率(Hz)
CLOCK_XT1 32768(32.768k) CLOCK_DCO 自主设置倍频
CLOCK_VLO 10000(10k) CLOCK_DCO_DIV 同CLOCK_DCO
CLOCK_REFO 32768(32.768k) CLOCK_XT2 4000000(4M)
2.频率配置过程
2.1 XT1时钟配置初始化
/*******************************************************************************
* 函数名称:XT1_Config(STATUS status)
* 功能说明:设置是否使能XT1
* 参数说明:STATUS status:是否使能XT1
* 函数返回:无
* 使用示例:XT1_Config(ENABLE); //使能XT1
********************************************************************************/
static inline void XT1_Config(STATUS status)
{
if(status != DISABLE)
{
if(UCS->XT1_OFF == BIT_SET)
{
GPIO_MultiBits_Init(P5,(GPIO_Pin_4|GPIO_Pin_5),GPI|SEL); //选用 XT1 第二功能
UCS->XT1_OFF = RESET ; // 开启 XT1
do
{
UCS->XT1_LFOFFG = RESET; // 清除XT1,CLOCK_DCO 失效标志
SFRIFG1 &= ~OFIFG; //
}while (UCS->XT1_LFOFFG == BIT_SET); //
}
}
else
{
UCS->XT1_OFF = BIT_SET ; // 关闭 XT1
}
}
2.2 XT2时钟配置初始化
/*******************************************************************************
* 函数名称:XT2_Config(STATUS status)
* 功能说明:设置是否使能XT2
* 参数说明:STATUS status:是否使能XT2
* 函数返回:无
* 使用示例:XT2_Config(TRUE); //使能XT2
********************************************************************************/
static inline void XT2_Config(STATUS status)
{
if(status != DISABLE)
{
if(UCS->XT2_OFF == BIT_SET)
{
GPIO_MultiBits_Init(P5,(GPIO_Pin_2|GPIO_Pin_3),GPI|SEL); //选用 CLOCK_XT2 第二功能
UCS->XT2_OFF = RESET; //开启 CLOCK_XT2
do
{
UCS->XT2_OFFG = RESET;
SFRIFG1 &= ~OFIFG;
}while (UCS->XT2_OFFG == BIT_SET);
}
}
else
{
UCS->XT2_OFF = BIT_SET ; // 关闭XT2
}
}
2.3 内部时钟
CLOCK_VLO,CLOCK_REFO为内部时钟源,不需要配置和初始化。
2.4 DCO及DCO_DIV配置过程
由于DCO是可以自主倍频的,倍频函数为CLOCK_DCO_PLLConfig(FLLREF_Source, FLLREF_DIVx, uint32_t DCO_FLL_Fre),由于DCO_DIV分频为1且不允许修改,即DCO_DIV与DCO同频,下面好好分析一下倍频过程
2.4.1 时钟分频系数,共计6种选择
typedef enum
{
FLLREF_DIV_1 , //不分频
FLLREF_DIV_2 , //二分频
FLLREF_DIV_4 , //四分频
FLLREF_DIV_8 , //八分频
FLLREF_DIV_12 , //十二分频
FLLREF_DIV_16 , //十六分频
}FLLREF_DIVx; //FLL参考时钟分频
2.4.2 参考分频时钟,总计3个
typedef enum
{
FLLREF_XT1 =0u, //32.768k
FLLREF_REFO =2u, //10k
FLLREF_XT2 =5u //4M
}FLLREF_Source; //FLL参考时钟源
2.4.3 倍频函数
/*******************************************************************************
* 函数名称:CLOCK_DCO_PLLConfig(FLLREF_Source refsource, FLLREF_DIVx refdiv, uint32_t DCO_FLL_Fre)
* 功能说明:设置DCO频率,单位(HZ)
* 参数说明:FLLREF_Source refsource :参考时钟源
FLLREF_DIVx refdiv :参考时钟源分频系数
uint32_t DCO_FLL_Fre :DCO设置频率
* 函数返回:无
********************************************************************************/
void CLOCK_DCO_PLLConfig (FLLREF_Source refsource, FLLREF_DIVx refdiv, uint32_t DCO_FLL_Fre)
{
static const uint16_t ref_div_value[6]={1,2,4,8,12,16};
/*根据频率提高内核电压*/
//SetVcoreUp ( (DCO_FLL_Fre < 12MHz) ? 0 : ((DCO_FLL_Fre < 16MHz) ? 1 : ((DCO_FLL_Fre < 20MHz) ? 2 :3))); //设置内核电压
if(DCO_FLL_Fre < 12MHz)
SetVcoreUp (0x00); //设置内核电压
else if(DCO_FLL_Fre < 16MHz)
SetVcoreUp (0x01);
else if(DCO_FLL_Fre < 20MHz)
SetVcoreUp (0x02);
else
SetVcoreUp (0x03);
__bis_SR_register(SCG0); // 禁止倍频环FLL,
UCS->CTL0 = 0x0000; // 清零 DCOx, MODx
if (DCO_FLL_Fre < 0.63MHz) // fsystem < 0.63MHz
UCS->DCORSEL = 0;
else if (DCO_FLL_Fre < 1.25MHz) // 0.63MHz < fsystem < 1.25MHz
UCS->DCORSEL = 1;
else if (DCO_FLL_Fre < 2.5MHz) // 1.25MHz < fsystem < 2.5MHz
UCS->DCORSEL = 2;
else if (DCO_FLL_Fre < 5MHz) // 2.5MHz < fsystem < 5MHz
UCS->DCORSEL = 3;
else if (DCO_FLL_Fre < 10MHz) // 5MHz < fsystem < 10MHz
UCS->DCORSEL = 4;
else if (DCO_FLL_Fre < 20MHz) // 10MHz < fsystem < 20MHz
UCS->DCORSEL = 5;
else if (DCO_FLL_Fre < 40MHz) // 20MHz < fsystem < 40MHz
UCS->DCORSEL = 6;
else
UCS->DCORSEL = 7;
UCS->FLLREFDIV = refdiv;
UCS->SELREF = refsource;
float Fref_value;
if(refsource == FLLREF_XT2)
{
XT2_Config(TRUE);
Fref_value = (float)((uint32_t)EXTAL_IN_XT2_HZ/ref_div_value[refdiv]);
}
else if(refsource == FLLREF_XT1)
{
XT1_Config(TRUE);
Fref_value = (float)(EXTAL_IN_XT1_HZ/ref_div_value[refdiv]);
}
else if(refsource == FLLREF_REFO)
{
Fref_value = (float)(REFOCLK_FREQUENCY/ref_div_value[refdiv]);
}
uint16_t FLLN_VALUE = (uint16_t)((DCO_FLL_Fre/Fref_value+0.5f)-1u);
ASSERT(FLLN_VALUE < 1024,"CLOCK_DCO_PLLConfig","FLLN_VALUE不允许超过1023,请将DCO频率设低或者更换为更高频率的参考时钟源!"); //不允许超过1023,请将DCO频率设低或者更换为更高频率的参考时钟源
g_sClock.DCO_FLL_Frequency = DCO_FLL_Fre;
UCS->FLLN = FLLN_VALUE; //
UCS->FLLD = 0; //设置DCO分频
__bic_SR_register(SCG0); // 使能FLL
do
{
UCS->DCO_FFG = RESET; // 清除,CLOCK_DCO 失效标志
SFRIFG1 &= ~OFIFG; // 清除时钟失效标志
}while (UCS->DCO_FFG == BIT_SET); // 检查DCO失效标志
//将使用DCO作为时钟源的时钟频率值修改
if(UCS->SELM == CLOCK_DCO || UCS->SELM == CLOCK_DCO_DIV)
{
CLOCK_DIVx div = (CLOCK_DIVx)UCS->DIVM;
CLOCK_MCLK_Config ((CLOCK_Source)UCS->SELM, div);
}
if(UCS->SELS == CLOCK_DCO || UCS->SELS == CLOCK_DCO_DIV)
{
CLOCK_DIVx div = (CLOCK_DIVx)UCS->DIVS;
CLOCK_SMCLK_Config((CLOCK_Source)UCS->SELS, div);
}
if(UCS->SELA == CLOCK_DCO || UCS->SELA == CLOCK_DCO_DIV)
{
CLOCK_DIVx div = (CLOCK_DIVx)UCS->DIVA;
CLOCK_ACLK_Config ((CLOCK_Source)UCS->SELS, div);
}
}
2.5 通过案例分析总结关键步骤
使用示例:
CLOCK_DCO_PLLConfig(FLLREF_REFO, FLLREF_DIV_1, 16MHZ);
//设置DCO倍频环以REFO的一分频作为参考时钟源,倍频到16MHZ
1. 传入参数,分别传入参考时钟源FLLREF_REFO,分频系数FLLREF_DIV_1,所要倍频数
2. 根据时钟源选择内核电压,这里SetVcoreUp (0x02); UCS->DCORSEL = 5;
3. 确定时钟来源,计算参考频率,这里 Fref_value = 32768
4. 确定锁相环PLLN_VALUE值,这里PLLN_VALUE=487
5. 更新配置参数得到所要时钟频率
2.6 内核电压设置函数
/*******************************************************************************
函数功能:设置内核电压值(与频率设置有关)
函数参数:u8 level :电压阶梯 小于3
********************************************************************************/
void SetVcoreUp (uint8_t level)
{
#if 1 //仿真时修改为0,否则会卡在死循环里
// Open PMM registers for write
PMMCTL0_H = PMMPW_H;
// Set SVS/SVM high side new level
SVSMHCTL = SVSHE + SVSHRVL0 * level + SVMHE + SVSMHRRL0 * level;
// Set SVM low side to new level
SVSMLCTL = SVSLE + SVMLE + SVSMLRRL0 * level;
// Wait till SVM is settled
uint16_t i=50000;
while (((PMMIFG & SVSMLDLYIFG) == 0)&&((i--)>0));
// Clear already set flags
PMMIFG &= ~(SVMLVLRIFG + SVMLIFG);
// Set VCore to new level
PMMCTL0_L = PMMCOREV0 * level;
// Wait till new level reached
i =50000;
if ((PMMIFG & SVMLIFG))
while(((PMMIFG & SVMLVLRIFG) == 0)&&((i--)>0));
/*
if ((PMMIFG & SVMLIFG))
while ((PMMIFG & SVMLVLRIFG) == 0);
*/
// Set SVS/SVM low side to new level
SVSMLCTL = SVSLE + SVSLRVL0 * level + SVMLE + SVSMLRRL0 * level;
// Lock PMM registers for write access
PMMCTL0_H = 0x00;
#endif
}
3.各时钟输出
#define MCLK_OUT() GPIO_Init(P7,7,GPO | SEL) //主时钟输出, P7.7
#define SMCLK_OUT() GPIO_Init(P2,2,GPO | SEL) //子系统时钟输出P2.2
#define ACLK_OUT() GPIO_Init(P1,0,GPO | SEL) //辅助时钟输出 P1.0
#define CLOCK_OUT()
3.1 设置主时钟源
/*************************************************************************
* 函数名称:CLOCK_MCLK_Config (CLOCK_Source mclk , CLOCK_DIVx mclk_div)
* 功能说明:设置主时钟源及分频
* 参数说明:CLOCK_Source mclk :主时钟时钟源
CLOCK_DIVx mclk_div :主时钟分频系数
* 函数返回:无
* 使用示例:CLOCK_MCLK_Config (CLOCK_DCO , DIV_1); //主时钟使用DCO作为时钟源,分频系数为1(不分频)
*************************************************************************/
---------------------
作者:klaus_x
来源:CSDN
原文:https://blog.csdn.net/klaus_x/article/details/81039706
版权声明:本文为博主原创文章,转载请附上博文链接!
void CLOCK_MCLK_Config (CLOCK_Source mclk , CLOCK_DIVx mclk_div)
{
if(mclk == CLOCK_XT2)
{
XT2_Config(TRUE);
}
else if(mclk == CLOCK_XT1)
{
XT1_Config(TRUE);
}
UCS->SELM = mclk; //选择DCO作为时钟源
UCS->DIVM = mclk_div;
switch(mclk)
{
case CLOCK_XT1 :g_sClock.MCLK.nHZ = EXTAL_IN_XT1_HZ;break;
case CLOCK_VLO :g_sClock.MCLK.nHZ = VLOCLK_FREQUENCY;break;
case CLOCK_REFO :g_sClock.MCLK.nHZ = REFOCLK_FREQUENCY;break;
case CLOCK_DCO :g_sClock.MCLK.nHZ = g_sClock.DCO_FLL_Frequency;break;
case CLOCK_DCO_DIV:g_sClock.MCLK.nHZ = g_sClock.DCO_FLL_Frequency;break;
case CLOCK_XT2 :g_sClock.MCLK.nHZ = EXTAL_IN_XT2_HZ;break;
default :return;
}
g_sClock.MCLK.nHZ >>= mclk_div;
g_sClock.MCLK.nKHZ = g_sClock.MCLK.nHZ/1000u;
g_sClock.MCLK.fMHZ = g_sClock.MCLK.nHZ/1000000.0;
}
3.2 设置系统时钟源
/*************************************************************************
* 函数名称:CLOCK_SMCLK_Config (CLOCK_Source smclk, CLOCK_DIVx smclk_div)
* 功能说明:设置系统时钟源及分频
* 参数说明:CLOCK_Source smclk :系统时钟时钟源
CLOCK_DIVx smclk_div :系统时钟分频系数
* 函数返回:无
* 使用示例:CLOCK_SMCLK_Config (CLOCK_DCO , DIV_2); //系统时钟使用DCO作为时钟源,分频系数为2(二分频)
*************************************************************************/
void CLOCK_SMCLK_Config (CLOCK_Source smclk, CLOCK_DIVx smclk_div)
{
if(smclk == CLOCK_XT2)
{
XT2_Config(TRUE);
}
else if(smclk == CLOCK_XT1)
{
XT1_Config(TRUE);
}
UCS->SELS = smclk;//选择smclk时钟源
UCS->DIVS = smclk_div;
switch(smclk)
{
case CLOCK_XT1 :g_sClock.SMCLK.nHZ = EXTAL_IN_XT1_HZ;break;
case CLOCK_VLO :g_sClock.SMCLK.nHZ = VLOCLK_FREQUENCY;break;
case CLOCK_REFO :g_sClock.SMCLK.nHZ = REFOCLK_FREQUENCY;break;
case CLOCK_DCO :g_sClock.SMCLK.nHZ = g_sClock.DCO_FLL_Frequency;break;
case CLOCK_DCO_DIV:g_sClock.SMCLK.nHZ = g_sClock.DCO_FLL_Frequency;break;
case CLOCK_XT2 :g_sClock.SMCLK.nHZ = EXTAL_IN_XT2_HZ;break;
default :return;
}
g_sClock.SMCLK.nHZ >>= smclk_div;
g_sClock.SMCLK.nKHZ = g_sClock.SMCLK.nHZ/1000u;;
g_sClock.SMCLK.fMHZ = g_sClock.SMCLK.nHZ/1000000.0;
}
3.3 设置辅助时钟源
/*************************************************************************
* 函数名称:CLOCK_ACLK_Config (CLOCK_Source aclk , CLOCK_DIVx aclk_div)
* 功能说明:设置辅助时钟源及分频
* 参数说明:CLOCK_Source aclk :辅助时钟时钟源
CLOCK_DIVx aclk_div :辅助时钟分频系数
* 函数返回:无
* 使用示例:CLOCK_ACLK_Config (XT! , DIV_4); //辅助时钟使用XT1作为时钟源,分频系数为4(四分频)
*************************************************************************/
void CLOCK_ACLK_Config (CLOCK_Source aclk , CLOCK_DIVx aclk_div)
{
if(aclk == CLOCK_XT2)
{
XT2_Config(TRUE);
}
else if(aclk == CLOCK_XT1)
{
XT1_Config(TRUE);
}
UCS->SELA = aclk;//选择时钟源
UCS->DIVA = aclk_div; //设置分频系数为0
switch(aclk)
{
case CLOCK_XT1 :g_sClock.ACLK.nHZ = EXTAL_IN_XT1_HZ;break;
case CLOCK_VLO :g_sClock.ACLK.nHZ = VLOCLK_FREQUENCY;break;
case CLOCK_REFO :g_sClock.ACLK.nHZ = REFOCLK_FREQUENCY;break;
case CLOCK_DCO :g_sClock.ACLK.nHZ = g_sClock.DCO_FLL_Frequency;break;
case CLOCK_DCO_DIV:g_sClock.ACLK.nHZ = g_sClock.DCO_FLL_Frequency;break;
case CLOCK_XT2 :g_sClock.ACLK.nHZ = EXTAL_IN_XT2_HZ;break;
default :return;
}
g_sClock.ACLK.nHZ >>= aclk_div;
g_sClock.ACLK.nKHZ = g_sClock.ACLK.nHZ/1000u;;
g_sClock.ACLK.fMHZ = g_sClock.ACLK.nHZ/1000000.0;
}
4.更改时钟来源操作
具体路径请改变msp430f5529_system.h里面的宏定义修改时钟源及时钟分频
//宏定义初始化时钟频率及时钟源
#define FLL_REF FLLREF_REFO //FLL参考时钟源
#define FLLREF_DIV FLLREF_DIV_1 //FLL参考时钟分频系数
#define DCO_CLK_HZ 25MHZ //DCO时钟频率
//主时钟设置
#define MCLK_SOURCE CLOCK_DCO //主时钟时钟源
#define MCLK_DIV CLOCK_DIV_1 //主时钟时钟分频系数
//系统时钟设置
#define SMCLK_SOURCE CLOCK_XT2 //系统时钟时钟源
#define SMCLK_DIV CLOCK_DIV_1 //系统时钟分频系数
//辅助时钟设置
#define ACLK_SOURCE CLOCK_REFO //辅助时钟时钟源
#define ACLK_DIV CLOCK_DIV_1 //辅助时钟分频系数
5.时钟图
上一篇:MSP430定时器介绍
下一篇:NEC单片机 0527系列编程解读
推荐阅读最新更新时间:2024-03-16 16:25