前言
最近因為專案產品硬體設計有問題,導致設計的一款產品把硬體電源開關以及硬體系統復位功能去掉了。更嚴重的是,這產品已經開始生產了,硬體已經無法修改,所以軟體必須上看門狗,否則裝置當機或是異常後就只能拆裝置拔電池復位了。
我們使用的MCU是普冉的PY32F030,這顆晶片在低功耗應用場景下,使用看門狗會有很多的問題和缺陷,需要非常注意,稍有不慎,就會出問題。
關於看門狗在低功耗場景下的應用,幾個問題點可以提前思考一下:
- 看門狗是在中斷中餵狗還是在主程式中餵狗比較好?
- 看門狗初始化可以放到時鐘初始化之前麼?
- 如果時鐘死掉了,看門狗還能正常工作麼?
- 低功耗深度休眠後還需要餵狗麼?如果需要,要怎麼設計?使用什麼喚醒裝置餵狗?
- 軟體獨立看門狗與硬體獨立看門狗它們有什麼區別?
- 在看門狗初始化之前系統異常了會怎樣?
- 選項位元組裡開啟硬體看門狗與軟體程式碼開啟有什麼區別?
- 如果異常不可避免,有沒一個地方可以快取裝置狀態,系統異常復位後狀態不被清除
(一)看門狗分類
看門狗的分類,根據實現方式的不同,可以分為軟體看門狗和硬體看門狗:
- 軟體看門狗:透過軟體實現的一種機制,通常由系統中的軟體來設定和管理
- 硬體看門狗: 嵌入在處理器或晶片中的專用硬體模組
根據使用方式的不同,又可以區分為獨立看門狗和視窗看門狗
-
獨立看門狗: 獨立看門狗通常用於監控整個系統的執行狀態,而不特定於某個任務或程式,當系統故障,死鎖,無響應的時候,應用程式無法進行正常餵狗,看門狗超時從而產生復位。
-
視窗看門狗: 視窗看門狗更專注於監控特定任務或程式的執行狀態,並在特定的時間視窗內完成。比如在某個任務中,它的執行時間要求非常高,可以使用視窗看門狗,它有一個時間視窗,如果太早餵狗和太晚餵狗,都會產生異常,正因為它餵狗時間有個時間視窗,所以才叫視窗看門狗。
我使用的普冉PY32F030系列MCU,它是32位Cortex-M0+的核心,裡面帶有一個獨立看門狗IWDG和一個視窗看門狗WWDG。
其中,獨立看門狗和視窗看門狗,還有軟體和硬體的區別,主要差異是在看門狗的啟動方式上不同。下面我們的介紹,主要針對獨立看門狗。
(二)啟動看門狗
看門狗的啟動有多種方式:
- 透過介面設定啟動
- 直接設定暫存器啟動
- 設定選項位元組啟動
(1)透過介面設定
這裡可以直接參考官方sample進行初始化:
IWDG_HandleTypeDef IwdgHandle;
HAL_Init();
/*##-3- Configure & Start the IWDG peripheral #########################################*/
IwdgHandle.Instance = IWDG;
IwdgHandle.Init.Prescaler = IWDG_PRESCALER_32;//T=1MS
IwdgHandle.Init.Reload = (1000); //1ms*1000=1s
IwdgHandle.Init.Window = IWDG_WINDOW_DISABLE;
if(HAL_IWDG_Init(&IwdgHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
這裡需要特別注意,因為IWDG是依賴於LSI時鐘的,也就是在HAL_IWDG_Init 函式呼叫之前,必須先開啟LSI時鐘。
官方給的sample中,是在HAL_Init()中把LSI時鐘開啟了。當你把上面這段程式碼移植到你自己工程上,如果你LSI沒有開啟,或者是在HAL_IWDG_Init後面才開LSI時鐘,你呼叫HAL_IWDG_Init就會一直失敗,系統一直ERROR,整個MCU會啟動不了。
(2)透過暫存器直接設定
直接往 IWDG_SR,IWDG_RLR,IWDG_KR三個暫存器地址寫入對應的引數,使能IWDG
void init_wtd(void)
{
volatileu int32_t *IWDG_KR_ADDR = (volatileuint32_t *)0x40003000UL;
volatileu int32_t *IWDG_PR_ADDR = (volatileuint32_t *)0x40003004UL;
volatileu int32_t *IWDG_RLR_ADDR = (volatileuint32_t *)0x40003008UL;
*IWDG_KR_ADDR = 0x5555;
*IWDG_PR_ADDR = 0x03;
*IWDG_RLR_ADDR = 0xF40;
}
實際IWDG是有四個暫存器,還有一個IWDG_PR,它與前面一樣,如果不初始化時鐘,看門狗會啟動不了,就算是設定了,看門狗也是不會啟動。
如果要使能時鐘,可以新增時鐘設定語句:
SET_BIT(RCC->CSR, RCC_CSR_LSION);
直接設定暫存器有一個好處,就是在boot中, 因為對程式碼量要求比較高,可以比較精簡的實現功能
(3)透過選項位元組配置
MCU上內部有一個小的flash,裡面有個FLASH user option,在這裡面可以設定MCU的一些配置引數
這個引數是可以透過燒錄器在燒錄的時候就把引數配置進去,對於已經燒錄的裝置,可以透過寫選項位元組的方式把IWDG_SW置位或是清零。
void Option_config_NRST_to_gpio_hwwdg(void)
{
FLASH_OBProgramInitTypeDef OBInitCfg;
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
/* 初始化flash擦寫時間引數 */
HAL_FLASH_Init(FLASH_PROGRAM_ERASE_CLOCK_8MHZ);
/* 獲取option bytes資料 */
HAL_FLASHEx_OBGetConfig(&OBInitCfg);
//配置Nreset為GPIO
if(((OBInitCfg.USERConfig & OB_RESET_MODE_GPIO) != OB_RESET_MODE_GPIO)||((OBInitCfg.USERConfig & OB_IWDG_SW) == OB_IWDG_SW))
{
/* 修改 USER(RESET , WWDG, IWDG) 配置值 , 注意一定要3個一起配置*/
OBInitCfg.OptionType = OPTIONBYTE_USER;
MODIFY_REG(OBInitCfg.USERConfig, (OB_RESET_MODE_GPIO|OB_WWDG_SW|OB_IWDG_SW), (OB_RESET_MODE_GPIO | OB_WWDG_SW | OB_IWDG_HW));
/* 啟動option byte程式設計 */
HAL_FLASHEx_OBProgram(&OBInitCfg);
/* 產生一個復位,option byte裝載 */
HAL_FLASH_OB_Launch();
}
}
透過選項位元組配置了硬體看門狗之後,晶片會自動開啟LSI時鐘,這個時候,軟體要關閉LSI時鐘是關閉不了的。
軟體獨立看門狗與硬體獨立看門狗的區別:
- 軟體獨立看門狗透過軟體初始化,可以透過關閉時鐘的方式把它關閉了
- 如果在裝置上電到看門狗初始化之前系統異常了,看門狗是不生效的,這種情況比較多的出現在軟體初始化的時候異常卡死。
- 硬體獨立看門狗透過燒錄器燒錄的時候配置,或者是透過軟體程式,修改選項位元組裡面引數進行修改
- 硬體獨立看門狗一但配置上,它從上電的時候就會開始生效,停止不了,除非重新修改配置項引數。
- 硬體獨立看門狗開啟之後,LSI時鐘會自動開啟,並且關閉不了。
(三)休眠喚醒餵狗
在低功耗裝置中,MCU更加多的時候是在深度睡眠的模式,以達到省功耗的目的。在深度休眠模式下,看門狗還是在正常執行的。
也就是說,在深度休眠模式下,還是需要定時喚醒裝置進行餵狗,喂完狗之後,裝置再重新進入休眠。
(1)常規方式
官方補充文件上有介紹,在PY32F030、PY32F003、PY32F002A系列上,在休眠前,需要進行下面幾個操作:
- 關閉非喚醒源中斷
- 關閉系統滴答 HAL_SuspendTick();
- 保證RTC穩定 while(RTC->DIVL<2);
實際在使用的時候,我們比較常用的方式是,使用RTC的秒中斷,在休眠的時候,每秒喚醒一下裝置,然後進行餵狗操作,最後再休眠下去。
(2)異常情況
實際測試的時候發現,在普冉030使用RTC喚醒餵狗的方式,隨著時間的推移,裝置會出現異常導致看門狗復位。
我們升級五百臺裝置,24小時內,會有幾臺裝置偶爾出現該問題,36小時後,大部分的裝置基本上都會出現這個異常。
普冉官方的解釋是,它們RTC作為喚醒源確實是會存在這個問題,沒有好的解決方案,只能是改用LPTIM來做喚醒源。出現這類問題的根本原因是如果休眠的stop指令與喚醒源中斷同一時間觸發,那麼他們晶片就會掛死。
實際使用的時候,使用LPTIM的方式,還是會存在上面的內容,只是出現的機率會比較低而已。
(3)補救方案
上面的異常情況,是裝置在產線上才發現的,那要怎麼解?客戶肯定也是接受不了這種頻繁重啟的情況,特別是在低功耗裝置上。
最後的方式是將RAM進行分割槽,分出一個IRAM2區,將一些狀態位儲存在IRAM2區,該區啟動的時候不進行初始化,看門狗復位的時候,該區的資料也不會被清除掉。
如果是檢測到看門狗異常導致的復位,可以透過儲存在狀態位資訊恢復到復位前的狀態。
使用IRAM2區不初始化的方式需要注意一點:如果程式分為boot和app兩個部分,需要在boot和app上同時設定該區域,否則可能在boot執行階段,IRAM2區的資料就被清除掉了。
結尾
針對普冉PY32F030 MCU,如果要使用獨立看門狗,需要注意幾點:
- 最好是在燒錄的時候就直接配置啟動硬體看門狗
- 不要使用RTC作為休眠喚醒源進行餵狗
- 最好預留一個IRAM分割槽,以備不時之需
有些坑,沒踩之前並不知道這是一個坑,對於做嵌入式應用軟體的工程師而言,他並不知道晶片設計上會存在什麼樣的缺陷。
如果一顆晶片,價格比別人便宜很多倍,那麼在使用的時候就需要特別注意了,為啥它可以做到這麼便宜?是不是哪裡有坑我們不清楚?就算時間再緊急,最好也要小批次試產之後才能批次使用。