??
字號(hào):
關(guān)于中斷處理的系列問題
中斷的任務(wù)被調(diào)度后,再度獲得運(yùn)行時(shí)是從任務(wù)被中斷處執(zhí)行。
中斷的任務(wù)被調(diào)度后,再度獲得運(yùn)行時(shí)是從任務(wù)被中斷處執(zhí)行。
在中斷ISR中調(diào)用OSIntExit(), 在OSIntExit()中又調(diào)用OSIntCtxSW(),此時(shí)堆棧結(jié)構(gòu)如下:
棧頂-->OSIntCtxSW()返回地址 2字節(jié)
OSIntExit()返回地址 2字節(jié)
SP-4-->保存寄存器PUSHALL
中斷斷點(diǎn)(任務(wù)返回地址)
。。。
可見SP-4就是寄存器信息和中斷返回地址,OSCtxSw()彈棧后就回到了任務(wù)斷點(diǎn)。
KEIL調(diào)用函數(shù)時(shí)壓入堆棧的就是2字節(jié)的返回地址。
中斷剩余部分沒有被跳過,準(zhǔn)確的說是被OSCtxSw借用了。它的內(nèi)容只有POPALL和RETI,此處沒有錯(cuò)誤。
中斷完成后有可能使某些資源滿足,導(dǎo)致阻塞任務(wù)就緒,因此要進(jìn)行任務(wù)調(diào)度,這樣中斷返回后的任務(wù)就不一定是這個(gè)被中斷的任務(wù)了。
***************************************************************************************************
在UCOS 中典型的中斷處理被建議成如下:
void OSTickISR(void)
{
保存處理器寄存器的值;
調(diào)用OSIntEnter()或是將OSIntNesting加1;
調(diào)用OSTimeTick();
調(diào)用OSIntExit();
恢復(fù)處理器寄存器的值;
執(zhí)行中斷返回指令;
}
你的程序也是這么做的:
OSTickISR:
USING 0
PUSHALL
CLR TR0
MOV TH0,#70H ;定義Tick=50次/秒(即0.02秒/次)
MOV TL0,#00H ;OS_CPU_C.C 和 OS_TICKS_PER_SEC
SETB TR0
LCALL _?OSIntEnter
LCALL _?OSTimeTick
LCALL _?OSIntExit
POPALL
RETI
這樣好象有問題,我覺得“ 調(diào)用OSIntEnter()或是將OSIntNesting加1;”應(yīng)放在中斷的第一條語句來執(zhí)行,以保證在被更高級(jí)別中斷打斷之前將OSIntNesting加1,以避免在高級(jí)別中斷中發(fā)生任務(wù)切換。
如果在“保存處理器寄存器的值”時(shí)被打斷;發(fā)生任務(wù)切換,何時(shí)再返回到被打斷的中斷程序很難講了,從切換的原理,好象當(dāng)被中斷打斷了的任務(wù)再次運(yùn)行時(shí),應(yīng)是從被高級(jí)別中斷打斷的低級(jí)別中斷程序里面的斷點(diǎn)處繼續(xù)運(yùn)行,即回到中斷程序把其余下的部分執(zhí)行完,再返回任務(wù)。( 這樣理解請(qǐng)楊大師仔細(xì)批評(píng)指正一下), 這樣,中斷處理的時(shí)間太長了。中斷失去了意義。
對(duì)!“ 調(diào)用OSIntEnter()或是將OSIntNesting加1;”應(yīng)放在中斷的第一條語句來執(zhí)行。我當(dāng)時(shí)沒有考慮清楚,這是又一個(gè)BUG。
你的理解正確。
中斷處理延遲在OS里是很常見的現(xiàn)象,最大中斷處理延遲是評(píng)價(jià)OS性能的重要指標(biāo)。這說明CPU的負(fù)荷能力是有限的,工程上以最大中斷處理延遲為指標(biāo)選擇CPU速度,只要延遲在允許的范圍內(nèi)就可以接受。如果“中斷處理的時(shí)間太長了,中斷失去了意義”,那么說明所選CPU的能力不夠。
在理解OS工作原理的時(shí)候,不要想得太理想化,否則總是不得要領(lǐng),你的思維定勢會(huì)誤導(dǎo)你的思考。注意計(jì)算機(jī)是個(gè)離散數(shù)字系統(tǒng),它不能連續(xù)運(yùn)行。有些觀念應(yīng)該確立,例如:單CPU系統(tǒng)在微觀上串行,在宏觀上并發(fā);實(shí)時(shí)指在一定時(shí)間范圍內(nèi)完成任務(wù);中斷處理必然有延遲等等。
不是你沒考慮清楚,而是UCOS 邵貝貝翻譯的UCOS 書里也是這么寫的,不知UCOS 源碼是依據(jù)此而產(chǎn)生一些BUGS?
而且您設(shè)計(jì)的調(diào)度方案,當(dāng)程序任務(wù)再度運(yùn)行時(shí),是直接返回到任務(wù)。而不是返回到中斷里, 所以當(dāng)任務(wù)再度運(yùn)行時(shí)是回到任務(wù)去的,中斷剩余部分就被跳過去了。如果中斷剩余部分有重要的內(nèi)容,那就有BUG了。
這樣理解對(duì)不對(duì)呢?
uC/OS-II一進(jìn)入中斷,理論上應(yīng)立即原語執(zhí)行OSIntNesting+1,以便后續(xù)中斷了解中斷嵌套情況,不至于在中斷嵌套里切換任務(wù)。我認(rèn)為原作此處是個(gè)BUG。有些CPU要求中斷后必須至少執(zhí)行一條指令,這期間不會(huì)嵌套中斷,那么這條指令就可以是OSIntNesting+1原語操作或者關(guān)中斷(以便原語操作),這樣中斷嵌套就被嚴(yán)密監(jiān)視了,不會(huì)漏掉導(dǎo)致判斷錯(cuò)誤。
任務(wù)切換是通過模擬一次中斷實(shí)現(xiàn)的,它和硬件中斷產(chǎn)生的堆棧樣式相同。在中斷嵌套里不會(huì)執(zhí)行任務(wù)切換,所有嵌套中斷都使用被中斷任務(wù)的堆棧空間,在最后一個(gè)中斷快要退出時(shí)進(jìn)行任務(wù)調(diào)度。
此時(shí)中斷剩余部分只有兩個(gè)內(nèi)容:POPALL和RETI,再?zèng)]有其他內(nèi)容,更不用說重要內(nèi)容了。如果不需調(diào)度,中斷正常完成,否則,保存現(xiàn)場到TCB,切換任務(wù)到高優(yōu)先級(jí)。現(xiàn)場內(nèi)容包括了斷點(diǎn)返回地址,中斷剩余部分沒有被跳過,它保存在此任務(wù)的TCB里,下次調(diào)度到此任務(wù)時(shí),OSCtxSw借用這個(gè)中斷的剩余部分,直接返回到任務(wù)斷點(diǎn)繼續(xù)執(zhí)行任務(wù)。因?yàn)镺SCtxSw也是模擬一次中斷,棧與這個(gè)中斷的剩余部分一模一樣,可以直接借用。
中斷的重要工作均被完成后才會(huì)切換任務(wù),最后一個(gè)中斷剩余的退出部分讓給OSCtxSw,假想成發(fā)生了一次切換中斷(切換中斷模擬的就是硬件中斷),而不是硬件中斷。
第一次任務(wù)切換時(shí)沒有中斷棧,就人工模擬一個(gè)。在硬件中斷里本身就有一個(gè)棧,那就直接拿過來用。
***************************************************************************************************
看了您的大作,對(duì)其中無任務(wù)切換中斷的處理好象有點(diǎn)想不通。你在串口中斷程序中不作任務(wù)切換,所以不調(diào)用OSIntEnter(),OSIntNesting沒增加;當(dāng)有更高級(jí)別的中斷嵌套發(fā)生時(shí),則有可能發(fā)生任務(wù)切換。這樣串口中斷的堆棧壓入和彈出分別在不同任務(wù)堆棧中,這樣是否會(huì)造成堆棧混亂?
是不是即使無任務(wù)切換中斷處理都應(yīng)成對(duì)調(diào)用OSIntEnter()和 OSIntExit()?如果調(diào)用會(huì)有什么壞影響嗎?
SerialISR:
USING 0
PUSHALL
CLR EA
LCALL _?serial
SETB EA
POPALL
RETI
在以上串口中斷程序中,從SETB EA 之后到RETI之間,仍然可被高級(jí)別中斷打端,有可能發(fā)生任務(wù)切換。即使任務(wù)的堆棧不亂,那串口中斷程序何時(shí)能得以繼續(xù)運(yùn)行也是問題,相當(dāng)于中端程序中調(diào)了一個(gè)花費(fèi)很長時(shí)間的子程序, 這樣理解對(duì)嗎?
同意你的觀點(diǎn)!
我主要是想節(jié)省一個(gè)任務(wù)號(hào),同時(shí)提高效率,任務(wù)切換太費(fèi)時(shí)間了,中斷的標(biāo)準(zhǔn)處理也比較煩瑣,所以當(dāng)時(shí)采用了關(guān)閉中斷的臨界資源處理方式,現(xiàn)在看來這么做是有問題的,這是個(gè)BUG。你把它按標(biāo)準(zhǔn)中斷的處理方式做就可以解決這個(gè)問題。本來想偷機(jī)取巧來著,沒想到漏了破綻,呵呵。
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -