由Cortex-M3权威指南可以知道,中断向量表可以实现重定位,因此尝试将中断向量表放在RAM区,从而实现动态调整中断处理流程(ISR)。
首先自己定义主堆栈区域:
-
#define MSP_STACK_SIZE (0x400)
-
uint32_t MSPStack[1024] @ ".noinit";
-
-
__vector_table
-
DCD MSPStack;sfe(CSTACK)
-
DCD Reset_Handler
-
-
DCD NMI_Handler
-
DCD HardFault_Handler
-
DCD MemManage_Handler
-
DCD BusFault_Handler
-
DCD UsageFault_Handler
由于Cortex-M3使用的是“向下生长的满栈”,堆栈指针SP指向最后一个被压入堆栈的32位数值,在下一次压栈时,SP先自减4,再存入新的数值。因此需要对自定义的堆栈进行初始化,将SP指向正确的位置。(在此之前尽量不要进行函数调用)
-
Reset_Handler
-
LDR R0, =MSPStack
-
MOV R1, #MSP_STACK_SIZE
-
LSL R1, R1, #2 ;each element is 4 bytes
-
ADD R0, R0, R1
-
MSR MSP, R0
-
LDR R0, =SystemInit
-
BLX R0
-
LDR R0, =__iar_program_start
-
BX R0
这样SP就指向了正确的位置,并可以进行函数调用了(系统复位后,默认进入特权级的线程模式,参考下图);由下图可知,系统复位后默认使用的时MSP。
在进入main函数之后,通过修改VTOR寄存器,实现向量表的重定位;
-
NVIC_SetVectorTable(0x20000000, 0);
-
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset)
-
{
-
SCB->VTOR = NVIC_VectTab | (Offset & (uint32_t)0x1FFFFF80);
-
}
0x20000000对应VTOR的第29位为1,故向量表位于RAM区,偏移为0表示位于RAM区的首地址。
接下来应该为该RAM区重建新的中断向量表了
-
typedef void (*NVIC_IRQ_HANDLE)();
-
#pragma location=0x20000000 // #pragma location用于下面变量的绝对地址定位
-
//__root 保证没有使用的函数或者变量也能够包含在目标代码中
-
__root NVIC_IRQ_HANDLE handle[] =
-
{
-
(NVIC_IRQ_HANDLE)MSPStack,
-
Reset_Handler,
-
-
NMI_Handler,
-
HardFault_Handler,
-
MemManage_Handler,
-
BusFault_Handler,
-
UsageFault_Handler,
-
//__vector_table_0x1c
-
0,
-
0,
-
0,
-
0,
-
SVC_Handler,
-
DebugMon_Handler,
-
0,
-
PendSV_Handler,
-
SysTick_Handler,
-
-
DMA_IRQHandler , //0: DMA Interrupt
-
GPIO_EVEN_IRQHandler , //1: GPIO_EVEN Interrupt
-
TIMER0_IRQHandler , //2: TIMER0 Interrupt
-
USART0_RX_IRQHandler , //3: USART0_RX Interrupt
-
USART0_TX_IRQHandler , //4: USART0_TX Interrupt
-
USB_IRQHandler , //5: USB Interrupt
-
ACMP0_IRQHandler , //6: ACMP0 Interrupt
-
ADC0_IRQHandler , //7: ADC0 Interrupt
-
DAC0_IRQHandler , //8: DAC0 Interrupt
-
I2C0_IRQHandler , //9: I2C0 Interrupt
-
I2C1_IRQHandler , //10: I2C1 Interrupt
-
GPIO_ODD_IRQHandler , //11: GPIO_ODD Interrupt
-
TIMER1_IRQHandler , //12: TIMER1 Interrupt
-
TIMER2_IRQHandler , //13: TIMER2 Interrupt
-
TIMER3_IRQHandler , //14: TIMER3 Interrupt
-
USART1_RX_IRQHandler , //15: USART1_RX Interrupt
-
USART1_TX_IRQHandler , //16: USART1_TX Interrupt
-
LESENSE_IRQHandler , //17: LESENSE Interrupt
-
USART2_RX_IRQHandler , //18: USART2_RX Interrupt
-
USART2_TX_IRQHandler , //19: USART2_TX Interrupt
-
UART0_RX_IRQHandler , //20: UART0_RX Interrupt
-
UART0_TX_IRQHandler , //21: UART0_TX Interrupt
-
UART1_RX_IRQHandler , //22: UART1_RX Interrupt
-
UART1_TX_IRQHandler , //23: UART1_TX Interrupt
-
LEUART0_IRQHandler , //24: LEUART0 Interrupt
-
LEUART1_IRQHandler , //25: LEUART1 Interrupt
-
LETIMER0_IRQHandler , //26: LETIMER0 Interrupt
-
PCNT0_IRQHandler , //27: PCNT0 Interrupt
-
PCNT1_IRQHandler , //28: PCNT1 Interrupt
-
PCNT2_IRQHandler , //29: PCNT2 Interrupt
-
RTC_IRQHandler, //30: RTC Interrupt
-
BURTC_IRQHandler , //31: BURTC Interrupt
-
CMU_IRQHandler , //32: CMU Interrupt
-
VCMP_IRQHandler , //33: VCMP Interrupt
-
LCD_IRQHandler , //34: LCD Interrupt
-
MSC_IRQHandler , //35: MSC Interrupt
-
AES_IRQHandler , //36: AES Interrupt
-
EBI_IRQHandler , //37: EBI Interrupt
-
EMU_IRQHandler , //38: EMU Interrupt
-
0 , //39: Reserved Interrupt
-
};
由于该handle中的中断处理函数偏移固定,故可以很轻松的重定义该处理函数;
由于RAM起始的0x100大小用于新的中断向量表,故在链接文件中需要做如下修改:
-
define symbol __ICFEDIT_region_RAM_start__ = 0x20000100;
-
define symbol __ICFEDIT_region_RAM_end__ = (0x20000100+0x00008000-1 - 0x100);
注意事项:
复位后,对于所有优先级可编程的异常,其优先级都被初始化为0(最高)。同时为了确认具体使用了几位表示优先级,可以先往一个优先级寄存器中写入0xFF, 读出多少个1,就表示使用多少位表示优先级。
中断重定位后,新的中断向量表中的前4字节不起作用,不会影响当前的MSP。
阅读(2342) | 评论(0) | 转发(0) |