02-笔记:LPC1788-系统时钟

时钟系统概述

LPC178x/177x 系列 Cortex-M3 的时钟系统结构如图 4.10 所示,它包含 3 个独立振荡器,
它们分别为主振荡器、内部 RC 振荡器和 RTC 振荡器。每个振荡器可根据不同应用要求选择使
用。时钟部分的功能包括:
 振荡器;
 PLL;
 时钟选择和分频器;
 功率控制;
 唤醒定时器;
 外部时钟输出。

寄存器描述

振荡器

复位后,LPC178x/177x 系列 Cortex-M3 自动选择内部 RC 振荡器作为系统的时钟源。
这使 得系统能在没有外部晶振的情况下运行。
在 ISP 模式中,BootLoader 程序也是使用内部 RC 振 荡器作为时钟源。
用户可以通过软件方式修改时钟源选择寄存器,从而选择 3 种振荡器中的一种作为系统主 时钟源。
 注意,在切换前必须保证即将使用的时钟源已经可用。
所有振荡器在用作 CPU 的时钟源时,可以通过 PLL 获得较高的 F CCLK 值(必须小于或等于 120MHz)。

1. 内部 RC 振荡器

内部 RC 振荡器(IRC)可用作看门狗定时器的时钟源,也可以用作驱动 PLL0 和 CPU 的 时钟源。
IRC 的精度达不到 USB 接口的时间基准精度要求(USB 接口需要一个更精确的时间 基准以遵循 USB 规范),
因此在使用 LPC178x/177x 系列 Cortex-M3 的 USB 功能时要求使用精 度更高的外部晶体振荡器作为系统时钟源。
除此之外,如果 CAN 波特率高于 100Kbit/s,则 IRC 也不能应用于 CAN1/2 模块。
IRC 的频率为 12MHz,精度可达±1%范围。
在上电或任何片上复位时,LPC178x/177x 系列 Cortex-M3 使用 IRC 作为时钟源。
此后,软 件可将其切换为另一种可用的时钟源。

2. 主振荡器

主振荡器(外部晶体振荡器)可作为 CPU 的时钟源(不管是否使用 PLL0)。主振荡器工作
在 1MHz~25MHz 下。该频率可通过主 PLL(PLL0)来提高至 CPU 操作频率的最大值。主振
荡器的输出称为 OSC_CLK。PLLCLKIN 选择用作 PLL0 输入时钟,在本文中将 Cortex-M3 处理
器时钟频率称为 CCLK。除非 PLL0 有效且已连接,否则 PLLCLKIN 和 CCLK 的频率相同。详
细内容请参考本章“PLL0 和 PLL1(锁相环 0)”小节描述。
LPC178x/177x 系列 Cortex-M3 的主振荡器可工作在两种模式下:从属模式和主振荡模式。
在从属模式下,输入时钟信号应该与一个 100pF 的电容(图 4.11(a)的 Cc)相连,其幅值为
200mVrms 到 1000mVrms,相当于方波信号在 280mV 到 1.4V 之间浮动。在这种配置下 XTAL2
引脚可以不连接。
在主振荡模式下,使用的外部元件和模型见图 4.11 的(b)和(c),以及表 4.12 和表 4.13。由
于片内集成了反馈电阻,只需在外部连接一个晶体和电容 Cx1、Cx2 就可形成基本模式的振荡
电路(基本频率用 L、CL 和 Rs 来表示)。图 4.11(c)的电容 Cp 是并联封装电容,其值不能大于
7pF。参数 Fc、CL、Rs 和 Cp 都由晶体制造商提供。
由于芯片操作总是从内部 RC 振荡器开始,且主振荡器在某些应用中并没有使用,因此主 振荡器只能由软件请求来启动。
通过把 SCS 寄存器的 OSCEN 置位可实现这种操作,如表 4.8 所述。
主振荡器提供了一个状态标志(SCS 寄存器中的 OSCSTAT 位),程序可据此得知振荡器 何时可用。
待确定振荡器运行稳定后,软件可控制切换为主振荡器模式使其作为系统时钟源。
在启动主振荡器之前,频率范围必须通过配置 SCS 寄存器中的 OSCRANGE 位来选择。
注:有关 SCS 寄存器的内容请参考“系统控制块”一节。

3.RTC 振荡器

RTC 振荡器可以向 RTC 提供 1Hz 的时钟和一个可以输出到 CLKOUT 引脚上的 32KHz 时 钟输出。

4.看门狗振荡器

看门狗定时器具有一个专用的振荡器,它向看门狗定时器提供 500KHz 的时钟,如果看门 狗定时器使能,那么它会一直运行。
看门狗振荡器时钟可以在 CLKOUT 引脚上输出,以允许 用户观察它的频率。
在特定器件里,温度和电源变化可产生高至±17%的频率变动。
在相同的操作条件下,器件 间的频率差别可以高达±30%。




PLL 工作原理及使用

LPC178x/177x 系列 Cortex-M3 内部具有两个 PLL 模块,分别为 PLL0(主 PLL)和 PLL1 (Alt PLL)。
其中 PLL0 时钟源可以为主振荡器或 IRC 振荡器,而 PLL1 的时钟源只能是主振 荡器,
一般是用作特定外设如 USB 的时钟源。
二者均支持 10MHz~25MHz 范围内的输入时钟 频率。

PLL 工作原理

PLL 时钟源的选择在 CLKSRCSEL 寄存器中设置(见“时钟源选择多路复用”的描述),
PLL 将输入时钟升频,然后再分频以提供 CPU 及芯片外设所使用的实际时钟。PLL 可产生的时
钟频率高达 120MHz,是 CPU 所允许的最大值。
为了便于理解 PLL 的工作原理,将内部结构简化为图 4.13。PLL 的输出时钟信号就是电流
控制振荡器(CCO)的输出,CCO 的振荡频率由“相位频率检测”部件控制,该部件会比较两
个输出信号的相位和频率,并根据误差输出不同的电流值来控制 CCO 的振荡频率。这样的环
路可以保证“相位频率检测”部件的两路输入信号非常接近(可认为一样)。
通常 CCO 的输出频率是有限的,超出这个范围则无法输出预期的时钟信号。LPC178x/177x
系列 Cortex-M3 内部的 CCO 可工作在 156MHz~320MHz。图 4.13 中所示的“M 分频”和“2P
分频”就是为了保证 CCO 工作在正常范围内而设计的。
需要特别注意的是,PLL 作为时钟系统中的一个重要模块,它为系统的内核以及所有部件
(包括看门狗定时器)提供时钟,如果操作不当将会引起非常严重的后果。所以为了避免程序
对 PLL 正在使用的相关参数意外修改,芯片厂商从硬件上提供了保护,该保护是由一个类似于
操作看门狗定时器的代码序列来实现,详情请参阅 PLLFEED 寄存器的描述。
注: PLL 在芯片复位和进入掉电模式时会被关闭并从时钟系统中切换出去。芯片从掉电模式被唤醒后,
PLL 并不会自动使能和连接,只能通过软件使能。程序必须在配置并激活 PLL 后等待其锁定,然后再连接 PLL 。
警告:PLL 值的不正确设定会导致芯片的错误操作。

PLL 寄存器描述

PLL 的激活通过 PLLCON 寄存器来控制,见表 4.16。下面给出更详细的描述。
注:不适当地设置 PLL 值会导致器件不能正确地操作!


PLL 和启动/引导代码的相互作用
当在用户 Flash 中无有效代码(由校验和字决定)或在启动时拉低 ISP 使能引脚(P2.10)
时,芯片将进入 ISP 模式,并且引导代码将用 IRC 设置 PLL。因此,当用户启动 JTAG 来调试
用户代码时,用户代码不能认为 PLL 被禁止。在用户启动代码中必须对 PLL 进行重新设置。


时钟分频器

CPU 时钟选择寄存器(CCLKSEL – 0x400F C104)

PLL0 输出时钟必须要经过分频才能提供给 CPU 使用,PLL0 输出的分频由 CCLKSEL 寄存器进 行控制。当 PLL0 被旁路时,可通过 1 分频。当 PLL0 正在运行时,输出必须经过分频以使 CPU 时钟频率(CCLK)工作在限定的频率范围内,LPC178x/177x 系列 Cortex-M3 CPU 的时钟频率 最大值为 120MHz。可使用一个 5 位 CCLKSEL 分频器进行选择合适的置位来降低 CPU 的操作 频率,以达到暂时节省功耗无需关闭 PLL0 的目的。
注:当在应用中使用 USB 接口时, F CCLK 必须至少为 18MHz 以便于支持 USB 子系统的内部操作。

USB 时钟选择寄存器(USBCLKSEL – 0x400F C108)

USBCLKSEL 寄存器控制如何选用 USB 子系统的时钟,也控制着此时钟的分频操作,再把 分频的时钟供给 USB 模块使用。所选的 PLL 的输出必须要分频,以使 USB 时钟频率为 48MHz, 占空比为 50%。在 PLL 操作范围内,分频器允许从 48MHz 的任意偶数倍(即 96MHz 的任意倍 数)中获取正确的 USB 时钟。
注:从内部 RC 振荡器中获取的时钟不可用作 USB 子系统的时钟。

EMC 时钟选择寄存器(EMCCLKSEL – 0x400F C100)

EMCCLKSEL 寄存器控制着时钟的分频操作,然后把分频的时钟供给 EMC 使用。EMC 使 用的基准时钟与 CPU 和 APH 外设的相同。EMC 时钟可以等于 CPU 时钟或 CPU 时钟的一半。 其主要的使用场合就是当 CPU 运行的速度快于外部总线可以支持的速率时使用。

外设时钟选择寄存器(PCLKSEL – 0x400F C1A8)

PCLKSEL 寄存器控制着所有 APH 外设使用的基准时钟。5 位分频器允许使用一定范围内 的频率。
注:外设时钟速率不能高于 CPU 时钟速率。






固件库时钟初始化过程
/* Determine clock frequency according to clock register values             */

/**
 * Initialize the system
 *
 * @param  none
 * @return none
 *
 * @brief  Setup the microcontroller system.
 *         Initialize the System.
 */
void SystemInit (void)
{
#if (CLOCK_SETUP)                       /* Clock Setup                        */
  LPC_SC->SCS       = SCS_Val;
  if (SCS_Val & (1 << 5)) {             /* If Main Oscillator is enabled      */
    while ((LPC_SC->SCS & (1<<6)) == 0);/* Wait for Oscillator to be ready    */
  }

  LPC_SC->CLKSRCSEL = CLKSRCSEL_Val;    /* Select Clock Source for sysclk/PLL0*/

#if (PLL0_SETUP)
  LPC_SC->PLL0CFG   = PLL0CFG_Val;
  LPC_SC->PLL0CON   = 0x01;             /* PLL0 Enable                        */
  LPC_SC->PLL0FEED  = 0xAA;
  LPC_SC->PLL0FEED  = 0x55;
  while (!(LPC_SC->PLL0STAT & (1<<10)));/* Wait for PLOCK0                    */
#endif

#if (PLL1_SETUP)
  LPC_SC->PLL1CFG   = PLL1CFG_Val;
  LPC_SC->PLL1CON   = 0x01;             /* PLL1 Enable                        */
  LPC_SC->PLL1FEED  = 0xAA;
  LPC_SC->PLL1FEED  = 0x55;
  while (!(LPC_SC->PLL1STAT & (1<<10)));/* Wait for PLOCK1                    */
#endif

  LPC_SC->CCLKSEL   = CCLKSEL_Val;      /* Setup Clock Divider                */
  LPC_SC->USBCLKSEL = USBCLKSEL_Val;    /* Setup USB Clock Divider            */
  LPC_SC->EMCCLKSEL = EMCCLKSEL_Val;    /* EMC Clock Selection                */
  LPC_SC->PCLKSEL   = PCLKSEL_Val;      /* Peripheral Clock Selection         */
  LPC_SC->PCONP     = PCONP_Val;        /* Power Control for Peripherals      */
  LPC_SC->CLKOUTCFG = CLKOUTCFG_Val;    /* Clock Output Configuration         */
#endif

#if (FLASH_SETUP == 1)                  /* Flash Accelerator Setup            */
  LPC_SC->FLASHCFG  = FLASHCFG_Val|0x03A;
#endif
#ifdef  __RAM_MODE__
  SCB->VTOR  = 0x10000000 & 0x3FFFFF80;
#else
  SCB->VTOR  = 0x00000000 & 0x3FFFFF80;
#endif
}
 
1
/* Determine clock frequency according to clock register values             */
2
3
/**
4
 * Initialize the system
5
 *
6
 * @param  none
7
 * @return none
8
 *
9
 * @brief  Setup the microcontroller system.
10
 *         Initialize the System.
11
 */
12
void SystemInit (void)
13
{
14
#if (CLOCK_SETUP)                       /* Clock Setup                        */
15
  LPC_SC->SCS       = SCS_Val;
16
  if (SCS_Val & (1 << 5)) {             /* If Main Oscillator is enabled      */
17
    while ((LPC_SC->SCS & (1<<6)) == 0);/* Wait for Oscillator to be ready    */
18
  }
19
20
  LPC_SC->CLKSRCSEL = CLKSRCSEL_Val;    /* Select Clock Source for sysclk/PLL0*/
21
22
#if (PLL0_SETUP)
23
  LPC_SC->PLL0CFG   = PLL0CFG_Val;
24
  LPC_SC->PLL0CON   = 0x01;             /* PLL0 Enable                        */
25
  LPC_SC->PLL0FEED  = 0xAA;
26
  LPC_SC->PLL0FEED  = 0x55;
27
  while (!(LPC_SC->PLL0STAT & (1<<10)));/* Wait for PLOCK0                    */
28
#endif
29
30
#if (PLL1_SETUP)
31
  LPC_SC->PLL1CFG   = PLL1CFG_Val;
32
  LPC_SC->PLL1CON   = 0x01;             /* PLL1 Enable                        */
33
  LPC_SC->PLL1FEED  = 0xAA;
34
  LPC_SC->PLL1FEED  = 0x55;
35
  while (!(LPC_SC->PLL1STAT & (1<<10)));/* Wait for PLOCK1                    */
36
#endif
37
38
  LPC_SC->CCLKSEL   = CCLKSEL_Val;      /* Setup Clock Divider                */
39
  LPC_SC->USBCLKSEL = USBCLKSEL_Val;    /* Setup USB Clock Divider            */
40
  LPC_SC->EMCCLKSEL = EMCCLKSEL_Val;    /* EMC Clock Selection                */
41
  LPC_SC->PCLKSEL   = PCLKSEL_Val;      /* Peripheral Clock Selection         */
42
  LPC_SC->PCONP     = PCONP_Val;        /* Power Control for Peripherals      */
43
  LPC_SC->CLKOUTCFG = CLKOUTCFG_Val;    /* Clock Output Configuration         */
44
#endif
45
46
#if (FLASH_SETUP == 1)                  /* Flash Accelerator Setup            */
47
  LPC_SC->FLASHCFG  = FLASHCFG_Val|0x03A;
48
#endif
49
#ifdef  __RAM_MODE__
50
  SCB->VTOR  = 0x10000000 & 0x3FFFFF80;
51
#else
52
  SCB->VTOR  = 0x00000000 & 0x3FFFFF80;
53
#endif
54
}
55



自定义时钟初始化过程
#ifndef __SYS_H_
#define __SYS_H_
#include "common.h"

#define SystemCoreClock  120000000  //cpu时钟频率,计算时有用
#define ApbClock        120000000   //120M
#define EmcClock        60000000    //60M
#define UsbClock        48000000    //48M

void SystemInit(void);//系统时钟初始化,启动代码调用

#endif

 

 

#include "sys.h"
#define XTAL_FREQ   12000000
#define LPC_PBOOST  *((volatile unsigned long  *)(0X400FC1B0))

void SystemInit(void)
{
    LPC_SC->SCS       = 0x00000021;//osc晶振使能,地址线不移位模式
    while ((LPC_SC->SCS & (1<<6)) == 0);/* 等待osc晶振准备好    */
    LPC_SC->CLKSRCSEL = 0x00000001;    /*选择osc为系统输入时钟*/
    LPC_PBOOST |= (3<<0);   //打开功耗提升,可以提升到120MHZ
   

//      PLL0 Configuration (Main PLL)
//      PLL0 Configuration Register (PLL0CFG)
//         PLL out clock = (F_cco / (2 * P))
//         F_cco = (F_in * M * 2 * P)
//         F_in  must be in the range of 1 MHz to 25 MHz
//         PLL out clock must be in the range of 9.75 MHz to 160 MHz
//         F_cco   156-320M
//      MSEL: PLL Multiplier Selection 0-4bit m
//         M Value
//      PSEL: PLL Divider Selection 5-6bit p
//         P Value
//         1
//         2
//         4
//         8

    LPC_SC->PLL0CFG   = 0x00000009;//选择倍频系数 P = 1 M = 10 FCCO = FIN*P*M*2=240M PLL_OUT = FCCO/(2*P)=120M
    LPC_SC->PLL0CON   = 0x01;             /* PLL0 使能 */
    LPC_SC->PLL0FEED  = 0xAA;
    LPC_SC->PLL0FEED  = 0x55;
    while (!(LPC_SC->PLL0STAT & (1<<10)));/* 等待PLL锁定 */
    
    LPC_SC->PLL1CFG   = 0x00000023; //选择倍频系数 m = 4 p = 2 fcco = fin*2*p*m = 192m pllout = 192/2*p = 48M
    LPC_SC->PLL1CON   = 0x01;             /* PLL1 使能    */
    LPC_SC->PLL1FEED  = 0xAA;
    LPC_SC->PLL1FEED  = 0x55;
    while (!(LPC_SC->PLL1STAT & (1<<10)));  /* 等待PLL1 锁定 */
    
    LPC_SC->CCLKSEL   = (1<<0)|(1<<8);      /* pll0为主时钟,分频数为1 */
    LPC_SC->USBCLKSEL = (1<<0)|(2<<8);      /* pll1为cpu主时钟 */
    LPC_SC->EMCCLKSEL = (1<<0);             /* EMC 为系统是时钟的一半  */
    LPC_SC->PCLKSEL   = (1<<0);             /* 外设时钟分频数为1,120M */
    LPC_SC->PCONP     = 0x00;               /* 可以关闭的外设全部被关闭 */
    LPC_SC->CLKOUTCFG &= ~(1<<8);           /* 停止时钟输出    */
    LPC_SC->FLASHCFG  = (5<<12)|0x03A;//6个cpu flash访问时钟,最安全的设置,120M时候可用

#ifdef  __RAM_MODE__//设置中断向量表的位置,一般不改
  SCB->VTOR  = 0x10000000 & 0x3FFFFF80;
#else
  SCB->VTOR  = 0x00000000 & 0x3FFFFF80;
#endif
}



 
1
#ifndef __SYS_H_
2
#define __SYS_H_
3
#include "common.h"
4
5
#define SystemCoreClock  120000000  //cpu时钟频率,计算时有用
6
#define ApbClock        120000000   //120M
7
#define EmcClock        60000000    //60M
8
#define UsbClock        48000000    //48M
9
10
void SystemInit(void);//系统时钟初始化,启动代码调用
11
12
#endif
13
14
 
15
16
 
17
18
#include "sys.h"
19
#define XTAL_FREQ   12000000
20
#define LPC_PBOOST  *((volatile unsigned long  *)(0X400FC1B0))
21
22
void SystemInit(void)
23
{
24
    LPC_SC->SCS       = 0x00000021;//osc晶振使能,地址线不移位模式
25
    while ((LPC_SC->SCS & (1<<6)) == 0);/* 等待osc晶振准备好    */
26
    LPC_SC->CLKSRCSEL = 0x00000001;    /*选择osc为系统输入时钟*/
27
    LPC_PBOOST |= (3<<0);   //打开功耗提升,可以提升到120MHZ
28
   
29
30
//      PLL0 Configuration (Main PLL)
31
//      PLL0 Configuration Register (PLL0CFG)
32
//         PLL out clock = (F_cco / (2 * P))
33
//         F_cco = (F_in * M * 2 * P)
34
//         F_in  must be in the range of 1 MHz to 25 MHz
35
//         PLL out clock must be in the range of 9.75 MHz to 160 MHz
36
//         F_cco   156-320M
37
//      MSEL: PLL Multiplier Selection 0-4bit m
38
//         M Value
39
//      PSEL: PLL Divider Selection 5-6bit p
40
//         P Value
41
//         1
42
//         2
43
//         4
44
//         8
45
46
    LPC_SC->PLL0CFG   = 0x00000009;//选择倍频系数 P = 1 M = 10 FCCO = FIN*P*M*2=240M PLL_OUT = FCCO/(2*P)=120M
47
    LPC_SC->PLL0CON   = 0x01;             /* PLL0 使能 */
48
    LPC_SC->PLL0FEED  = 0xAA;
49
    LPC_SC->PLL0FEED  = 0x55;
50
    while (!(LPC_SC->PLL0STAT & (1<<10)));/* 等待PLL锁定 */
51
    
52
    LPC_SC->PLL1CFG   = 0x00000023; //选择倍频系数 m = 4 p = 2 fcco = fin*2*p*m = 192m pllout = 192/2*p = 48M
53
    LPC_SC->PLL1CON   = 0x01;             /* PLL1 使能    */
54
    LPC_SC->PLL1FEED  = 0xAA;
55
    LPC_SC->PLL1FEED  = 0x55;
56
    while (!(LPC_SC->PLL1STAT & (1<<10)));  /* 等待PLL1 锁定 */
57
    
58
    LPC_SC->CCLKSEL   = (1<<0)|(1<<8);      /* pll0为主时钟,分频数为1 */
59
    LPC_SC->USBCLKSEL = (1<<0)|(2<<8);      /* pll1为cpu主时钟 */
60
    LPC_SC->EMCCLKSEL = (1<<0);             /* EMC 为系统是时钟的一半  */
61
    LPC_SC->PCLKSEL   = (1<<0);             /* 外设时钟分频数为1,120M */
62
    LPC_SC->PCONP     = 0x00;               /* 可以关闭的外设全部被关闭 */
63
    LPC_SC->CLKOUTCFG &= ~(1<<8);           /* 停止时钟输出    */
64
    LPC_SC->FLASHCFG  = (5<<12)|0x03A;//6个cpu flash访问时钟,最安全的设置,120M时候可用
65
66
#ifdef  __RAM_MODE__//设置中断向量表的位置,一般不改
67
  SCB->VTOR  = 0x10000000 & 0x3FFFFF80;
68
#else
69
  SCB->VTOR  = 0x00000000 & 0x3FFFFF80;
70
#endif
71
}
72
73
74
75

猜你喜欢

转载自www.cnblogs.com/bog-box/p/LPC1788-RCC-notes.html
02-