【.Net MF深入研究】中断处理机制

简介: .Net Micro Framework的中断处理机制相对比较简单,不支持中断嵌套,中断优先级功能的实现由相关硬件提供支持,软件层面仅仅进行相关优先级的设定即可。

.Net Micro Framework的中断处理机制相对比较简单,不支持中断嵌套,中断优先级功能的实现由相关硬件提供支持,软件层面仅仅进行相关优先级的设定即可。

下面以TI DM335开发板为例简单介绍一下相关技术细节(这里仅介绍普通中断IRQ)。

1 中断向量表

我们知道中断向量表一般默认的存放在内存0起始地址处。

先让我们在NativeSampleTinyCLR目录中找到Scatterfile_tools_xxx.xml文件,我们会发现在其中都会有如下这么一段文字:

<ExecRegion Name="ER_RAM_RO" Base="0x00000000" Options="ABSOLUTE" Size="0x1A000">

    <FileMapping Name="VectorsTrampolines.obj" Options="(+RO, +FIRST)" />

</ExecRegion>

这是一个编译选项,告诉ARM编译器,连接时把VectorsTrampolines.obj的相关内容放在位置0处(我们可以用WinHex查看编译后的Bin文件,我们会发现Bin文件中最开始的内容就是中断向量表的内容)。

下面是VectorsTrampolines.s文件的汇编代码:

;**************************************************************************

    IMPORT  UNDEF_SubHandler

    IMPORT  ABORTP_SubHandler

    IMPORT  ABORTD_SubHandler 

    IMPORT  IRQ_Handler      ; from stubs.cpp

    EXPORT  ARM_Vectors

;**************************************************************************

    AREA |.text|, CODE, READONLY

    ; ARM directive is only valid for ARM/THUMB processor, but not CORTEX

    IF :DEF:COMPILE_ARM :LOR: :DEF:COMPILE_THUMB

    ARM

    ENDIF   

ARM_Vectors

    ; RESET

RESET_VECTOR

    b       UNDEF_VECTOR

    ; UNDEF INSTR

UNDEF_VECTOR

    ldr     pc, UNDEF_SubHandler_Trampoline

    ; SWI

SWI_VECTOR

    DCD     0xbaadf00d

    ; PREFETCH ABORT

PREFETCH_VECTOR

    ldr     pc, ABORTP_SubHandler_Trampoline

    ; DATA ABORT

DATA_VECTOR

    ldr     pc, ABORTD_SubHandler_Trampoline

    ; unused

USED_VECTOR

    DCD     0xbaadf00d

    ; IRQ

IRQ_VECTOR

    ldr     pc, IRQ_SubHandler_Trampoline

    ; FIQ

    ; we place the FIQ handler where it was designed to go, immediately at the end of the vector table

    ; this saves an additional 3+ clock cycle branch to the handler

FIQ_Handler

    IF :DEF: FIQ_SAMPLING_PROFILER   

    ldr     pc,FIQ_SubHandler_Trampoline        

FIQ_SubHandler_Trampoline   

    DCD     FIQ_SubHandler

    ENDIF   

UNDEF_SubHandler_Trampoline

    DCD     UNDEF_SubHandler

ABORTP_SubHandler_Trampoline

    DCD     ABORTP_SubHandler

ABORTD_SubHandler_Trampoline

    DCD     ABORTD_SubHandler

; route the normal interupt handler to the proper lowest level driver

IRQ_SubHandler_Trampoline

    DCD       IRQ_Handler

;**************************************************************************

从中我们可以看出,当硬件触发IRQ中断时,跳转的最终位置为IRQ_Handler

 

【疑问】中断向量表的内容最开始的时候一定是存放在Flash(或其它存储介质)中,它是如何被转移到内存0处的呢(当然调试时也可以通过调试器把中断向量表直接Download到内存中去)?

【解答】在FirstEntry.s汇编代码中有这么一句代码 bl  BootstrapCode”,BootstrapCode是一个子函数,该函数优先于“b   BootEntry”执行,在BootstrapCode函数中又调用了一个子函数PrepareImageRegions,在PrepareImageRegions函数中我们就可以看到拷贝中断向量表的相关代码:

UINT32* src = (UINT32*)&LOAD_RAM_RO_BASE;

UINT32* dst = (UINT32*)&IMAGE_RAM_RO_BASE;

UINT32  len = (UINT32 )&IMAGE_RAM_RO_LENGTH + (UINT32)&Image$$ER_RAM_RW$$Length;

Prepare_Copy( src, dst, len );

 

注:FIQ_SAMPLING_PROFILER选项是没有定义的,所以在DM335开发板上支持FIQ是有问题的。

2 中断函数(IRQ_Handler

中断向量表一经设置,则触发相关中断时,CPU会把PC指针指到相关的入口地址处,对IRQ中断来说,其入口地址就是IRQ_Handler

DM335平台,IRQ_Handler函数的内容如下:

void __irq IRQ_Handler(void)

{

    DM335_INTC_Driver::IRQ_Handler();

}

void /*__irq*/DM335_INTC_Driver::IRQ_Handler(void)

{

    DM335_INTC &pAic = DM335::INTC();

    unsigned int index;

    // set before jumping elsewhere or allowing other interrupts

    SystemState_SetNoLock(SYSTEM_STATE_ISR);

    SystemState_SetNoLock(SYSTEM_STATE_NO_CONTINUATIONS);   

         while(pAic.IRQENTRY != 0x0)

    {

        index = (pAic.IRQENTRY>>2) - 1;

             if(index < 32)

                pAic.IRQ0 |= 1 << index;

        else

                pAic.IRQ1 |= 1 << (index % 32);

        s_IsrTable[index].Handler.Execute();  //执行对应的中断处理函数

    }

    SystemState_ClearNoLock(SYSTEM_STATE_NO_CONTINUATIONS); // nestable

    SystemState_ClearNoLock(SYSTEM_STATE_ISR); // nestable

}

在中断函数执行之前,其实已经执行了中断寄存器的初始工作,比如根据需要打开或关闭(Enable/Disable)相关的中断,对我们的应用来说串口和USB的中断是要打开的,而DMA中断就是关闭的。此外根据你应用的需求,你也可以设置不同中断的优先级(0~7,其中0~1对应快速中断,对我们来说由于快速中断无效,所以中断的优先级最高可设为2)。

相同等级的中断同时来到,是谁来排序呢?

DM335来说,是由硬件完成的,DM335提供一个寄存器IRQENTRYIRQENTRY寄存器中存放的值,就是下一个要执行的中断号(要经过一定的换算),该寄存器就像一个队列的出队口,排好队的中断依次出列,直到IRQENTRY的值为0为止(表示当前队列中没有任何中断被触发)。

(当然我们也可以直接根据IRQ0IRQ1中的值触发二级中断函数,但是这样来做,设定的中断优先级就没有任何意义了。)

这时候我们就可以根据不同的中断号,执行相对应的二级中断函数了。

那中断来了,程序是如何知道该执行那个二级中断函数呢?请看下一节内容就明白了。

3 中断连接函数

CPU_INTC_ActivateInterrupt函数是把硬件的中断号和要执行的中断函数联系起来,其原型是:

BOOL CPU_INTC_ActivateInterrupt(UINT32 Irq_Index, HAL_CALLBACK_FPN ISR, void *ISR_Param)

Irq_Index – 中断号(可根据相关硬件手册进行设定)

ISR – 该中断触发时所要执行的中断函数

ISR_Param –中断函数的入口参数(可以为空)

 

当然根据需要也可以断开这种连接,或关掉相应的中断,这些函数由于比较好理解,所以这里就不过多介绍了。    

     我们以USB驱动为例,简单介绍一下CPU_INTC_ActivateInterrupt函数的使用,在USB的初始化函数中,我们添加了如下代码:

      CPU_INTC_ActivateInterrupt(DM335_INTC::c_IRQ_Index_USBINT, Global_ISR, NULL);

      其中断函数Global_ISR的部分代码如下:

      void DM335_USB_Driver::Global_ISR(void *Param)

{

          DM335_USB &usb = DM335_USB::Type();

UINT32 endpoint = 0;

          UINT32 tmp = usb.Base.INTSRCR;

          usb.Base.INTCLRR = usb.Base.INTSRCR;

 

          //在这里面就可以根据USB相关寄存器的值,确定那一个中断被触发了

          // … …

       }

这样一层一层,由根到枝,按图索骥,获知实际的中断,并最终执行相关的处理代码(如接收数据或发送数据等等)。

4 中断控制

     Porting Kit提供的样例代码中,我们会在中断函数中看到不少GLOBAL_LOCK(irq)代码,由于MF目前不支持中断嵌套,所以从某种意义上说,在中端函数中添加代码GLOBAL_LOCK(irq)是没有意义的(对IRQ中断来说,CPU在触发该中断时,就已经关闭了IRQ中断位,除非你在中断函数中又打开了,当然你这样做的目的一般就是支持中断嵌套了,这部分内容暂不在讨论之列)。

GLOBAL_LOCK是一个宏,其实现为:

#define GLOBAL_LOCK(x)     SmartPtr_IRQ x

SmartPtr_IRQ类的代码为:

class SmartPtr_IRQ

{

    UINT32 m_state;

    void*  m_context;

public:

    SmartPtr_IRQ(void* context=NULL)  { m_context = context; Disable(); }

    ~SmartPtr_IRQ() { Restore(); }

}

void SmartPtr_IRQ::Disable()

{

    UINT32 Cp;

    UINT32 Cs;

    __asm

    {

        MRS     Cp, CPSR

        ORR     Cs, Cp, #0x80

        MSR     CPSR_c, Cs

    }

    m_state = Cp;

}

void SmartPtr_IRQ::Restore()

{

    UINT32 Cp = m_state;

    if((Cp & DISABLED_MASK) == 0)

    {

        ASSERT_SYSTEM_IRQ_MODE(Cp);

        __asm

        {

            MRS     Cp, CPSR

            BIC     Cp, Cp, #0x80

            MSR     CPSR_c, Cp

        }

    }

}

 

由以上代码可知,定义SmartPtr_IRQ的实例的同时,就执行了构造函数,也就是执行了Disable函数(关闭IRQ中断)。换句话说,GLOBAL_LOCK(irq)代码的作用就是,在irq的生命周期内关闭IRQ中断。

相信,如果MF的后续版本开始支持中断嵌套,该部分的内容才会变的复杂。

5 补充说明

MF应用程序(C#)中的中断(或事件函数)其实和我们这章内容所说的中断不是一会事,由以上内容我们可以了解到,中断函数串序执行,所以每一个中断函数执行时间尽量短,否则整个系统的效率便会大大降低。所以我们上层的事件函数是不可能直接勾连在中端函数内,因为在实际的应用中,我们非常有可能在事件函数中执行很多耗时的操作的。实际上TinyCLR代码对这两部分进行了一定得隔离处理,等我们有时间在一一剖析相关的实现机理。

除了中断函数被执行外,对嵌入式应用来说剩下的也就是一个Main函数(对MF来说就是ApplicationEntryPoint)和一个while循环了。对于我们的TinyCLR来说其实就是一个在相对简陋的操作系统上的一个精彩应用而已:

void ApplicationEntryPoint()

{

    CLR_SETTINGS clrSettings;

    memset(&clrSettings, 0, sizeof(CLR_SETTINGS));

    clrSettings.MaxContextSwitches = 50;

#if !defined(BUILD_RTM)

    clrSettings.PerformGarbageCollection = false;

    clrSettings.PerformHeapCompaction    = false;

#endif

    clrSettings.WaitForDebugger          = false;

    ClrStartup( clrSettings );

#if !defined(BUILD_RTM)

    debug_printf( "Exiting./r/n" );

#else

    ::CPU_Reset();

#endif

}

相关文章
|
4月前
分享一份 .NET Core 简单的自带日志系统配置,平时做一些测试或个人代码研究,用它就可以了
分享一份 .NET Core 简单的自带日志系统配置,平时做一些测试或个人代码研究,用它就可以了
|
5月前
|
机器学习/深度学习 计算机视觉 网络架构
【YOLOv8改进 - 注意力机制】HCF-Net 之 PPA:并行化注意力设计 | 小目标
YOLO目标检测专栏介绍了HCF-Net,一种用于红外小目标检测的深度学习模型,它通过PPA、DASI和MDCR模块提升性能。PPA利用多分支特征提取和注意力机制,DASI实现自适应特征融合,MDCR通过多层深度可分离卷积细化空间特征。HCF-Net在SIRST数据集上表现出色,超越其他方法。论文和代码分别在[arxiv.org](https://arxiv.org/pdf/2403.10778)和[github.com/zhengshuchen/HCFNet](https://github.com/zhengshuchen/HCFNet)上。YOLOv8的PPA类展示了整合注意力机制的结构
|
6月前
|
机器学习/深度学习 JSON 测试技术
CNN依旧能战:nnU-Net团队新研究揭示医学图像分割的验证误区,设定先进的验证标准与基线模型
在3D医学图像分割领域,尽管出现了多种新架构和方法,但大多未能超越2018年nnU-Net基准。研究发现,许多新方法的优越性未经严格验证,揭示了验证方法的不严谨性。作者通过系统基准测试评估了CNN、Transformer和Mamba等方法,强调了配置和硬件资源的重要性,并更新了nnU-Net基线以适应不同条件。论文呼吁加强科学验证,以确保真实性能提升。通过nnU-Net的变体和新方法的比较,显示经典CNN方法在某些情况下仍优于理论上的先进方法。研究提供了新的标准化基线模型,以促进更严谨的性能评估。
170 0
|
7月前
|
机器学习/深度学习 算法 数据可视化
MATLAB基于深度学习U-net神经网络模型的能谱CT的基物质分解技术研究
MATLAB基于深度学习U-net神经网络模型的能谱CT的基物质分解技术研究
|
7月前
|
小程序 安全 JavaScript
.NET微信网页开发之通过UnionID机制解决多应用用户帐号统一问题
.NET微信网页开发之通过UnionID机制解决多应用用户帐号统一问题
.NET微信网页开发之通过UnionID机制解决多应用用户帐号统一问题
|
机器学习/深度学习 数据采集 存储
【3-D深度学习:肺肿瘤分割】创建和训练 V-Net 神经网络,并从 3D 医学图像中对肺肿瘤进行语义分割研究(Matlab代码实现)
【3-D深度学习:肺肿瘤分割】创建和训练 V-Net 神经网络,并从 3D 医学图像中对肺肿瘤进行语义分割研究(Matlab代码实现)
270 0
|
安全 JavaScript API
.NET微信网页开发之通过UnionID机制,解决用户在不同公众号,或在公众号、移动应用之间帐号统一问题
.NET微信网页开发之通过UnionID机制,解决用户在不同公众号,或在公众号、移动应用之间帐号统一问题
245 0
.NET微信网页开发之通过UnionID机制,解决用户在不同公众号,或在公众号、移动应用之间帐号统一问题
|
存储 开发框架 Java
【CLR C#】浅谈.Net的GC(垃圾回收)机制及其整体流程
在.NET程序开发中,为了将开发人员从繁琐的内存管理中解脱出来,将更多的精力花费在业务逻辑上,CLR提供了自动执行垃圾回收的机制来进行内存管理,开发人员甚至感觉不到这一过程的存在。.NET程序可以找出某个时间点上哪些已分配的内存空间没有被程序使用,并自动释放它们。自动找出并释放不再使用的内存空间机制,就称为垃圾回收机制。本文主要介绍.Net中的GC(垃圾回收)机制及其整体流程。
【CLR C#】浅谈.Net的GC(垃圾回收)机制及其整体流程
|
开发框架 监控 .NET
ASP.NET Core : 二十三. 深入聊一聊配置的内部处理机制(四)
上一章介绍了配置的多种数据源被注册、加载和获取的过程,本节看一下这个过程系统是如何实现的。
117 0
ASP.NET Core : 二十三. 深入聊一聊配置的内部处理机制(四)
|
XML 存储 JSON
ASP.NET Core : 二十三. 深入聊一聊配置的内部处理机制(三)
上一章介绍了配置的多种数据源被注册、加载和获取的过程,本节看一下这个过程系统是如何实现的。
139 0
ASP.NET Core : 二十三. 深入聊一聊配置的内部处理机制(三)