MSP430时钟定性分析

MSP430时钟定性分析

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_XT132768(32.768k)CLOCK_DCO自主设置倍频
CLOCK_VLO10000(10k)CLOCK_DCO_DIV同CLOCK_DCO
CLOCK_REFO32768(32.768k)CLOCK_XT24000000(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_VLOCLOCK_REFO为内部时钟源,不需要配置和初始化。

2.4 DCO及DCO_DIV配置过程

由于DCO是可以自主倍频的,倍频函数为CLOCK_DCO_PLLConfig(FLLREF_Source, FLLREF_DIVx, uint32_t DCO_FLL_Fre),由于DCO_DIV分频为1且不允许修改,即DCO_DIVDCO同频,下面好好分析一下倍频过程

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()                             do{MCLK_OUT();SMCLK_OUT();ACLK_OUT();}while(0)  //所有时钟输出

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(不分频)
*************************************************************************/  
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.时钟图

1

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值