μC/OS-III---I笔记13---中断管理

摘要:
因此,上面的第二行汇编代码实际上将PRIMASK保存到R0并将其返回到变量cpu_Sr,第三行是关闭全局中断的CM3命令,该命令保存在LR中以调用cpu_Sr_BX。BX返回Save()之前的下一条指令的PC指针。此外,应成对使用进入和退出调度嵌套,这将导致调度程序始终被锁定=OS_ERR_NONE){return;}#Endif中断延迟提交过程

中断管理
先看一下最常用的临界段进入的函数:进入临界段 OS_CRITICAL_ENTER() 退出临界段OS_CRITICAL_EXIT()他们两个的宏是这样的.

在使能中断延迟提交时:
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u                             /* Deferred ISR Posts ------------------------------ */
                                                                 /* Lock the scheduler                                */
#define  OS_CRITICAL_ENTER()                                       
         do {                                                      
             CPU_CRITICAL_ENTER();                                 
             OSSchedLockNestingCtr++;                              
             if (OSSchedLockNestingCtr == 1u) {                    
                 OS_SCHED_LOCK_TIME_MEAS_START();                  
             }                                                     
             CPU_CRITICAL_EXIT();                                  
         } while (0)
                                                                 /* Lock the scheduler but re-enable interrupts       */
#define  OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT()                     
         do {                                                      
             OSSchedLockNestingCtr++;                              
                                                                   
             if (OSSchedLockNestingCtr == 1u) {                    
                 OS_SCHED_LOCK_TIME_MEAS_START();                  
             }                                                     
             CPU_CRITICAL_EXIT();                                  
         } while (0)

                                                                 /* Scheduling occurs only if an interrupt occurs     */
#define  OS_CRITICAL_EXIT()                                        
         do {                                                      
             CPU_CRITICAL_ENTER();                                 
             OSSchedLockNestingCtr--;                              
             if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) {     
                 OS_SCHED_LOCK_TIME_MEAS_STOP();                   
                 if (OSIntQNbrEntries > (OS_OBJ_QTY)0) {           
                     CPU_CRITICAL_EXIT();                          
                     OS_Sched0();                                  
                 } else {                                          
                     CPU_CRITICAL_EXIT();                          
                 }                                                 
             } else {                                              
                 CPU_CRITICAL_EXIT();                              
             }                                                     
         } while (0)

#define  OS_CRITICAL_EXIT_NO_SCHED()                               
         do {                                                      
             CPU_CRITICAL_ENTER();                                 
             OSSchedLockNestingCtr--;                              
             if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) {     
                 OS_SCHED_LOCK_TIME_MEAS_STOP();                   
             }                                                     
             CPU_CRITICAL_EXIT();                                  
         } while (0)


#else                                                            /* Direct ISR Posts -------------------------------- */

在没有使能中断延迟提交时:

#define  OS_CRITICAL_ENTER()                    CPU_CRITICAL_ENTER()

#define  OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT()

#define  OS_CRITICAL_EXIT()                     CPU_CRITICAL_EXIT()

#define  OS_CRITICAL_EXIT_NO_SCHED()            CPU_CRITICAL_EXIT()

#endif

先看一下在没有使能中断延迟提交时的临界段进入的函数:进入临界段 CPU_CRITICAL_ENTER() 退出临界段CPU_CRITICAL_EXIT()
他们两个的宏是这样的

#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); } while (0) 
#define CPU_CRITICAL_EXIT() do { CPU_INT_EN(); } while (0)

另一层宏是

#define CPU_INT_DIS() do { cpu_sr = CPU_SR_Save(); } while (0) 
#define CPU_INT_EN() do { CPU_SR_Restore(cpu_sr); } while (0)

接着另一层宏是

CPU_SR_Save
MRS R0, PRIMASK ; Set prio int mask to mask all (except faults)
CPSID I
BX LR

这里关于C语言调用汇编,规定32位的返回值存放到R0,64位的R0存放第32为,R1存放高32位。所以上边的汇编代码第二行实际就是将PRIMASK保存到R0最后返回给变量cpu_sr ,第三行是一个CM3关全局中断的命令,在LR保存了调用CPU_SR_Save()之前的下一条指令PC指针,BX就返回了。

CPU_SR_Restore ; 
MSR PRIMASK, R0
BX LR

这里注意调用这个函数时传入了cpu_sr,根据C调用汇编的规定这个变量被存放到R0里,所以第二句就是将cpu_sr 恢复到PRIMASK,由CM3权威指南可以知道,这是一个中断管理的寄存器,写1屏蔽所有中断,只剩下faul和NMI,写0则开启中断;c语言调用汇编时规定,当传递参数少于4个时,从右往左依次存放到R0~R3中,当传入参数多于4个时,多出来的参数会先入栈;

注意在调用进入临界段时常常有这个函数CPU_SR_ALLOC()它的宏是

#define CPU_SR_ALLOC() CPU_SR cpu_sr = (CPU_SR)0

即定义的一个CPU_SR的变量初始化为0;

对于延迟提交使能下的进入临界段代码,就是加了一个调度器嵌套层数OSSchedLockNestingCtr++的操作,它代表了调度器被锁住的嵌套层数,OS_CRITICAL_ENTER直接锁住调度器,OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT()这个宏调用之前一般先关闭中断,接着宏锁住调度器然后锁住调度器,再恢锁调度器前的中断状态(这里不是开中断),在没有使能中断延迟时,会增加中断关闭的时间。解开调度嵌套也有两种

  • OS_CRITICAL_EXIT()
  • 解开调度时进行任务调度(延迟);
  • OS_CRITICAL_EXIT_NO_SCHED()
  • 解开调度时不进行任务调度;

这两个函数后应该都根据选项选择是否调用OSSchedule()进行任务调度。且进入调度嵌套和退出嵌套要成对使用负责会导致调度器被一直锁住。锁住调度器是用户无法进行任务切换,也无法将当前任务挂起。

中断在系统中相当于优先级最高的任务,因此对于中断的处理是十分紧急的从CM3的内核中断响应机制就能知道cpu对于中断的相应是追求极致的快速,所以UCOS对于这里也有对应的措施,系统级的一些处理时间比较长的任务不允许在中断中调用,对于一些中断中的提交函数会放到中断延迟提交里完成,把中断级的任务放到任务级从而减少关中断时间,减少对中断的实时性的影响。

中断延迟提交:

当用户在把宏OS_CFG_ISR_POST_DEFERRED使能,使用延迟提交在系统初始化时会自动初始化延迟提交队列然后创建一个延迟提交任务。

OSInit()函数内的延迟提交任务初始化

#if OS_CFG_ISR_POST_DEFERRED_EN > 0u
    OS_IntQTaskInit(p_err);                                 /* Initialize the Interrupt Queue Handler Task            */
    if (*p_err != OS_ERR_NONE) {
        return;
    }
#endif

中断延迟提交的过程就是把要提交的内容先保存起来,然后把系统初始化时创建一个优先级 为0(最高)的延迟提交任务就绪,在中断函数执行完成后就会执行延迟的提交。对于OS_IntQTaskInit(p_err)主要作用就是初始化延迟提交队列,并创建任务。在之前的任务管理章节我们知道一个任务被创建就会加如就绪列表等待调用时就会执行.

μC/OS-III---I笔记13---中断管理第1张μC/OS-III---I笔记13---中断管理第2张
void  OS_IntQTaskInit (OS_ERR  *p_err)
{
    OS_INT_Q      *p_int_q;
    OS_INT_Q      *p_int_q_next;
    OS_OBJ_QTY     i;



#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif
    //延迟提交溢出计数清零 
    OSIntQOvfCtr = (OS_QTY)0u;                              /* Clear the ISR queue overflow counter                   */
    //延迟提交信息队列的内存不能是空 
    if (OSCfg_IntQBasePtr == (OS_INT_Q *)0) {
       *p_err = OS_ERR_INT_Q;
        return;
    }
    //延迟信息队列的长最小是1 
    if (OSCfg_IntQSize < (OS_OBJ_QTY)2u) {
       *p_err = OS_ERR_INT_Q_SIZE;
        return;
    }
    //延迟提交任务每次运行的最长时间 
    OSIntQTaskTimeMax = (CPU_TS)0;

    p_int_q           = OSCfg_IntQBasePtr;                  /* Initialize the circular ISR queue                      */
    p_int_q_next      = p_int_q;
    p_int_q_next++;
    //将信息对垒串成单项链表 
    for (i = 0u; i < OSCfg_IntQSize; i++) {
        p_int_q->Type    =  OS_OBJ_TYPE_NONE;
        p_int_q->ObjPtr  = (void      *)0;
        p_int_q->MsgPtr  = (void      *)0;
        p_int_q->MsgSize = (OS_MSG_SIZE)0u;
        p_int_q->Flags   = (OS_FLAGS   )0u;
        p_int_q->Opt     = (OS_OPT     )0u;
        p_int_q->NextPtr = p_int_q_next;
        p_int_q++;
        p_int_q_next++;
    }
    //单项链表“圈”操作方便延时提交队列内存的使用 
    p_int_q--;
    p_int_q_next        = OSCfg_IntQBasePtr;
    p_int_q->NextPtr    = p_int_q_next;
    OSIntQInPtr         = p_int_q_next;
    OSIntQOutPtr        = p_int_q_next;
    //延迟提交队列中要进行提交的内核对象个数 
    OSIntQNbrEntries    = (OS_OBJ_QTY)0u;
    //延迟提交队列中要进行提交的内核对象的最大个数
    OSIntQNbrEntriesMax = (OS_OBJ_QTY)0u;

                                                            /* -------------- CREATE THE ISR QUEUE TASK ------------- */
    if (OSCfg_IntQTaskStkBasePtr == (CPU_STK *)0) {
       *p_err = OS_ERR_INT_Q_STK_INVALID;
        return;
    }

    if (OSCfg_IntQTaskStkSize < OSCfg_StkSizeMin) {
       *p_err = OS_ERR_INT_Q_STK_SIZE_INVALID;
        return;
    }
    //创建延迟提交任务 
    OSTaskCreate((OS_TCB     *)&OSIntQTaskTCB,
                 (CPU_CHAR   *)((void *)"uC/OS-III ISR Queue Task"),
                 (OS_TASK_PTR )OS_IntQTask,
                 (void       *)0,
                 (OS_PRIO     )0u,                          /* This task is ALWAYS at priority '0' (i.e. highest)     */
                 (CPU_STK    *)OSCfg_IntQTaskStkBasePtr,
                 (CPU_STK_SIZE)OSCfg_IntQTaskStkLimit,
                 (CPU_STK_SIZE)OSCfg_IntQTaskStkSize,
                 (OS_MSG_QTY  )0u,
                 (OS_TICK     )0u,
                 (void       *)0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR     *)p_err);
}

#endif
OS_IntQTaskInit ()

函数内创建的延迟提交任务

void  OS_IntQTask (void  *p_arg)
{
    CPU_BOOLEAN  done;
    CPU_TS       ts_start;
    CPU_TS       ts_end;
    CPU_SR_ALLOC();



    p_arg = p_arg;                                          /* Not using 'p_arg', prevent compiler warning            */
    while (DEF_ON) {
        done = DEF_FALSE;
        while (done == DEF_FALSE) {
            CPU_CRITICAL_ENTER();
            //还有内核对象等待提交?
            //
            if (OSIntQNbrEntries == (OS_OBJ_QTY)0u) {
                //任务删除 
                OSRdyList[0].NbrEntries = (OS_OBJ_QTY)0u;   /* Remove from ready list                                 */
                OSRdyList[0].HeadPtr    = (OS_TCB   *)0;
                OSRdyList[0].TailPtr    = (OS_TCB   *)0;
                OS_PrioRemove(0u);                          /* Remove from the priority table                         */
                CPU_CRITICAL_EXIT();
                OSSched();
                done = DEF_TRUE;                            /* No more entries in the queue, we are done              */
            } 
            //
            else {
                CPU_CRITICAL_EXIT();
                ts_start = OS_TS_GET();
                //提交信息 
                OS_IntQRePost();
                ts_end   = OS_TS_GET() - ts_start;          /* Measure execution time of tick task                    */
                if (OSIntQTaskTimeMax < ts_end) {
                    OSIntQTaskTimeMax = ts_end;
                }
                CPU_CRITICAL_ENTER();
                //提交信息队列出口指向更新 
                OSIntQOutPtr = OSIntQOutPtr->NextPtr;       /* Point to next item in the ISR queue                    */
                OSIntQNbrEntries--;
                CPU_CRITICAL_EXIT();
            }
        }
    }
}

函数内先检查提交信息队列是否为空了也就是提交完了,如果 提交完成了就将延迟提交任务从对应优先级的就绪任务列表移除,如果还有信息队列等待提交就继续调用OS_IntQRePost();进行内核对象提交。

μC/OS-III---I笔记13---中断管理第3张μC/OS-III---I笔记13---中断管理第4张
void  OS_IntQRePost (void)
{
    CPU_TS  ts;
    OS_ERR  err;

    //根据提交对象的类型进行选择内核对象提交函数 
    switch (OSIntQOutPtr->Type) {                           /* Re-post to task                                        */
        case OS_OBJ_TYPE_FLAG:
#if OS_CFG_FLAG_EN > 0u
             (void)OS_FlagPost((OS_FLAG_GRP *) OSIntQOutPtr->ObjPtr,
                               (OS_FLAGS     ) OSIntQOutPtr->Flags,
                               (OS_OPT       ) OSIntQOutPtr->Opt,
                               (CPU_TS       ) OSIntQOutPtr->TS,
                               (OS_ERR      *)&err);
#endif
             break;

        case OS_OBJ_TYPE_Q:
#if OS_CFG_Q_EN > 0u
             OS_QPost((OS_Q      *) OSIntQOutPtr->ObjPtr,
                      (void      *) OSIntQOutPtr->MsgPtr,
                      (OS_MSG_SIZE) OSIntQOutPtr->MsgSize,
                      (OS_OPT     ) OSIntQOutPtr->Opt,
                      (CPU_TS     ) OSIntQOutPtr->TS,
                      (OS_ERR    *)&err);
#endif
             break;

        case OS_OBJ_TYPE_SEM:
#if OS_CFG_SEM_EN > 0u
             (void)OS_SemPost((OS_SEM *) OSIntQOutPtr->ObjPtr,
                              (OS_OPT  ) OSIntQOutPtr->Opt,
                              (CPU_TS  ) OSIntQOutPtr->TS,
                              (OS_ERR *)&err);
#endif
             break;

        case OS_OBJ_TYPE_TASK_MSG:
#if OS_CFG_TASK_Q_EN > 0u
             OS_TaskQPost((OS_TCB    *) OSIntQOutPtr->ObjPtr,
                          (void      *) OSIntQOutPtr->MsgPtr,
                          (OS_MSG_SIZE) OSIntQOutPtr->MsgSize,
                          (OS_OPT     ) OSIntQOutPtr->Opt,
                          (CPU_TS     ) OSIntQOutPtr->TS,
                          (OS_ERR    *)&err);
#endif
             break;

        case OS_OBJ_TYPE_TASK_RESUME:
#if OS_CFG_TASK_SUSPEND_EN > 0u
             (void)OS_TaskResume((OS_TCB *) OSIntQOutPtr->ObjPtr,
                                 (OS_ERR *)&err);
#endif
             break;

        case OS_OBJ_TYPE_TASK_SIGNAL:
             (void)OS_TaskSemPost((OS_TCB *) OSIntQOutPtr->ObjPtr,
                                  (OS_OPT  ) OSIntQOutPtr->Opt,
                                  (CPU_TS  ) OSIntQOutPtr->TS,
                                  (OS_ERR *)&err);
             break;

        case OS_OBJ_TYPE_TASK_SUSPEND:
#if OS_CFG_TASK_SUSPEND_EN > 0u
             (void)OS_TaskSuspend((OS_TCB *) OSIntQOutPtr->ObjPtr,
                                  (OS_ERR *)&err);
#endif
             break;

        case OS_OBJ_TYPE_TICK:
#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
            //任务时间片轮换调度任务 
             OS_SchedRoundRobin(&OSRdyList[OSPrioSaved]);
#endif
            //时间任务管理 
             (void)OS_TaskSemPost((OS_TCB *)&OSTickTaskTCB,                /* Signal tick task                        */
                                  (OS_OPT  ) OS_OPT_POST_NONE,
                                  (CPU_TS  ) OSIntQOutPtr->TS,
                                  (OS_ERR *)&err);
#if OS_CFG_TMR_EN > 0u
             //定时器任务提交 
             OSTmrUpdateCtr--;
             if (OSTmrUpdateCtr == (OS_CTR)0u) {
                 OSTmrUpdateCtr = OSTmrUpdateCnt;
                 ts             = OS_TS_GET();                             /* Get timestamp                           */
                 (void)OS_TaskSemPost((OS_TCB *)&OSTmrTaskTCB,             /* Signal timer task                       */
                                      (OS_OPT  ) OS_OPT_POST_NONE,
                                      (CPU_TS  ) ts,
                                      (OS_ERR *)&err);
             }
#endif
             break;

        default:
             break;
    }
}
OS_IntQRePost()

这个函数内就是根据延迟提交的内核对象的类型然后分别调用内核对应的Post函数对内核对象进行提交。从而完成内核对象的延迟提交。

免责声明:文章转载自《μC/OS-III---I笔记13---中断管理》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇通过键盘方向键控制TreeView节点的移动jemeter批量测试下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

操作系统知识总结

操作系统 面向进程和线程学习操作系统。 目录 Chapter 1 Chapter 2 Chapter 3 Chapter 4 Chapter 5 进程线程模型 进程间通信 同步互斥机制 存储管理 网络I/O模型 内容 进程线程模型 线程和进程的概念已经在操作系统书中被翻来覆去讲了很多遍。很多概念虽然都是套话,但没能理解透其中深意会导致很多内容...

《马哥出品高薪linux运维教程》wingkeung学习笔记-linux基础入门课程

计算机原理概念: 1、CPU和内存中的存储单元通信线路称为总线(BUS),总线是被指令和数据复用的,所以也称为前端总线。 2、计算机中计算频率的时间标准即晶体振荡器原理,精确计算时间长度,根据相同的时间统计变化的次数,即保持时钟同步。 3、每一个芯片在厂家生产时都有一个以微码(汇编语言)形式存在内置接口,完成一定意义上的智能操作。 4、CPU中控制器在未从...

react学习

1.state属性 state顾名思义就是状态,它只是用来控制这个组件本身自己的状态,我们可以用state来完成对行为的控制、数据的更新、界面的渲染. setState更新是异步的,事件处理过程 setState 不会同步更新 this.state, React 控制之外的情况, setState 会同步更新 this.state 总结:尽量少地用 sta...

(三) ffmpeg filter学习-编写自己的filter

目录 目录 什么是ffmpeg filter 如何使用ffmpeg filter 1 将输入的1920x1080缩小到960x540输出 2 为视频添加logo 3 去掉视频的logo 自己写一个过滤器 filter的结构体 filter_frame调用流程 1 decode_video ffmpegc 2 av_buffersrc_add_fr...

什么是零拷贝

 1、名词介绍   内核:操作系统的核心   用户空间:指的是用户进程的运行空间   内核空间:指的是内核的运行空间   用户态:如果进程运行在用户空间就是用户态   内核态:如果进程运行在内核空间就是内核态   DMA拷贝:     对一个IO操作而言,是通过CPU发出对应的指令来完成的,但是相比CPU来说,IO的速度太慢了,CPU有大量的时间处于等待I...

Linux平台Cpu使用率的计算

proc文件系统 /proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为内核与进程提供通信的接口。用户和应用程序可以通过/proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息,如进程,是动态改变的,所以用户或应用程序读取/proc目录中的文件时,proc文件系统是动态从系统内核读出所需信息并提交的。 /pr...