UCOS-II中OS_CPU_IRQ_ISR移植過程分析
16-19、接下來的操作本應該是完成將SP的值保存到任務堆??臻g的,但是在UC/OS-II中存在一個全局變量OSIntNesting,它表明了中斷嵌套的次數,因此需要對這個值進行一次加1操作。
21、接下來的操作就是判斷是否在中斷嵌套中,也就是對全局變量進行比較操作,如果這個值是1,則認為只有一個中斷產生,如果不等于1,則認為實在中斷嵌套中。本文引用地址:http://m.butianyuan.cn/article/201612/324516.htm
CMP R1,#1 ;if(OSIntNesting==1){
22、BNE %F1;如果是在中斷嵌套中,則直接跳轉到下面的中斷處理函數中
23-25、
LDR R4,=OSTCBCur ;OSTCBHighRdy->OSTCBStkPtr=SP;
LDR R5,[R4]
STR SP,[R5]
說明是從任務到中斷的過程,也就是只有一個中斷產生,不是在中斷嵌套中,這時就需要將SP的值保存到任務控制塊中。 以上的操作也就完成了任務情景的保存操作,接下來的操作就應該是真正的中斷處理函數啦。
27、1 MSR CPSR_c,#IRQMODE|NOINT;實質上是完成CPU模式的切換操作,進入到IRQ模式下。
接下來的實際處理過程就如前面兩篇文章中討論的中斷處理過程。
29-30、
LDR R0, =INTOFFSET
LDR R0, [R0]
得到INTOFFSET的值,實際上就是得到偏移量,實質上就是中斷號產生中斷,通過這個寄存器可以快速的確定在二級向量表中該中斷的向量位置,該向量表中就保存了對應中斷處理函數的函數地址。
32、LDR R1, IRQIsrVect
43、IRQIsrVect DCD HandleEINT0
這兩句說明了我前面的分析,IRQIsrVect實際上就是一個標號,其中存儲了HandleEINT0,HandleEINT0又是我們IRQ中斷向量的入口地址(前一篇文章已經說明),也就是說HandleEINT0是二級向量表的開始地址。因此此時R1中實際上就保存了HandleEINT0。
33、MOV LR, PC;就是完成簡單的保存過程,這個過程實質上就是保存了函數調用的返回地址。
34、LDR PC, [R1, R0, LSL #2];這句代碼的意義是將地址R1+R0*4處的內容加載到PC中,也就是實現函數的跳轉,即函數的調用過程。其中R1=HandleEINT0,而R0恰好又是一個偏移量,每一個指針的空間是4個字節(jié),那么R1+R0*4地址處剛好就是對應中斷號的向量。其中就保存了對應中斷函數的地址。因此PC就保存了這個調用函數的入口地址。也就是實現了處理函數調用過程。
35、 MSR CPSR_c,#SVCMODE|NOINT; 執(zhí)行這句代碼的前提就是被調用的函數執(zhí)行完畢了,相關的入棧出棧操作也已經完成,恢復到了調用前的狀態(tài)。此時需要將CPU的模式切換到SVC模式下。
36、BL OSIntExit ;這個操作完成了中斷的切換,如果不是在中斷嵌套中,那么最高優(yōu)先級的任務就會被執(zhí)行,進入最高優(yōu)先的任務之后就不會再返回了,這是UC/OS-II中任務的特點,之后的代碼也就不會執(zhí)行了。這是特別需要注意的。但是如果任務處在中斷嵌套中,那么OSIntExit只是減少中斷嵌套的次數,并不完成其他的操作。那么這時候就需要恢復之前被中斷的任務了,也就是需要完成任務堆棧的彈出操作。
39-41、
LDMFD SP!,{R4} ;POP the tasks CPSR
MSR SPSR_cxsf,R4
LDMFD SP!,{R0-R12,LR,PC}^
這幾句代碼的實現實質上是完成了在中斷嵌套中時的任務切換操作。
討論:
不知道我理解的對不對,我認為這段代碼存在一定的問題,具體的問題如下,因為在中斷嵌套中,CPU執(zhí)行的肯定就是中斷服務函數,此時的任務處于低優(yōu)先級的,并不需要我們保存任務的信息。為什么這段代碼能夠運行的原因我認為主要是因為這種處理的方式是不可能導致中斷嵌套問題產生的。因為我們在進入中斷以后關閉了中斷使能位,不會產生中斷嵌套也就看不出問題所在。我認為如果在支持中斷嵌套的CPU中,應該首先檢測是否在中期嵌套中,如果在中斷嵌套中,則不需要任務寄存器的保存,如果不在,則需要保存。
關閉中斷的方式避免了中斷嵌套產生的可能,這也說明一直需要保存任務的情景,使得這段代碼是有效的。
總結:
在討論ARM的移植過程中,我覺得首先應該搞清楚每一種情況下CPU的工作模式,同時搞清楚寄存器的特殊性,同時搞清楚中斷處理的一般過程。
評論