Exynos4412裸機開發 —— 看門狗定時器
一、看門狗定時器概述
看門狗(WatchDog Timer) 定時器和PWM的定時功能目的不一樣。它的特點是,需要不同的接收訊號(一些外接看門狗晶片)或重新設定計數器,保持計數值不為0。一旦一些時間接收不到訊號,或計數值為0,看門狗將發出復位訊號復位系統或產生中斷。
看門狗的作用是微處理器收到干擾進入錯誤狀態後,使系統在一定時間間隔內復位。因此看門狗是保證系統長期、可靠和穩定執行的有效措施。目前大部分的嵌入式晶片內部都集成了看門狗定時器來提高系統執行的可靠性。
4412處理器的看門狗是當系統被故障干擾時,用於處理器的復位操作,也可以作為一個通用的16位定時器來請求中斷操作。看門狗定時器產生128個PCLK週期的復位訊號。主要特性有如下兩個。
1)通用的中斷方式的16位定時器。
2)當計數器減到0(發生溢位)時,產生128個PCLK週期的復位訊號。
看門狗定時器功能框圖如下:
看門狗模組包括一個預比例因子放大器,一個四分頻的分頻器,一個16位計數器。看門狗的時鐘訊號源來自PCLK,為了得到寬範圍的看麼狗訊號,PCLK先被預分頻,然後再進過分頻器分頻。預分頻比例因子和分頻器的分頻值,都可以由看門狗控制暫存器(WTCON)決定,預分頻比例因子的範圍是0~255,分頻器的分頻比可以是16、32、64或128。看門狗定時器時鐘週期的計算如下:
式中Prescaler value 為預分頻比例放大器的值;Divison_factor是四分頻的分頻比,可以是16、32、64或128.
一旦看門狗定時器被允許,看門狗定時器資料暫存器(WTDAT)的值就不能被自動地裝在到看門狗定時器(WTCNT)中。因此,看門狗啟動前要將一個初始值寫入看門狗計數器(WTCNT)中。當4412用嵌入式ICE除錯時,看門狗定時器的復位功能就不被啟動,看門狗定時器能從CPU核心訊號判斷出當前CPU是否處於除錯狀態。如果看門狗定時器確定當前模式是除錯模式,儘管看門狗產生溢位訊號,但是仍然不會產生復位訊號。
二、看門狗定時器相關定時器
1、看門狗定時器控制暫存器(WTCON)
WTCON暫存器的內容包括:使用者是否啟動看門狗定時器、4個分頻比的選擇、是否允許中斷產生、是否允許復位操作等。
如果使用者想把看門狗定時當做一般定時器使用,應該中斷使能,禁止看門狗定時器復位。
WTCON描述如下:
2、看門狗定時器資料暫存器(WTDAT)
WTDAT用於指定超時時間,在看門狗把復位功能禁止並開啟中斷使能後,此時看門狗定時器就是一個普通的定時器,使用方法和普通定時器一樣。當使用復位功能後,由於WTCNT的值減到0時,系統就會復位,所以WTCNT的值裝不進看門狗計數暫存器(WTCNT)中。復位後初始值為0x8000。WTDAT描述如下:
3、看門狗計數暫存器(WTCNT)
WTCNT包含看門狗定時器工作的時候,計數器的當前計數值。WTCNT描述如下:
三、看門狗定時器的程式編寫
1、看門狗軟體程式設計流程
以為看門狗是對系統地復位或中斷的操作,所以不需要外圍的硬體電路。要實現看門狗的功能,只需要對看門夠的暫存器組進行操作,即對看門狗的控制暫存器(WTCON)、看門狗資料暫存器(WTDAT)、看門狗計數暫存器(WTCNT)的操作。
其一般流程如下:
1)設定看門狗中斷操作,包括全域性中斷和看門狗中斷使能及看門狗中斷向量的定義,如果只是進行復位操作,這一步不用設定。
2)對看門狗控制暫存器(WTCON)的設定,包括設定預分頻比例因子、分頻器的分頻值,中斷使能和復位使能等。
3)對看門狗資料暫存器(WTDAT)和看門狗計數暫存器(WTCNT)的設定。
4)啟動看門狗定時器。
2、具體程式碼如下:
- #include "exynos_4412.h"
- #include "led.h"
- #include "pwm.h"
- void mydelay_ms(int time)
- {
- int i, j;
- while(time--)
- {
- for (i = 0; i < 5; i++)
- for (j = 0; j < 514; j++);
- }
- }
- //*(volatile unsigned int *)(0x11000c20) = 0;
- /*
- * 裸機程式碼,不同於LINUX 應用層, 一定加迴圈控制
- */
- void do_irq(void)
- {
- staticint a = 1;
- int irq_num;
- irq_num = CPU0.ICCIAR&0x3ff; //獲取中斷號
- switch(irq_num)
- {
- case 57:
- printf("in the irq_handler\n");
- EXT_INT41_PEND = EXT_INT41_PEND |((0x1 << 1)); //清GPIO中斷標誌位
- ICDICPR.ICDICPR1 = ICDICPR.ICDICPR1 | (0x1 << 25); //清GIC中斷標誌位
- break;
- case 75:
- printf("in the WDT interrupt!\n");
- WDT.WTCLRINT = 0;
- ICDICPR.ICDICPR2 = ICDICPR.ICDICPR2 | (0x1 << 11); //清GIC中斷標誌位
- break;
- }
- CPU0.ICCEOIR = CPU0.ICCEOIR&(~(0x3ff))|irq_num; //清cpu中斷標誌位
- }
- void wdt_init(void)
- {
- WDT.WTCON = (249 << 8) | (1 << 5) | (1 << 2)|(1 << 0);
- WDT.WTDAT = 25000;
- ICDDCR = 1; //使能分配器
- ICDISER.ICDISER2 = ICDISER.ICDISER2 | (0x1 << 11); //使能相應中斷到分配器
- ICDIPTR.ICDIPTR18 = ICDIPTR.ICDIPTR18 & (~(0xff << 24))|(0x1 << 24); //選擇CPU介面
- CPU0.ICCPMR = 255; //中斷遮蔽優先順序
- CPU0.ICCICR = 1; //使能中斷到CPU
- }
- int main (void)
- {
- wdt_init();
- printf("hello reset!\n");
- while(1)
- {
- WDT.WTCNT = 25000;
- mydelay_ms(100);
- }
- return 0;
- }