? ? ? 🔥《嵌入式系统开发》系列专栏主要以LPC1100系列微控制器为硬件平台,详细介绍Cortex—-M0微控制器的原理与开发技术,基于keil仿真软件平台设计最小应用系统板和具有在板仿真器的口袋开发板以及相关例程。
? ? ? 🔥本文已收录于嵌入式系统开发系列专栏:嵌入式系统开发 欢迎订阅,持续更新。
【嵌入式系统设计】LPC1100系列微控制器基础——时钟系统
文章目录
LPC1100时钟产生单元
工作机制
系统控制模块SCB寄存器(与系统时钟有关)
振荡器选择
?内部RC振荡器
主振荡器
看门狗振荡器
看门狗振荡器控制寄存器WDTOSCCTRL
系统振荡器控制寄存器SYSOSCCTRL
?PLL工作原理与使用
PLL频率计算中的公式
PLL初始化步骤
系统初始化函数void Systemlnit (void)
void SystemCoreClockU pdate (void)函数
LPC1100时钟产生单元
工作机制
?LPC1100含有3个独立的振荡器:
系统振荡器:12MHZ
内部RC振荡器(IRC):12MHZ(与外部晶振相关)
看门狗振荡器(MDT):0.2MHZ
●复位后,LPC1100系列微控制器自动选择内部RC振荡器(12MHz) 作为系统的时钟源,这使得系统能在没有外部晶振的情况下运行。 ●一旦进入ISP模式,Boot Block程序使用内部RC振荡器作为PLL的输入时钟源,并产生14.748MHz系统时钟。(产生误差较小的波特率) ●系统AHB时钟控制寄存器SYSAHBCLKCTRL控制着各种外设和存储器的系统时钟。 ●UART和SSP0/1都有单独的时钟分频器,可以从主时钟分频产生外设所需的时钟频率。 ●主时钟以及从IRC振荡器、系统振荡器和看门狗振荡器输出的时钟均可以直接在GLKOUT弓|脚上观察到。
系统控制模块SCB寄存器(与系统时钟有关)
振荡器选择
●用户可以通过软件方式修改时钟源选择寄存器,从而选择3种振荡器中的一种作为系统主时钟源。但需要注意,在切换前必须保证即将使用的时钟源已经可用。 ●所有振荡器在用作CPU时钟源时,可以通过PLL获得较高的Fcclk值(必须小于或等于50MHz)。
?内部RC振荡器
内部RC振荡器(IRC) 可用作看i门狗定时器的时钟源,也可以用作系统PLL和CPU的时钟源。 ●IRC的标称频率为12MHz (精度为+1%),在一些特殊的应用场合(例如USB接口通信等)则需要使用精度更高的外部晶体振荡器作为系统时钟源。 ●在上电或任何片上复位时,LPC1100系列微控制器使用IRC作为时钟源。此后,用户可通过编程切换到另一种可用的时钟源。
●在ISP模式,Boot Block将用IRC作为系统时钟源设置PLL,并产生14.748MHz系统时钟。
主振荡器
●主振荡器(外部晶体振荡器)可作为CPU的时钟源(不管是否使用PLL)。主振荡器工作在10MHz ~ 25MHz下,用户可通过PLL来提高CPU的工作频率。主振荡器的输出称为
OSC_ CLK,可被选择用作PLL入时钟PLLCLKIN。 ●Cortex-M0处理器的工作频率称为CCLK,在PLL无效或还未连接时,PLLCLKIN和CCLK的值是相同的。
看门狗振荡器
●看门狗振荡器(WDT)可用作看i门狗定时器的时钟源,也可以用作CPU的时钟源。 ●由于看门狗振荡器的频率为500KHz ~ 3.4MHz (精度为士25%) ,所以在一.些特殊的应用场合(例如使用串口)则需要使用IRC振荡器或精度更高的外部晶体振荡器作为系统时钟源。
看门狗振荡器控制寄存器WDTOSCCTRL
看门狗振荡器控制寄存器用于配置看门狗振荡器。 ●利用位FREQSEL对Fclkana时钟信号进行调节,并可以利用位DIVSEL对Fclkana时钟信号进行分频。 ●看门狗振荡器的输出时钟频率的计算公式如下: wdt_ OSC_ cIk = Fclkana/ (2x(1+DIVSEL) ●当看门狗振荡控制器复位时,看门狗振荡器的输出时钟频率为: wdt_ OSC_ clk = 1.6MHz/2x (1+0) =800kHz
系统振荡器控制寄存器SYSOSCCTRL
系统振荡器控制寄存器用于配置系统振荡器的频率范围。
?PLL工作原理与使用
LPC1100系列微型控制器利用PLL来为内核以及外设提供时钟信号
●?PLL时钟源的选择在SYSPLLCLKSEL寄存器中设置,PLL将输入时钟升频,然后再分频以提供CPU及芯片外设所使用的实际时钟。PLL可产生的时钟频率最可达50MHz,这也是CPU的最高工作频率。 ●PLL接受的输入时钟频率范围为10MHz~25MHz,输入时钟直接馈送到"相位频率检测”部件,该部件会比较两个输出信号的相位和频率,并根据误差输出不同的电流值来控制CCO的振荡频率。 ●通常CCO的输出频率是有限的,超出这个范围则无法输出预期的时钟信号。LPC1100系列微控制器内部的CCO可工作在156MHz ~ 320MHz。
PLL频率计算中的公式
●FCLKouτ= M x FCLKIN = FCCO / (2xP) ●为了选择合适的M和P值,推荐如下步骤: ●指定输入时钟频率FCLKIN ; ●计算M值以获得所需的输出频率FCLKOUT1,M=FCLKOUT/?FcLKIN; ●找出一个值使得Fcco=2xPx FCLKOUT; ●检查所有的频率和分频器值设置,是否符合系统PLL控制寄存器(SYSPLLCTRL)位功能描述内的限定。 ●在PLL的输入时钟频率范围为10MHz~25MHz下,允许M值的范围为1~32,这是支持主振荡器和IRC操作的整个M值的范围。
例如:输出频率48MHZ,输入频率12MHZ
此时M为4;
FCCO可为192MHZ;
此时P为2;
PLL初始化步骤
●如果选择主振荡器作为PLL的输入时钟源,则在PDRUNCFG中对主振荡器先.上电; ●在系统PLL时钟源选择寄存器中选择作为PLL输入的时钟源,主振荡器或IRC振荡器; ●写系统PLL时钟源更新使能寄存器,使系统PLL时钟源选择有效; ●在系统PLL控制寄存器中写计算好的M和P值; ●在PDRUNCFG中对系统PLL上电,并等待PLL信号锁定; ●在主时钟源选择寄存器中选择PLL时钟作为系统的时钟; ●写主时钟源选择更新使能寄存器,使主时钟源选择系统PLL时钟输出有效。
●系统PLL控制寄存器连接并使能系统PLL、配置PLL倍频器和分频值。
系统初始化函数void Systemlnit (void)
●CMSIS在文件system_ LPC11xx. c中定义了LPC1100的系统初始化函数void Systemlnit (void), 在函数中对系统主时钟进行了配置,启动文件startup_ LPC11xx. s在复位后直接调用了该函数完成了系统初始化,系统时钟被设置为48MHz,然后跳转到main函数。
void SystemInit (void) {
volatile uint32_t i;
#if (CLOCK_SETUP) /* Clock Setup */
#if ((SYSPLLCLKSEL_Val & 0x03) == 1)
LPC_SYSCON->PDRUNCFG &= ~(1 << 5); /* Power-up System Osc */
LPC_SYSCON->SYSOSCCTRL = SYSOSCCTRL_Val;
for (i = 0; i < 200; i++) __NOP();
#endif
LPC_SYSCON->SYSPLLCLKSEL = SYSPLLCLKSEL_Val; /* Select PLL Input */
LPC_SYSCON->SYSPLLCLKUEN = 0x01; /* Update Clock Source */
LPC_SYSCON->SYSPLLCLKUEN = 0x00; /* Toggle Update Register */
LPC_SYSCON->SYSPLLCLKUEN = 0x01;
while (!(LPC_SYSCON->SYSPLLCLKUEN & 0x01)); /* Wait Until Updated */
#if ((MAINCLKSEL_Val & 0x03) == 3) /* Main Clock is PLL Out */
LPC_SYSCON->SYSPLLCTRL = SYSPLLCTRL_Val;
LPC_SYSCON->PDRUNCFG &= ~(1 << 7); /* Power-up SYSPLL */
while (!(LPC_SYSCON->SYSPLLSTAT & 0x01)); /* Wait Until PLL Locked */
#endif
#if (((MAINCLKSEL_Val & 0x03) == 2) )
LPC_SYSCON->WDTOSCCTRL = WDTOSCCTRL_Val;
LPC_SYSCON->PDRUNCFG &= ~(1 << 6); /* Power-up WDT Clock */
for (i = 0; i < 200; i++) __NOP();
#endif
LPC_SYSCON->MAINCLKSEL = MAINCLKSEL_Val; /* Select PLL Clock Output */
LPC_SYSCON->MAINCLKUEN = 0x01; /* Update MCLK Clock Source */
LPC_SYSCON->MAINCLKUEN = 0x00; /* Toggle Update Register */
LPC_SYSCON->MAINCLKUEN = 0x01;
while (!(LPC_SYSCON->MAINCLKUEN & 0x01)); /* Wait Until Updated */
LPC_SYSCON->SYSAHBCLKDIV = SYSAHBCLKDIV_Val;
#endif
}
void SystemCoreClockU pdate (void)函数
●CMSIS在文件system_ LPC11xx.c中定义了一 -个全局变量SystemCoreClock和一-个函数void SystemCoreClockUpdate(void),用来获得当前处理器的工作频率,用户程序可以直接使用该变量。 ●用户程序每次在时钟配置完成之后,需要调用这个函数来更新SystemCoreClock变量"(CCLK),否则在使用.SystemCoreClock变量时可能会导致错误。 ●uint32_ t SystemCoreClock =__ SYSTEM_ CLOCK; ●/*!< System Clock Frequency (Core Clock)*/
void SystemCoreClockUpdate (void) /* Get Core Clock Frequency */
{
uint32_t wdt_osc = 0;
/* Determine clock frequency according to clock register values */
switch ((LPC_SYSCON->WDTOSCCTRL >> 5) & 0x0F) {
case 0: wdt_osc = 0; break;
case 1: wdt_osc = 500000; break;
case 2: wdt_osc = 800000; break;
case 3: wdt_osc = 1100000; break;
case 4: wdt_osc = 1400000; break;
case 5: wdt_osc = 1600000; break;
case 6: wdt_osc = 1800000; break;
case 7: wdt_osc = 2000000; break;
case 8: wdt_osc = 2200000; break;
case 9: wdt_osc = 2400000; break;
case 10: wdt_osc = 2600000; break;
case 11: wdt_osc = 2700000; break;
case 12: wdt_osc = 2900000; break;
case 13: wdt_osc = 3100000; break;
case 14: wdt_osc = 3200000; break;
case 15: wdt_osc = 3400000; break;
}
wdt_osc /= ((LPC_SYSCON->WDTOSCCTRL & 0x1F) << 1) + 2;
switch (LPC_SYSCON->MAINCLKSEL & 0x03) {
case 0: /* Internal RC oscillator */
SystemCoreClock = __IRC_OSC_CLK;
break;
case 1: /* Input Clock to System PLL */
switch (LPC_SYSCON->SYSPLLCLKSEL & 0x03) {
case 0: /* Internal RC oscillator */
SystemCoreClock = __IRC_OSC_CLK;
break;
case 1: /* System oscillator */
SystemCoreClock = __SYS_OSC_CLK;
break;
case 2: /* Reserved */
case 3: /* Reserved */
SystemCoreClock = 0;
break;
}
break;
case 2: /* WDT Oscillator */
SystemCoreClock = wdt_osc;
break;
case 3: /* System PLL Clock Out */
switch (LPC_SYSCON->SYSPLLCLKSEL & 0x03) {
case 0: /* Internal RC oscillator */
if (LPC_SYSCON->SYSPLLCTRL & 0x180) {
SystemCoreClock = __IRC_OSC_CLK;
} else {
SystemCoreClock = __IRC_OSC_CLK * ((LPC_SYSCON->SYSPLLCTRL & 0x01F) + 1);
}
break;
case 1: /* System oscillator */
if (LPC_SYSCON->SYSPLLCTRL & 0x180) {
SystemCoreClock = __SYS_OSC_CLK;
} else {
SystemCoreClock = __SYS_OSC_CLK * ((LPC_SYSCON->SYSPLLCTRL & 0x01F) + 1);
}
break;
case 2: /* Reserved */
case 3: /* Reserved */
SystemCoreClock = 0;
break;
}
break;
}
SystemCoreClock /= LPC_SYSCON->SYSAHBCLKDIV;
}
LPC1100时钟产生单元(初始化后)
?小问题:如何降低系统工作频率为24MHz?
笔者认为:
1.选择合适的M和P值
2.重新调用这个函数来更新SystemCoreClock变量
? ? ? 🔥《嵌入式系统开发》系列专栏主要以LPC1100系列微控制器为硬件平台,详细介绍Cortex—-M0微控制器的原理与开发技术,基于keil仿真软件平台设计最小应用系统板和具有在板仿真器的口袋开发板以及相关例程。
? ? ? 🔥本文已收录于嵌入式系统开发系列专栏:嵌入式系统开发 欢迎订阅,持续更新。
|