NXP LPC17xx之时钟模块

来源:互联网 发布:怎么注册开淘宝店 编辑:程序博客网 时间:2024/06/06 03:12

1 模块介绍

图1.系统框图

    时钟模块的晶振源一共有3个:主晶振、内部RC晶振、RTC晶振。
   


1.1 主时钟

    一般为12M的晶振,外部输入,LPC1765的引脚名是XTAL1/XTAL2。它是CPU主频的主要时钟源,主晶振的频率范围为1M Hz ~  25MHz

1.2 内部RC振荡器

    顾名思义,内置的RC振荡器,当然不会很准了,所以该时钟源不能用于USB模块。内部RC振荡器是芯片复位后默认的系统时钟源,频率为:4M Hz

1.3 RTC时钟

    RTC晶振(1 Hz ~ 32768 Hz)主要用于RTC模块实现时钟功能,还有就是看门狗模块,当然,如果你发神经病的话,你可以拿它作为PLL0或CPU的时钟源。RTC晶振一般都是使用32768 Hz的频率,这个频率用来跑秒是最好不过的了。外部输入,引脚名为RTCX1/RTCX2。

1.4 Main PLL(PLL0)

    通过寄存器CLKSRCSEL[1:0]可以选择介入Main PLL的时钟源,PLL的功能就是实现稳定的高频率时钟输出,大概框图如下:

图2.PLL系统框图
    这里要注意,pllclkin的时钟范围是32768Hz~50MHz,。pllclkin会先被N分频(NSEL[7:0]),得到refclk,refclk和M-DIVIDER(MSEL[14:0])输出的频率差通过鉴频鉴相器、滤波器,最后通过流控晶体振荡器产生的频率Fcco,Fcco最后又通过2*M分频后与Frefclk进行比较,如此循环反馈和调节的过程,最终使得两个频率相同,该过程就是锁相。
    若pllclk为目标频率,则有:
(Fpllclk*M)/2 = Frefclk,
即:
Fpllclkin/N = Fpllclk/(2*M)
最后,结合图1,有
Fpllclk = (Fpllclkin*2*M)/N


1.5 usbclk、cclk、pclk

    pllclk是个很重要的时钟,它直接为usb模块、系统主频、外设提供时钟源,后端就很好理解了,结合图1很清楚能够明白,稍微配置下寄存器就OK了。其中,cclk就是CPU的主频了。


2 LPC1700CMSIS SystemInit()函数分析


    LPC1700CMSIS标准库是专门为LPC17xx系列芯片所设计的底层驱动标准代码,它提供所有外设的控制接口,能大量缩短项目的开发周期。其实之前我对使用库文件这种行为是很不齿的,呵呵,其实也没啥,就是希望当时能够多做一些多学一些,因为写底层驱动还是一个很重要的工作。随着后面慢慢工作重心转向产品功能实现以后,我也慢慢理解了库文件所带来的便利了,呵呵!不过也是建立在已经有了较多底层驱动设计经验的基础上的情况下,言归正传,贴代码:

    以下是一些宏定义:
/** @addtogroup LPC17xx_System_Defines  LPC17xx System Defines  @{ */#define CLOCK_SETUP           1#define SCS_Val               0x00000020#define CLKSRCSEL_Val         0x00000001#define PLL0_SETUP            1#define PLL0CFG_Val           0x00050063#define PLL1_SETUP            1#define PLL1CFG_Val           0x00000023#define CCLKCFG_Val           0x00000003#define USBCLKCFG_Val         0x00000000#define PCLKSEL0_Val          0x00000000#define PCLKSEL1_Val          0x00000000#define PCONP_Val             0x042887DE#define CLKOUTCFG_Val         0x00000000</span>

    SystemInit()函数源码:
00499 void SystemInit (void)00500 {00501 #if (CLOCK_SETUP)                       /* Clock Setup                        */00502   LPC_SC->SCS       = <span style="color:#ff6666;">SCS_Val</span>;00503   if (LPC_SC->SCS & (1 << 5)) {             /* If Main Oscillator is enabled  */00504     while ((LPC_SC->SCS & (1<<6)) == 0);/* Wait for Oscillator to be ready    */00505   }00506 00507   LPC_SC->CCLKCFG   = CCLKCFG_Val;      /* Setup Clock Divider                */00508   /* Periphral clock must be selected before PLL0 enabling and connecting00509    * - according errata.lpc1768-16.March.2010 -00510    */00511   LPC_SC->PCLKSEL0  = PCLKSEL0_Val;     /* Peripheral Clock Selection         */00512   LPC_SC->PCLKSEL1  = PCLKSEL1_Val;00513 00514 #if (PLL0_SETUP)00515   LPC_SC->CLKSRCSEL = CLKSRCSEL_Val;    /* Select Clock Source for PLL0       */00516 00517   LPC_SC->PLL0CFG   = PLL0CFG_Val;      /* configure PLL0                     */00518   LPC_SC->PLL0FEED  = 0xAA;00519   LPC_SC->PLL0FEED  = 0x55;00520 00521   LPC_SC->PLL0CON   = 0x01;             /* PLL0 Enable                        */00522   LPC_SC->PLL0FEED  = 0xAA;00523   LPC_SC->PLL0FEED  = 0x55;00524   while (!(LPC_SC->PLL0STAT & (1<<26)));/* Wait for PLOCK0                    */00525 00526   LPC_SC->PLL0CON   = 0x03;             /* PLL0 Enable & Connect              */00527   LPC_SC->PLL0FEED  = 0xAA;00528   LPC_SC->PLL0FEED  = 0x55;00529   while (!(LPC_SC->PLL0STAT & ((1<<25) | (1<<24))));/* Wait for PLLC0_STAT & PLLE0_STAT */00530 #endif00531 00532 #if (PLL1_SETUP)00533   LPC_SC->PLL1CFG   = PLL1CFG_Val;00534   LPC_SC->PLL1FEED  = 0xAA;00535   LPC_SC->PLL1FEED  = 0x55;00536 00537   LPC_SC->PLL1CON   = 0x01;             /* PLL1 Enable                        */00538   LPC_SC->PLL1FEED  = 0xAA;00539   LPC_SC->PLL1FEED  = 0x55;00540   while (!(LPC_SC->PLL1STAT & (1<<10)));/* Wait for PLOCK1                    */00541 00542   LPC_SC->PLL1CON   = 0x03;             /* PLL1 Enable & Connect              */00543   LPC_SC->PLL1FEED  = 0xAA;00544   LPC_SC->PLL1FEED  = 0x55;00545   while (!(LPC_SC->PLL1STAT & ((1<< 9) | (1<< 8))));/* Wait for PLLC1_STAT & PLLE1_STAT */00546 #else00547   LPC_SC->USBCLKCFG = USBCLKCFG_Val;    /* Setup USB Clock Divider            */00548 #endif00549   LPC_SC->PCONP     = PCONP_Val;        /* Power Control for Peripherals      */00550 00551   LPC_SC->CLKOUTCFG = CLKOUTCFG_Val;    /* Clock Output Configuration         */00552 #endif00553 00554 #if (FLASH_SETUP == 1)                  /* Flash Accelerator Setup            */00555   LPC_SC->FLASHCFG  = FLASHCFG_Val;00556 #endif00557 00558 //  Set Vector table offset value00559 #if (__RAM_MODE__==1)00560   SCB->VTOR  = 0x10000000 & 0x3FFFFF80;00561 #else00562   SCB->VTOR  = 0x00000000 & 0x3FFFFF80;00563 #endif00564 }

2.1 阶段1-时钟源和分频选择

  LPC_SC->SCS       = SCS_Val;                                                   (1)  if (LPC_SC->SCS & (1 << 5)) {             /* If Main Oscillator is enabled  */ (2)    while ((LPC_SC->SCS & (1<<6)) == 0);/* Wait for Oscillator to be ready    */  }  LPC_SC->CCLKCFG   = CCLKCFG_Val;      /* Setup Clock Divider                */ (3)  /* Periphral clock must be selected before PLL0 enabling and connecting   * - according errata.lpc1768-16.March.2010 -   */  LPC_SC->PCLKSEL0  = PCLKSEL0_Val;     /* Peripheral Clock Selection         */ (4)  LPC_SC->PCLKSEL1  = PCLKSEL1_Val;                                              (5)

    (1)中SCS_Val = 0x00000020,主要是配置Main OSC作为PLL0的时钟源,之后(2)则不停轮询,直到Main OSC准备好为止,这里我觉得是等待晶振稳定。(3)中CCLKCFG_Val =0x00000003,实现对PLL0输出时钟的4分频——Fpll0/4。(5)中PCLKSEL0_Val 和PCLKSEL1_Val都是0,表示所有外设的时钟源都为CCLK/4,即CPU主频的1/4。

2.2 阶段2-PLL0初始化

<span style="font-size:14px;">  LPC_SC->CLKSRCSEL = CLKSRCSEL_Val;    /* Select Clock Source for PLL0       */ (1)  LPC_SC->PLL0CFG   = PLL0CFG_Val;      /* configure PLL0                     */ (2)   LPC_SC->PLL0FEED  = 0xAA;  LPC_SC->PLL0FEED  = 0x55;  LPC_SC->PLL0CON   = 0x01;             /* PLL0 Enable                        */ (3)  LPC_SC->PLL0FEED  = 0xAA;  LPC_SC->PLL0FEED  = 0x55;  while (!(LPC_SC->PLL0STAT & (1<<26)));/* Wait for PLOCK0                    */ (4)  LPC_SC->PLL0CON   = 0x03;             /* PLL0 Enable & Connect              */ (5)  LPC_SC->PLL0FEED  = 0xAA;  LPC_SC->PLL0FEED  = 0x55;  while (!(LPC_SC->PLL0STAT & ((1<<25) | (1<<24))));  /* Wait for PLLC0_STAT & PLLE0_STAT */</span>

    这里主要就是实现对锁相环0的配置了,就是前面提到的N值、M值等的配置。(1)中CLKSRCSEL_Val = 0x00000001,选择PLL0时钟源,这里选择Main OSC,(3)就是对M值和N值进行设定了,
<span style="font-family:FangSong_GB2312;">PLL0CFG_Val = 0x00050063,即M=100,注意,M的实际值为寄存器的值+1,即99+1,同理N=6,(5)就是使能PLL0了。每次对PLL0的寄存器进行配置时需要依次向PLL0FEED写入0xAA、0x55以使配置生效。OK,最后我们来计算验证下PLL0的输出频率是多少?根据公式:<span style="font-family: FangSong_GB2312; font-size: 18px;">Fpllclk = (Fpllclkin*2*M)/N,若Main OSC为12M,则Fpllclk = 12*2*100/6=400M。最后Fcclk = Fpllclk / 4 = 100M,就是系统时钟频率,那么外设时钟源频率为25M。</span></span>
<span style="font-family:FangSong_GB2312;"><span style="font-family: FangSong_GB2312; font-size: 18px;"></span></span>

2.3 阶段3-初始化PLL1

    这里略过了,很简单,暂时还没用到USB模块,先不管了,其实理解了PLL0,这个也基本就理解了,无外乎它专用于USB时钟生成,肯定会有一些区别而已。

2.4 阶段4-初始化FLASH加速模块

#if (FLASH_SETUP == 1)                  /* Flash Accelerator Setup            */  LPC_SC->FLASHCFG  = FLASHCFG_Val;#endif
    FLASHCFG_VAL = 0x0000303A,为默认值。FLASH加速模块在后面再介绍了。

2.5 阶段5-设置VTOR

#if (__RAM_MODE__==1)  SCB->VTOR  = 0x10000000 & 0x3FFFFF80;#else  SCB->VTOR  = 0x00000000 & 0x3FFFFF80;#endif

    




0 0
原创粉丝点击