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

  • 相关阅读:
    JNI中java类型的简写
    JNI 资源释放
    【翻译自mos文章】当指定asm disk 为FRA时,11.2.0.3的dbua hang住
    Codeforces 85D Sum of Medians(线段树)
    Win8.1应用开发之异步编程
    VC++的内联汇编
    WPF实现界面动态布局
    找唯一不出现三次而出现1次的数子O(n)位运算算法
    模块管理常规功能自己定义系统的设计与实现(31--第三阶段 权限设计[1])
    Codeforces Round #FF (Div. 2):C. DZY Loves Sequences
  • 原文地址:https://www.cnblogs.com/xinjie/p/2209665.html
Copyright © 2011-2022 走看看