有人說在MCU的開發(fā)應用過程中遇到過一次中斷事件觸發(fā)兩次中斷的奇怪事情。有這樣的事嗎?應該說有真有假,這里以STM32為例來聊聊該話題。
所謂假的,就是指基于誤會以為一次事件觸發(fā)了兩次甚至多次中斷。比方按鍵事件沒有做好消抖處理,或者中斷請求標志位沒有被及時清零等。順便說下,對于STM32芯片而言,如果中斷請求標志沒有被清零會沒完沒了的循環(huán)進相應中斷服務程序。
這里重點聊聊真的,即一次中斷事件進入兩次中斷服務程序,的確有機會碰到。偶爾也有人反映類似問題,比方做UART通信時,一個空閑事件進入兩次空閑中斷,感覺相關標志沒法清除;有人通過定時器觸發(fā)SPI傳輸,一個定時器事件竟然進入兩次中斷連續(xù)給SPI數(shù)據(jù)寄存器賦值兩次。
發(fā)生這種一次觸發(fā)事件進入兩次中斷的情況時,一般有個非常明顯的特征,那就是在中斷服務程序里對中斷請求標志的清零代碼往往放在中斷服務程序的最末尾。我們不妨弄個具體的實例感受下。
下面以一個定時器更新中斷為例。我讓定時器工作在基于向上計數(shù)的單脈沖PWM模式,即啟動計數(shù)器后,當發(fā)生溢出產(chǎn)生更新事件時即告停止。那么每次啟動定時器后按理有且只有一次進入更新中斷服務程序。我在中斷服務程序里放個計數(shù)變量,統(tǒng)計進入中斷的次數(shù)。我這里使用STM32F4的開發(fā)板測試的。
先看看中斷服務程序里清除中斷請求標志的代碼不是放在最后一行的情況。其中變量counterX用來統(tǒng)計進入中斷服務程序次數(shù)。

這次測試結果沒問題,一次更新事件對應進入一次中斷服務程序。我將上面的中斷服務程序稍微調(diào)整下代碼前后順序,讓清除中斷請求位的代碼放在最后,再看看下面結果。

嗯?counterX結果變?yōu)?了,一次觸發(fā)事件怎么進了兩次中斷服務程序呢?!
這時不同的人往往會有不同的判斷或結論。比方中斷請求標志一次清不掉啊;同樣的寫法別的系列或型號卻可以,認為太莫名其妙啦!【其實,到底是不是完全相同的寫法只是感覺,就像我上面的寫法不細究的話也可以說是一樣的寫法】,或者說芯片很奇葩啊云云。
怎么會這樣呢?原因就在于那行清除中斷請求位的代碼放在最后,在第一次退出中斷服務程序時該請求位尚未完成被清零的狀態(tài)。程序指令執(zhí)行速度越快,這種可能性就越高。既然該中斷請求位依然保持置1的有效狀態(tài),經(jīng)硬件觸發(fā)再次進入中斷服務程序就順理成章了。
有人會問,我在退出中斷服務程序之前不是已經(jīng)做了中斷請求位的清零操作嗎?怎么沒有立即生效呢?再怎么“立即”也是需要時間的,程序指令的執(zhí)行完畢和指令執(zhí)行后的狀態(tài)改變并不一定同步。比方你到包子鋪去跟老板說買3個饅頭,老板滿口應諾后,你不能立即扭頭就走啊。他還需要點時間來處理,不然一輩子都買不到3個饅頭。具體結合到stm32芯片,程序執(zhí)行是基于哈佛結構的流水線形式,前面代碼執(zhí)行時依然可以執(zhí)行后序的指令代碼。
談到這里,有人或許想到在清除中斷請求位的代碼后面加上一句內(nèi)存屏蔽指令,即DSB。應該說加這個DSB指令是有效的,即該指令前的所有內(nèi)存訪問指令執(zhí)行完畢后才執(zhí)行后序指令代碼。不過,一般來講,在這個地方用不著它,我們只須注意別將清除中斷請求位的代碼放在服務程序的末尾,稍微給清零操作留點實現(xiàn)時間。就像上面打比方買饅頭一樣,給老板一點為你取饅頭的時間就行。
也許有人會說,我中斷服務程序里就只需做中斷請求位清零這一件事怎么辦呢?那你就隨便在清零操作代碼后面隨便一兩行無關緊要的代碼也行,確保不發(fā)生1次事件進兩次中斷即可。
剛才前面說了,當清除中斷請求位的代碼放在服務程序最后時,程序指令執(zhí)行速度越快,一次觸發(fā)事件進入兩次中斷服務程序的可能性就越高。我們不妨看看下面基于STM32H7系列的一段中斷服務程序代碼。是TIM3的更新中斷服務程序,截圖里的兩行代碼為中斷服務程序的最末兩行。注意,清除中斷標志的代碼沒有在最末一行。

其基本功能就是每進一次更新中斷,先清中斷標志,然后給SPI數(shù)據(jù)寄存器賦值令其發(fā)送一個16位數(shù)據(jù)。顯然,結合我們前面的分析,如果代碼這樣寫一般來講是不太可能發(fā)生一次事件觸發(fā)2次中斷的,事實上當程序代碼在FLASH里運行時也的確沒有任何問題。
但當將中斷服務程序放到RAM里,比方放到DTCM里去運行時發(fā)生了功能異常。結果變成了每次更新事件發(fā)送的數(shù)據(jù)不是16位而是32位了。這個32位數(shù)據(jù)正是因為一次更新事件連續(xù)兩次進入中斷服務程序,兩次發(fā)送SPI數(shù)據(jù)。那為什么完全相同的代碼在FLASH里運行沒這個問題呢,因為代碼在DTCM的運行速率要比在FLASH里快,盡管在清中斷請求標志的代碼后面已經(jīng)有了兼具延時功能的那句針對SPI數(shù)據(jù)寄存器的賦值語句,在退出中斷前該請求標志位還是未完成清零而再進了一次中斷。
看來,這里還得稍微加多點延時以保證中斷請求標志在退出中斷前被清零。為了避免加延時代碼的盲目性,即要么短了要么長了,我們可以使用對標志位的輪詢方式,將代碼稍加改動變成下面的樣子。

之后,再行驗證測試都是正常的。若有興趣的話,可以在清標志位的代碼后面加DSB指令驗證測試下。
責任編輯:pj
-
芯片
+關注
關注
463文章
54010瀏覽量
466146 -
mcu
+關注
關注
147文章
18925瀏覽量
398265 -
計數(shù)器
+關注
關注
32文章
2316瀏覽量
98192
發(fā)布評論請先 登錄
脈沖/頻率計數(shù)采集模塊:高速脈沖+頻率,支持斷電保存
功率MOSFET器件的單脈沖雪崩能量參數(shù)解讀
CW32定時器及其中斷介紹
LAT1183+高精度定時器中 single-shot 計數(shù)模式不工作應用筆記
【乾芯QXS320F開發(fā)板試用】ePWM 模塊 Up-Down 計數(shù)模式與動態(tài)占空比控制
CW32A030微控制器定時器
CW32L0開發(fā)板學習記錄四,高級定時器ATIM學習
如何通過PWM脈沖控制電機?
HbirdV2-SoC自帶pwm配置介紹
STM32H7開啟單脈沖模式 PWM波脈沖寬度不受CCR控制怎么解決?
開關電源三種控制模式:PWM/PFM/PSM
MOSFET單脈沖雪崩擊穿能量的失效模式
基于向上計數(shù)的單脈沖PWM模式
評論