精华内容
下载资源
问答
  • 规定中断向量表起始地址为0000h,结束地址为03FF,即(0000000000)b~(1111111111)b,总共占用了前1024个字节。 注:0200h~02FFh地址空闲,还没有给定中断向量地址 索引方式: 中断向量表的索引地址由两部分构成,...

    中断向量表

    介绍

    在dos系统中,总共设计了256种中断,每个中断都有一个中断号,通过中断号来映射中断程序的地址。为了实现映射的功能,引入中断向量表。规定中断向量表的起始地址为0000h,结束地址为03FF,即(0000000000)b~(1111111111)b,总共占用了前1024个字节。
    注:0200h~02FFh地址空闲,还没有给定中断向量地址

    在这里插入图片描述

    索引方式:

    中断向量表的索引地址由两部分构成,分别是CS和IP,其低地址存放IP,高地址存放CS。当触发中断号x时,操作系统先保存PSW和PC到核心栈中,然后设置IP=[0000:[x*2]],CS=[0000:[x*2+2]],然后进行中断调用。
    例如:
    当触发21h号中断时,系统先保存PSW和PC,然后将IP设置为[0000:[42h]],CS设置为[0000:[44h]],然后执行中断调用。

    修改中断向量表

    修改中断向量表,其实就是修改目标中断的CS和IP的值,让中断发生时,CS:IP指向我们自定义的中断。
    比如修改0号中断的中断向量表。

        mov ax, 0
        mov es, ax
    
        mov word ptr es:[0*4], 200h
        mov word ptr es:[0*4+2],0;设置中断向量表
    

    自定义中断

    思路

    前面我们已经说到,0200h~02FFh这个地址空间是空闲的,可以用来存放程序。而中断向量表的作用是用于索引中断向量,于是,我们可以利用修改中断向量表,使其指向我们自定义的中断程序,便可以实现自定义中断的效果。
    在这里插入图片描述

    实现效果:

    0号中断为除数为0中断,将其自定义为:在屏幕的正中央输出heppen 0 interrupt。
    在这里插入图片描述

    实现代码

    伪码描述:
    1.根据中断号找到中断向量地址。
    2.修改中断向量地址为我们自定义的中断向量地址。
    3.运行设置程序do0.exe
    4.运行测试程序test.exe
    汇编代码

    ;do0.asm
    
    assume cs:codesg
    
    codesg segment
    start: 
        mov ax, cs
        mov ds, ax;源段地址
        mov si, offset do0;源地址偏移
    
        mov ax, 0
        mov es, ax;目标段地址
        mov di, 200h;目标地址偏移
        
        mov cx, offset do0end - offset do0;目标地址长度
    
        cld;设置传输方向为正
        rep movsb;ds:[si]->es:[di] 循环cx次
    
        mov ax, 0
        mov es, ax
    
        mov word ptr es:[0*4], 200h
        mov word ptr es:[0*4+2],0;设置中断向量表
    
        mov ax, 4c00h
        int 21h;
    do0:
        jmp short do0start
        db "happen 0 interrupt";中断后显示的数据
    do0start:
        mov ax, 0h
        mov ds, ax
        mov si, 202h;数据的起始地址
    
        mov ax, 0B800h
        mov es, ax
        mov di, 12*160+36*2;设置显示位置
        mov cx, 18
    
    s:  mov al,[si];将数据放入显存
        mov ah,0FFh
        mov es:[di], ax
        inc si
        add di, 2
        loop s
    
        mov ax, 4c00h
        int 21h
    
    do0end:
        nop
    codesg ends
    
    end start
    
    ;test.asm
    
    assume cs:codesg
    
    codesg segment
    start:
        mov ax, 12h
        mov dx, 0h
        div dx
    
        mov ax, 4c00h
        int 21h
    codesg ends
    end start
    

    执行步骤

    1.ml do0.asm
    2.do0.exe
    3.ml test.asm
    4.do0.exe
    也可以逐步编译,连接
    1.masm do0.asm
    2.link do0.obj
    3.do0.exe
    4.masm test.asm
    5.link test.obj
    6.test.exe

    展开全文
  • ARM Cortex-M系列之中断向量表

    千次阅读 2020-04-22 14:13:48
    ARM Cortex-M架构的芯片的中断向...ARM Cortex-M手册规定在片上闪存起始地址处需要有一个有效的中断向量表。芯片上电或复位后首先从中向量表中读出入口函数地址和栈指针。将入口函数地址和栈指针装载入寻址寄存器...

    ARM Cortex-M架构的芯片的中断向量表(Interrupt Vector Table)前16位的中断由ARM核设定。16位以后的中断为芯片厂商自行定义。ARM Cortex-M架构芯片一般带有片上闪存(flash)。ARM Cortex-M手册规定在片上闪存起始地址处需要有一个有效的中断向量表。芯片上电或复位后首先从中向量表中读出入口函数地址和栈指针。将入口函数地址和栈指针装载入寻址寄存器(PC)和栈指针(SP)寄存器后,开始执行程序。

    中断向量表格式

    中断向量表每一位为一个32bit的地址。每一个地址对应一个中断函数的地址(第一位除外)。除了第一位以外,所有地址的目标都为寻址寄存器(PC)。当相应中断触发时,ARM Cortex-M硬件会自动把中断向量表中相应的中断函数地址装载入寻址寄存器(PC)然后开始执行中断函数。如上所述,前16位为ARM保留的系统中断,建议读者熟记。之后的中断为芯片自定义的外部中断,可以在使用时查询手册或者厂商提供的驱动程序。

    Exception NumberIRQ Number中断注释
    NANASP初始栈指针
    1NAReset复位函数地址
    2-14NMI不可屏蔽中断
    3-13Hard fault
    4-12Memory fault (Reserved in CM0/0+)内存管理错误中断
    5-11Bus fault (Reserved in CM0/0+)总线错误中断
    6-10Usage fault (Reserved in CM0/0+)使用错误中断
    7-9Reserved保留位(未使用)
    8-8Reserved保留位(未使用)
    9-7Reserved保留位(未使用)
    10-6Reserved保留位(未使用)
    11-5SVC通常用于请求privileged模式,或者在OS中用于请求系统资源
    12-4Reserved保留位(调试用)
    13-3Reserved保留位(未使用)
    14-2PendSV通常用于在OS中切换任务
    15-1SysTick系统节拍时钟中断

    中断向量表定义

    中断向量表可以通过汇编语言定义也可以通过C语言定义。以下列出两种方式的示例程序。

    C

    这里我们定义了一个数组,数组的每一项对应相应的中断函数。如上所述,数组的第一项为初始栈指针,第二项为入口函数地址。余下的所有中断都指向了一个通用中断函数。开发者可以根据需求替代相应的中断函数。
    上文还提到中断向量表需要放置于闪存起始地址处。这里__attribute__((section(".vectors")))为gcc的特定语法(如果开发者使用IAR或者其他编译器,语法有所不同),目的是告诉编译器在链接所有对象文件(objects)时把_vector[]数组放在链接脚本(linker script)中的.vectors段落(section)。在链接脚本中,.vector段落被定义于闪存起始处。

    #ifndef ARMV7M_PERIPHERAL_INTERRUPTS
    #  error ARMV7M_PERIPHERAL_INTERRUPTS must be defined to the number of I/O interrupts to be supported
    #endif
    
    extern void exception_common(void);
    unsigned _vectors[] __attribute__((section(".vectors"))) =
    {
      /* Initial stack */
      IDLE_STACK,
      /* Reset exception handler */
      (unsigned)&__start,
      /* Vectors 2 - n point directly at the generic handler */
      [2 ... (15 + ARMV7M_PERIPHERAL_INTERRUPTS)] = (unsigned)&exception_common
    };
    

    Assembly

    这里以STM32Cube生成的startup_stm32f401retx.S为示例。同样的,汇编程序中也定义了默认中断函数。所有中断也都指向了默认的中断函数Default_Handler(默认为无限循环)。

       .section  .text.Default_Handler,"ax",%progbits
    Default_Handler:
    Infinite_Loop:
      b  Infinite_Loop
      .size  Default_Handler, .-Default_Handler
    

    之后是中断向量表。这里为了缩减示例代码长度,略去了中间的中断函数定义。注意在初始处 .section .isr_vector,"a",%progbits语句指定了g_pfnVectors在链接是需要被放置在isr_vector段落,也就是闪存起始地址处。

    /******************************************************************************
    *
    * The minimal vector table for a Cortex M3. Note that the proper constructs
    * must be placed on this to ensure that it ends up at physical address
    * 0x0000.0000.
    * 
    *******************************************************************************/
      .section  .isr_vector,"a",%progbits
      .type  g_pfnVectors, %object
      .size  g_pfnVectors, .-g_pfnVectors
        
    g_pfnVectors:
      .word  _estack
      .word  Reset_Handler
      .word  NMI_Handler
      .word  HardFault_Handler
      .word  MemManage_Handler
      .word  BusFault_Handler
      .word  UsageFault_Handler
      .word  0
      .word  0
      .word  0
      .word  0
      .word  SVC_Handler
      .word  DebugMon_Handler
      .word  0
      .word  PendSV_Handler
      .word  SysTick_Handler
      
      /* External Interrupts */
      .word     WWDG_IRQHandler                   /* Window WatchDog              */                                        
      .word     PVD_IRQHandler                    /* PVD through EXTI Line detection */                        
      .word     TAMP_STAMP_IRQHandler             /* Tamper and TimeStamps through the EXTI line */            
      .word     RTC_WKUP_IRQHandler               /* RTC Wakeup through the EXTI line */                      
      .word     FLASH_IRQHandler                  /* FLASH                        */                                          
      .word     RCC_IRQHandler                    /* RCC                          */                                            
      .word     EXTI0_IRQHandler                  /* EXTI Line0                   */                                                            
      ... /* 省略 */
      .word     FPU_IRQHandler                    /* FPU                          */
      .word     0                                 /* Reserved                     */                   
      .word     0                                 /* Reserved                     */
      .word     SPI4_IRQHandler                   /* SPI4                         */   
    

    在中断向量表的定义之后,程序还将所有函数定义为.weak。也就是说如果开发者在其他地方重新定义了同样名称的中断函数,那么默认的中断函数实现会被自动覆盖。weak是GNU GCC编译器定义的关键词,如果采用其他编译器会有对应的关键词。

    /*******************************************************************************
    *
    * Provide weak aliases for each Exception handler to the Default_Handler. 
    * As they are weak aliases, any function with the same name will override 
    * this definition.
    * 
    *******************************************************************************/
       .weak      NMI_Handler
       .thumb_set NMI_Handler,Default_Handler
      
       .weak      HardFault_Handler
       .thumb_set HardFault_Handler,Default_Handler
      
       .weak      MemManage_Handler
       .thumb_set MemManage_Handler,Default_Handler
      
       .weak      BusFault_Handler
       .thumb_set BusFault_Handler,Default_Handler
    
       .weak      UsageFault_Handler
       .thumb_set UsageFault_Handler,Default_Handler
    
       .weak      SVC_Handler
       .thumb_set SVC_Handler,Default_Handler
    
       .weak      DebugMon_Handler
       .thumb_set DebugMon_Handler,Default_Handler
    ... /* 省略 */
       .weak      FPU_IRQHandler                  
       .thumb_set FPU_IRQHandler,Default_Handler  
    
       .weak      SPI4_IRQHandler                  
       .thumb_set SPI4_IRQHandler,Default_Handler 
    

    中断向量表偏移寄存器 (Vector Table Offset Register)

    ARM Cortex-M默认的中断向量表地址位于闪存起始地址处。但是ARM Cortex-M3/4系列提供了一个中断向量表偏移寄存器(Vector Table Offset Reigster)。系统中中断向量表的位置是0x00000000加上偏移寄存器的值。上电复位后这个寄存器值为0,所以中断向量表默认位于0x00000000闪存起始处。这个寄存器的目的是为了让开发者可以重新设置中断向量表的位置。

    • 中断向量表偏移寄存器第29位(bit 29)定义了中断向量表的位置。0表示位于闪存程序(code)中,1表示位于内存中(SRAM)。
    • 中断向量表寄存器低7位(bit 6~0)为系统预留位。
    • 偏移地址寄存器值有对齐要求。这个要求和系统中断数量或者说中断向量表长度相关。偏移地址寄存器值至少是128 (32words = 128bytes)的整数倍,这也意味着中断偏移寄存器中地址的低7位始终会是0。如果系统中断数量大于16个,则总中断数为ARM预留的16个中断加上n个系统中断。如果(n+2)不为2的指数,则向上找到最近的2的指数m。每个地址为4bytes所以对齐要求为m*4。例如系统有21个中断,加上ARM预留的16个中断位,则中断向量表有效长度为37words。最近的2的指数值为64words = 256bytes。所以偏移寄存器的值必须为256的整数倍。

    中断向量表偏移寄存器应用

    中断向量表偏移寄存器最普遍的用法是在系统上电复位后将中断向量表指向内存RAM地址空间。如上所述,系统上电复位后默认中断向量表位于闪存起始地址处。闪存的缺点是在系统运行时不能方便的修改任意字节。大部风芯片闪存采取的是NOR Flash。修改特定字节需要先将整个Bank的数据复制入内存RAM,擦除Bank中所有数据后,将RAM中特定字节更新后将整个Bank重新写入闪存。一般NOR Flash Bank的大小为512bytes到2Kbytes。这里就会存在很大的数据丢失或者损坏的风险。所以如果开发者希望在系统运行中更新闪存中的中断向量表中中断函数地址会很不方便而且风险很大。这时可以在系统复位后将闪存中的中断向量表复制进内存地址空间。然后利用中断向量表偏移寄存器将中断向量表指向位于内存中的中断向量表。这以后开发者就可以在程序运行过程中随时更新中断向量表中中断函数地址。

    在移植实时操作系统RTOS时,RTOS常常会在系统初始化时将中断向量表指向内存,然后将除ARM预留系统中断外,所有中断函数都指向统一的操作系统中断函数。中断触发后先调用操作系统中断函数,然后再调用开发者定义的中断函数。

    /****************************************************************************
     * Name: up_ramvec_initialize
     *
     * Description:
     *   Copy vectors to RAM an configure the NVIC to use the RAM vectors.
     *
     ****************************************************************************/
    
    void up_ramvec_initialize(void)
    {
      const up_vector_t *src;
      up_vector_t *dest;
      int i;
    
      /* The vector table must be aligned */
    
      DEBUGASSERT(((uint32_t)g_ram_vectors & ~NVIC_VECTAB_TBLOFF_MASK) == 0);
    
      /* Copy the ROM vector table at address zero to RAM vector table.
       *
       * This must be done BEFORE the MPU is enable if the MPU is being used to
       * protect against NULL pointer references.
       */
    
      src  = (const CODE up_vector_t *)getreg32(NVIC_VECTAB);
      dest = g_ram_vectors;
    
      irqinfo("src=%p dest=%p\n", src, dest);
    
      for (i = 0; i < ARMV7M_VECTAB_SIZE; i++)
        {
          *dest++ = *src++;
        }
    
      /* Now configure the NVIC to use the new vector table. */
    
      putreg32((uint32_t)g_ram_vectors, NVIC_VECTAB);
    
      /* The number bits required to align the RAM vector table seem to vary
       * from part-to-part.  The following assertion will catch the case where
       * the table alignment is insufficient.
       */
    
      irqinfo("NVIC_VECTAB=%08x\n", getreg32(NVIC_VECTAB));
      DEBUGASSERT(getreg32(NVIC_VECTAB) == (uint32_t)g_ram_vectors);
    }
    

    这样的优势是操作系统可以在调用用户中断函数前后进行个性化操作。比如中断函数本身并没有参数,如果操作系统调用用户中断函数,其就可以传递用户参数。以下为从开源RTOS Nuttx中摘录并简化的一个操作系统中断函数。中断触发后,系统用中断号搜索由操作系统创建的中断函数列表。如果用户在列表中注册了自定义的中断函数并且设置的中断函数参数,则系统会调用中断函数并传递用户预设的参数。如果列表中对应中断函数为空,系统会执行默认中断函数。

    void irq_dispatch(int irq, FAR void *context)
    {
      xcpt_t vector = irq_unexpected_isr;
      void *arg = NULL;
      unsigned int ndx = irq;
    
    #if NR_IRQS > 0
      if ((unsigned)irq < NR_IRQS)
      {
          if (g_irqvector[ndx].handler)
          {
              vector = g_irqvector[ndx].handler;
              arg    = g_irqvector[ndx].arg;
          }
          INCR_COUNT(ndx);
        }
    #endif
    
      /* Then dispatch to the interrupt handler */
      CALL_VECTOR(ndx, vector, irq, context, arg);
      UNUSED(ndx);
    
      /* Record the new "running" task.  g_running_tasks[] is only used by
       * assertion logic for reporting crashes.
       */
    
      g_running_tasks[this_cpu()] = this_task();
    }
    
    展开全文
  • D语言中的Cortex-M4系列中断向量表处理向量表:在mculib4d中的定义方式 向量表: // form file:stm32f401xc.h struct IRQn_Type { /****** Cortex-M4 Processor Exceptions Numbers *********************************...

    D语言中的Cortex-M4系列中断向量表处理

    向量表:

    // form file:stm32f401xc.h
    struct IRQn_Type
    {
    /******  Cortex-M4 Processor Exceptions Numbers ****************************************************************/
      Reset_IRQn				  = -15,
      NonMaskableInt_IRQn         = -14,    /*!< 2 Non Maskable Interrupt                                          */
      MemoryManagement_IRQn       = -12,    /*!< 4 Cortex-M4 Memory Management Interrupt                           */
      BusFault_IRQn               = -11,    /*!< 5 Cortex-M4 Bus Fault Interrupt                                   */
      UsageFault_IRQn             = -10,    /*!< 6 Cortex-M4 Usage Fault Interrupt                                 */
      SVCall_IRQn                 = -5,     /*!< 11 Cortex-M4 SV Call Interrupt                                    */
      DebugMonitor_IRQn           = -4,     /*!< 12 Cortex-M4 Debug Monitor Interrupt                              */
      PendSV_IRQn                 = -2,     /*!< 14 Cortex-M4 Pend SV Interrupt                                    */
      SysTick_IRQn                = -1,     /*!< 15 Cortex-M4 System Tick Interrupt                                */
    /******  STM32 specific Interrupt Numbers **********************************************************************/
      WWDG_IRQn                   = 0,      /*!< Window WatchDog Interrupt                                         */
      PVD_IRQn                    = 1,      /*!< PVD through EXTI Line detection Interrupt                         */
      TAMP_STAMP_IRQn             = 2,      /*!< Tamper and TimeStamp interrupts through the EXTI line             */
      RTC_WKUP_IRQn               = 3,      /*!< RTC Wakeup interrupt through the EXTI line                        */
      FLASH_IRQn                  = 4,      /*!< FLASH global Interrupt                                            */
      RCC_IRQn                    = 5,      /*!< RCC global Interrupt                                              */
      EXTI0_IRQn                  = 6,      /*!< EXTI Line0 Interrupt                                              */
      EXTI1_IRQn                  = 7,      /*!< EXTI Line1 Interrupt                                              */
      EXTI2_IRQn                  = 8,      /*!< EXTI Line2 Interrupt                                              */
      EXTI3_IRQn                  = 9,      /*!< EXTI Line3 Interrupt                                              */
      EXTI4_IRQn                  = 10,     /*!< EXTI Line4 Interrupt                                              */
      DMA1_Stream0_IRQn           = 11,     /*!< DMA1 Stream 0 global Interrupt                                    */
      DMA1_Stream1_IRQn           = 12,     /*!< DMA1 Stream 1 global Interrupt                                    */
      DMA1_Stream2_IRQn           = 13,     /*!< DMA1 Stream 2 global Interrupt                                    */
      DMA1_Stream3_IRQn           = 14,     /*!< DMA1 Stream 3 global Interrupt                                    */
      DMA1_Stream4_IRQn           = 15,     /*!< DMA1 Stream 4 global Interrupt                                    */
      DMA1_Stream5_IRQn           = 16,     /*!< DMA1 Stream 5 global Interrupt                                    */
      DMA1_Stream6_IRQn           = 17,     /*!< DMA1 Stream 6 global Interrupt                                    */
      ADC_IRQn                    = 18,     /*!< ADC1, ADC2 and ADC3 global Interrupts                             */
      EXTI9_5_IRQn                = 23,     /*!< External Line[9:5] Interrupts                                     */
      TIM1_BRK_TIM9_IRQn          = 24,     /*!< TIM1 Break interrupt and TIM9 global interrupt                    */
      TIM1_UP_TIM10_IRQn          = 25,     /*!< TIM1 Update Interrupt and TIM10 global interrupt                  */
      TIM1_TRG_COM_TIM11_IRQn     = 26,     /*!< TIM1 Trigger and Commutation Interrupt and TIM11 global interrupt */
      TIM1_CC_IRQn                = 27,     /*!< TIM1 Capture Compare Interrupt                                    */
      TIM2_IRQn                   = 28,     /*!< TIM2 global Interrupt                                             */
      TIM3_IRQn                   = 29,     /*!< TIM3 global Interrupt                                             */
      TIM4_IRQn                   = 30,     /*!< TIM4 global Interrupt                                             */
      I2C1_EV_IRQn                = 31,     /*!< I2C1 Event Interrupt                                              */
      I2C1_ER_IRQn                = 32,     /*!< I2C1 Error Interrupt                                              */
      I2C2_EV_IRQn                = 33,     /*!< I2C2 Event Interrupt                                              */
      I2C2_ER_IRQn                = 34,     /*!< I2C2 Error Interrupt                                              */
      SPI1_IRQn                   = 35,     /*!< SPI1 global Interrupt                                             */
      SPI2_IRQn                   = 36,     /*!< SPI2 global Interrupt                                             */
      USART1_IRQn                 = 37,     /*!< USART1 global Interrupt                                           */
      USART2_IRQn                 = 38,     /*!< USART2 global Interrupt                                           */
      EXTI15_10_IRQn              = 40,     /*!< External Line[15:10] Interrupts                                   */
      RTC_Alarm_IRQn              = 41,     /*!< RTC Alarm (A and B) through EXTI Line Interrupt                   */
      OTG_FS_WKUP_IRQn            = 42,     /*!< USB OTG FS Wakeup through EXTI line interrupt                     */
      DMA1_Stream7_IRQn           = 47,     /*!< DMA1 Stream7 Interrupt                                            */
      SDIO_IRQn                   = 49,     /*!< SDIO global Interrupt                                             */
      TIM5_IRQn                   = 50,     /*!< TIM5 global Interrupt                                             */
      SPI3_IRQn                   = 51,     /*!< SPI3 global Interrupt                                             */
      DMA2_Stream0_IRQn           = 56,     /*!< DMA2 Stream 0 global Interrupt                                    */
      DMA2_Stream1_IRQn           = 57,     /*!< DMA2 Stream 1 global Interrupt                                    */
      DMA2_Stream2_IRQn           = 58,     /*!< DMA2 Stream 2 global Interrupt                                    */
      DMA2_Stream3_IRQn           = 59,     /*!< DMA2 Stream 3 global Interrupt                                    */
      DMA2_Stream4_IRQn           = 60,     /*!< DMA2 Stream 4 global Interrupt                                    */
      OTG_FS_IRQn                 = 67,     /*!< USB OTG FS global Interrupt                                       */
      DMA2_Stream5_IRQn           = 68,     /*!< DMA2 Stream 5 global interrupt                                    */
      DMA2_Stream6_IRQn           = 69,     /*!< DMA2 Stream 6 global interrupt                                    */
      DMA2_Stream7_IRQn           = 70,     /*!< DMA2 Stream 7 global interrupt                                    */
      USART6_IRQn                 = 71,     /*!< USART6 global interrupt                                           */
      I2C3_EV_IRQn                = 72,     /*!< I2C3 event interrupt                                              */
      I2C3_ER_IRQn                = 73,     /*!< I2C3 error interrupt                                              */
      FPU_IRQn                    = 81,     /*!< FPU global interrupt                                              */
      SPI4_IRQn                   = 84      /*!< SPI4 global Interrupt                                              */
    } ;
    

    在mculib4d中的定义方式

    static import ldc.attributes;								// 附加参数
    
    enum isr_vector = ldc.attributes.section(".isr_vector");	// 存储 section 的定义
    enum naked = ldc.attributes.naked;							// naked 函数
    
    @naked extern(C) void Def_Handler(string nm)()				// 默认中断模板
    {
    	while(true){}
    }
    
    alias VectorFunc = void function();							// 函数型
    
    alias NonMaskableInt_IRQn = Def_Handler!"NonMaskableInt_IRQn";	// 建立一个模板函数
    enum IRQs_Max = 0x64;										//初始化的SP定义到了LD脚本内
    enum IRQs_Offset = 0x0f;									// 原始定义有负数,需要有修正
    
    extern(C) static immutable VectorFunc[IRQs_Max] CortexM_IVT = {
      VectorFunc[IRQs_Max] ret;
    
      ret[0 + IRQs_Offset] = &Reset_Handler;
      ret[IRQn_Type.NonMaskableInt_IRQn + IRQs_Offset] = &NonMaskableInt_IRQn;
      /*
      	其他的中断定义
      */
      
      return ret;
    }();
    
    pragma(mangle, NonMaskableInt_IRQn.mangleof) void irq1()		// 可在代码中通过定义替换中断默认模板
    {
    	
    }
    
    @naked extern(C) void Reset_Handler()							// 主函数
    {
    	while(true){}
    }
    
    

    采用这种方式是为了更容易的阅读与书写定位.

    mculib4d

    这是我搞的一套d语言搞 Cortex-M4 单片机的库,详情可以在 https://gitee.com/sdvcn/mculib4d 这里了解

    展开全文
  • 此外STM32其内部通过一张“中断向量表”来响应中断,程序启动后,将首先从“中断向量表”取出复位中断向量执行复位中断程序完成启动,而这张“中断向量表”的起始地址是0x08000004,当中断来临, STM32 的内部硬件...

    一、IAP原理

    IAP即是在应用编程, IAP 是用户自己的程序在运行过程中对User Flash 的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产
    品中的固件程序进行更新升级。 通常实现IAP 功能时,即用户程序运行中作自身的更新操作,所以需要在设计固件程序时编写两个项目代码,第一个项目程序不执行正常的功能操作,而只是通过某种通信方式(如 USB、USART)接收程序或数据,执行对第二部分代码的更新;第二个项目代码才是真正的功能代码。这两部分项目代码都同时烧录在 User Flash 中,当芯片上电后,首
    先是第一个项目代码开始运行,它作如下操作:
    1)检查是否需要对第二部分代码进行更新
    2)如果不需要更新则转到 第4个步骤
    3)执行更新操作
    4)跳转到第二部分代码执行

    二、stm32正常的程序运行流程

    STM32 的内部闪存( FLASH)地址起始于 0x08000000,一般情况下,程序文件就从此地址开始写入。此外STM32其内部通过一张“中断向量表”来响应中断,程序启动后,将首先从“中断向量表”取出复位中断向量执行复位中断程序完成启动,而这张“中断向量表”的起始地址是0x08000004,当中断来临, STM32 的内部硬件机制亦会自动将 PC 指针定位到“中断向量表”处,并根据中断源取出对应的中断向量执行中断服务程序。
    在图1中, STM32 在复位后,先从 0X08000004 地址取出复位中断向量的地址,并跳转到复位中断服务程序,如图标号①所示;在复位中断服务程序执行完之后,会跳转到我们的main 函数,如图标号②所示;而我们的main 函数一般都是一个死循环,在 main 函数执行过程中,如果收到中断请求(发生重中断),此时STM32 强制将 PC 指针指回中断向量表处,如图标号③所示;然后,根据中断源进入相应的中断服务程序,如图标号④所示;在执行完中断服务程序以后,程序再次返回main 函数执行,如图标号⑤所示。
    图1:stm32程序运行流程

    三、IAP程序运行流程

    在下图2 所示流程中, STM32 复位后,还是从 0X08000004 地址取出复位中断向量的地址,并跳转到复位中断服务程序,在运行完复位中断服务程序之后跳转到IAP 的 main 函数,如图标号①所示,此部分同图1 一样;在执行完 IAP 以后(即将新的 APP 代码写入 STM32的FLASH,灰底部分。新程序的复位中断向量起始地址为 0X08000004+N+M),跳转至新写入程序的复位向量表,取出新程序的复位中断向量的地址,并跳转执行新程序的复位中断服务程序,随后跳转至新程序的 main 函数,如图标号②和③所示,同样 main 函数为一个死循环,并且注意到此时 STM32 的FLASH,在不同位置上,共有两个中断向量表。在 main 函数执行过程中,**如果 CPU 得到一个中断请求, PC 指针仍强制跳转到地址0X08000004 中断向量表处,而不是新程序的中断向量表,如图标号④所示;程序再根据我们设置的中断向量表偏移量,跳转到对应中断源新的中断服务程序中,如图标号⑤所示;在执行完中断服务程序后,程序返回 main 函数继续运行,如图标号⑥所示。**通过以上两个过程的分析,我们知道 IAP 程序必须满足两个要求:

    1) 新程序必须在 IAP 程序之后的某个偏移量为 x 的地址开始;
    2) 必须将新程序的中断向量表相应的移动,移动的偏移量为 x;

    图2:IAP程序运行流程

    四、程序起始地址的设置

    如下图,在keil设置程序要烧录的地址,点击 Options for Targe-> Target选项卡
    图3:keil设置烧录地址
    默认的条件下,图中 IROM1 的起始地址( Start)一般为 0X08000000,大小(Size)为0X80000,即从0X08000000 开始的512K 空间为我们的程序存储(假设使用的STM32F103ZET6,其 FLASH大小是 512K)。而图中,我们设置起始地址( Start)为 0X08010000,即偏移量为 0X10000( 64K字节),因而,留给 APP 用的 FLASH 空间( Size)只有0X80000-0X10000=0X70000( 448K 字节)大小了。设置好 Start 和Szie,就完成APP 程序的起始地址设置。

    五.程序中如何设置中断向量表的偏移量

    看完三IAP程序运行流程的讲解,想必知道了第二部分程序得设置中断向量表的偏移量,否则如果第二部分程序存在中断功能,当发生中断时,程序不能正确的找到对应的中断函数。后面会做实验验证结果,接下来请看如何改中断向量表的偏移地址,我使用的是stm32f407,打开System_stm32f4xx.c这个文件,在
    void SystemInit(void)这个函数中有如下代码:
    #ifdef VECT_TAB_SRAM
    SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;
    #else
    SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
    #endif
    我们没有定义VECT_TAB_SRAM这个宏,所以执行的是
    SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
    其中VECT_TAB_OFFSET就是偏移量,代码的定义是
    #define VECT_TAB_OFFSET 0x00
    把它修改成你需要的偏移量即可,比如第二部分代码要放在0x08000100,那么偏移量就是0x100,即改成
    #define VECT_TAB_OFFSET 0x100即可。

    至于为什么要在SystemInit(void)里面改这个,请查看启动文件,相关部分代码如下:
    Reset_Handler PRO
    EXPORT Reset_Handler [WEAK]
    IMPORT SystemInit
    IMPORT __main

                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP
    

    程序在进入复位中断后,先执行SystemInit这个函数后,才跳到main函数去执行,所以中断向量表的地址在执行main函数前就已经设置了

    六、实验验证

    1.我写了第一部分的程序,支持跳转到第二部分程序
    2.第二部分程序,定义了一个中断函数,当按下按键1,则进入外部中断0点亮LED1
    3.第二部分程序我先不修改中断偏移量,烧录完两个程序,当我按下按键,LED1不亮,证明程序没有跳转到中断函数执行
    4.第二部分程序我修改中断偏移量,烧录完两个程序,当我按下按键,LED1点亮,证明修改了中断偏移量后程序跑入的是第二部分程序的中断函数

    展开全文
  • STM32 中断向量表的位置 、重定向

    千次阅读 2014-02-20 17:01:56
     这篇文章已经说了STM32的启动过程: ... ...我们也知道怎么跳到main函数了,那么,...从stm32f10x.s可以看到,已经定义好了一大堆的中断响应函数,这就是中断向量表,标号__Vectors,表示中断向量表入口地址,例
  • lanmanck原创】 这篇文章已经说了STM32的启动过程: http://blog.csdn.net/lanmanck/article/details/8252560 我们也知道怎么跳到main函数了,那么,中断发生后,又是怎么跑到中断入口地址的呢? 从stm32f...
  • STM32中断向量表偏移地址配置方法

    千次阅读 2018-09-14 19:05:36
    1------------------------------------------------------------------------- from: ... ST公司重定位向量表的库函数: void NVIC_SetVectorTable(uint32_t NVIC...
  • 从stm32f10x.s可以看到,已经定义好了一大堆的中断响应函数,这就是中断向量表,标号__Vectors,表示中断向量表入口地址,例如:AREARESET,DATA,READONLY;定义只读数据段,实际上是在CODE区(假设STM32从FLASH启动...
  • 系统复位后中断向量表始终是在0x00000000地址。 系统启动后可以对中断向量表进行重定向: SCB->VTOR = vector_addr;
  • 9.2 中断向量表的结构

    千次阅读 2019-09-20 21:02:56
    9.2 中断向量表的结构 我现在已经知道了,在运算的时候 一旦遇到了异常情况,就翻到第一页的第一行开始写的这些操作的指示,开始往下执行。开始往下执行,这就能解决问题了。但是问题在于这段操作,解决的是我那个...
  • 问题背景 项目使用STM32F030,需要通过IAP进行固件升级,在FLASH里面要烧录两份代码:一个Boot loader,一个用户应用...但在STM32F0xx系列以Cortex-M0为内核的单片机中却怎么也找不到这个设置中断向量表的寄存器,用
  • 来源:公众号【鱼鹰谈单片机】作者:鱼鹰OspreyID :emOsprey在有 boot 的情况下,一般需要重新设置 app 的中断向量表,使得中断向量表从 boot 切换到 APP ...
  • ARM中断向量表的简单分析

    千次阅读 2018-01-10 20:38:43
    一般编写arm的裸机程序的时候,创建中断向量表就把它放在0x00000000~0x0000001c中,一般都放在这个位置上。但是中断向量表也可以放在0xffff0000~0xffff001c中,知道这是怎么设置的么?开始看到的时候真的有点奇怪,...
  • 一,中断的定义 二 ,中断处理的过程 三,8086/8088CPU可以处理256种不同类型的终端 四,中断服务程序的设计方法 五中断向量表的建立
  • Cortex-M3 异常中断向量表 【Cortex-M3异常与中断】 支持10个系统异常和最多240个外部中断; 支持3个固定的高优先级和多达256级的可编程优先级,支持128级抢占; #0~15在Cortex-M3中定义,IRQ#0~239中断由各个...
  • 因为之前写个stm32的IAP升级程序,所以我总结了做IAP升级的三个主要的难点...2、如何配置程序的起始地址 3、如何从IAP跳转到APP程序 4、使用库函数要注意的地方(防止被坑) 说文章的时候我已经完成了一个最简单的I...
  • STM32中断向量表的偏移量设置方法

    万次阅读 2020-09-28 09:35:13
    STM32中断向量偏移 总结一下在IAP升级中APP程序的中断向量表的偏移 讲解中断偏移之前先看一下程序的启动流程 STM32F4 的内部闪存...序完成启动,而这张“中断向量表”的起始地址是 0x08000004,当中断来临,ST
  • 中断向量表

    千次阅读 2008-09-30 17:07:00
     系统刚引导时,内存0x00000到0x0003FF共1KB的空间用于存放中断向量表。每个中断向量占用4个字节,共可存储256个中断向量。 2. 系统引导时,处在实模式下,只可寻址1MB,为什么要用4个字节来寻址中断呢处理程序? ...
  • TC3XX 多核ECU的中断向量表解疑

    千次阅读 2020-11-26 05:20:58
    关于多核ECU的中断向量表,热心网友问了一个很好的问题 今天研究了一下,先说结论: 每个core都有自己单独的memory去存储自己的中断向量表,而且每个core的中断优先级是相互独立的。也就是说,每个core都可以有...
  • 这一节我们以外部中断为例子,讲讲中断的优先级和中断向量表的知识。 1)cubemx生成代码 首先还是在cubemx中生成代码,选择器件、设置SYS(调试接口)、设置RCC(外部晶振时钟源)。 然后设置GPIO引脚,选择PC...
  • 中断向量 中断向量表

    千次阅读 2015-05-27 11:24:39
    2、中断向量:早期的微机系统中将由硬件产生的中断标识码(中断源的识别标志,可用来形成相应的中断服务程序的入口地址或存放中断服务程序的首地址)称为中断向量。在某些计算机中,中断向量的位置存放一条跳转到...
  • 最近在解决一个问题,看到一篇代码,将中断向量表定位到RAM中,代码所在的文章在这里: ... 大家都知道,MCU的中断向量表通常是在flash的0x00000000地址,这一点从你编译...
  • 9.3 中断向量表的发展

    2019-09-20 21:03:10
    计算机组成 9 中断和异常 9.3 中断向量表的发展 现在这个手册的制造者已经说了,他在第一页就留好了一个表格...这是8086的总共一兆的地址空间,在这其中最低的1K字节固定用来放置中断向量表。这个中断向量表当中包...
  • stm32f0cortex m0 做bootloader中断向量表重映射 环境 MDK5 STM32F042K6Tx Cortex-M0 问题 使用了一款Cortex-M0内核的芯片STM32F042K6Tx,发现它中断向量表的重映射方法与STM32F10x不同 STM32F10x...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,237
精华内容 3,294
关键字:

中断向量表起始地址