Cortex-M7中断向量表的重定向

1 前言

        系统上电后,PC会指向复位向量,即向量表中的Reset_Handler,而系统就是通过Vector Table Offset Register (VTOR)的值加上4字节来找到复位向量的入口的。

        因为地址 0 处应该存储引导代码,所以它通常映射到 Flash 或者是 ROM 器件,并且它们的值不得在运行时改变。然而,为了支持动态重分发中断, CM3 允许向量表重定位——从其它地址处开始定位各异常向量。这些地址对应的区域可以是代码区,但更多是在 RAM 区。在 RAM 区就可以修改向量的入口地址了。为了实现这个功能, NVIC 中有一个寄存器,称为“向量表偏移量寄存器”(在地址 0xE000_ED08 处),通过修改它的值就能重定位向量表。            ---引自《Cortex-M3权威指南》

        简单来说,系统上电后默认中断向量表在地址0,通过VTOR将向量表重定向到RAM中,就可以对其进行操作了,可以在运行时更改其中的中断服务函数。 在Cortex-M7中,支持重定向的偏移地址范围为0x00000000-0xFFFFFF80;此外,如果重定位后的向量表位域可缓存(cacheable)区域,则在使用STR或LDR指令时需要用DSB,ISB等同步隔离指令来清洗流水线。

2 中断向量表偏移寄存器(VTOR)

        Vector Table Offset Register,VTOR的值表示中断向量表相对于地址0x00000000的偏移量。该寄存器在特权级下可读写,其地址为0xE000ED08,复位后为不确定值。

  图1 Vector Table Offset Register

        如图1所示,该寄存器的bit0~bit6为预留位,这些bit默认为0,bit7~bit31记录了偏移量。在设置向量表偏移地址时,必须按照向量表中的异常数制定对齐规则,即将向量表的向量个数向上圆整成2的k次方幂,然后计算处所需要的大小,并按该大小进行字节对齐。例如当有16个系统中断和21个外部中断时,总计37个异常,将向量表的向量个数向上圆整成2的6次方幂64,每个向量大小为4字节,所以向量表的偏移值必须按4*64 = 256 = 0x100字节进行对齐。

        低7位默认为0,也就意味着偏移量至少是按128 = 32*4字节对齐的,这样意味着CPU至少需要支持32个异常(包括16个系统异常和16个外部中断)。

        至于为什么这么做呢?应该是与中断向量的硬件机制有关。有一种猜测,是该机制取了对齐地址的全0位的个数作为向量表的大小(向量个数),以便于取向量时使用或运算,而不是加法运算。

3 VTOR的相关示例

3.1 VTOR的初始化

        在系统上电后,通常需要对VTOR进行初始化。例如,可以在选择在SystemInit函数关中断后,随即进行VTOR的初始化,而这个函数在Reset_Handler中调用。

/*----------------------------------------------------------------------------
  System initialization function
 *----------------------------------------------------------------------------*/
void SystemInit (void)
{
	__disable_irq();							// disable interrupts

#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U)
  SCB->VTOR = (uint32_t) &__VECTOR_TABLE;       // init the VTOR
#endif

#if defined (__FPU_USED) && (__FPU_USED == 1U)
  SCB->CPACR |= ((3U << 10U*2U) |           /* enable CP10 Full Access */
                 (3U << 11U*2U)  );         /* enable CP11 Full Access */
#endif

#ifdef UNALIGNED_SUPPORT_DISABLE
  SCB->CCR |= SCB_CCR_UNALIGN_TRP_Msk;
#endif

// MPU CONFIG and ENABLE
#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U)
  MPUInit();
#endif

// CACHE ENABLE
#if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
  SCB_InvalidateICache();
  SCB_EnableICache();
#endif
#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
  SCB_InvalidateDCache();
//  SCB_EnableDCache();
#endif

  SystemCoreClockUpdate();

  __enable_irq();							// enable interrupts
}

3.2 VTOR的访问  

         VTOR初始化完成后,软件就可以在特权级模式下访问该寄存器,从而找到中断向量表的位置。 例如,freeRTOS的函数prvPortStartFirstTask中,就是通过地址0xE000ED08找到向量表首地址,然后读取向量表的第一个向量的值(MSP的栈顶地址,起始地址),然后将MSP复位为该初始值(主堆栈的栈顶地址):

/*-----------------------------------------------------------*/

static void prvPortStartFirstTask( void )
{
    /* Start the first task.  This also clears the bit that indicates the FPU is
     * in use in case the FPU was used before the scheduler was started - which
     * would otherwise result in the unnecessary leaving of space in the SVC stack
     * for lazy saving of FPU registers. */
    __asm volatile (
        " ldr r0, =0xE000ED08 	\n"/* Use the NVIC offset register to locate the stack. */
        " ldr r0, [r0] 			\n"
        " ldr r0, [r0] 			\n"
        " msr msp, r0			\n"/* Set the msp back to the start of the stack. */
        " mov r0, #0			\n"/* Clear the bit that indicates the FPU is in use, see comment above. */
        " msr control, r0		\n"
        " cpsie i				\n"/* Globally enable interrupts. */
        " cpsie f				\n"
        " dsb					\n"
        " isb					\n"
        " svc 0					\n"/* System call to start first task. */
        " nop					\n"
        " .ltorg				\n"
        );
}
/*-----------------------------------------------------------*/

        cmsis中也提供了VTOR相关的标准接口,从中实现也可以清晰的看到中断向量表的实现就是一个一维数组:

/**
  \brief   Set Interrupt Vector
  \details Sets an interrupt vector in SRAM based interrupt vector table.
           The interrupt number can be positive to specify a device specific interrupt,
           or negative to specify a processor exception.
           VTOR must been relocated to SRAM before.
  \param [in]   IRQn      Interrupt number
  \param [in]   vector    Address of interrupt handler function
 */
__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector)
{
  uint32_t vectors = (uint32_t )SCB->VTOR;
  (* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4)) = vector;
  __DSB();
}

/**
  \brief   Get Interrupt Vector
  \details Reads an interrupt vector from interrupt vector table.
           The interrupt number can be positive to specify a device specific interrupt,
           or negative to specify a processor exception.
  \param [in]   IRQn      Interrupt number.
  \return                 Address of interrupt handler function
 */
__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn)
{
  uint32_t vectors = (uint32_t )SCB->VTOR;
  return (uint32_t)(* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4));
}

  • 30
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Cortex-M7编程手册是指针对ARM公司推出的Cortex-M7内核的编程指南。Cortex-M7是一种高性能、高效能的嵌入式处理器,被广泛应用于物联网、汽车、工业控制以及消费电子等领域。 Cortex-M7编程手册的目的是向开发人员提供有关如何优化使用Cortex-M7的信息和指导。该手册详细介绍了Cortex-M7内核的功能、寄存器和指令集,帮助开发人员了解处理器的架构和工作原理。 手册首先介绍了Cortex-M7的特性和优势,例如高性能时钟系统、深度流水线、硬件分析和调试等。然后,手册介绍了处理器的主要寄存器,包括通用寄存器、特殊寄存器和控制寄存器等,开发人员可以了解如何使用这些寄存器来配置和控制处理器的运行。 手册还详细介绍了Cortex-M7的指令集和编程模型。通过学习指令集和指令的编码方式,开发人员可以编写高效的程序来充分发挥处理器的性能。此外,手册还提供了一些面向特定应用场景的编程示例,帮助开发人员理解如何在实际应用中使用Cortex-M7。 最后,手册还介绍了一些优化技巧和调试方法,帮助开发人员进一步提升程序的性能和可靠性。通过深入理解Cortex-M7的内部结构和工作原理,开发人员可以通过合理的软件设计和编程方法来优化程序的执行效率。 总之,Cortex-M7编程手册是一本对于想要了解和开发基于Cortex-M7的嵌入式系统的开发人员来说非常有价值的参考书。它提供了全面的指导和信息,帮助开发人员充分发挥Cortex-M7处理器的性能。 ### 回答2: Cortex-M7编程手册是一本关于ARM Cortex-M7处理器编程的指南手册。它提供了关于这款处理器的详细技术资料和编程指令,以帮助工程师更好地理解和利用Cortex-M7处理器的性能和功能。手册的内容主要包括以下几个方面。 首先,手册介绍了Cortex-M7处理器的架构和特点。它详细解释了处理器的组成部分,包括核心、寄存器、存储器系统和外设。通过了解这些组成部分的工作原理,开发者可以更好地理解Cortex-M7处理器的内部结构和运行机制。 然后,手册介绍了Cortex-M7处理器的编程模型和指令集。编程模型是指处理器的寄存器和内存布局,以及程序执行的规则。指令集包括处理器支持的各种操作和功能的指令。手册会详细介绍常见的指令,如数据传输指令、算术运算指令、逻辑运算指令等。通过学习这些指令,开发者可以编写高效和功能强大的Cortex-M7程序。 此外,手册还介绍了Cortex-M7处理器的中断和异常处理机制。中断是指处理器在执行程序时遇到的事件,如外部设备的输入信号或定时器的触发。异常是指程序运行时发生的错误或异常情况。手册会详细介绍中断和异常的处理流程,以及如何编写中断服务程序和异常处理程序。 最后,手册提供了一些示例代码和开发工具的介绍,以帮助开发者更好地使用Cortex-M7处理器。这些示例代码可以作为学习和参考的资源,开发工具则可以提供更方便的开发环境和调试功能。 总之,Cortex-M7编程手册是一本帮助开发者理解和使用Cortex-M7处理器的要参考资料。通过学习和掌握手册中的内容,开发者可以编写出高效、功能强大的Cortex-M7程序,实现各种应用需求。 ### 回答3: Cortex-M7编程手册是一本专门针对Cortex-M7处理器的编程指南,旨在帮助开发者更好地理解和使用Cortex-M7处理器。 该手册首先介绍了Cortex-M7处理器的架构和核心特性。Cortex-M7是一款高性能而低功耗的微控制器处理器,采用了ARMv7-M架构,并支持Thumb-2指令集。手册详细说明了Cortex-M7处理器的指令集,包括地址模式、数据处理指令、逻辑指令、分支指令等,开发者可以根据手册中的信息来编写针对Cortex-M7处理器的汇编程序。 此外,手册还介绍了Cortex-M7处理器的内存管理单元(MMU)和保护单元(MPU),并详细说明了如何配置和使用它们。MMU和MPU可以有效地保护系统的安全性和稳定性,开发者可以根据手册中的指导来配置和优化内存管理和保护机制。 此外,手册还介绍了如何在Cortex-M7处理器上进行外设编程,包括串口、SPI、I2C等常见外设的编程方法。手册还涵盖了中断处理、系统调试和性能优化等方面的内容,开发者可以根据手册中的指导来实现高效的系统设计和调试。 总之,Cortex-M7编程手册是一本涵盖了Cortex-M7处理器架构、指令集和各种编程技术的全面指南。通过学习和应用该手册,开发者可以更好地理解和使用Cortex-M7处理器,从而开发出更高效、稳定的嵌入式系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值