有人說在MCU的開發(fā)應(yīng)用過程中遇到過一次中斷事件觸發(fā)兩次中斷的奇怪事情。有這樣的事嗎?應(yīng)該說有真有假,這里以STM32為例來聊聊該話題。
所謂假的,就是指基于誤會(huì)以為一次事件觸發(fā)了兩次甚至多次中斷。比方按鍵事件沒有做好消抖處理,或者中斷請(qǐng)求標(biāo)志位沒有被及時(shí)清零等。順便說下,對(duì)于STM32芯片而言,如果中斷請(qǐng)求標(biāo)志沒有被清零會(huì)沒完沒了的循環(huán)進(jìn)相應(yīng)中斷服務(wù)程序。
這里重點(diǎn)聊聊真的,即一次中斷事件進(jìn)入兩次中斷服務(wù)程序,的確有機(jī)會(huì)碰到。偶爾也有人反映類似問題,比方做UART通信時(shí),一個(gè)空閑事件進(jìn)入兩次空閑中斷,感覺相關(guān)標(biāo)志沒法清除;有人通過定時(shí)器觸發(fā)SPI傳輸,一個(gè)定時(shí)器事件竟然進(jìn)入兩次中斷連續(xù)給SPI數(shù)據(jù)寄存器賦值兩次。
發(fā)生這種一次觸發(fā)事件進(jìn)入兩次中斷的情況時(shí),一般有個(gè)非常明顯的特征,那就是在中斷服務(wù)程序里對(duì)中斷請(qǐng)求標(biāo)志的清零代碼往往放在中斷服務(wù)程序的最末尾。我們不妨弄個(gè)具體的實(shí)例感受下。
下面以一個(gè)定時(shí)器更新中斷為例。我讓定時(shí)器工作在基于向上計(jì)數(shù)的單脈沖PWM模式,即啟動(dòng)計(jì)數(shù)器后,當(dāng)發(fā)生溢出產(chǎn)生更新事件時(shí)即告停止。那么每次啟動(dòng)定時(shí)器后按理有且只有一次進(jìn)入更新中斷服務(wù)程序。我在中斷服務(wù)程序里放個(gè)計(jì)數(shù)變量,統(tǒng)計(jì)進(jìn)入中斷的次數(shù)。我這里使用STM32F4的開發(fā)板測(cè)試的。
先看看中斷服務(wù)程序里清除中斷請(qǐng)求標(biāo)志的代碼不是放在最后一行的情況。其中變量counterX用來統(tǒng)計(jì)進(jìn)入中斷服務(wù)程序次數(shù)。
這次測(cè)試結(jié)果沒問題,一次更新事件對(duì)應(yīng)進(jìn)入一次中斷服務(wù)程序。我將上面的中斷服務(wù)程序稍微調(diào)整下代碼前后順序,讓清除中斷請(qǐng)求位的代碼放在最后,再看看下面結(jié)果。
嗯?counterX結(jié)果變?yōu)?了,一次觸發(fā)事件怎么進(jìn)了兩次中斷服務(wù)程序呢?!
這時(shí)不同的人往往會(huì)有不同的判斷或結(jié)論。比方中斷請(qǐng)求標(biāo)志一次清不掉啊;同樣的寫法別的系列或型號(hào)卻可以,認(rèn)為太莫名其妙啦!【其實(shí),到底是不是完全相同的寫法只是感覺,就像我上面的寫法不細(xì)究的話也可以說是一樣的寫法】,或者說芯片很奇葩啊云云。
怎么會(huì)這樣呢?原因就在于那行清除中斷請(qǐng)求位的代碼放在最后,在第一次退出中斷服務(wù)程序時(shí)該請(qǐng)求位尚未完成被清零的狀態(tài)。程序指令執(zhí)行速度越快,這種可能性就越高。既然該中斷請(qǐng)求位依然保持置1的有效狀態(tài),經(jīng)硬件觸發(fā)再次進(jìn)入中斷服務(wù)程序就順理成章了。
有人會(huì)問,我在退出中斷服務(wù)程序之前不是已經(jīng)做了中斷請(qǐng)求位的清零操作嗎?怎么沒有立即生效呢?再怎么“立即”也是需要時(shí)間的,程序指令的執(zhí)行完畢和指令執(zhí)行后的狀態(tài)改變并不一定同步。比方你到包子鋪去跟老板說買3個(gè)饅頭,老板滿口應(yīng)諾后,你不能立即扭頭就走啊。他還需要點(diǎn)時(shí)間來處理,不然一輩子都買不到3個(gè)饅頭。具體結(jié)合到stm32芯片,程序執(zhí)行是基于哈佛結(jié)構(gòu)的流水線形式,前面代碼執(zhí)行時(shí)依然可以執(zhí)行后序的指令代碼。
談到這里,有人或許想到在清除中斷請(qǐng)求位的代碼后面加上一句內(nèi)存屏蔽指令,即DSB。應(yīng)該說加這個(gè)DSB指令是有效的,即該指令前的所有內(nèi)存訪問指令執(zhí)行完畢后才執(zhí)行后序指令代碼。不過,一般來講,在這個(gè)地方用不著它,我們只須注意別將清除中斷請(qǐng)求位的代碼放在服務(wù)程序的末尾,稍微給清零操作留點(diǎn)實(shí)現(xiàn)時(shí)間。就像上面打比方買饅頭一樣,給老板一點(diǎn)為你取饅頭的時(shí)間就行。
也許有人會(huì)說,我中斷服務(wù)程序里就只需做中斷請(qǐng)求位清零這一件事怎么辦呢?那你就隨便在清零操作代碼后面隨便一兩行無關(guān)緊要的代碼也行,確保不發(fā)生1次事件進(jìn)兩次中斷即可。
剛才前面說了,當(dāng)清除中斷請(qǐng)求位的代碼放在服務(wù)程序最后時(shí),程序指令執(zhí)行速度越快,一次觸發(fā)事件進(jìn)入兩次中斷服務(wù)程序的可能性就越高。我們不妨看看下面基于STM32H7系列的一段中斷服務(wù)程序代碼。是TIM3的更新中斷服務(wù)程序,截圖里的兩行代碼為中斷服務(wù)程序的最末兩行。注意,清除中斷標(biāo)志的代碼沒有在最末一行。
其基本功能就是每進(jìn)一次更新中斷,先清中斷標(biāo)志,然后給SPI數(shù)據(jù)寄存器賦值令其發(fā)送一個(gè)16位數(shù)據(jù)。顯然,結(jié)合我們前面的分析,如果代碼這樣寫一般來講是不太可能發(fā)生一次事件觸發(fā)2次中斷的,事實(shí)上當(dāng)程序代碼在FLASH里運(yùn)行時(shí)也的確沒有任何問題。
但當(dāng)將中斷服務(wù)程序放到RAM里,比方放到DTCM里去運(yùn)行時(shí)發(fā)生了功能異常。結(jié)果變成了每次更新事件發(fā)送的數(shù)據(jù)不是16位而是32位了。這個(gè)32位數(shù)據(jù)正是因?yàn)橐淮胃率录B續(xù)兩次進(jìn)入中斷服務(wù)程序,兩次發(fā)送SPI數(shù)據(jù)。那為什么完全相同的代碼在FLASH里運(yùn)行沒這個(gè)問題呢,因?yàn)榇a在DTCM的運(yùn)行速率要比在FLASH里快,盡管在清中斷請(qǐng)求標(biāo)志的代碼后面已經(jīng)有了兼具延時(shí)功能的那句針對(duì)SPI數(shù)據(jù)寄存器的賦值語句,在退出中斷前該請(qǐng)求標(biāo)志位還是未完成清零而再進(jìn)了一次中斷。
看來,這里還得稍微加多點(diǎn)延時(shí)以保證中斷請(qǐng)求標(biāo)志在退出中斷前被清零。為了避免加延時(shí)代碼的盲目性,即要么短了要么長(zhǎng)了,我們可以使用對(duì)標(biāo)志位的輪詢方式,將代碼稍加改動(dòng)變成下面的樣子。
之后,再行驗(yàn)證測(cè)試都是正常的。若有興趣的話,可以在清標(biāo)志位的代碼后面加DSB指令驗(yàn)證測(cè)試下。
責(zé)任編輯:pj
-
芯片
+關(guān)注
關(guān)注
459文章
52464瀏覽量
440144 -
mcu
+關(guān)注
關(guān)注
146文章
17961瀏覽量
366154 -
計(jì)數(shù)器
+關(guān)注
關(guān)注
32文章
2291瀏覽量
96351
發(fā)布評(píng)論請(qǐng)先 登錄
第二十章 TIM——基本定時(shí)器

STM32H7開啟單脈沖模式 PWM波脈沖寬度不受CCR控制怎么解決?
開關(guān)電源三種控制模式:PWM/PFM/PSM
MOSFET單脈沖雪崩擊穿能量的失效模式

MCU定時(shí)器/計(jì)數(shù)器
STM32F103高級(jí)定時(shí)器中,開啟單脈沖模式是不是會(huì)立刻清除計(jì)數(shù)器使能位?
【RA-Eco-RA2L1-48PIN-V1.0開發(fā)板試用】——PWM
微控制器中的PWM模塊介紹
脈沖模式調(diào)制的優(yōu)點(diǎn)是什么
MOSFET規(guī)格書中單脈沖雪崩能量EAS如何理解?電路設(shè)計(jì)咋用它計(jì)算MOS會(huì)損壞嗎?

高級(jí)定時(shí)器PWM輸入模式的配置方法

數(shù)字單脈沖多普勒雷達(dá)與DSP教學(xué)

使用TMS320C40 DSP實(shí)現(xiàn)單脈沖雷達(dá)的數(shù)字跟蹤器

評(píng)論