Cortex-M3中断重定位-LMLPHP

由Cortex-M3权威指南可以知道,中断向量表可以实现重定位,因此尝试将中断向量表放在RAM区,从而实现动态调整中断处理流程(ISR)。


首先自己定义主堆栈区域:


点击(此处)折叠或打开

  1. #define MSP_STACK_SIZE (0x400)
  2. uint32_t MSPStack[1024] @ ".noinit";

  3. __vector_table
  4.         DCD MSPStack;sfe(CSTACK)
  5.         DCD Reset_Handler

  6.         DCD NMI_Handler
  7.         DCD HardFault_Handler
  8.         DCD MemManage_Handler
  9.         DCD BusFault_Handler
  10.         DCD UsageFault_Handler


由于Cortex-M3使用的是“向下生长的满栈”,堆栈指针SP指向最后一个被压入堆栈的32位数值,在下一次压栈时,SP先自减4,再存入新的数值。因此需要对自定义的堆栈进行初始化,将SP指向正确的位置。(在此之前尽量不要进行函数调用)


点击(此处)折叠或打开

  1. Reset_Handler
  2.         LDR R0, =MSPStack
  3.         MOV R1, #MSP_STACK_SIZE
  4.         LSL R1, R1, #2 ;each element is 4 bytes
  5.         ADD R0, R0, R1
  6.         MSR MSP, R0
  7.         LDR R0, =SystemInit
  8.         BLX R0
  9.         LDR R0, =__iar_program_start
  10.         BX R0


这样SP就指向了正确的位置,并可以进行函数调用了(系统复位后,默认进入特权级的线程模式,参考下图);由下图可知,系统复位后默认使用的时MSP。

Cortex-M3中断重定位-LMLPHP

在进入main函数之后,通过修改VTOR寄存器,实现向量表的重定位;


点击(此处)折叠或打开

  1. NVIC_SetVectorTable(0x20000000, 0);
  2. void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset)
  3. {
  4.   SCB->VTOR = NVIC_VectTab | (Offset & (uint32_t)0x1FFFFF80);
  5. }


0x20000000对应VTOR的第29位为1,故向量表位于RAM区,偏移为0表示位于RAM区的首地址。

接下来应该为该RAM区重建新的中断向量表了


点击(此处)折叠或打开

  1. typedef void (*NVIC_IRQ_HANDLE)();
  2.  #pragma location=0x20000000 // #pragma location用于下面变量的绝对地址定位
  3. //__root 保证没有使用的函数或者变量也能够包含在目标代码中
  4. __root NVIC_IRQ_HANDLE handle[] =
  5. {
  6.         (NVIC_IRQ_HANDLE)MSPStack,
  7.         Reset_Handler,

  8.         NMI_Handler,
  9.         HardFault_Handler,
  10.         MemManage_Handler,
  11.         BusFault_Handler,
  12.         UsageFault_Handler,
  13.         //__vector_table_0x1c
  14.         0,
  15.         0,
  16.         0,
  17.         0,
  18.         SVC_Handler,
  19.         DebugMon_Handler,
  20.         0,
  21.         PendSV_Handler,
  22.         SysTick_Handler,

  23.          DMA_IRQHandler , //0: DMA Interrupt
  24.          GPIO_EVEN_IRQHandler , //1: GPIO_EVEN Interrupt
  25.          TIMER0_IRQHandler , //2: TIMER0 Interrupt
  26.          USART0_RX_IRQHandler , //3: USART0_RX Interrupt
  27.          USART0_TX_IRQHandler , //4: USART0_TX Interrupt
  28.          USB_IRQHandler , //5: USB Interrupt
  29.          ACMP0_IRQHandler , //6: ACMP0 Interrupt
  30.          ADC0_IRQHandler , //7: ADC0 Interrupt
  31.          DAC0_IRQHandler , //8: DAC0 Interrupt
  32.          I2C0_IRQHandler , //9: I2C0 Interrupt
  33.          I2C1_IRQHandler , //10: I2C1 Interrupt
  34.          GPIO_ODD_IRQHandler , //11: GPIO_ODD Interrupt
  35.          TIMER1_IRQHandler , //12: TIMER1 Interrupt
  36.          TIMER2_IRQHandler , //13: TIMER2 Interrupt
  37.          TIMER3_IRQHandler , //14: TIMER3 Interrupt
  38.          USART1_RX_IRQHandler , //15: USART1_RX Interrupt
  39.          USART1_TX_IRQHandler , //16: USART1_TX Interrupt
  40.          LESENSE_IRQHandler , //17: LESENSE Interrupt
  41.          USART2_RX_IRQHandler , //18: USART2_RX Interrupt
  42.          USART2_TX_IRQHandler , //19: USART2_TX Interrupt
  43.          UART0_RX_IRQHandler , //20: UART0_RX Interrupt
  44.          UART0_TX_IRQHandler , //21: UART0_TX Interrupt
  45.          UART1_RX_IRQHandler , //22: UART1_RX Interrupt
  46.          UART1_TX_IRQHandler , //23: UART1_TX Interrupt
  47.          LEUART0_IRQHandler , //24: LEUART0 Interrupt
  48.          LEUART1_IRQHandler , //25: LEUART1 Interrupt
  49.          LETIMER0_IRQHandler , //26: LETIMER0 Interrupt
  50.          PCNT0_IRQHandler , //27: PCNT0 Interrupt
  51.          PCNT1_IRQHandler , //28: PCNT1 Interrupt
  52.          PCNT2_IRQHandler , //29: PCNT2 Interrupt
  53.          RTC_IRQHandler, //30: RTC Interrupt
  54.          BURTC_IRQHandler , //31: BURTC Interrupt
  55.          CMU_IRQHandler , //32: CMU Interrupt
  56.          VCMP_IRQHandler , //33: VCMP Interrupt
  57.          LCD_IRQHandler , //34: LCD Interrupt
  58.          MSC_IRQHandler , //35: MSC Interrupt
  59.          AES_IRQHandler , //36: AES Interrupt
  60.          EBI_IRQHandler , //37: EBI Interrupt
  61.          EMU_IRQHandler , //38: EMU Interrupt
  62.          0 , //39: Reserved Interrupt
  63. };


由于该handle中的中断处理函数偏移固定,故可以很轻松的重定义该处理函数;

由于RAM起始的0x100大小用于新的中断向量表,故在链接文件中需要做如下修改:


点击(此处)折叠或打开

  1. define symbol __ICFEDIT_region_RAM_start__ = 0x20000100;
  2. define symbol __ICFEDIT_region_RAM_end__ = (0x20000100+0x00008000-1 - 0x100);


注意事项:Cortex-M3中断重定位-LMLPHP

        复位后,对于所有优先级可编程的异常,其优先级都被初始化为0(最高)。同时为了确认具体使用了几位表示优先级,可以先往一个优先级寄存器中写入0xFF, 读出多少个1,就表示使用多少位表示优先级。

        中断重定位后,新的中断向量表中的前4字节不起作用,不会影响当前的MSP。

11-06 08:55