關於時鐘體系和各類時鐘部件

寫在前面:覺得這章比較簡單,沒有花較大篇幅來講,很多寄存器的相關用法可以參照S3C2440的官方手冊,很容易看懂
1系統時鐘
(1) FCLK:用於CPU核
HCLK:用於AHB總線上設備:CPU核、存儲器控制器、中斷控制器、LCD控制器、DMA和USB主機模塊
PCLK:用於APB總線上設備:WATCHDOG、IIS、I2C、PWM定時器、MMC接口、ADC、UART、GPIO、RTC和SPI
(2 )開發板時鐘頻率爲12 MHZ,通過PLL提高系統時鐘:MPLL和UPLL(S3C2440);UPLL用於USB設備,MPLL用於FCLK、HCLK、PLCK
(3 )上電→FCLK=Fin(外部輸入時鐘)→設置MPLL(Lock Time:長短由寄存器LOCKTIME設定)→新的時鐘輸出正常
(4)幾個重要寄存器
MPLLCON寄存器用於設置FCLK與Fin的倍數
CLKDIVN寄存器用於設置FCLK、HCLK、PCLK三者的比例
2 PWM定時器
(1)5個16位的定時器,其中定時器0、1、2、3有PWM功能,即它們都有一個輸出引腳,可以通過定時器來控制引腳週期性的高、低電平變化;定時器4沒有輸出引腳
(2)PLCK→2個8位預分頻器(定時器0、1共用第一個定時器2、3、4共用第二個;輸出2分頻,4分頻,8分頻,16分頻或者外部時鐘TCLK0/TCLK1)
TCFG0:經過分頻器出來的時鐘頻率:PLCK/(TCFG0或TCFG0+1)
TCFG1設定相應定時器爲經過分頻器出來的時鐘頻率的幾分頻
定時器工作頻率= PLCK/(TCFG0或TCFG0+1)/幾分頻
(3)TCMPn=TCMPBn,TCNTn=TCNTBn→while(TCNTn==TCMPn) ~TOUTn →while(TCNTn==0) ~TOUTn,並觸發中斷(若中斷使能的話),且如果在TCON寄存器中將定時器設爲“自動加載”,則TCMPn=TCMPBn,TCNTn=TCNTBn
輸出管腳TOUTn默認爲高電平,可以通過TCON改變,可能通過讀取TCNTOn寄存器得知TCNTn的值
(4)TCON寄存器:使用參考S3C2440手冊
在第一次使用定時器時,要設置“手動更新”位爲1以使TCNTBn/TCMPBn的值裝入內部寄存器TCNTn、TCMPn中,下一次如果還要設置這一位,需要先將其清0
3 WATCHDOG定時器
(1)PLCK→2個8位預分頻器(輸出16分頻,32分頻,64分頻,128分頻或者外部時鐘TCLK0/TCLK1)
初始計數值寫入 WTCNT→while(WTCNT==0)自動重新裝載WTCNT=WTDAT,並可以產生中斷信號,可以輸出復位信號
(2)WATDOG定時器工作頻率=PCLK/(WTCON+1)/幾分頻
大部分功能都在WTCON中設定
(3)在啓動WATDOG定時器前,必須往這個寄存器定入初始計數值
4:MPLL和定時器操作實驗:完整代碼:timer.tar.gz timernoMPLL.tar.gz(使用系統默認的時鐘)
(1) 設置/啓動MPLL
#define S3C2410_MPLL_200MHZ ((0x5c<<12)|(0x04<<4)|(0x00))
#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
/*
* 對於MPLLCON寄存器,爲MDIV,爲PDIV,爲SDIV
* 有如下計算公式:
* S3C2410: MPLL(FCLK) = (m * Fin)/(p * 2^s)
* S3C2410: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)
* 其中: m = MDIV + 8, p = PDIV + 2, s = SDIV
* 對於本開發板,Fin = 12MHz
* 設置CLKDIVN,令分頻比爲:FCLK:HCLK:PCLK=1:2:4,
* FCLK=200MHz,HCLK=100MHz,PCLK=50MHz
*/
void clock_init(void)
{
// LOCKTIME = 0x00ffffff; // 使用默認值即可
CLKDIVN = 0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1

/* 如果HDIVN非0,CPU的總線模式應該從“fast bus mode”變爲“asynchronous bus mode” */
__asm__(
"mrc p15, 0, r1, c1, c0, 0/n" /* 讀出控制寄存器 */
"orr r1, r1, #0xc0000000/n" /* 設置爲“asynchronous bus mode” */
"mcr p15, 0, r1, c1, c0, 0/n" /* 寫入控制寄存器 */
);

/* 判斷是S3C2410還是S3C2440 */
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
{
MPLLCON = S3C2410_MPLL_200MHZ; /* 現在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */
}
else
{
MPLLCON = S3C2440_MPLL_200MHZ; /* 現在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */
}
}
(2) 設置存儲控制器
void memsetup(void)
{
volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;

/* 這個函數之所以這樣賦值,而不是像前面的實驗(比如mmu實驗)那樣將配置值
* 寫在數組中,是因爲要生成”位置無關的代碼”,使得這個函數可以在被複制到
* SDRAM之前就可以在steppingstone中運行
*/
/* 存儲控制器13個寄存器的值 */
p = 0x22011110; //BWSCON
p = 0x00000700; //BANKCON0
p = 0x00000700; //BANKCON1
p = 0x00000700; //BANKCON2
p = 0x00000700; //BANKCON3
p = 0x00000700; //BANKCON4
p = 0x00000700; //BANKCON5
p = 0x00018005; //BANKCON6
p = 0x00018005; //BANKCON7

/* REFRESH,
* HCLK=12MHz: 0x008C07A3,
* HCLK=100MHz: 0x008C04F4
*/
p = 0x008C04F4;
/* REFRESH=0x008C0000+R_CNT
R_CNT=2^11+1-SDRAM時鐘頻率(MHZ)*SDRAM刷新週期(uS)
p = 0x000000B1; //BANKSIZE
p = 0x00000030; //MRSRB6
p = 0x00000030; //MRSRB7
}
(3)初始化定時器0
/*
* Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value}
* {prescaler value} = 0~255
* {divider value} = 2, 4, 8, 16
* 本實驗的Timer0的時鐘頻率=100MHz/(99+1)/(16)=62500Hz
* 設置Timer0 0.5秒鐘觸發一次中斷:
*/
void timer0_init(void)
{
TCFG0 = 99; // 預分頻器0 = 99
TCFG1 = 0x03; // 選擇16分頻
TCNTB0 = 31250; // 0.5秒鐘觸發一次中斷
TCON |= (1<<1); // 手動更新
TCON = 0x09; // 自動加載,清“手動更新”位,啓動定時器0
}

(4)定時器中斷使能
/*
* 定時器0中斷使能
*/
void init_irq(void)
{
// 定時器0中斷使能
INTMSK &= (~(1<<10));
}

本文地址:http://baidianfeng.cqdb.net/66869330-1276010585 轉載請註明出處

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章