要讓LPC824正常工作,首先要對它的時鍾源進行配置。LPC824的最高工作頻率為30MHz,因此給它的主時鍾頻率最大不能超過30MHz。實際上,通常都是使用頻率較低的晶振,以降低外部電磁干擾,然后再通過內部倍頻的方式把主時鍾頻率提高。根據管方手冊給出的數據,外部晶振的頻率范圍是1MHz~25MHz,一般情況下使用12MHz晶振,然后內部進行2倍頻,主時鍾工作頻率為24MHz。
要對LPC824的時鍾進行配置,必須要了解它的時鍾結構,先來看一下它的時鍾結構圖,如下圖所示。
首先來看主時鍾,給主時鍾(main clock)提供選擇有4個源,分別是:內部RC振盪器、未倍頻之前的PLL時鍾、內部看門狗時鍾、經過PLL倍頻之后的時鍾。由對主時鍾源選擇寄存器(MAINCLKSEL)的操作來進行選擇,同一時刻只能選擇一種時鍾做為主時鍾。
下表給出了主時鍾源選擇寄存器MAINCLKSEL的全部位結構,其字節地址為0x40048070。注意,由於LPC824是32位微控制器,所以它內部的寄存器全都是32位的。
(1)第0、1兩位(SEL)為主時鍾源選擇位,這兩位的值從0x0到0x3,分別對應選擇內部RC時鍾、未倍頻之前的PLL時鍾、內部看門狗時鍾、經過PLL倍頻之后的時鍾。
(2)第2到31位為保留位。
一般情況下都會選擇系統PLL倍頻后的時鍾作為主時鍾,因此大多數時候MAINCLKSEL寄存器的值都會選擇0x3(執行語句“LPC_SYSCON->MAINCLKSEL=0x00000003”)。
接下來看系統PLL時鍾,PLL(Phase Locked Loop)即鎖相環,它的功能很多,這里主要利用它來實現倍頻的功能。從時鍾結構圖中可以看出,供給PLL選擇的有3個源,一個是片內RC振盪器,另一個是系統振盪器,再一個是外部輸入。通過對系統PLL時鍾選擇寄存器的操作可進行選擇,但同一時刻只能選擇一種時鍾作為輸入時鍾。
下表給出了系統PLL時鍾選擇寄存器SYSPLLCLKSEL的全部位結構,其字節地址為0x40048040。
(1)第0、1兩位(SEL)為系統PLL時鍾源選擇位,值為0x0時選擇內部RC時鍾,值為0x1時選擇系統振盪時鍾(即外部晶振),值為0x3時選擇外部時鍾輸入,其他值為保留。
(2)第2到31位為保留位。
為了提高LPC824的時鍾精度,一般情況下SYSPLLCLKSEL寄存器的值會選擇0x1(執行語句“LCP_SYSCON->SYSPLLCLKSEL=0x00000001”),以選擇外部晶體振盪器作為時鍾輸入。
從時鍾結構圖中可以看到,主時鍾分成4路供給不同的模塊。其中一路主時鍾經過系統AHB時鍾分頻選擇(SYSAHBCLKDIV)后作為系統時鍾提供給AHB。在LPC824中,只有高速設備(如GPIO、SRAM等)才需要AHB。為了給不同速度的模塊(如內核、存儲、APB等)提供時鍾,需要對系統AHB時鍾分頻選擇寄存器進行操作,以對主時鍾進行分頻。
下表給出了系統AHB時鍾分頻選擇寄存器SYSAHBCLKDIV的全部位結構,其字節地址為0x40048078。
(1)第0到7位(DIV)為系統AHB時鍾選擇位,值為0時禁止系統時鍾,其他值為AHB時鍾的分頻值。
(2)第8到31位為保留位。
從表中可以看到,AHB時鍾分頻的最大值為255。系統的默認值為1(也可執行語句“LPC_SYSCON->SYSAHBCLKDIV=0x00000001”來實現),即為AHB提供不分頻的主時鍾。剩余3個模塊(USART、IOCON、CLKOUT)的時鍾也一樣由主時鍾來分頻,只不過它們默認的分頻值為0,即默認不提供時鍾,也就是說剩余的3個模塊在默認狀態下不工作,需要的時候再通過程序打開,以降低功耗。
下表給出的是掉電配置寄存器PDRUNCFG的全部位結構,其字節地址為0x40048238。
(1)第0位(IRCOUT_PD)為內部RC振盪器輸出掉電控制位,置0時上電,置1時掉電,默認為上電。
(2)第1位(IRC_PD)為內部RC振盪器掉電控制位,置0時上電,置1時掉電,默認為上電。
(3)第2位(FLASH_PD)為FLASH掉電控制位,置0時上電,置1時掉電,默認為上電。
(4)第3位(BOD_PD)為BOD掉電控制位,置0時上電,置1時掉電,默認為上電。
(5)第4位(ADC_PD)為ADC掉電控制位,置0時上電,置1時掉電,默認為掉電。
(6)第5位(SYSOSC_PD)為系統振盪器掉電控制位,置0時上電,置1時掉電,默認為掉電。
(7)第6位(WDTOSC_PD)為看門狗振盪器掉電控制位,置0時上電,置1時掉電,默認為掉電。
(8)第7位(SYSPLL_PD)為系統PLL掉電控制位,置0時上電,置1時掉電,默認為掉電。
(9)第8到14位為保留位,但它們有默認值,在對這些位進行寫入操作時,必須按照默認值來寫。
(10)第15位(ACMP)為模擬比較器掉電控制位,置0時上電,置1時掉電,默認為掉電。
(11)第16到31位為保留位。
從上表中可以看出,系統振盪器和系統PLL在默認情況下是掉電的,也就是說默認狀態下它們處於不工作狀態,要讓它們工作就必須給它們的控制位置0(執行語句“LPC_SYSCON->PDRUNCFG &= ~(1 << 5)”和“LCP_SYSCON->PDRUNCFG &= ~(1 << 7)”),以更改為上電狀態。
下表給出了系統振盪器控制寄存器SYSOSCCTRL的全部位結構,其字節地址為0x40048020。
(1)第0位(BYPASS)為系統振盪器旁路控制位,置0時未旁路,置1時被旁路,默認為未旁路。
(2)第1位(FREQRANGE)為低功耗振盪器確定頻率范圍選擇位,置0時外部晶振的頻率范圍為1~20MHz,置1時為15~20MHz,默認為1~20MHz。
(3)第2到31位為保留位。
從上表中可以看出,如果要讓系統振盪器工作,則SYSOSCCTRL寄存器的第0位就應該選擇0,即不被旁路,只有從外部直接輸入振盪信號的情況下才會選擇旁路(比如使用有源晶振)。若系統使用12MHz外部晶振,則第1位應該選擇0。實際上LPC824復位后的值就是該配置值,當然也可執行語句“LCP_SYSCON->SYSOSCCTRL = 0x00000000”來實現。
在配置了LPC824的時鍾之后(無論是PLL時鍾還是主時鍾),都需要“更新”一下才能正常工作。根據官方數據手冊,更新操作要給相應的更新允許寄存器進行“toggle”操作(即先向其寫0再緊接着寫1),這樣之后時鍾才能正常運行。
以下兩表分別給出了系統PLL時鍾源更新允許寄存器SYSPLLCLKUEN和主時鍾源更新允許寄存器MAINCLKUEN的全部位結構,它們的字節地址分別為0x40048044、0x40048074。
(1)第0位(ENA)為允許系統PLL時鍾源更新控制位,置0時無變化,置1時更新,默認為無變化。
(2)第1到31位為保留位。
(1)第0位(ENA)為允許主時鍾源更新控制位,置0時無變化,置1時更新,默認為無變化。
(2)第1到31位為保留位。
在PLL時鍾源和主時鍾源更改后,緊接着要及時更新相應的允許寄存器才能讓它們正常工作。此外還要注意,“toggle”后需要再次查詢相應的允許寄存器是否已更新,若沒有就需要等待直到其更新為止(例如在更新PLL時鍾源更新允許寄存器SYSPLLCLKUEN后要執行語句“while (!(LPC_SYSCON->SYSPLLCLKUEN & 0x01));”,以等待其更新完成)。
接下看PLL的配置,要讓PLL對輸入時鍾進行倍頻或分頻,就得配置系統倍頻控制寄存器,下表給出了系統倍頻控制寄存器SYSPLLCTRL的全部位結構,其字節地址為0x40048008。
(1)第0到4位(MSEL)為反饋分頻器的值,分頻器的值M為MSEL+1。
(2)第5、6兩位(PSEL)為后分頻器的值,分頻器的值為2×P。
(3)第7到31位為保留位,不能對它們寫1。
PLL的輸出頻率要符合下面的公式:
上式中,Fclkout為PLL的輸出頻率,Fclkin為外部晶振的頻率,FCCO的值必須在156MHz ~320MHz之間,M為倍頻的倍數,P值要符合要求。若以12MHz的晶振做為輸入,系統主時鍾要為24MHz,則M=2(MSEL=00001),P的值只能取4(PSEL=10)才能滿足公式要求。因此寄存器SYSPLLCTRL的值應該為1000001(0x41),所以要配置此項可執行語句“LPC_SYSCON->SYSPLLCTRL = 0x00000041”。
下表給出了倍頻狀態寄存器SYSPLLSTAT的全部位結構,其字節地址為0x4004800C。
(1)第0位(LOCK)為PLL鎖定狀態標志位,為0時未鎖定,為1時鎖定。
(2)第1到31位為保留位。
在改變了PLL的倍頻之后,要查詢SYSPLLSTAT寄存器來確定PLL鎖定了沒有,若沒有就進入等待直到其鎖定為止(執行語句“while (!(LPC_SYSCON->SYSPLLSTAT & 0x01));”)。
CPU要對GPIO進行操作,就必須給GPIO時鍾信號,即需要使能GPIO的時鍾。在默認情況下GPIO時鍾是允許的,也可以對系統AHB時鍾控制寄存器中相應的位進行操作來選擇允許時鍾。
下表給出了系統AHB時鍾控制寄存器SYSAHBCLKCTRL的全部位結構,其字節地址為0x40048080。
(1)第0位(SYS)為允許AHB時鍾標志位,該位為只讀,值為0時保留,為1時允許,默認為允許。
(2)第1位(ROM)為允許ROM時鍾控制位,置0時禁止,置1時允許,默認為允許。
(3)第2位(RAM0_1)為允許SRAM0和SRAM1時鍾控制位,置0時禁止,置1時允許,默認為允許。
(4)第3位(FLASHREG)為允許flash寄存器接口時鍾控制位,置0時禁止,置1時允許,默認為允許。
(5)第4位(FLASH)為允許flash時鍾控制位,置0時上電禁止,置1時允許,默認為允許。
(6)第5位(I2C0)為允許I2C0時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(7)第6位(GPIO)為允許GPIO時鍾控制位,置0時禁止,置1時允許,默認為允許。
(8)第7位(SWM)為允許開關矩陣時鍾控制位,置0時禁止,置1時允許,默認為允許。
(9)第8位(SCT)為允許配置SCTimer/PWM時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(10)第9位(WKT)為允許自喚醒定時器時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(11)第10位(MRT)為允許多速率定時器時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(12)第11位(SPI0)為允許SPI0時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(13)第12位(SPI1)為允許SPI1時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(14)第13位(CRC)為允許CRC時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(15)第14位(UART0)為允許USART0時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(16)第15位(UART1)為允許USART1時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(17)第16位(UART2)為允許USART2時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(18)第17位(WWDT)為允許WWDT時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(19)第18位(IOCON)為允許IOCON時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(20)第19位(ACMP)為允許模擬比較器時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(21)第20位為保留位。
(22)第21位(I2C1)為允許I2C1時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(23)第22位(I2C2)為允許I2C2時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(24)第23位(I2C3)為允許I2C3時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(25)第24位(ADC)為允許ADC時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(26)第25位為保留位。
(27)第26位(MTB)為允許微跟蹤緩沖區控制寄存器時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(28)第27、28兩位為保留位。
(29)第29位(DMA)為允許DMA時鍾控制位,置0時禁止,置1時允許,默認為禁止。
(30)第30、31兩位為保留位。
從上表中可以看出,第6位即為“通用輸入輸出端口GPIO”的時鍾配置項,執行語句“LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6)”就可以開啟GPIO的時鍾。在打開了GPIO的時鍾后,PIO0_0~PIO0_28端口才能正常使用,不過默認狀態就是開啟的。
由上述可見,基於Cortex-M0+內核的微控制器由於強化了時鍾配置,所以在一般情況下使用該類型的芯片,首要的任務就是配置正確的時鍾。
下面給出一個時鍾初始化的配置函數,可通過它來了解LPC824時鍾配置的整個過程。
void SysCLK_config(void)
{
uint8_t i;
LPC_SYSCON->PDRUNCFG &= ~(1 << 5); //給系統振盪器上電
LPC_SYSCON->SYSOSCCTRL = 0x00000000; //系統振盪器未旁路,1~12MHz輸入
for (i = 0; i < 200; i++) __nop(); //延時等待振盪器穩定
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 18); //使能IOCON時鍾
LPC_IOCON->PIO0_8 &= ~(3 << 3); //把P0_8引腳配置為無上下拉電阻方式
LPC_IOCON->PIO0_9 &= ~(3 << 3); //把P0_9引腳配置為無上下拉電阻方式
LPC_SWM->PINENABLE0 &= ~(3 << 6); //把P0_8、P_9引腳配置為XTALIN、XTALOUT引腳
LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 18); //禁止IOCON時鍾
LPC_SYSCON->SYSPLLCLKSEL = 0x00000001; //PLL輸入選擇外部晶體振盪
LPC_SYSCON->SYSPLLCLKUEN = 0x00;
LPC_SYSCON->SYSPLLCLKUEN = 0x01; //先寫0后寫1更新時鍾源
while (!(LPC_SYSCON->SYSPLLCLKUEN & 0x01)); //等待更新完成
LPC_SYSCON->SYSPLLCTRL = 0x00000041; //M=2、P=4,倍頻后的時鍾為24MHz
LPC_SYSCON->PDRUNCFG &= ~(1 << 7); //給PLL上電
while (!(LPC_SYSCON->SYSPLLSTAT & 0x01)); //等待PLL鎖定
LPC_SYSCON->MAINCLKSEL = 0x00000003; //主時鍾選擇PLL倍頻后的時鍾
LPC_SYSCON->MAINCLKUEN = 0x00;
LPC_SYSCON->MAINCLKUEN = 0x01; //先寫0后寫1更新時鍾源
while (!(LPC_SYSCON->MAINCLKUEN & 0x01)); //等待更新完成
LPC_SYSCON->SYSAHBCLKDIV = 0x00000001; //AHB為1分頻,AHB時鍾為24MHz
在上述配置中,系統外部時鍾晶振為12MHz,則在該函數執行完后,LPC824時鍾就會被設置為主時鍾24MHz,AHB時鍾24MHz。另外,由於在默認狀態下,LPC824的PIO0_8和PIO0_9兩個引腳是GPIO功能,所以要連接外部晶振先要把它們配置為XTALIN、XTALOUT引腳,否則芯片不能正常工作。
上述時鍾配置程序是最基本的,也是必須的,因此在任何程序開始前,都應該先調用該時鍾配置函數,以對LPC824進行基本的時鍾配置,為后續程序提供保障。另外,系統的主時鍾也可以由內部RC時鍾或看門狗時鍾來充當,這將會在后面再討論。