JZ2440開發板:修改ARM芯片時鐘(學習筆記)
想要修改ARM芯片的時鐘,需要去查詢芯片手冊和原理圖,獲取相關的信息(見下方圖片)
首先來看時鐘的結構圖

根據結構圖可以看出,時鐘源有兩種選擇:1. XTIpll和XTOpll所連接的晶振
2. EXTCLK引腳外接一個時鐘源
OM[3:2]用來選擇到底使用哪個時鐘源

再查看原理圖,可以發現:OM3和OM2硬件上都是接GND,所以可以知道:采用12MHz晶振作為時鐘源


閱讀芯片手冊,還可以查詢到其他寄存器的相關信息,見下圖:

JZ2440內部使用三種時鐘:
FCLK: 用于ARM920T芯片,即CPU
HCLK:通過AHB總線,提供給ARM920T芯片、內存控制器,中斷控制器,LCD控制器等等
PCLK: 通過APB總線,提供給一些外圍設備使用,如WDT,IIS,I2C等等
FCLK通過HDIVN分頻得到HCLK,通過PDIVN分頻得到PCLK,這里設置FCLK:HCLK:PCLK=400MHz : 100MHz : 50Hz
1、修改MPLLCON寄存器中MDIV ,PDIV ,SDIV的值為92 ,1 ,1,可以得到FCLK為400MHz
2、修改CLKDIVN中,HDIVN和PDIVN分別為0b10和1,使得HCLK=FCLK/4 , PCLK=HCLK/2


閱讀芯片手冊中,晶振作為時鐘源的時序圖,可以發現,當配置PLL時,會有一個LOCKTIME時間,用來等待輸出的FCLK頻率穩定

在這里,不對LOCKTIME進行修改,仍然使用它的默認值0xFFFFFFFF

繼續閱讀芯片手冊,有一個備注信息:
當HDIVN不是0且CPU工作于快速總線模式的時候,CPU會采用HCLK作為它的時鐘頻率,
因此如果想讓HDIVN修改后,CPU采用FCLK,必須添加下方代碼,讓CPU工作于異步模式
mrc p15,0,r0,c1,c0,0
orr r0,r0,#R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0
【代碼 #R1_nF:OR:R1_iA 的意思】———— 點我

對時鐘修改的分析就大致差不多了,接下來寫匯編文件實現要求
.text .global _start _start: /* 關閉看門狗,如果不關閉,系統會自動重啟 */ ldr r0,=0x53000000 ldr r1,=0 str r1,[r0] /* 修改時鐘,FCLK=400MHz,HCLK=100MHz,PCLK=50MHz */ /* 設置配置MPLL時的LOCKTIME時間為默認值 */ ldr r0,=0x4c000000 ldr r1,=0xFFFFFFFF str r1,[r0] /* 設置FCLK:HCLK:PCLK=8:2:1 */ ldr r0,=0x4c000014 ldr r1,=0x5 str r1,[r0] /* 設置CPU工作于異步模式 ** 如果不作此設置,當HDIVN不是0時,CPU會采用HCLK的頻率而不是采用FCLK的頻率 */ mrc p15,0,r0,c1,c0,0 orr r0,r0,#0xc0000000 // #R1_nF:OR:R1_iA等價于#0xc0000000 mcr p15,0,r0,c1,c0,0 /* 設置MPLL的PMS,使得FCLK=400MHz ** m = MDIV+8 = 92+8=100 ** p = PDIV+2 = 1+2 = 3 ** s = SDIV = 1 ** FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400MHz */ ldr r0,=0x4C000004 ldr r1,=(92<<12)|(1<<4)|(1<<0) str r1,[r0] /* 設置好PLL之后,就會鎖定lock time,直到PLL穩定輸出 */ /* cpu會工作于新的頻率FCLK /* 判斷是nor啟動還是nand啟動 ** 先把0地址原來的值讀取出來,保存到r0寄存器中 ** 再把0寫入0地址對應的內存單元,之后讀取0地址內存單元的值 ** 如果讀取出來的值與原來的值不一致,說明是nor啟動 ** 如果讀取出來的值與原來的值一致,說明是nand啟動,此時需要修改棧的地址 */ mov r1,#0 ldr r0,[r1] // 讀取原來的值,備份一下 str r1,[r1] // 把0寫入0地址 ldr r2,[r1] // 讀取0地址新的值 cmp r2,r0 // 如果r0和r2的值一樣,說明是nand啟動,此時修改sp的值 /* 設置棧:sp */ ldr sp,=0x40000000+4096 // 先默認nor啟動// moveq sp,#4096 // 如果r2=r1,把4096傳給sp,改為nand啟動 streq r0,[r1] // 如果r2=r1,恢復0地址原來的值 bl main // 跳轉到main函數 halt: b halt // 不停的跳轉到halt,相當于死循環,方便觀察效果
另外再附上JZ2440開發板3盞LED燈循環點亮的C程序(和按鍵點亮LED燈需要知道的知識差不多,這里不再作分析),用來觀察時鐘修改后的效果
#include "s3c2440_soc.h" void delay(volatile int d) //延時函數 { while(d--); } int main(void) { /*設置GPFCON的GPF4/5/6,讓它們變成輸出引腳*/ GPFCON &=~((3<<8)|(3<<10)|(3<<12)); //先讓GPFCON的GPF4/5/6清零 GPFCON |=((1<<8)|(1<<10)|(1<<12)); //配置好GPFCON的GPF4/5/6,讓它們變成輸出引腳 /*循環點亮3盞燈*/ int val=0,tmp; //val取值范圍0b000~0b111,剛好三盞燈 while(1) { tmp=~val; //因為val為0的時候,燈會由亮到滅,所以這里需要取反,才能讓燈從滅到亮 tmp &=7; //只需要三位的值就好了 GPFDAT &=~(7<<4); //GPFDAT寄存器先清零,因為是4,5,6位,所以這里7左移4位就可以 GPFDAT |=(tmp<<4); delay(100000); //加上一個延時,不然燈切換太快了,看不出來 val++; if(val==8) { val=0; } } return 0; }
上傳到 linux,編譯得到 led.bin文件,燒寫到開發板之后,發現LED燈切換得比以前快多了,因為CPU是400MHz了,ARM芯片時鐘修改成功。

浙公網安備 33010602011771號