針對學習STM32視窗看門狗和原子戰艦所給的WWDG常式時候,存在的問題做如下記錄。 1. WWDG逾時公式推導 1.1 WWDG工作示意圖
1.2 WWDG逾時公式推導
(1) 上視窗的值可以只有設定,7位位元最大隻可以設定為127(0x7F),最小又必須大於下視窗的0x40,所以其取值範圍為64~127(即:0x40~0x7F)
(2) 配置寄存器WWDG->CFR
視窗看門狗的時鐘來自於PCLK1,在時鐘配置中,其頻率為外部時鐘經倍頻器後的二分頻時鐘,即為36MHz
(3)依據上述分析知,視窗時間計算公式為:
上視窗時間: T_min
= (WWDG_CR[6:0] - WWDG_CFR[6:0])/(Tck/(2^WDGTB))(us)
= (WWDG_CR[6:0] - WWDG_CFR[6:0])/((Tpck1/4096)/(2^WDGTB))(us)
= 4096 * (2^WDGTB)*(WWDG_CR[6:0] -WWDG_CFR[6:0])/(72/2) (us)
= 4096 *(2^WDGTB)*(WWDG_CR[6:0] - WWDG_CFR[6:0])/36 (us)
下視窗時間: T_max = 4096 * (2^WDGTB)*(WWDG_CR[6:0] - 0x3F)/36(us)
視窗看門狗的逾時公式(重新整理時間公式):
Twwdg = T_max - T_min
= 4096 *(2^WDGTB)*(WWDG_CFR[6:0] - 0x3F)/36 (us)
= 4096 *(2^WDGTB)*(WWDG_CFR[6:0] - 63)/36 (us)
又因為 WWDG_CFR[6:0]取值範圍是:0~127,
(WWDG_CFR[6:0] –63)>0,
所以,
1<= (WWDG_CFR[6:0] – 63) <= 127-63=64
又因為 一個6位二進位X[5:0]數值範圍是0~63,
1 <= X[5:0]+1 <= 64
所以,
上式可以表述為:
Twwdg = 4096 * (2^WDGTB)*(T[5:0]+1)/36 (us)
(4)依據上式,可以計算出WWDG的定時時間範圍:
WDGTB(計數器分頻值) |
最早喂狗時間/us |
最晚喂狗時間/ms |
0 |
113 |
7.28 |
1 |
227 |
14.56 |
2 |
455 |
29.12 |
3 |
910 |
58.25 |
2. 原子戰艦WWDG庫函數常式存在的問題
2.1 問題描述
正常情況下,燒錄原子戰艦所提供的WWDG庫函數(v3.5)常式,會看到起初紅燈點亮,後熄滅,黃燈開始閃爍。但是,燒錄該程式,只看到紅燈閃爍。這說明了WWDG產生了中斷,但是中斷函數中的黃燈閃爍語句(LED1=~LED1)並沒有執行。 2.2 問題解決
針對上述問題描述,可排除WWDG初始化錯誤的問題(因為紅燈LED0在閃爍,說明WWDG已經產生的複位),定位到中斷初始化失敗或中斷函數編寫錯誤的問題。中斷函數比較簡單,檢查後可以排除中斷函數編寫錯誤的問題。
下面,針對中斷初始化函數進行檢查。檢查後,可以發現原常式中缺失了中斷通道使能設定,即“NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //通道使能”。代碼修改前後對比如下所示。修改後,再次燒錄執行,會發現現象正常:起初紅燈點亮,後熄滅,黃燈開始閃爍。
(1)中斷初始化原始代碼:
//WWDG中斷初始化void WWDG_NVIC_Init(){ NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; //WWDG中斷 //搶佔2 子優先順序3 組2 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_Init(&NVIC_InitStructure);//NVIC 初始化}
(2)中斷初始化修改後代碼:
//WWDG中斷初始化void WWDG_NVIC_Init(){ NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; //WWDG中斷 //搶佔2 子優先順序3 組2 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //通道使能 NVIC_Init(&NVIC_InitStructure);//NVIC 初始化}
2.3 問題補充——WWDG初始化時庫函數調用順序
(1)對於下述的WWDG初始化函數,燒錄後,運行正常。但是,將WWDG使能並裝載初始值語句WWDG_Enable(WWDG_CNT)放於清除提前喚醒中斷標誌位語句WWDG_ClearFlag()和開啟視窗看門狗中斷語句WWDG_EnableIT()之後,再次執行,現象異常:只有紅色燈在閃爍,黃色燈一直熄滅。
正確程式:
//儲存WWDG計數器的設定值,預設為最大.u8 WWDG_CNT=0x7f;//初始化視窗看門狗 //tr :T[6:0],計數器值//wr :W[6:0],視窗值//fprer:分頻係數(WDGTB),僅最低2位有效//Fwwdg=PCLK1/(4096*2^fprer).void WWDG_Init(u8 tr,u8 wr,u32 fprer){ RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG時鐘使能 WWDG_CNT=tr&WWDG_CNT; //初始化WWDG_CNT. WWDG_SetPrescaler(fprer);////設定IWDG預分頻值 WWDG_SetWindowValue(wr);//設定視窗值 WWDG_NVIC_Init();//初始化視窗看門狗 NVICWWDG_Enable(WWDG_CNT); //使能WWDG 並裝載初始值 WWDG_ClearFlag();//清除提前喚醒中斷標誌位 WWDG_EnableIT(); //開啟視窗看門狗中斷}
異常程式:
//儲存WWDG計數器的設定值,預設為最大.u8 WWDG_CNT=0x7f;//初始化視窗看門狗 //tr :T[6:0],計數器值//wr :W[6:0],視窗值//fprer:分頻係數(WDGTB),僅最低2位有效//Fwwdg=PCLK1/(4096*2^fprer).void WWDG_Init(u8 tr,u8 wr,u32 fprer){ RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG時鐘使能 WWDG_CNT=tr&WWDG_CNT; //初始化WWDG_CNT. WWDG_SetPrescaler(fprer);////設定IWDG預分頻值 WWDG_SetWindowValue(wr);//設定視窗值 WWDG_NVIC_Init();//初始化視窗看門狗 NVIC WWDG_ClearFlag();//清除提前喚醒中斷標誌位 WWDG_EnableIT(); //開啟視窗看門狗中斷 WWDG_Enable(WWDG_CNT); //使能WWDG 並裝載初始值}
(2)錯因分析
執行WWDG_Enable(WWDG_CNT)語句,會使能WWDG,並將初始值CNT裝載至計數器中。執行此句,還會將WWDG_SR的EWIF置1,造成程式無法進入中斷處理函數。
用JLINK在keil中對此進行單步調試可以發現,執行WWDG_Enable(WWDG_CNT)語句之後,WWDG_SR的EWIF被置1,如下圖所示。
第一步:執行WWDG_Enable(WWDG_CNT)語句之前,狀態寄存器WWDG_SR=0x0000,即EWIF=0
第二步: 執行WWDG_Enable(WWDG_CNT)語句之後,狀態寄存器WWDG_SR=0x0001,即EWIF=1
(3)結論
WWDG使能函數必須在WWDG清除提前喚醒中斷標誌位和開啟視窗看門狗中斷之前執行。