文章目录
- 1. 中断
- 1.1 Cat1 与 Cat2 对比
- 1.2 入口宏的汇编实现
- 1.3 中断屏蔽级别机制
- 1.4 OS 如何介入 Cat2 ISR
- 1.4.1 介入时机总览
- 1.4.2 Os_Isr_Entry 详解
- 1.4.3 Os_Isr_Exit 详解
- 2. 定时器中断(OS_HRT)
- 2.1 OS_HRT是什么
- 2.2 OS_HRT流程图
- 2.3 OS_HRT的触发流程
- 2.4 OS_HRT中断服务函数代码
1. 中断
1.1 Cat1 与 Cat2 对比
| 特性 | Cat1 ISR | Cat2 ISR |
| OS介入 | 完全不介入 | OS完全管理(Entry/Exit/调度) |
| 可屏蔽性 | 不可被 OS 屏蔽(高于 Cat2 屏蔽级别) | 可被 OS 通过 ICR 屏蔽级别屏蔽 |
| 向量入口宏 | Os_Arch_Cat1Entry(func, core, level) | Os_Arch_Cat2Entry(cfg, core, level) |
| 入口动作 | 直接 ji func 跳转,无上下文保存调用 | svlcx → Os_Arch_SaveContext → Os_Isr_Entry |
| 能否调用 OS 服务 | 不能 | 可调用受限 OS 服务(如 SetEvent、GetResource) |
| 上下文切换 | 不切换(用被中断任务的栈) | OS 切换到 ISR 专用栈 |
| 资源管理 | 无 | OS 跟踪 ISR 持有的 Resource/Spinlock |
| 调度触发 | 不触发 | 退出时可能触发任务调度 |
| ProcType 标记 | OS_ISR_CAT1_TYPE_MASK (0x100) | OS_ISR_CAT2_TYPE_MASK (0x080) |
| 典型用途 | 极高频/极低延迟硬件中断 | 普通外设中断、OS_HRT、软中断 |
| 返回方式 | 直接 ji 跳转(func 自行 rfe) | rslcx + rfe |
1.2 入口宏的汇编实现
- Cat2入口(OS介入)
Os_Arch_Cat2Entry(cfg,core,x):.align5svlcx;保存 Lower Context 到 CSA call Os_Arch_SaveContext;保存被中断上下文指针到 Core Buffer mov.aa a5,a2;传参:被中断上下文 movh.a a4,hi:cfg;传参:ISR 配置地址 lea a4,[a4]lo:cfg call Os_Isr_Entry;★ OS 介入入口 rslcx;恢复 Lower Context rfe;从中断返回- Cat1入口(OS不介入)
Os_Arch_Cat1Entry(func,core,x):.align5svlcx;仅保存 Lower Context movh.a a14,hi:func;计算回调地址 lea a14,[a14]lo:func ji a14;★ 直接跳转到用户回调,不经过 OSCat1 的 ji 是无条件跳转,用户 ISR 函数自己负责 rslcx + rfe 返回。
1.3 中断屏蔽级别机制
Os_Isr_DisableAllInterrupts / Os_Isr_SuspendOSInterrupts 的区别在
/* DisableAllInterrupts: 屏蔽到 Cat1 级别(几乎屏蔽所有中断) */Os_Arch_SetIntMaskLevel(OS_CAT1_MASKLEVE);// 26/* SuspendOSInterrupts: 屏蔽到 Cat2 级别(只屏蔽 Cat2,Cat1 仍可抢占) */Os_Arch_SetIntMaskLevel(OS_CAT2_MASKLEVE);// 261.4 OS 如何介入 Cat2 ISR
1.4.1 介入时机总览
OS 对 Cat2 的介入分为 入口(Entry) 和 出口(Exit) 两个钩子,包围用户 ISR 回调:
硬件触发中断 │ ▼[Cat2 向量表入口]── svlcx+Os_Arch_SaveContext │ ▼[Os_Isr_Entry]★ OS 介入点1│-禁中断、禁调度 │-栈溢出检查 │-设置 ProcType=CAT2 │-记录当前 ISR 到 Core 状态 │-压栈被中断上下文 │-切换到 ISR 专用栈 ▼[用户 ISR 回调](如 OS_HRT、Os_MultiCoreServer_Handler)│ 可调用 OS 服务(SetEvent/GetResource 等) ▼[返回 Os_Isr_Entry 后半段]│-清中断 pending │-栈溢出复检 │-弹出被中断上下文 │-若还有嵌套 ISR:恢复上层 ISR 上下文 │-若是最外层 ISR: │ ├─ 使能调度 │ ├─ 检查是否需要调度 → 调度器选择下一个任务 │ └─ 恢复被中断任务或切换到新任务 ▼[Os_Isr_Exit]★ OS 介入点2(用户主动调用时) │-强制释放未释放的 Resource │-强制释放未释放的 Spinlock │-清除残留的中断禁用状态 │-调用 Os_Arch_ResetContext_Switch 切换上下文 ▼ rslcx+rfe 返回1.4.2 Os_Isr_Entry 详解
前置处理(进入 ISR 上下文):
coreId=Os_Core_GetLogicId();Os_Arch_IntDisableAll();// 1. 关中断OS_CORE_DISABLESCH(coreId);// 2. 禁止调度(防止 ISR 期间触发调度)// 3. 栈溢出检查(针对被中断的任务栈)taskCfg=OS_TASK_GETCFG(OS_CORE_GETCURRENTTASKID(coreId));Os_Stack_Measure(taskCfg->contextCfg->stackEndAddr);// 4. Timing Protection 帧间隔检查if(OS_CORE_CHECKTPISENABLE(coreId)&&!isrCfg->ifTpIsr){Os_Tp_CheckFrameInterval(isrCfg->tpCfg);// 保存被中断 Task/ISR 的执行预算Os_Tp_SaveCurrenBudget(currentTpCfg,coreId);Os_Tp_StartNextBudget(isrCfg->tpCfg,coreId);}// 5. 标记当前核处于 Cat2 ISR 上下文OS_CORE_SETPROTYPE(coreId,OS_ISR_CAT2_TYPE_MASK);OS_CORE_SETCURRISR(coreId,isrCfg->isrDyn);Os_Core_IsrBuffPush(coreId,currentContext);// 6. 压栈被中断上下文调用用户 ISR 回调(区分系统 App / 普通 App):
if(OS_IFSYSAPP(coreId,isrCfg->ownerAppId)){// 系统 App:直接调用,不切栈不切 MPU(性能优化)Os_Arch_Stack_Switch(tmpContext,isrCfg->isrDyn->context);Os_Isr_CallCallbackDirect(isrCfg,coreId);// 内部会 Os_Arch_IntEnableAll()Os_Arch_Stack_Restore(tmpContext);}else{// 普通 App:切换 MPU 保护范围(App/ISR/Stack 三重)Os_Mp_Switch(TRUE,isrCfg->appMpCfg);Os_Mp_Switch(FALSE,isrCfg->isrMpCfg);Os_Arch_MpStackSwitch(...);// 通过 Os_Arch_Context_Switch_ISR 切换上下文(含信任域切换)Os_Arch_Context_Switch_ISR(tmpContext,isrCfg->isrDyn->context);}Os_Isr_CallCallbackDirect 内部(系统 App 路径)
Os_Arch_IntEnableAll();// 开中断,允许高优先级抢占isrcallback();// ★ 执行用户 ISR 回调(如 OS_HRT)// 退出回调后的安全检查(防御性编程):if(OS_ISR_MASK_RESOURCE(isrCfg))// 若有未释放 ResourceOs_Resource_ForceReleaseAll(...);if(OS_ISR_MASK_SPINLOCK(isrCfg))// 若有未释放 SpinlockOs_Spinlock_ForceReleaseAll(...);if(OS_CORE_MASK_INTERRUPT(coreId)&&OS_ISR_ISTPISR(isrId))// 若中断被禁Os_Core_CleanInterrupts(coreId);Os_Arch_IntDisableAll();后置处理(退出 ISR 上下文):
Os_Arch_ClearPendingIRQ(isrCfg->source);// 清中断 pendingOs_Stack_Measure(isrCfg->contextCfg->stackEndAddr);// ISR 栈溢出复检nextContext=Os_Core_IsrBuffPop(coreId);// 弹出被中断上下文if(OS_ZERO_VALUE!=OS_CORE_GETINTCNTS(coreId)){// 嵌套 ISR 场景:恢复上层 ISR 的保护域和上下文intedIsrCfg=OS_ISR_GETCFG(((Os_IsrDynType*)nextContext)->isrId);Os_Isr_RestoreNextIsrProtection(intedIsrCfg,coreId);OS_CORE_SETCURRISR(coreId,intedIsrCfg->isrDyn);}else{// 最外层 ISR:恢复到任务上下文intedTaskCfg=OS_TASK_GETCFG(((Os_TaskDynType*)nextContext)->taskId);OS_CORE_ALLOWSCH(coreId);// 使能调度if(Os_Schedler_NeedSchedle(...))// ★ 检查是否需要调度{nextTask=Os_Schedler_Schedle(...);// 执行调度Os_Task_TaskSwitch_ForIsr(intedTaskCfg,nextTaskCfg);// 切换到新任务Os_Arch_SetNextContext(nextTask->context);}else{Os_Isr_RestoreInterruptedTask(intedTaskCfg,coreId);// 恢复被中断任务}}1.4.3 Os_Isr_Exit 详解
Os_Isr_Exit 是用户 ISR 主动调用以提前退出 ISR 的接口(正常返回路径不经过它)。它执行强制清理:
FUNC(void,OS_CODE)Os_Isr_Exit(void){CoreIdType coreId=Os_Core_GetLogicId();Os_Arch_ContextDynType*nextContext=Os_Core_IsrGetIsrBuff(coreId);isrId=OS_CORE_GETCURRENTISRID(coreId);isrCfg=OS_ISR_GETCFG(isrId);// 1. 强制释放 Resource(LIFO)if(OS_ISR_MASK_RESOURCE(isrCfg)){Os_Resource_ForceReleaseAll(OS_ISR_GETRESLISTHEAD(isrCfg->isrDyn));Os_Hook_CallErrorHook(OSServiceId_Os_Isr_Exit,E_OS_RESOURCE);// 报错}// 2. 强制释放 Spinlockif(OS_ISR_MASK_SPINLOCK(isrCfg)){Os_Spinlock_ForceReleaseAll(OS_ISR_GETSPINLISTHEAD(isrCfg->isrDyn));Os_Hook_CallErrorHook(OSServiceId_Os_Isr_Exit,E_OS_SPINLOCK);}// 3. 清除残留的中断禁用状态if(OS_CORE_MASK_INTERRUPT(coreId)){Os_Core_CleanInterrupts(coreId);Os_Hook_CallErrorHook(OSServiceId_Os_Isr_Exit,E_OS_DISABLEDINT);}Os_Arch_IntDisableAll();Os_Arch_ResetContext_Switch(isrCfg->contextCfg,nextContext);// 切换上下文}2. 定时器中断(OS_HRT)
2.1 OS_HRT是什么
OS_HRT(High-Resolution Timer)是 AUTOSAR OS 中基于硬件 STM(System Timer Module)的高精度计数器中断服务例程,对应 OS_ISR(OS_HRT) 函数。它本质上是一个 Cat2 类别的 ISR,由 STM 比较匹配触发,负责处理 Counter 的 Expiration Point 队列。
2.2 OS_HRT流程图
2.3 OS_HRT的触发流程
STM 硬件(TIM0==CMP0)│ ▼ 产生中断 → 跳到 Os_Arch_Cat2Entry 生成的向量表入口 │(svlcx 保存上下文 → call Os_Arch_SaveContext → call Os_Isr_Entry)▼Os_Isr_Entry(Cat2 通用入口,设置 ProcType=CAT2、当前 ISR ID 等)│ ▼ 调用 ISR 回调(即 OS_HRT 函数体,通过 isrCfg->contextCfg->entryAddr) │ ▼ OS_HRT 处理 Expiration Point 队列 │ ▼Os_Isr_Exit(恢复上下文/触发调度)│ ▼ rslcx+rfe 返回被中断现场2.4 OS_HRT中断服务函数代码
OS_ISR(OS_HRT) { CoreIdType coreId; ISRType isrId; CounterType cntId; Os_CntExpListNodeCfgType* expListNode; const Os_CounterBaseCfgType* counterBaseCfg; Os_Arch_IntState intState; Os_StatusType ret; uint8 setNextPointFlag = OS_COUNTER_SET_POINT; coreId = Os_Core_GetLogicId(); // 1. 获取当前核 ID isrId = OS_CORE_GETCURRENTISRID(coreId); // 2. 获取当前 ISR ID(由 Cat2 入口设置) if( OS_ISR_ISTIMER(isrId) ) // 3. 确认是定时器 ISR { cntId = OS_ISR_GETCNTID(isrId); counterBaseCfg = OS_COUNTER_GETCFG(cntId); // 4. 清除 STM 中断标志(SRC + STM ISCR 双清) Os_Arch_Mach_HrtClearInterrupt(((const Os_CounterHrtCfgType*)counterBaseCfg)->HwConfig); Os_Arch_IntDisable(&intState); // 5. 临界区开始 // 6. 从优先级队列弹出到期的 Expiration Point ret = Os_Counter_ExpListPop(counterBaseCfg, &expListNode); if( E_OS_BUFFEMPTY != ret ) { // 7. 执行到期动作(Alarm 回调 / SetEvent 等) (void)Os_Counter_WorkFunc(expListNode, &setNextPointFlag); } // 8. 如果 WorkFunc 没有自行设置下一个比较点,则从队列取下一个 if( OS_COUNTER_NOTSET_POINT == setNextPointFlag ) { Os_Counter_SetNextPoint(counterBaseCfg); } Os_Arch_IntEnable(intState); // 9. 临界区结束 } }