搜索

[学习笔记] AC7801时钟自由配置

[复制链接]
113|1
 楼主 | 2021-3-16 16:15 | 显示全部楼层 |阅读模式
本帖最后由 wangjj19950516 于 2021-3-16 16:34 编辑

最近很多小伙伴在问时钟配置的问题:1.例程中没有看到配置时钟,程序却可以正常运行,到底是怎么回事?2.如何自己进行时钟配置?
今天为大家详细解答上面两个问题。

一、例程中的时钟究竟是怎么回事
     打开任何一个官方例程,大家会发现,没有时钟配置,然而各个模块的功能却能按照系统时钟为48MHZ正常运行。这就导致很多人一上来不确定时钟是多少,也不知道自己该如何配置所需的时钟。
      其实是在启动文件中,已经对时钟进行了初始化,默认按外部8M晶振,配置系统时钟为48MHZ,APB为系统时钟的2分频,为24MHZ。在system_ac780x.c文件中,可以找到下面这个系统初始化函数,里面有SetSysClock()函数,对时钟进行了初始化。
  1. void SystemInit (void)
  2. {
  3. #if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U)
  4.     SCB->VTOR = (uint32_t) &__Vectors;
  5. #endif

  6.     SystemCoreClock = SYSTEM_CLOCK;

  7.     SetEflashClock();
  8.     SetSysClock();
  9.     CKGEN_SetAPBClockDivider(APBCLK_DIV);
  10.     //SPM_EnableLVD(DISABLE);  //disable LVD if need
  11. }
复制代码

如果需要配置不一样的时钟,可以通过系统文件里的宏定义修改,但并不建议在系统文件上修改,可以自己写配置函数。

二、时钟模块简介
1.时钟源:
高速内部时钟(HSI):内部 RC 振荡器提供 8MHz 时钟源
外部高速时钟(HSE):外部 OSC 提供 4MHZ ~30MHz 晶振
低速内部时钟(LSI): 内部低速 RC OSC 提供 32KHz 时钟源
系统时钟 (SYSPLL): 提供高达 48MHz 的高速时钟

2.系统时钟框图
     手册中的框图可以帮助我们更好的理解时钟的每个配置步骤。
捕获1.JPG

输入频率:支持4~30MHZ
VCO = 输入频率*FBKDIV/PREDIV
系统时钟 = VCO/POSDIV/SYSCLKDIV
     同时,手册中也提供了典型的配置参数供参考。因为有些点的频率值是有限制的,比如VCO的频率范围是0.5GHZ~1.5GHZ,那么直接参考典型配置参考表就肯定不会有问题,找到合适的参数即可。
捕获2.JPG

三、配置自己的时钟
    以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。

捕获3.JPG
为了直观的测试时钟的频率,用一个定时器,定时产生中断,在中断中翻转一个I/O电平,以此来测时钟频率。定时器初始化如下:定时器的时钟源为APB时钟24M,配置定时器装载值为24000000,则1S产生一次中断。
  1. void TIMER_Config(void)
  2. {
  3.   TIMER_ConfigType  config;
  4.   memset(&config, 0, sizeof(config));
  5.         
  6.   config.periodValue = 24000000;           /*!< TIMER channel period value */
  7.   config.linkModeEn = DISABLE ;         /*!< TIMER channel linkmode enable */
  8.   config.interruptEn = ENABLE ;        /*!< TIMER channel interrupt enable */
  9.   config.callBack = TIM_CallBack;   /*!< TIMER channel callback pointer */
  10.   config.timerEn = ENABLE;            /*!< TIMER channel enable/disable */
  11.   TIMER_Init(TIMER_CHANNEL0, &config);    //TIMER0初始化配置
  12. }
复制代码

中断处理
  1. void TIM_CallBack(void *device, uint32_t wpara, uint32_t lpara)
  2. {
  3.         if (wpara & TIMER_CHANNEL_TF_T**_Msk)
  4.         {
  5.                 GPIOC->ODR ^= (1<<7);
  6.         }
  7. }
复制代码


2.外部时钟配置——库函数
  1. void SYS_CLOCK_HSE(void)
  2. {
  3.     /* check if xosc enable success? */
  4.     if (SPM_EnableXOSC(ENABLE) == SUCCESS)
  5.     {
  6.         CKGEN_SetPLLReference(PLL_REF_EXTERNAL_OSC);//PLL参考时钟选择外部振荡器
  7.     }
  8.     else  /* if xosc enable fail, */
  9.     {}

  10.     /* set system clock divider */
  11.     CKGEN_SetSysclkDiv(0);//系统时钟1分频
  12.     /* check if pll enable success? */
  13.     if (SPM_EnablePLL(ENABLE) == SUCCESS)/使能SYSPLL
  14.     {
  15.         CKGEN_SetPllPrevDiv(0);//PREDIV
  16.         CKGEN_SetPllPostDiv(8);//PLL_POSDIV
  17.         CKGEN_SetPllFeedbackDiv(96);//PLL_FBKDIV
  18.         CKGEN_SetSysclkSrc(SYSCLK_SRC_PLL_OUTPUT);//系统时钟源选择PLL时钟
  19.     }
  20.     else  /* pll enable fail */
  21.     {}
  22.                 CKGEN_SetAPBClockDivider(APBCLK_DIVIDER_2);//APB时钟为系统时钟2分频
  23. }
复制代码
3.外部时钟配置——寄存器
外部时钟的使能以及就绪标志,PLL使能以及就绪标志等,在第6章系统电源管理SPM模块下的SPM_PWR_MGR_CFG1寄存器里。
配置过程比较常规,使能时钟——>等待时钟就绪——>PLL时钟源选择——>时钟分频及倍频配置——>系统时钟源选择
  1. void SYS_CLOCK_HSE_REG(void)
  2. {
  3.         SPM->PWR_MGR_CFG1 |= 1<<29;//外部高速时钟XOSC使能
  4.         while((SPM->PWR_MGR_CFG1 &(0X80000000))==0)//等待XOSC就绪
  5.         {}
  6.   
  7.         SPM->PWR_MGR_CFG1 |= (1<<27);//SYSPLL使能
  8.         while((SPM->PWR_MGR_CFG1 &(0X40000000))==0)//等待PLL时钟就绪
  9.         {}
  10.         CKGEN->CTRL |= (1<<20);//PLL参考时钟选择外部振荡器

  11.         CKGEN->SYSPLL1_CFG0 = ((CKGEN->SYSPLL1_CFG0 & (~(uint32_t)(0x3<<30)))|(0<<30));          //PREDIV
  12.         CKGEN->SYSPLL1_CFG0 = ((CKGEN->SYSPLL1_CFG0 & (~(uint32_t)(0x1f<<25)))|(8<<25));        //POSDIV
  13.         CKGEN->SYSPLL1_CFG0 = ((CKGEN->SYSPLL1_CFG0 & (~(uint32_t)(0xff<<15)))|(96<<15));        //FBKDIV
  14.                
  15.         CKGEN->CTRL |= ((CKGEN->CTRL & (~(3<<4)))|(0<<4));        //系统时钟分频为1
  16.         CKGEN->CTRL |= (1<<0);//系统时钟源选择PLL时钟
  17.         CKGEN->CTRL |= (1<<8);//APB为系统时钟2分频
  18. }
复制代码
4.内部时钟配置——库函数
  采用内部高速8M时钟源做配置
  1. void SYS_CLOCK_HSI(void)
  2. {
  3.           CKGEN_SetPLLReference(PLL_REF_INTERAL_OSC);//PLL参考时钟选择内部振荡器
  4.     CKGEN_SetPllPrevDiv(0);             //PREDIV
  5.     CKGEN_SetPllPostDiv(8);             //POSDIV
  6.     CKGEN_SetPllFeedbackDiv(96);    //FBKDIV
  7.     CKGEN_SetSysclkDiv(0);              //系统时钟1分频
  8.     /* check if pll enable success? */
  9.     if (SPM_EnablePLL(ENABLE) == SUCCESS)
  10.     {
  11.         /* pll enable success,use pll output as system clock src */
  12.         CKGEN_SetSysclkSrc(SYSCLK_SRC_PLL_OUTPUT);//系统时钟源选择PLL时钟
  13.     }
  14.     else
  15.     {
  16.         /* pll enable fail */
  17.     }
  18.                 CKGEN_SetAPBClockDivider(APBCLK_DIVIDER_2);//APB为系统时钟2分频
  19. }
复制代码

5.内部时钟配置——寄存器
  1. void SYS_CLOCK_HSI_REG(void)
  2. {
  3.         CKGEN->CTRL &= ~(1<<20);//PLL参考时钟选择内部振荡器
  4.         SPM->PWR_MGR_CFG1 |= (1<<27);//SYSPLL使能
  5.         while((SPM->PWR_MGR_CFG1 &(0X40000000))==0)//等待PLL时钟就绪
  6.         {}        
  7.         
  8.         CKGEN->SYSPLL1_CFG0 = ((CKGEN->SYSPLL1_CFG0 & (~(uint32_t)(0x3<<30)))|(0<<30));          //PREDIV
  9.         CKGEN->SYSPLL1_CFG0 = ((CKGEN->SYSPLL1_CFG0 & (~(uint32_t)(0x1f<<25)))|(8<<25));        //POSDIV
  10.         CKGEN->SYSPLL1_CFG0 = ((CKGEN->SYSPLL1_CFG0 & (~(uint32_t)(0xff<<15)))|(96<<15));        //FBKDIV
  11.                
  12.        CKGEN->CTRL |= ((CKGEN->CTRL & (~(3<<4)))|(0<<4));        //SYSCLK_DIV,系统时钟1分频
  13.         CKGEN->CTRL |= (1<<0);//系统时钟源选择PLL时钟
  14.         CKGEN->CTRL |= (1<<8);//APB为系统时钟2分频
  15. }
复制代码

6.主函数
主函数中调用时钟初始化函数,并对TIMER0配置,同时需要对使用到的I/O进行配置
  1. int main(void)
  2. {
  3.         //SYS_CLOCK_HSE();
  4.         SYS_CLOCK_HSE_REG();
  5.         //SYS_CLOCK_HSI();
  6.         //SYS_CLOCK_HSI_REG();
  7.         TIMER_Config();
  8.         
  9.         GPIO_SetFunc(GPIOC, GPIO_PIN7, GPIO_FUN0);/*功能复用选择*/
  10.         GPIO_SetDir(GPIOC, GPIO_PIN7, GPIO_OUT);
  11.         GPIO_SetPinLevel(GPIOC, GPIO_PIN7, GPIO_LEVEL_HIGH);
  12.         while(1)
  13.         {
  14.         }
  15. }
复制代码


至此,就完成了时钟的自由配置,通过PC7引脚可以观察是否与设定频率相符。
附上调试代码 CLOCK.rar (43.03 KB, 下载次数: 6)

使用特权

评论回复
| 2021-3-17 08:51 | 显示全部楼层
It's me,

使用特权

评论回复
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 我要提问 投诉建议 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

在线客服 快速回复 返回顶部 返回列表