天天看點

ARM裸機 - 定時器簡介,看門狗定時器

1.什麼是定時器(timer)

定時器/計數器作為SoC的外設,主要用來實作定時執行代碼的功能。

定時器可以讓SoC在執行主程式的同時,可以(通過定時器)具有計時功能,到了一定時間(計時結束)後,定時器會産生中斷提醒CPU,CPU會去進行中斷并執行定時器中斷的ISR。進而去執行預先設定好的事件。

定時時間是由2個東西共同決定的:一個是TCNT中的計數值,一個是時鐘周期。

定時器内部有1個寄存器TCNT,計時開始時我們會把一個總的計數值(譬如說300)放入TCNT寄存器中,然後每隔一個時鐘周期(假設為1ms)TCNT中的值會自動減1(硬體自動完成,不需要CPU軟體去幹預),直到TCNT中減為0的時候,TCNT就會觸發定時器中斷。

2.S5PV210中的定時器

PWM定時器:

這種是最常用的,像簡單單片機(譬如51單片機)中的定時器也是這類,一般SoC中産生PWM信号都是靠這個定時器子產品的。

系統定時器:

系統定時器稱為systick,系統定時器也是用來産生固定時間間隔(TCNT×時鐘周期)信号的。

一般做作業系統移植的時候,這裡不會由我們自己來做,一般原廠提供的基礎移植部分就已經包含了。

看門狗定時器:

看門狗定時器可以選擇發出複位信号複位CPU,在實踐中應用很多,尤其是工業領域(環境複雜、幹擾多)機器容易出問題,此時一般都會用看門狗來進行系統複位。

實時時鐘RTC(real time clock):

定時器關注的是時間段(而不是時間點),定時器計時從開啟定時器的那一刻開始,到定的時間段結束為止産生中斷;RTC中工作用的是時間點(xx年x月x日x時x分x秒星期x)。

RTC和定時器的差別,就相當于是鐘表和鬧鐘的差別。

3.看門狗定時器

結構框圖:

ARM裸機 - 定時器簡介,看門狗定時器

幾個主要寄存器: 

WTCON :

ARM裸機 - 定時器簡介,看門狗定時器

WTDAT :

ARM裸機 - 定時器簡介,看門狗定時器

 WTCNT:

ARM裸機 - 定時器簡介,看門狗定時器

WTCLRINT:

ARM裸機 - 定時器簡介,看門狗定時器

4.代碼實作

#define		WTCON		(0xE2700000)
#define		WTDAT		(0xE2700004)
#define		WTCNT		(0xE2700008)
#define 	WTCLRINT	(0xE270000C)

#define 	rWTCON		(*(volatile unsigned int *)WTCON)
#define 	rWTDAT		(*(volatile unsigned int *)WTDAT)
#define 	rWTCNT		(*(volatile unsigned int *)WTCNT)
#define 	rWTCLRINT	(*(volatile unsigned int *)WTCLRINT)


// 初始化WDT使之可以産生中斷
void wdt_init_interrupt(void)
{
	// 第一步,設定好預分頻器和分頻器,得到時鐘周期是128us
	rWTCON &= ~(0xff<<8);
	rWTCON |= (65<<8);				// 1MHz
	
	rWTCON &= ~(3<<3);
	rWTCON |= (3<<3);				// 1/128 MHz, T = 128us
	
	// 第二步,設定中斷和複位信号的使能或禁止
	rWTCON |= (1<<2);				// enable wdt interrupt
	rWTCON &= ~(1<<0);				// disable wdt reset
	
	// 第三步,設定定時時間
	// WDT定時計數個數,最終定時時間為這裡的值×時鐘周期
	//rWTDAT = 10000;					// 定時1.28s
	//rWTCNT = 10000;					// 定時1.28s
	
	// 其實WTDAT中的值不會自動刷到WTCNT中去,如果不顯式設定WTCON中的值,它的值就是
	// 預設值,然後以這個預設值開始計數,是以這個時間比較久。如果我們自己顯式的
	// 設定了WTCNT和WTDAT一樣的值,則第一次的定時值就和後面的一樣了。
	rWTDAT = 1000;					// 定時0.128s
	//rWTCNT = 1000;					// 定時0.128s
	
	// 第四步,先把所有寄存器都設定好之後,再去開看門狗
	rWTCON |= (1<<5);				// enable wdt
}


// wdt的中斷處理程式
void isr_wdt(void)
{
	static int i = 0;
	// 看門狗定時器時間到了時候應該做的有意義的事情
	printf("wdt interrupt, i = %d...", i++);
	
	// 清中斷
	intc_clearvectaddr();
	rWTCLRINT = 1;
}