單片機死機問題是一個令廣大工程師頭疼的問題,最近小編又遇到一起實際案例,讓我們來看看是怎么回事。 ![]() 根據該工程師描述,當被測產品被大功率對講機的發射信號干擾時,會出現死機現象,程序開了看門狗也沒有復位。 我首先讓他做了一個實驗,通過一個IO口把看門狗的內部低速時鐘輸出,觀察在死機的時候該時鐘是否還存在。工程師測試后反饋,死機的時候IO口時鐘就不再輸出了。另外他提到程序里用到一個定時器(使用的是內部高速時鐘作為時鐘源),做了一個周期翻轉IO的操作,死機時IO口也不再翻轉。 這聽起來似乎有點嚴重,難不成是對講機把MCU徹底干崩潰了?小編第一時間購買火車票,不顧當地臺風,緊急趕往客戶現場。 遇到這種情況,首先要穩定的復現問題。到了現場之后,該工程師給我做了演示,一開始也確實是對講機開啟后,很快就會讓板子接出來的一個原本正常閃爍的指示燈不再閃爍。 ![]() 最初想到的是對講機可能干擾到了MCU的電源,實際接上示波器觀察3.3V輸出相對穩定,干擾時約有200mv左右的波動。Vcore引腳電壓也有波動(如圖所示黃色波形)。Vcore正常輸出應為1.5V ![]() 將Vcore信號放大后,可見干擾波形頻率為434MHz,這與對講機顯示屏上顯示的頻率基本一致。 ![]() 另外我用開發板簡單寫了一個翻轉IO的程序,使用對講機測試,未出現問題。實際測了VDD和Vcore波形,和上述他的板子基本一致。這基本可以說明不是電源引起的問題。 隨后我們進行了多次實驗。期間,他曾將板子拿到電腦旁修改代碼并重新下載了幾次程序,但之后突然無法再次復現問題,即使我將對講機按鍵按到“冒煙”也無法復現。這引起了我的高度警覺,我隱約感覺問題可能與軟件代碼有關。于是我們又焊接了一塊板子進行測試,這個板子也是怎么也復現不了。 此時我更加確信是軟件上的差異導致了此問題,因為同樣的硬件和軟件,不可能之前很容易復現,現在卻完全無法復現。 后來我坐到他的工位旁,和他一起看了下代碼,我們先將他的業務代碼精簡至最簡狀態,然后逐個添加功能模塊進行測試,最終定位到了問題點。只有當添加SPI通信的代碼塊時才會出現問題;若無此代碼塊,則問題不會出現。 后來進一步定位,所謂的死機是卡在下圖中while(1)循環里了,程序實際還在運行 ![]() 分析至此,引出了兩個關鍵問題,一是為什么看門狗沒有起作用?難不成是外部干擾影響到了內部32K時鐘或是讓看門狗功能工作異常了? 二是為什么干擾會引起SPI RXFNE標志位無法置位? 最終還是搞清楚了這兩個問題。先回答第一個問題,查看main函數可見: ![]() 第一個問題出在87行看門狗初始化上:看門狗初始化得太晚了!在單片機程序中,看門狗定時器的初始化位置通常非常關鍵。最佳位置是將其放在程序啟動初期,盡早啟用看門狗可以確保如果程序在后續初始化或主循環之前的啟動代碼中就發生跑飛或卡死,也能被及時復位。 在85行調用的這個函數里就會進行SPI的通信,這個時候出現了上述情況的卡死,而看門狗這時還沒有起作用,因此就會一直卡住。另外客戶IO口輸出內部32K是89行,周期翻轉IO是在while(1)里 97行,所以整體的外在表現就是死機。若周期翻轉IO操作是在定時器中斷服務程序中進行,則也不會表現出徹底死機的現象。 程序98行也會有SPI的通信,如果是在這里引起的SPI while(1)卡住,看門狗會起作用并觸發復位,這也與實際測試中有時能觀察到復位的表現一致 只需將看門狗初始化代碼的位置提前,即可避免此類卡死問題。 這里多提一點,有的單片機是上電復位后默認就使能看門狗的,這時要注意及時喂狗,避免前期初始化的時候就引起復位。 第二個問題的原因在于:對講機會干擾SPI時鐘信號。當SPI時鐘受到干擾時,SPI通信無法正常進行,導致RXFNE(接收緩沖區非空)標志位無法置位。這很好理解:SPI時鐘持續受擾,必然導致通信失敗,自然無法正確接收數據置位RXFNE。 我后來單獨做了測試,直接在SPI CLK信號上施加干擾,即可輕易復現RXFNE標志位無法置位的問題。 ![]() 因此,有經驗的工程師除了main()主循環外,通常不會在代碼中編寫其他while(1)死循環,因為這確實存在較大的風險! |
|
來自: TopSemic嵌入式 > 《待分類》