uC/OS-Il---多级中断机制

目录

  • 中断处理的一般流程
  • 多级中断机制的出现
  • 多级中断机制的实现
    • 必须在一个任务或中断中配对使用
      • 保存当前中断状态并关中断---OS_ENTER_CRITICAL()
        • 汇编语言函数---OS_CPU_SR_Save()
      • 恢复之前的中断状态以便开中断---OS_EXIT_CRITICAL()
        • 汇编语言函数---OS_CPU_SR_Restore()
    • 必须在中断服务程序中配对用
      • 进入中断服务程序---OSIntEnter()
      • 退出中断服务程序---OSIntExit()

中断处理的一般流程

一般的中断处理流程可以按照以下顺序进行:

  • 保存当前中断状态【OS_ENTER_CRITICAL()】:在进入中断服务程序(ISR)之前,需要保存当前的中断状态。这可以通过将中断状态寄存器的值保存到内存中,或者使用特定的指令将中断状态压入堆栈来实现。保存当前中断状态的目的是为了确保在ISR执行期间不会被其他中断打断。
  • 进入中断服务程序【OSIntEnter()】:保存完当前中断状态后,处理器会跳转到相应的中断服务程序中执行特定的处理逻辑。中断服务程序是由开发人员编写的,用于响应中断事件并执行相应的处理操作。
  • 进行中断处理:在中断服务程序中,会执行与中断相关的处理逻辑。这包括根据中断类型进行相应的处理,访问和操作中断相关的寄存器和数据结构,以及执行与中断相关的任务或操作。
  • 退出中断处理/退出中断服务程序【OSIntExit()】
  • 恢复中断状态【OS_EXIT_CRITICAL()】:在中断处理完成后,通常会恢复之前保存的中断状态,以允许其他中断继续响应。这可以通过将之前保存的中断状态从内存中恢复,或者使用特定的指令将中断状态从堆栈中弹出来实现。

这个流程确保了在中断处理期间,中断的响应是可控的,并且能够保护中断服务程序的临界区代码的执行。通过保存和恢复中断状态,可以确保不同中断之间的正确协调和处理,同时保持系统的可靠性和实时性。

多级中断机制的出现

多级中断机制的目的是为了实现以下功能:

  • 实时性:多级中断机制可以提供更高的实时性。在嵌入式系统中,可能会有多个中断源同时触发中断请求,如果只有一级中断,那么只能按照中断的优先级依次处理,无法及时响应高优先级的中断请求。而多级中断机制可以根据中断的优先级进行分级处理,优先处理高优先级的中断请求,从而提高系统的实时性。
  • 中断嵌套:多级中断机制可以支持中断的嵌套。当一个中断正在处理时,如果另一个中断请求到达,可以通过多级中断机制将当前正在处理的中断暂时挂起,处理新的中断请求,然后再返回继续处理之前的中断。这样可以有效地处理多个中断请求,提高系统的灵活性和响应能力。
    • uC/OS-II支持多级中断嵌套,即在一个中断处理程序中可以发生另一个中断。
    • 这是通过保存和恢复中断状态以及使用中断屏蔽寄存器来实现的。
  • 中断优先级控制:多级中断机制可以对中断进行优先级控制。通过设置不同的中断优先级,可以确保高优先级的中断能够及时得到处理,而低优先级的中断则可以在高优先级中断处理完毕后再进行处理。这样可以根据系统需求对中断进行灵活的调度和控制。

多级中断机制的实现

必须在一个任务或中断中配对使用

OS_ENTER_CRITICAL();  // 禁用中断

// 临界区代码,对共享资源进行操作

OS_EXIT_CRITICAL();   // 恢复中断

保存当前中断状态并关中断—OS_ENTER_CRITICAL()

  • 在进入临界区之前,调用OS_ENTER_CRITICAL()函数会保存当前的中断状态,并禁用中断。这样可以确保在临界区内不会被其他中断打断。
  • 通过调用OS_ENTER_CRITICAL()宏函数,可以将当前的中断状态保存到cpu_sr变量中,以便在临界区执行完毕后恢复。
  • OS_ENTER_CRITICAL()函数通常在任务的临界区代码之前被调用,用于禁用中断以保护任务的临界区代码
#define  OS_CRITICAL_METHOD   3u

#if OS_CRITICAL_METHOD == 3u
#define  OS_ENTER_CRITICAL()  {cpu_sr = OS_CPU_SR_Save();}
#define  OS_EXIT_CRITICAL()   {OS_CPU_SR_Restore(cpu_sr);}
#endif
汇编语言函数—OS_CPU_SR_Save()
OS_CPU_SR_Save
    MRS     R0, PRIMASK                ; Set prio int mask to mask all (except faults)
    CPSID   I
    BX      LR
  • MRS R0, PRIMASK:将当前的优先级屏蔽寄存器(PRIMASK)的值加载到寄存器R0中。PRIMASK寄存器用于控制全局中断的使能和禁止。
  • CPSID I:禁止所有中断。通过将中断控制状态寄存器(CPSR)的中断使能位(I)置为1,禁止所有中断的触发。
  • BX LR:返回到调用该函数的地址。使用BX LR指令将程序控制权返回给调用者。
  • 注释【Set prio int mask to mask all (except faults)】:这句话的意思是将优先级中断屏蔽寄存器设置为屏蔽所有中断(除了故障中断)
    • 在某些处理器架构中,有一个优先级中断屏蔽寄存器(Priority Interrupt Mask
      Register),用于控制中断的优先级和屏蔽。通过设置该寄存器的值,可以选择性地屏蔽或允许特定优先级的中断。
      这句话中提到的操作是将优先级中断屏蔽寄存器设置为屏蔽所有中断,除了故障中断。这意味着除了故障中断(如硬件故障或异常)之外,其他所有中断都会被屏蔽,不会被处理器响应。
      这种设置通常用于特殊情况下,例如在处理器初始化或特定任务执行期间,需要暂时屏蔽所有中断,以确保关键代码的执行或处理器的稳定性。只有故障中断才能继续被处理器响应,以确保系统的可靠性和安全性。

这段代码的作用是将当前的中断状态保存到寄存器R0中,并禁止所有中断。通过保存中断状态,可以在后续需要时恢复中断状态,以确保临界区的原子性和可靠性。

恢复之前的中断状态以便开中断—OS_EXIT_CRITICAL()

  • 在退出临界区时,调用OS_EXIT_CRITICAL()函数会恢复之前保存的中断状态,允许其他中断继续执行。
  • 通过调用OS_EXIT_CRITICAL()宏函数,可以将之前保存的中断状态从cpu_sr变量中恢复,使得中断状态回到进入临界区之前的状态。这样可以确保在临界区执行期间不会发生中断,保证临界区的原子性和可靠性。
#define  OS_CRITICAL_METHOD   3u

#if OS_CRITICAL_METHOD == 3u
#define  OS_ENTER_CRITICAL()  {cpu_sr = OS_CPU_SR_Save();}
#define  OS_EXIT_CRITICAL()   {OS_CPU_SR_Restore(cpu_sr);}
#endif
汇编语言函数—OS_CPU_SR_Restore()
OS_CPU_SR_Restore
    MSR     PRIMASK, R0
    BX      LR
  • MSR PRIMASK, R0:将寄存器R0的值写入PRIMASK寄存器,这个值用于恢复中断状态。
  • BX LR:将程序控制权返回到调用该函数的地址,即返回到LR寄存器中保存的地址。

这段代码的作用是将之前保存的中断状态寄存器的值恢复,以便恢复之前的中断状态。

必须在中断服务程序中配对用

进入中断服务程序—OSIntEnter()

  • 进入中断服务程序(ISR)应该在中断已经被禁用的情况下调用
  • OSIntEnter()函数是在ISR中使用,用于禁用中断以保护ISR的临界区代码
  • 你的ISR可以直接增加OSIntNesting而不调用这个函数,因为OSIntNesting已经被声明为全局变量。即使直接增加了OSIntNesting,仍然必须调用OSIntExit()。
  • 必须成对地调用OSIntEnter()和OSIntExit()。换句话说,对于ISR开始时的每次调用OSIntEnter(),必须在ISR结束时调用一次OSIntExit()。
  • 可以嵌套中断,最多可以达到255层。
  • 代码在增加操作周围删除了OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL(),因为OSIntEnter()总是在中断被禁用的情况下调用。
void  OSIntEnter (void)
{
	if (OSRunning == OS_TRUE)
	{
		if (OSIntNesting < 255u)
		{
			OSIntNesting++;                      /*增加中断服务程序(ISR)的嵌套级别*/
		}
	}
}

退出中断服务程序—OSIntExit()

  • 这个函数用于通知uC/OS-II,你已经完成了对ISR(中断服务程序)的维护。当最后一个嵌套的ISR完成后,uC/OS-II会调用调度器来确定是否有新的高优先级任务准备运行。
  • 当调度器被锁定时(请参阅OS_SchedLock()),防止重新调度。
void  OSIntExit (void)
{
#if OS_CRITICAL_METHOD == 3u                               /* Allocate storage for CPU status register */
	OS_CPU_SR  cpu_sr = 0u;
#endif
	
	if (OSRunning == OS_TRUE)
	{
		OS_ENTER_CRITICAL();
		
		if (OSIntNesting > 0u)                           /*防止OSIntNesting变量的值溢出或循环*/
		{
			OSIntNesting--;
		}
		
		if (OSIntNesting == 0u)                          /*只有当所有的中断服务程序(ISR)都完成时,才重新调度…*/
		{
			if (OSLockNesting == 0u)                     /*…并且未被锁定*/
			{
				OS_SchedNew();
				OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
				
				if (OSPrioHighRdy != OSPrioCur)          /*如果当前任务是最高优先级的就绪任务,则不进行上下文切换*/
				{
#if OS_TASK_PROFILE_EN > 0u
					OSTCBHighRdy->OSTCBCtxSwCtr++;         /*"增加到此任务的上下文切换次数*/
#endif
					OSCtxSwCtr++;                          /*跟踪上下文切换的次数*/
					OSIntCtxSw();                          /*执行中断级别的上下文切换*/
				}
			}
		}
		
		OS_EXIT_CRITICAL();
	}
}

你可能感兴趣的:(μC/OS-II学习,操作系统,c语言)