2.3 创建中断UINT32 HalHwiCreate()

开发者可以调用函数UINT32 HalHwiCreate()创建中断,注册中断处理程序。我们先看看这个函数的参数,HWI_HANDLE_T hwiNum是硬件中断号,HWI_PRIOR_T hwiPrio中断的优先级,HWI_MODE_T mode中断模式,保留暂时没有使用。HWI_PROC_FUNC handler是需要注册的中断处理程序,中断被触发后会调用这个函数。HWI_ARG_T arg是中断处理程序的参数。

一起剖析下这个函数的源代码,⑴处代码开始,对入参进行校验,中断处理程序不能为空,中断号不能大于支持的最大中断号,中断优先级不能超过指定优先级的大小。如果待创建的中断号对应的中断执行入口程序不等于HalHwiDefaultHandler,说明已经创建过,返回错误码。关中断,然后执行⑵处的OsSetVector()函数设置指定中断号的中断处理程序。⑶处调用CMSIS函数使能中断、设置中断的优先级,打开中断,完成中断的创建。

LITE_OS_SEC_TEXT_INIT UINT32 HalHwiCreate(HWI_HANDLE_T hwiNum,
                                          HWI_PRIOR_T hwiPrio,
                                          HWI_MODE_T mode,
                                          HWI_PROC_FUNC handler,
                                          HWI_ARG_T arg)
{
    UINTPTR intSave;

⑴  if (handler == NULL) {
        return OS_ERRNO_HWI_PROC_FUNC_NULL;
    }

    if (hwiNum >= OS_HWI_MAX_NUM) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    if (g_hwiForm[hwiNum + OS_SYS_VECTOR_CNT] != (HWI_PROC_FUNC)HalHwiDefaultHandler) {
        return OS_ERRNO_HWI_ALREADY_CREATED;
    }

    if (hwiPrio > OS_HWI_PRIO_LOWEST) {
        return OS_ERRNO_HWI_PRIO_INVALID;
    }

    intSave = LOS_IntLock();
#if (OS_HWI_WITH_ARG == 1)
    OsSetVector(hwiNum, handler, arg);
#else
⑵   OsSetVector(hwiNum, handler);
#endif
⑶  NVIC_EnableIRQ((IRQn_Type)hwiNum);
    NVIC_SetPriority((IRQn_Type)hwiNum, hwiPrio);

    LOS_IntRestore(intSave);

    return LOS_OK;
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">

2.4 删除中断UINT32 HalHwiDelete()

中断删除操作是创建操作的反向操作,也比较好理解。开发者可以调用函数UINT32 HalHwiDelete(HWI_HANDLE_T hwiNum)来删除中断。函数需要指定中断号参数HWI_HANDLE_T hwiNum。一起剖析下这个函数的源代码,⑴处代码对入参进行校验,不能大于支持的最大中断号。⑵处调用CMSIS函数来失能中断,然后锁中断,执行⑶把中断向量表指定中断号的中断执行入口程序设置为默认程序HalHwiDefaultHandler

LITE_OS_SEC_TEXT_INIT UINT32 HalHwiDelete(HWI_HANDLE_T hwiNum)
{
    UINT32 intSave;

⑴  if (hwiNum >= OS_HWI_MAX_NUM) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

⑵  NVIC_DisableIRQ((IRQn_Type)hwiNum);

    intSave = LOS_IntLock();

⑶  g_hwiForm[hwiNum + OS_SYS_VECTOR_CNT] = (HWI_PROC_FUNC)HalHwiDefaultHandler;

    LOS_IntRestore(intSave);

    return LOS_OK;
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

2.5 中断处理执行入口程序

我们再来看看中断处理执行入口程序。默认的函数HalHwiDefaultHandler()如下,调用函数HalIntNumGet()获取中断号,打印输出,然后进行死循环。其中函数HalIntNumGet()读取寄存器ipsr来获取触发的中断的中断号。

LITE_OS_SEC_TEXT_MINOR VOID HalHwiDefaultHandler(VOID)
{
    UINT32 irqNum = HalIntNumGet();
    PRINT_ERR("%s irqNum:%d\n", __FUNCTION__, irqNum);
    while (1) {}
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

继续来看中断处理执行入口程序HalInterrupt(),源码如下。

⑴处把全局变量g_intCount表示的正在处理的中断数量加1,在中断执行完毕后,在⑹处再把正在处理的中断数量减1。⑵处调用函数HalIntNumGet()获取中断号,⑶、⑸处调用的函数HalPreInterruptHandler()HalAftInterruptHandler()在执行中断处理程序前、后可以处理些其他操作,当前默认为空函数。⑷处根据中断号从中断处理程序数组中获取中断处理程序,不为空就调用执行。

LITE_OS_SEC_TEXT VOID HalInterrupt(VOID)
{
    UINT32 hwiIndex;
    UINT32 intSave;

#if (LOSCFG_KERNEL_RUNSTOP == 1)
    SCB->SCR &= (UINT32) ~((UINT32)SCB_SCR_SLEEPDEEP_Msk);
#endif

    intSave = LOS_IntLock();

⑴  g_intCount++;

    LOS_IntRestore(intSave);

⑵  hwiIndex = HalIntNumGet();

    OsHookCall(LOS_HOOK_TYPE_ISR_ENTER, hwiIndex);

⑶  HalPreInterruptHandler(hwiIndex);

#if (OS_HWI_WITH_ARG == 1)
    if (g_hwiHandlerForm[hwiIndex].pfnHandler != 0) {
        g_hwiHandlerForm[hwiIndex].pfnHandler((VOID *)g_hwiHandlerForm[hwiIndex].pParm);
    }
#else
    if (g_hwiHandlerForm[hwiIndex] != 0) {
⑷      g_hwiHandlerForm[hwiIndex]();
    }
#endif

⑸   HalAftInterruptHandler(hwiIndex);

    OsHookCall(LOS_HOOK_TYPE_ISR_EXIT, hwiIndex);

    intSave = LOS_IntLock();
⑹  g_intCount--;
    LOS_IntRestore(intSave);
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

3、开关中断

最后,分享下开、关中断的相关知识,开、关中断分别指的是:

执行完毕特定的短暂的程序,打开中断,可以响应中断。

为了保护执行的程序不被打断,关闭相应外部的中断。

对应的开、关中断的函数定义在文件kernel\arch\include\los_context.h中,代码如下。
⑴处的UINT32 LOS_IntLock(VOID)会关闭中断,暂停响应中断。
⑵处的函数VOID LOS_IntRestore(UINT32 intSave)可以用来恢复UINT32 LOS_IntLock(VOID)函数关闭的中断,UINT32 LOS_IntLock(VOID)的返回值作为VOID LOS_IntRestore(UINT32 intSave)的参数进行恢复中断。
⑶处的函数UINT32 LOS_IntUnLock(VOID)会使能中断,可以响应中断。

    UINTPTR HalIntLock(VOID);
⑴  #define LOS_IntLock HalIntLock

    VOID HalIntRestore(UINTPTR intSave);
⑵  #define LOS_IntRestore HalIntRestore

    UINTPTR HalIntUnLock(VOID);
⑶  #define LOS_IntUnLock HalIntUnLock
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

可以看出,LOS_IntLockLOS_IntRestoreLOS_IntUnLock是定义的宏,他们对应定义在文件kernel\arch\arm\cortex-m7\gcc\los_dispatch.S中的汇编函数,源码如下。我们分析下这些汇编函数。寄存器PRIMASK是单一bit位的寄存器,置为1后,就关掉所有可屏蔽异常,只剩下NMI和硬故障HardFault异常可以响应。默认值是0,表示没有关闭中断。汇编指令CPSID I会设置PRIMASK=1,关闭中断,指令CPSIE I设置PRIMASK=0,开启中断。

⑴处HalIntLock函数把寄存器PRIMASK数值写入寄存器R0返回,并执行CPSID I关闭中断。⑵处HalIntUnLock函数把寄存器PRIMASK数值写入寄存器R0返回,并执行指令CPSIE I开启中断。两个函数的返回结果可以传递给⑶处HalIntRestore函数,把寄存器状态数值写入寄存器PRIMASK,用于恢复之前的中断状态。不管是HalIntLock还是HalIntUnLock,都可以和ArchIntRestore配对使用。

    .type HalIntLock, %function
    .global HalIntLock
HalIntLock:
    .fnstart
    .cantunwind

⑴  MRS R0, PRIMASK
    CPSID I
    BX LR
    .fnend

    .type HalIntUnLock, %function
    .global HalIntUnLock
HalIntUnLock:
    .fnstart
    .cantunwind

⑵  MRS R0, PRIMASK
    CPSIE I
    BX LR
    .fnend

    .type HalIntRestore, %function
    .global HalIntRestore
HalIntRestore:
    .fnstart
    .cantunwind

⑶  MSR PRIMASK, R0
    BX LR
    .fnend
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

小结

本文带领大家一起剖析了鸿蒙轻内核的中断模块的源代码,掌握中断相关的概念,中断初始化操作,中断创建、删除,开关中断操作等。

如果大家想更加深入的学习 OpenHarmony 开发的内容,不妨可以参考以下相关学习文档进行学习,助你快速提升自己:

OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy

《OpenHarmony源码解析》:https://qr18.cn/CgxrRy

系统架构分析:https://qr18.cn/CgxrRy

OpenHarmony 设备开发学习手册:https://qr18.cn/CgxrRy

在这里插入图片描述

OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy

data-report-view="{"mod":"1585297308_001","spm":"1001.2101.3001.6548","dest":"https://blog.csdn.net/maniuT/article/details/139473001","extend1":"pc","ab":"new"}">> id="blogExtensionBox" style="width:400px;margin:auto;margin-top:12px" class="blog-extension-box"> class="blog_extension blog_extension_type2" id="blog_extension"> class="extension_official" data-report-click="{"spm":"1001.2101.3001.6471"}" data-report-view="{"spm":"1001.2101.3001.6471"}"> class="blog_extension_card_left"> class="blog_extension_card_cont"> 鸿蒙开发学习资料领取!!! class="blog_extension_card_cont_r"> 微信名片
注:本文转载自blog.csdn.net的沧海一笑-dj的文章"https://blog.csdn.net/dengjin20104042056/article/details/97970997"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接

评论记录:

未查询到任何数据!