UCOS 中的中斷處理


最近遇到一個問題,當我在UCOS里調用系統延時"OSTimeDlyHMSM(0, 0, 0, 10)",程序進入硬件錯誤中斷“HardFault_Handler”中。

我開始以為是主堆棧空間嵌套過多導致溢出,於是設置增大了主堆棧,但依然沒有解決問題,和一個朋友聯系后得知,他寫代碼很少在ISR中調用系統延時,我開始有了想法,如果說ISR里不允許,那為什么操作系統端沒做限制呢?查看相關資料得知,是我對操作系統的不了解。

uCOS為了防止主堆棧的用空導致程序跑飛,定義了“OSIntNesting”全局變量。

而通過這個全局變量,操作系統能很容易的監控中斷的嵌套層次。

而想要利用這個樣的機制,你得在你的中斷服務程序中配合使用:

OSIntEnter()//告知操作系統你已經進入中斷 OSIntNesting++

OSIntExit()//告知操作系統你已經進入中斷 OSIntNesting--

 

正對此次問題的摘要:

摘要1:

  1 //文章來源:http://gliethttp.cublog.cn[轉載請聲明出處]
  2 
  3 //----------------------------------------------------------------------
  4 //1.OSTimeDly()函數
  5 void OSTimeDly (INT16U ticks)
  6 {
  7     INT8U y;
  8 #if OS_CRITICAL_METHOD == 3
  9     OS_CPU_SR cpu_sr = 0;
 10 #endif
 11     if (OSIntNesting > 0) {
 12         return;//在中斷處理函數中調用了OSTimeDly(),那么直接退出
 13     }
 14     if (ticks > 0) {
 15         OS_ENTER_CRITICAL();
 16 //調用OSTimeDly()的進程自己把自己從就緒控制矩陣中拿下來,
 17 //即:去掉調度器(x,y)矩形陣列(OSRdyTbl,OSRdyGrp)中該task對應的bit位,使得調度器不考慮
 18 //該task的調度
 19         y = OSTCBCur->OSTCBY;
 20         OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;
 21         if (OSRdyTbl[y] == 0) {
 22             OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
 23         }
 24 //延時ticks值,放入OSTCBDly單元,在os時鍾滴答處理函數OSTimeTick()中,會處理該單元[gliethttp]
 25         OSTCBCur->OSTCBDly = ticks;
 26         OS_EXIT_CRITICAL();
 27 //因為本task正在運行,所以本task現在的優先級最高,現在本task已經將自己從就緒控制矩陣中--調度器(x,y)矩形陣列
 28 //把自己摘掉,所以調度函數OS_Sched()一定會切換到另一個task中執行新task的代碼[gliethttp]
 29         OS_Sched();//具體參見《淺析μC/OS-II v2.85內核調度函數》
 30     }//ticks==0,那么什么也不做
 31 }
 32 //----------------------------------------------------------------------
 33 //2.OSTimeTick()--在定時中斷里引用的系統滴答函數
 34 void OSTimeTick (void)
 35 {
 36     OS_TCB *ptcb;
 37 #if OS_TICK_STEP_EN > 0
 38     BOOLEAN step;
 39 #endif
 40 #if OS_CRITICAL_METHOD == 3
 41     OS_CPU_SR cpu_sr = 0;//該3方式將使中斷狀態寄存器放入堆棧中
 42 
 43 #endif
 44 
 45 #if OS_TIME_TICK_HOOK_EN > 0
 46     OSTimeTickHook();
 47 #endif
 48 #if OS_TIME_GET_SET_EN > 0
 49     OS_ENTER_CRITICAL();
 50     OSTime++;
 51     OS_EXIT_CRITICAL();
 52 #endif
 53     if (OSRunning == OS_TRUE) {
 54 #if OS_TICK_STEP_EN > 0
 55 //控制內核的tick
 56         switch (OSTickStepState) {
 57             case OS_TICK_STEP_DIS:
 58                  step = OS_TRUE;
 59                  break;
 60             case OS_TICK_STEP_WAIT:
 61                  step = OS_FALSE;
 62                  break;
 63             case OS_TICK_STEP_ONCE:
 64 //本次tick將將影響到task的OSTCBDly域
 65 //但以后的tick將一直被屏蔽,不會影響到OSTCBDly域
 66 //直到外部將OSTickStepState改變為止[gliethttp]
 67                  step = OS_TRUE;
 68                  OSTickStepState = OS_TICK_STEP_WAIT;
 69                  break;
 70             default:
 71                  step = OS_TRUE;//本次tick將影響到task的OSTCBDly域
 72                  OSTickStepState = OS_TICK_STEP_DIS;
 73                  break;
 74         }
 75         if (step == OS_FALSE) {
 76             return;
 77         }
 78 #endif
 79         ptcb = OSTCBList;
 80 //2007-09-08 gliethttp
 81 //OSTCBList是一個按進程創建的先后順序鏈接成的task單向鏈表,最后創建的task在最前面,最先創建的
 82 //task在單向鏈表的尾端,
 83 //所以OS_TaskIdle空閑進程在鏈表的最后,因為它最先創建
 84         while (ptcb->OSTCBPrio != OS_TASK_IDLE_PRIO) {
 85             OS_ENTER_CRITICAL();
 86             if (ptcb->OSTCBDly != 0) {
 87                 if (--ptcb->OSTCBDly == 0) {
 88 //該task的延時時間已到,解析此次延時是OSTimeDly()引起的,還是OSQPend()之類超時引起的[gliethttp]
 89                     if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {
 90                         //2007-09-08 gliethttp
 91                         //如:由OSSemPend (pevent,timeout,perr);定義的timeout已經到了,對應task需要運行了
 92                         //超時時間到,所以不論當前進程是在做什么,只要時間一到
 93                         //該task就可以運行了,所以清除所有事件標志,之后狀態標示為OS_STAT_PEND_TO(超時)
 94                         ptcb->OSTCBStat &= ~(INT8U)OS_STAT_PEND_ANY;
 95                         ptcb->OSTCBStatPend = OS_STAT_PEND_TO;//超時異常
 96                     } else {
 97                         //2007-09-08 gliethttp
 98                         //說明該task調用的是OSTimeDly()
 99                         ptcb->OSTCBStatPend = OS_STAT_PEND_OK;//正常結束
100                     }
101                     if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {
102                         //2007-09-08 gliethttp
103                         //如果該task沒有suspend,那么把當前就緒的task加入到運行調度器的就緒控制矩陣中
104                         //等待被調度
105                         OSRdyGrp |= ptcb->OSTCBBitY;
106                         OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
107                     }
108                 }
109             }
110             ptcb = ptcb->OSTCBNext;//繼續運算下一個task的OSTCBDly時間域
111             OS_EXIT_CRITICAL();
112         }
113     }
114 }

摘要2:

前些天參照FL2440的bootloader的程序,寫了關於裸機USB設備驅動的測試程序。然后就想把USB的驅動程序移植到uCos系統中運行。
    對於USB設備驅動的工作原理,我這里不多說,網上有很多這方面的資料。這里只說明在UCOS系統中移植USB設備驅動所需要注意的細節。
    第一步:在uCos系統啟動以后,首先對USB設備進行初始化。 這里的初始化包含對中斷函數的設置和端點功能的設置 。

    第二步:創建一個端點0的控制處理任務函數。這個任務的優先級最好設置為最高優先級,以便能夠及時處理USB的枚舉。在任務函數中,我們通過請求信號量的方式來等待中斷服務程序發來的信號,當中斷服務程序檢測到是端點0的中斷,即發送一個信號。端點0的控制任務函數接收到此信號,便開始進入端點0的控制傳輸。如果沒有接收到信號,則此任務函數一直處於堵塞狀態。便於其他任務的調度執行。這里還有一點需要注意的是:在進入中斷函數時,要使用OSIntEnter()和OSIntExit()這兩個配套函數。我開始的時候沒有加入這兩個函數,結果導致一進入枚舉就會導致程序跑飛。

 1 //摘要來自http://blog.sina.com.cn/u/1093812390
 2 //USB控制傳輸任務函數
 3 
 4 void TaskUsb(void *pdata)
 5 {
 6 #if OS_CRITICAL_METHOD == 3
 7 OS_CPU_SR  cpu_sr;
 8 #endif
 9 INT8U err;
10 while(1){
11 OSSemPend(pSetup_Event,0,&err); //等待信號
12 if (err == OS_NO_ERR){
13 OS_ENTER_CRITICAL(); //關中斷
14 Ep0Handler(); //進行控制傳輸處理
15 OS_EXIT_CRITICAL(); //開中斷
16 }
17 }
18 }
19 
20 //中斷函數如下:
21 
22 void IsrUsbd(void)
23 {
24 #if OS_CRITICAL_METHOD == 3            OS_CPU_SR  cpu_sr;
25 #endif
26 
27 
28 U8 usbdIntpnd,epIntpnd;
29     U8 saveIndexReg = rINDEX_REG;
30     OS_ENTER_CRITICAL();   //關中斷
31 OSIntEnter(); //通知UCOS系統,已進入中斷處理程序 usbdIntpnd = rUSB_INT_REG; //讀取USB中斷寄存器
32 epIntpnd = rEP_INT_REG; //讀取端點中斷寄存器
33 ....
34 if (epIntpnd & EP0_INT) {
35     rEP_INT_REG = EP0_INT;
36     OSSemPost(pSetup_Event); //通知控制端口處理任務
37  }
38 ClearPending(BIT_USBD); rINDEX_REG = saveIndexReg;
39  OS_EXIT_CRITICAL(); //開中斷
40  OSIntExit(); //通知系統,已處理結束中斷服務程序。任務調度
41 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM