zoukankan      html  css  js  c++  java
  • (转载)STM32中断流程处理

    作为我的一个习惯,学习某一个平台的东西,总是先要摸清楚中断的处理流程,当然是从文件代码级的流程分析了。
     
    下面就说下stm32的中断流程。我们知道,stm32的库中写好了很多的驱动程序,可以说包括了所有的。同时也提供很多数据处理方式,例如串口的读写,用户可以选择轮询、中断、DMA等3中方式来处理。
     
    关于中断,stm32的库中做好了框架,用户只要填写好几个函数的实现就ok了,就像网上说的,这就是傻瓜式开发。
     
    了解中断,首先要知道stm32f10x_it.c这个文件,一般情况下是和main文件在同一个目录下的。打开这个文件,我们可以看到xyz_IRQHandler函数的实现,虽然说是实现,但是几乎都是空的。对了,这些函数就是要用户填写的中断处理函数,如果你用到了哪个中断来做相应的处理,你就要填写相应的中断处理函数,需要根据各外设的实际情况来填写,但是一般都会有关闭和开启中断。在这个文件中还有很多系统相关的中断处理函数,例如系统时钟SysTickHandler。具体的实现可以参考stm32\fwlib\FWLib\examples下的各例子。
     
    到这里,我们也只不过看了中断的处理函数,而这些处理函数是如何被硬件中断调用的呢?嗯,说到这里就不得不提一下stm32f10x_vector.c这个文件了。内容如下:

    typedef void( *intfunc )( void );
    typedef union { intfunc __fun; void * __ptr; } intvec_elem;
     
    /**************************************************************
    __sfe是IAR的“段操作符”segment operator。表示取某个段的后一个字节的地址。
    比如"CSTACK"定义为0x20001000~0x20001fff。那__sfe( "CSTACK" ) 就得到0x20002000这个值,刚好用来初始化msp堆栈指针。

    注意使用segment operator前,需要先定义段名如下: #pragma segment="CSTACK"
    RSTACK 程序返回用的,保存的是程序调用函数的返回地址  , 你填写的数值 X 2才是占用的字节数

    CSTACK 函数局部变量用的区域,所有的功能函数使用的局部变量都是从这个堆栈申请使用的,用完了再还回去。子函数里面用到的局部变量都是在这里面取来用的.
    *****************************************************************/
     
    //IAR对所用语言(这里是C)做的一些扩展,也就是说这里可以用扩展的功能
    #pragma language=extended#pragma segment="CSTACK"
     
    void __iar_program_start( void );
     
    /*****************************************************************
    把中断向量表放到中断向量表该放的地方。 如果没有次句,中断向量被当作普通常变量处理,被放置的位置由编译器连接后确定。
    在.icf文件中有place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
    ******************************************************************/
    #pragma location = ".intvec"

     
    /* STM32F10x Vector Table entries */
    const intvec_elem __vector_table[] =
    {
      { .__ptr = __sfe( "CSTACK" ) },
      &__iar_program_start,
      NMIException,
      HardFaultException,
      MemManageException,
      BusFaultException,
      UsageFaultException,
      0, 0, 0, 0,            /* Reserved */
      vPortSVCHandler,
      DebugMonitor,
      0,                      /* Reserved */
      xPortPendSVHandler,
      xPortSysTickHandler,
      WWDG_IRQHandler,
      PVD_IRQHandler,
      TAMPER_IRQHandler,
      RTC_IRQHandler,
      FLASH_IRQHandler,
      RCC_IRQHandler,
      EXTI0_IRQHandler,
      EXTI1_IRQHandler,
      EXTI2_IRQHandler,
      EXTI3_IRQHandler,
      EXTI4_IRQHandler,
      DMAChannel1_IRQHandler,
      DMAChannel2_IRQHandler,
      DMAChannel3_IRQHandler,
      DMAChannel4_IRQHandler,
      DMAChannel5_IRQHandler,
      DMAChannel6_IRQHandler,
      DMAChannel7_IRQHandler,
      ADC_IRQHandler,
      USB_HP_CAN_TX_IRQHandler,
      USB_LP_CAN_RX0_IRQHandler,
      CAN_RX1_IRQHandler,
      CAN_SCE_IRQHandler,
      EXTI9_5_IRQHandler,
      TIM1_BRK_IRQHandler,
      TIM1_UP_IRQHandler,
      TIM1_TRG_COM_IRQHandler,
      TIM1_CC_IRQHandler,
      vTimer2IntHandler,
      TIM3_IRQHandler,
      TIM4_IRQHandler,
      I2C1_EV_IRQHandler,
      I2C1_ER_IRQHandler,
      I2C2_EV_IRQHandler,
      I2C2_ER_IRQHandler,
      SPI1_IRQHandler,
      SPI2_IRQHandler,
      vUARTInterruptHandler,
      USART2_IRQHandler,
      USART3_IRQHandler,
      EXTI15_10_IRQHandler,
      RTCAlarm_IRQHandler,
      USBWakeUp_IRQHandler,
    };

    现在我们清楚了,这儿就是中断向量表,每一个item对应一个中断或异常处理,这里item的填写要和stm32spec中的Interrupt and exception vectors一节中的列表中的顺序一致。
     
    说道这里,又有一个问题,这个向量表是放在何处的呢?上面对.intvec的解释可以看出是被链接器放到了一个地址上(这里是0x08000000,NVIC_VectTab_FLASH)。但是stm32是怎么知道这个地址的呢,也许有个默认值,或者是就这一个固定值?)。我们在stm32f10x_nvic.c文件中发现下面这样的一个函数

    void NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset)
    {
      /* Check the parameters */
      assert(IS_NVIC_VECTTAB(NVIC_VectTab));
      assert(IS_NVIC_OFFSET(Offset)); 
      
      SCB->ExceptionTableOffset = (((u32)Offset << 0x07) & (u32)0x1FFFFF80);
      SCB->ExceptionTableOffset |= NVIC_VectTab;
    }

    同时在example目录下有vectortable_relocation这样的一个例子:This example describes how to use the NVIC firmware library to set the CortexM3 vector table in a specific address other than default.

    在这个例子里面就是直接调用了上面的那个函数,似乎意思很明显了。但是SCB->ExceptionTableOffset是如何起作用的呢?
     
    着重解释这个问题,先看一组定义:【stm32f10x_map.b】
    /* System Control Space memory map */
    #define SCS_BASE              ((u32)0xE000E000)
    #define SysTick_BASE          (SCS_BASE + 0x0010)
    #define NVIC_BASE             (SCS_BASE + 0x0100)
    #define SCB_BASE              (SCS_BASE + 0x0D00)
    #ifdef _SCB
    #define SCB                   ((SCB_TypeDef *) SCB_BASE)
    #endif
    typedef struct
    {
      vu32 CPUID;
      vu32 IRQControlState;
      vu32 ExceptionTableOffset;
      vu32 AIRC;
      vu32 SysCtrl;
      vu32 ConfigCtrl;
      vu32 SystemPriority[3];
      vu32 SysHandlerCtrl;
      vu32 ConfigFaultStatus;
      vu32 HardFaultStatus;
      vu32 DebugFaultStatus;
      vu32 MemoryManageFaultAddr;
      vu32 BusFaultAddr;
    } SCB_TypeDef;
     
    其实这里主要就是要弄清楚这个SCB是什么意思,因为这个结构是映射到一个物理地址上的。像别的控制寄存器都是这么个玩法,莫非这也是个某类控制器。google一下,果然对于系统控制寄存器组【上篇文章有提到】STM32的固件库中有如下定义:

    typedef struct
    {
      vuc32 CPUID;
      vu32 ICSR;
      vu32 VTOR;
      vu32 AIRCR;
      vu32 SCR;
      vu32 CCR;
      vu32 SHPR[3];
      vu32 SHCSR;
      vu32 CFSR;
      vu32 HFSR;
      vu32 DFSR;
      vu32 MMFAR;
      vu32 BFAR;
      vu32 AFSR;
    } SCB_TypeDef;
    /* System Control Block Structure */

    它们对应ARM手册中的名称为
    CPUID = CPUID Base Register
    ICSR = Interrupt Control State Register
    VTOR = Vector Table Offset Register
    AIRCR = Application Interrupt/Reset Control Register
    SCR = System Control Register
    CCR = Configuration Control Register
    SHPR = System Handlers Priority Register
    SHCSR = System Handler Control and State Register
    CFSR = Configurable Fault Status Registers
    HFSR = Hard Fault Status Register
    DFSR = Debug Fault Status Register
    MMFAR = Mem Manage Address Register
    BFAR = Bus Fault Address Register
    AFSR = Auxiliary Fault Status Register
     
    至此,我们终于清楚了,这个中断向量表的地址,最终是要写到某个控制器中去。那这么说来,上述的0x08000000可以是个别的值了,只要保证这一处的地址不能被别的程序访问就行了。

    本文出自 “bluefish” 博客,请务必保留此出处http://bluefish.blog.51cto.com/214870/160140

  • 相关阅读:
    Delphi公用函数单元
    Delphi XE5 for Android (十一)
    Delphi XE5 for Android (十)
    Delphi XE5 for Android (九)
    Delphi XE5 for Android (八)
    Delphi XE5 for Android (七)
    Delphi XE5 for Android (五)
    Delphi XE5 for Android (四)
    Delphi XE5 for Android (三)
    Delphi XE5 for Android (二)
  • 原文地址:https://www.cnblogs.com/xinjie/p/2209665.html
Copyright © 2011-2022 走看看