精华内容
下载资源
问答
  • STM32中断向量表的位置、重定向我们也知道怎么跳到main函数了,那么,中断发生后,又是怎么跑到中断入口地址的呢?...定义只读数据段,实际上是在CODE区(假设STM32从FLASH启动,则此中断向量表起始地址即为...

    STM32

    中断向量表的位置

    、重定向

    我们也知道怎么跳到

    main

    函数了,那么,中断发生后,又是怎么跑到中

    断入口地址的呢?从

    stm32f10x.s

    可以看到,已经定义好了一大堆的中断响应函

    数,这就是中断向量表,标号

    __Vectors

    ,表示中断向量表入口地址,例如:

    AREA

    RESET,

    DATA,

    READONLY

    ;

    定义只读数据段,实际上是在

    CODE

    区(假设

    STM32

    FLASH

    启动,则此中断向量表起始地址即为

    0x8000000

    )

    EXPORT

    __VectorsIMPORT

    OS_CPU_SysTickHandler

    IMPORT

    OS_CPU_PendSVHandler

    __Vectors

    DCD

    __initial_sp

    ;

    Top

    of

    Stack

    DCD

    Reset_Handler

    ; Reset Handler

    DCD

    NMI_Handler

    ;

    NMI

    Handler

    DCD

    HardFault_Handler

    ;

    Hard

    Fault

    Handler

    DCD

    MemManage_Handler

    ;

    MPU

    Fault

    Handler

    DCD

    BusFault_Handler

    ; Bus Fault Handler

    DCD

    UsageFault_Handler

    ;

    Usage Fault Handler

    这个向量表的编写是有讲究的,跟硬件一一对应不能乱写的,

    CPU

    找入口地

    址就靠它了,

    bin

    文件开头就是他们的地址,参考手册

    RM0008

    10.1.2

    节可

    以看到排列。

    我们再结合

    CORTEX-M3

    的特性,他上电后根据

    boot

    引脚来决定

    PC

    位置,

    比如

    boot

    设置为

    flash

    启动,则启动后

    PC

    跳到

    0x08000000

    。此时

    CPU

    会先取

    2

    个地址,第一个是栈顶地址,第二个是复位异常地址,故有了上面的写法,

    这样就跳到

    reset_handler

    那么这个

    reset_handler

    的实际地址是多少

    .

    ?下面的一堆例如

    Nmi_handler

    址又是多少呢?发生中断是怎么跑到这个地址的呢?下面挨个讲解。

    展开全文
  • 首先我们需要跳到main函数,这个就不多说了。那么,中断发生后,又是怎么跑到中断入口地址的呢?... 定义只读数据段,实际上是在CODE区(假设STM32从FLASH启动,则此中断向量表起始地址即为0x8000...

    首先我们需要跳到main函数,这个就不多说了。那么,中断发生后,又是怎么跑到中断入口地址的呢?

    从stm32f10x.s可以看到,已经定义好了一大堆的中断响应函数,这就是中断向量表,标号__Vectors,表示中断向量表入口地址,例如:

    AREA RESET, DATA, READONLY ; 定义只读数据段,实际上是在CODE区(假设STM32从FLASH启动,则此中断向量表起始地址即为0x8000000)

    EXPORT __Vectors

    IMPORT OS_CPU_SysTickHandler

    IMPORT OS_CPU_PendSVHandler

    __Vectors DCD __initial_sp ; Top of Stack

    DCD Reset_Handler ; Reset Handler

    DCD NMI_Handler ; NMI Handler

    DCD HardFault_Handler ; Hard Fault Handler

    DCD MemManage_Handler ; MPU Fault Handler

    DCD BusFault_Handler ; Bus Fault Handler

    DCD UsageFault_Handler ; Usage Fault Handler

    这个向量表的编写是有讲究的,跟硬件一一对应不能乱写的,CPU找入口地址就靠它了,bin文件开头就是他们的地址,参考手册RM0008的10.1.2节可以看到排列。

    我们再结合CORTEX-M3的特性,他上电后根据boot引脚来决定PC位置,比如boot设置为flash启动,则启动后PC跳到0x08000000。此时CPU会先取2个地址,第一个是栈顶地址,第二个是复位异常地址,故有了上面的写法,这样就跳到reset_handler。

    那么这个reset_handler的实际地址是多少.?下面的一堆例如Nmi_handler地址又是多少呢?发生中断是怎么跑到这个地址的呢?下面挨个讲解。

    1、我们可以通过反向来得知这些入口地址,查看工程下的map文件就可以看到了,这个地址跟keil里面设置的target->flash起始地址息息相关,实际上我们不太需要关心,让编译器分配,中断向量表放的就是他们的地址。

    2、对比ARM7/ARM9内核,Cortex-M3内核则是固定了中断向量表的位置而起始地址是可变化的。

    3、进到C语言后会先配置NVIC,NVIC_SetVectorTable()里面可以配置中断向量表的起始地址和偏移,主要是告诉CPU该向量表是位于Flash还是Ram,偏移是多少。例如设置为位于Flash内,偏移就是烧入的程序地址,可在Keil target中设置。这样CPU就知道入口地址了。本文引用地址:http://www.eepw.com.cn/article/201611/316107.htm

    4、发生中断后,CPU找到中断向量表地址,然后根据偏移(对号入座)再找到中断地址,这样就跳过去了。

    我们截一个图说明一下,map文件:

    对应的bin文件,看是不是放的上面地址:

    显然,200039c0就是栈顶地址,而08006F21就是reset_handler地址!

    如何定位?以放到0x20000000为例

    1、keil设置ram起始为0x20000100,我们在0x20000000~0x20000100放中断向量表,其他给程序用

    2、设置NVIC_SetVectorTable(NVIC_VectTab_FLASH,0);

    3、跳到C时把中断向量表拷贝到0x20000000

    展开全文
  • 文章目录1,中断硬件机制2,外部中断的配置2.1,查看原理图2.2,配置I/O口为中断模式2.3,配置中断为下降沿触发2.4,使能外部中断 1,中断硬件机制 2,外部中断的配置 2.1,查看原理图 2.2...

    1,ARM中断机制

    1.1,中断硬件机制

    在这里插入图片描述

    1.2,中断过程

    在这里插入图片描述

    1.3,中断源

    Exynos4412中断控制器包含160个中断控制源,分三类分别是:
    用于CPU之间通信的SGI
    (Software Generated Interrupt)
    专用于特定CPU核的PPI
    (Private Peripheral Interrupt)
    被多个CPU核共享的SPI
    (Shared Peripheral Interrupt)

    1.4,中断控制器

    中断源分发给不同的CPU.
    每个中断都有一个唯一对应的ID号,当中断发生时,该ID号会写入一个特定的寄存器。
    中断处理程序可以读取该寄存器来决定该调用哪个具体的中断处理函数。
    在这里插入图片描述

    2,外部中断的配置

    2.1,查看原理图

    在这里插入图片描述
    在这里插入图片描述

    可以看到按键k2,挂载在GPX1_1引脚上,对应XEINT9

    2.2,外部,配置芯片管脚工作模式

    2.2.1,配置I/O口为中断模式

    在这里插入图片描述

    在这里插入图片描述

    GPX1CON = (GPX1CON & ~(0x0f << 4) | (0x0f << 4));		// 设置管脚为中断模式   
    

    2.2.2,配置中断为下降沿触发

    在这里插入图片描述
    在这里插入图片描述

    EXT_INT41_CON = (EXT_INT41_CON & ~(0X07 << 4)) | (0X02 << 4);		//设置中断触发方式为下降沿
    

    2.2.3,使能外部中断

    在这里插入图片描述
    在这里插入图片描述

    EXT_INT41_MASK = (EXT_INT41_MASK & ~(0X01 << 1)) | (0X00 << 1);		//管脚中断使能(一关)
    

    2.3,内部,设置功能模块(中断控制模块 GIC)

    2.3.1,查GIC中断表,找出对应的中断端口号和ID号

    在这里插入图片描述
    在这里插入图片描述
    XEINT9对应的中断端口号是25,ID号是57

    2.3.2,设置GIC中断使能

    在这里插入图片描述
    在这里插入图片描述

    ICDISER1_CPU0 = ICDISER1_CPU0 | (0x01 << 25); 	//使能对应中断(二关) 
    

    2.3.3,分发配置

    在这里插入图片描述
    在这里插入图片描述

    根据样例选用默认设置

    //#define  ICDIPTR17_CPU0 (*(volatile unsigned int *)0x10490844) 	//分发配置,根据样例选用默认设置
    #define  ICDIPTR14_CPU0 (*(volatile unsigned int *)0x10490838) 	//分发配置,根据样例选用默认设置
    
    //ICDIPTR17_CPU0 = 0x01010101;
    ICDIPTR14_CPU0 = 0x01010101;
    

    ICDIPTR17_CPU0 = 0x01010101; //分发器中断使能 (三关),根据样例选用默认设置

    2.3.4,分发总使能

    在这里插入图片描述

    ICDDCR = ICDDCR | 0X01;		//分发器中断使能 (三关)
    

    2.3.5,CPU外部中断借口使能

    在这里插入图片描述

    ICCICR_CPU0 = ICCICR_CPU0 | 0x01;		//CPU接口中断使能(四关)
    

    2.3.6,设置CPU的中断优先级门限值

    在这里插入图片描述

    ICCPMR_CPU0 = 0xff;		//设置CPU的中断优先级门限值,当前为最低,所有的中断都可以处理     
    

    3,中断处理

    3.1,协处理器指令修改异常向量表起始地址

    1. CPU规定的异常向量表的地址是从0x00开始的,其中中断异常的地址是0x18
    2. 但是想开发版中下载程序的时候我们会制定一个起始地址,这样异常向量表的起始地址就不是0x00了
    3. 所以,需要重新制定模拟的异常向量表的起始地址
    MRC Pn,op1,Rd,CRn,CRm,op2  //mrc  p15,0,r0,c1,c0,0 读入cp15的c1寄存器的内容到r0中
    MCR Pn,op1,Rd,CRn,CRm,op2  //mcr  p15,0,r0,c1,c0,0 写r0内容到cp15的c1寄存器中
    

    通过协处理器设置异常向量表的起始地址为0x40008000

    @ set Vector Base Address 为0x40008000	
    ldr      r0,=0x40008000
    mcr    p15,0,r0,c12,c0,0
    

    在这里插入图片描述

    3.2,异常向量表

    _start: b       start_code
    ldr     pc, _undefined_instruction
    ldr     pc, _software_interrupt
    ldr     pc, _prefetch_abort
    ldr     pc, _data_abort
    ldr     pc, _not_used
    ldr     pc, _irq
    ldr     pc, _fiq
    _undefined_instruction: .word _undefined_instruction
    _software_interrupt:    .word _software_interrupt
    _prefetch_abort:        .word _prefetch_abort
    _data_abort:            .word _data_abort
    _not_used:              .word _not_used
    _irq:                   .word irq_handler 
    _fiq:                   .word _fiq
    irq_handler:
    	sub  lr,lr,#4 
    	stmfd sp!,{r0-r12,lr}  @保护现场
    	bl	do_irq
    irq_handler_end:
    	ldmfd sp!,{r0-r12,pc}^ @恢复现场
    

    软中断SWI中,lr既是返回地址,中断IRQ中lr-4才是返回地址

    3.3,中断处理函数

    3.3.1,获取中断ID号

    在这里插入图片描述

    int irq_num;
    irq_num = ICCIAR_CPU0 & 0X3ff; 	//获取中断ID号
    

    3.3.2,清GPIO的中断标志

    在这里插入图片描述

    EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 1); 		//清GPX1_1中断标志
    

    3.3.3,清GCI中断标志

    在这里插入图片描述
    在这里插入图片描述

    ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 25);  		//清GCI中GPX1_1的中断标志
    

    3.3.4,结束中断

    在这里插入图片描述

    ICCEOIR_CPU0 = (ICCEOIR_CPU0 & ~0x3ff) | irq_num;   	//结束对应的中断
    

    3.3.5,中断处理函数

    void do_irq()
    {
    /* 获取中断ID号,并根据不同的中断号做相应的处理 */
    	int irq_num;
    	irq_num = ICCIAR_CPU0 & 0X3ff; 	//获取中断ID号
    	switch(irq_num)
    	{
    		case 57:
    			uart2_putc('k');
    			uart2_putc('2');
    			EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 1); 		//清GPX1_1中断标志
    			ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 25);  		//清GCI中GPX1_1的中断标志
    			break;
    		default:
    			uart2_putc('d');
    	}
    	 /*结束中断  将处理完成的中断ID号写入该寄存器,则表示相应的中断处理完成*/
    	ICCEOIR_CPU0 = (ICCEOIR_CPU0 & ~0x3ff) | irq_num;   	//结束对应的中断
    }
    

    4,例

    4.1,start.S

        .global  delay1s 
        .text     
        .global _start
    _start:
    		b		reset                        @0x00
    		ldr		pc,_undefined_instruction  @0x04
    		ldr		pc,_software_interrupt     
    		ldr		pc,_prefetch_abort
    		ldr		pc,_data_abort
    		ldr		pc,_not_used
    		ldr		pc,_irq
    		ldr		pc,_fiq
    
    _undefined_instruction: .word  _undefined_instruction
    _software_interrupt:	.word  _software_interrupt
    _prefetch_abort:		.word  _prefetch_abort
    _data_abort:			.word  _data_abort
    _not_used:				.word  _not_used
    _irq:					.word  irq_handler
    _fiq:					.word  _fiq
    
    reset: 
    	ldr	r0,=0x40008000      @设置异常向量表的启始地址为 0x40008000
    	mcr	p15,0,r0,c12,c0,0		@ Vector Base Address Register
    
    init_stack:
    	ldr		r0,stacktop         /*get stack top pointer*/
    
    	/********svc mode stack********/
    		mov		sp,r0
    		sub		r0,#128*4          /*512 byte  for irq mode of stack*/
    	/****irq mode stack**/
    		msr		cpsr,#0xd2
    		mov		sp,r0
    		sub		r0,#128*4          /*512 byte  for irq mode of stack*/
    	/***fiq mode stack***/
    		msr 	cpsr,#0xd1
    		mov		sp,r0
    		sub		r0,#0
    	/***abort mode stack***/
    		msr		cpsr,#0xd7
    		mov		sp,r0
    		sub		r0,#0
    	/***undefine mode stack***/
    		msr		cpsr,#0xdb
    		mov		sp,r0
    		sub		r0,#0
       /*** sys mode and usr mode stack ***/
    		msr		cpsr,#0x10
    		mov		sp,r0             /*1024 byte  for user mode of stack*/
    
    		b		main    /* 跳转到c程序的main函数  */
    
    irq_handler:
    	sub lr,lr,#4 	@软中断SWI中,lr既是返回地址,中断IRQ中lr-4才是返回地址
    	stmfd sp!,{r0-r12,lr} 	@入栈保护现场
    	bl do_irq 	@调用C函数
    irq_handler_end:
    	ldmfd sp!,{r0-r12,pc}^ 	@出栈恢复现场
    
    delay1s:
         ldr      r4,=0x1ffffff   
    delay1s_loop:
         sub    r4,r4,#1
         cmp   r4,#0         
         bne    delay1s_loop
         mov   pc,lr	
    
    	.align	4
    
    	/****  swi_interrupt handler  ****/
    
    stacktop:    .word 		stack+4*512
    
    .data
    
    stack:	
      .space  4*512
    .end
    

    4.2,main.c

    #define GPA1CON 		(*(volatile unsigned int *)0x11400020) 	//volatile 确保本条指令不会因编译器的优化而省略
    #define ULCON2 			(*(volatile unsigned int *)0x13820000) 	//串口2线控:数据位,停止位,奇偶校验位
    #define UCON2 			(*(volatile unsigned int *)0x13820004) 	//串口2读取控制:串口读的方式(如:轮询/中断等),写的方式
    #define UBRDIV2 		(*(volatile unsigned int *)0x13820028) 	//串口2波特率设置
    #define UFRACVAL2 		(*(volatile unsigned int *)0x1382002c) 	//串口2波特率设置
    #define UTXH2 			(*(volatile unsigned int *)0x13820020) 	//串口2发送缓存器
    #define URXH2 			(*(volatile unsigned int *)0x13820024) 	//串口2接受缓存器
    #define UTRSTAT2 		(*(volatile unsigned int *)0x13820010) 	//串口2状态寄存器
    
    #define GPA0CON 		(*(volatile unsigned int *)0x11400000) 	//volatile 确保本条指令不会因编译器的优化而省略
    #define ULCON0 			(*(volatile unsigned int *)0x13800000) 	//串口0线控:数据位,停止位,奇偶校验位
    #define UCON0 			(*(volatile unsigned int *)0x13800004) 	//串口0读取控制:串口读的方式(如:轮询/中断等),写的方式
    #define UBRDIV0 		(*(volatile unsigned int *)0x13800028) 	//串口0波特率设置
    #define UFRACVAL0 		(*(volatile unsigned int *)0x1380002c) 	//串口0波特率设置
    #define UTXH0 			(*(volatile unsigned int *)0x13800020) 	//串口0发送缓存器
    #define URXH0 			(*(volatile unsigned int *)0x13800024) 	//串口0接受缓存器
    #define UTRSTAT0 		(*(volatile unsigned int *)0x13800010) 	//串口0状态寄存器
    
    #define GPX1CON 		(*(volatile unsigned int *)0x11000C20) 	//
    #define EXT_INT41_CON 	(*(volatile unsigned int *)0x11000E04) 	//外部中断1触发方式
    #define  EXT_INT41_MASK	(*(volatile unsigned int *)0x11000f04) 	//使能外部中断
    #define  ICDISER1_CPU0	(*(volatile unsigned int *)0x10490104) 	//GIC中断使能
    //#define  ICDIPTR17_CPU0 (*(volatile unsigned int *)0x10490844) 	//分发配置,根据样例选用默认设置
    #define  ICDIPTR14_CPU0 (*(volatile unsigned int *)0x10490838) 	//分发配置,根据样例选用默认设置
    #define  ICDDCR 		(*(volatile unsigned int *)0x10490000) 	//全局外部中断使能
    #define  ICCICR_CPU0 	(*(volatile unsigned int *)0x10480000) 	//CPU外部中断接口使能
    #define  ICCPMR_CPU0 	(*(volatile unsigned int *)0x10480004) 	//优先级设定
    #define  ICCIAR_CPU0 	(*(volatile unsigned int *)0x1048000c) 	//获取中断ID号
    #define  EXT_INT41_PEND	(*(volatile unsigned int *)0x11000f44) 	//清GPIO的中断标志
    #define  ICDICPR1_CPU0	(*(volatile unsigned int *)0x10490284) 	//清GIC[31:0]的中断标志
    #define  ICCEOIR_CPU0	(*(volatile unsigned int *)0x10480010) 	//结束中断
    
    #define  GPX2CON		(*(volatile unsigned int *)0x11000C40) 	//
    #define  GPF3CON		(*(volatile unsigned int *)0x11000C20) 	//
    #define  GPX1DATA		(*(volatile unsigned int *)0x11000C24) 	//
    #define  GPX2DATA		(*(volatile unsigned int *)0x11000C44) 	//
    #define  GPF3DATA		(*(volatile unsigned int *)0x114001E4) 	//
    
    #define GPX2_7_U (GPX2DATA |= (0X01 << 7)) 		//LED2
    #define GPX2_7_D (GPX2DATA &= ~(0X01 << 7))
    
    #define GPX1_0_U (GPX1DATA |= (0X01 << 0)) 		//LED3
    #define GPX1_0_D (GPX1DATA &= ~(0X01 << 0))
    
    #define GPF3_4_U (GPF3DATA |= (0X01 << 4)) 		//LED4
    #define GPF3_4_D (GPF3DATA &= ~(0X01 << 4))
    
    #define GPF3_5_U (GPF3DATA |= (0X01 << 5)) 		//LED5
    #define GPF3_5_D (GPF3DATA &= ~(0X01 << 5))
    
    void uart_init(void)
    {	
    	//4.设置波特率为115200
    	//For example, if the Baud rate is 115200 bps and SCLK_UART is 100 MHz,UBRDIVn and UFRACVALn are:
    	//DIV_VAL = (SCLK_UART/(bps * 16)) - 1
    	//DIV_VAL = (100000000/(115200 * 16)) – 1
    	//= 54.253 – 1
    	//= 53.253
    	//UBRDIVn = 53 (integer part of DIV_VAL)
    	//UFRACVALn/16 = 0.253
    	//Therefore, UFRACVALn = 4
    
    	//1.配置GPA1CON寄存器中的UART2    	GPA1_0  UART_2_RXD
    	// 									GPA1_1  UART_2_TXD
    	GPA1CON &= 0xffffff00;
    	GPA1CON |= 0x00000022;
    
    	//2.配置ULCON2寄存器  	串口2 8位数据位,1位停止位,无奇偶校验
    	ULCON2 &= 0Xffffffc0;
    	ULCON2 |= 0x00000003;
    
    	//3.配置UCON2寄存器 	通过轮询(polling)的模式读取串口数据     通过轮询(polling)的模式往串口写入数据数据
    	UCON2 &= 0xfffffff0;
    	UCON2 |= 0x00000005;
    
    	UBRDIV2 = 53;
    	UFRACVAL2 = 4;
    
    	
    	//1.配置GPA0CON寄存器中的UART0    	GPA0_0  UART_0_RXD
    	// 									GPA0_1  UART_0_TXD
    	GPA0CON &= 0xffffff00;
    	GPA0CON |= 0x00000022;
    
    	//2.配置ULCON0寄存器  	串口0 8位数据位,1位停止位,无奇偶校验
    	ULCON0 &= 0Xffffffc0;
    	ULCON0 |= 0x00000003;
    
    	//3.配置UCON0寄存器 	通过轮询(polling)的模式读取串口数据     通过轮询(polling)的模式往串口写入数据数据
    	UCON0 &= 0xfffffff0;
    	UCON0 |= 0x00000005;
    
    	//4.设置波特率为115200
    	UBRDIV0 = 53;
    	UFRACVAL0 = 4;
    }
    
    void interrupt_init()
    {
    	//*  key2    GPX1_1    EINT9   SPIPORT:25 	INTID:57                                        *
    	//*******外   配置芯片管脚工作模式**************************************
    	//1.配置GPX1CON寄存器中的WAKEUP_INT1_1         	GPX1_1
    	GPX1CON = (GPX1CON & ~(0x0f << 4)) | (0x0f << 4);
    	//2.通过EXT_INT41_CON1 配置外部中断1为下降沿触发
    	EXT_INT41_CON = (EXT_INT41_CON & ~(0X07 << 4)) | (0X02 << 4);
    	//3.使能外部中断
    	EXT_INT41_MASK = (EXT_INT41_MASK & ~(0X01 << 1)) | (0X00 << 1);
    	
    	
    	//*******内   功能块设置**************************************
    	//4.设置GIC中断使能  ICDISER1_CPU0  GPX1_1的中断,即XEINT9 中断端口号为25
    	ICDISER1_CPU0 = ICDISER1_CPU0 | (0x01 << 25);
    	//5.根据样例选用默认设置
      	//ICDIPTR17_CPU0 = 0x01010101;
      	ICDIPTR14_CPU0 = 0x01010101;
    	//6.分发总使能
    	ICDDCR = ICDDCR | 0X01;
    	//7.CPU外部中断借口使能
    	ICCICR_CPU0 = ICCICR_CPU0 | 0x01;
    	//8.设置CPU0的优先级门槛为最低
    	ICCPMR_CPU0 = 0xff;
    	
    	
    	
    	//*  key3    GPX1_2    EINT10   SPIPORT:26 	INTID:58  
    	//*******外   配置芯片管脚工作模式**************************************
    	//1.配置GPX1CON寄存器中的WAKEUP_INT1_2         	GPX1_2
    	GPX1CON = (GPX1CON & ~(0x0f << 8)) | (0x0f << 8);
    	//2.通过EXT_INT41_CON2 配置外部中断1为下降沿触发
    	EXT_INT41_CON = (EXT_INT41_CON & ~(0X07 << 8)) | (0X02 << 8);
    	//3.使能外部中断
    	EXT_INT41_MASK = (EXT_INT41_MASK & ~(0X01 << 2)) | (0X00 << 2);
    	
    	
    	//*******内   功能块设置**************************************
    	//4.设置GIC中断使能  ICDISER1_CPU0  GPX1_2的中断,即XEINT10 中断端口号为26
    	ICDISER1_CPU0 = ICDISER1_CPU0 | (0x01 << 26);
    	//5.根据样例选用默认设置
      	//ICDIPTR17_CPU0 = 0x01010101;
      	ICDIPTR14_CPU0 = 0x01010101;
    	//6.分发总使能
    	ICDDCR = ICDDCR | 0X01;
    	//7.CPU外部中断借口使能
    	ICCICR_CPU0 = ICCICR_CPU0 | 0x01;
    	//8.设置CPU0的优先级门槛为最低
    	ICCPMR_CPU0 = 0xff;
                                          
    }
    void led_init()
    {
    	GPX2CON = (GPX2CON & ~(0X0F << 28)) | (0X01 << 28); 	//设置LED2灯的配置寄存器 GPX2CON7为输出状态
    	GPX1CON = (GPX1CON & ~(0X0F << 0)) | (0X01 << 0); 		//设置LED3灯的配置寄存器 GPX1CON0为输出状态
    	GPF3CON = (GPF3CON & ~(0X0F << 16)) | (0X01 << 16); 	//设置LED4灯的配置寄存器 GPF3CON4为输出状态
    	GPF3CON = (GPF3CON & ~(0X0F << 20)) | (0X01 << 20); 	//设置LED5灯的配置寄存器 GPF3CON5为输出状态
    }
    void uart0_putc(char c)
    {
    	while(1)
    	{
    		if(UTRSTAT0 && 0X02) break;
    	}
    
    	UTXH0 = c;
    }
    char uart0_getc(char *c)
    {
    	while(1)
    	{
    		if(UTRSTAT0 && 0X01) break;
    	}
    	*c = URXH0;
    	uart0_putc(*c);
    
    	return *c;
    }
    
    void uart2_putc(char c)
    {
    	while(1)
    	{
    		if(UTRSTAT2 && 0X02) break;
    	}
    
    	UTXH2 = c;
    }
    void do_irq()
    {
    	int irq_num;
    	irq_num = ICCIAR_CPU0 & 0X3ff; 	//获取中断ID号
    	switch(irq_num)
    	{
    		case 57:
    			//LED2闪烁
    			GPX2_7_U;
    			delay1s();
    			GPX2_7_D;
    			EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 1); 		//清GPX1_1中断标志
    			ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 25);  		//清GCI中GPX1_1的中断标志
    			break;
    		case 58:
    			uart2_putc('3');
    			EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 2); 		//清GPX1_2中断标志
    			ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 26);  		//清GCI中GPX1_2的中断标志
    			break;
    
    		default:
    			uart2_putc('d');
    	}
    	ICCEOIR_CPU0 = (ICCEOIR_CPU0 & ~0x3ff) | irq_num;   	//结束对应的中断
    	
    }
    int main(void) 
    {
    	uart_init();
    	led_init();
    	interrupt_init();
    	char c;
    
    	while(1)
    	{
    		uart0_getc(&c);
    		uart2_putc('b');
    		delay1s();
    		delay1s();
    	}
    	
    	return 0;
    }
    
    展开全文
  • STM32中断向量表的偏移量设置方法

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

    STM32中断向量偏移

    总结一下在IAP升级中APP程序的中断向量表的偏移

    讲解中断偏移之前先看一下程序的启动流程

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

     

     

    1. 关于APP程序的中断向量表地址偏移(三种方法,stm32F2与F4系列通用。三种方法本质一样只是看到网上的各种例程的表现形式不一样)

    ① 直接操作寄存器

    之前我们讲解过,在系统启动的时候,会首先调用 SystemInit 函数初始化时钟系统,同时SystemInit 还完成了中断向量表的设置,我们可以打开 SystemInit 函数,看看函数体的结尾处有 这样几行代码:

    #ifdef VECT_TAB_SRAM

    SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;

    /* Vector Table Relocation in Internal SRAM. */

    #else

    SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;

    /* Vector Table Relocation in Internal FLASH. */

    #endif

    从代码可以理解, VTOR 寄存器存放的是中断向量表的起始地址。默认的情况VECT_TAB_SRAM 是没有定义,所以执行SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; 对于 FLASH APP,我们设置为 FLASH_BASE+偏移量 0x10000,所以我们可以在 SystemInit 函数里面修改 SCB->VTOR 的值。当然为了尽可能不修改系统级别文件,后面其他程序用的话会因为这里动过中断向量表,导致中断不能正常运行

    我们可以也可以在FLASH APP 的 main 函数最开头处添加如下代码实现中断向量表的起始地址的重设: SCB->VTOR = FLASH_BASE | 0x10000;

     

     

    在APP程序的main函数的开头设置中断向量表偏移

    SCB->VTOR = FLASH_BASE | 0x10000;

    其中0x10000是偏移量。。也就是前面的IAP程序所占用的空间大小,要是你的main函数中有SystemInit();的话要在SystemInit();之后添加。

    其中

    #define FLASH_BASE ((uint32_t)0x08000000) /*!<FLASH base address in the alias region */

    #define SRAM_BASE ((uint32_t)0x20000000) /*!< SRAM baseaddress in the alias region */

     

     

     

    对应keil设置中的(这是一般程序默认的,IAP升级中APP程序的这个地方还得根据中断偏移量改)

     

     

     

    ② 使用库函数设置偏移量

    在库文件中有专门的一个函数

    在APP程序初始化时调用函数NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x10000);

     

    其中/* Vector Table Base----------------------------------*/

    #define NVIC_VectTab_RAM ((u32)0x20000000)

    #define NVIC_VectTab_FLASH ((u32)0x08000000)

     

     

    /***********************************************************************

    Function Name : NVIC_SetVectorTable

    * Description : Sets the vector table location andOffset.

    * Input : - NVIC_VectTab: specifies if thevector table is in RAM or

    * FLASH memory.

    **********************************************************************/

    void NVIC_SetVectorTable (u32NVIC_VectTab, u32 Offset)

    {

    /* Check the parameters */

    assert_param(IS_NVIC_VECTTAB(NVIC_VectTab));

    assert_param(IS_NVIC_OFFSET(Offset));

     

    SCB->VTOR = NVIC_VectTab | (Offset & (u32)0x1FFFFF80);

    }

     

    ③修改库文件(不建议使用)

    直接修改固件库里面的数值。在void SystemInit(void)下的

    /* Configure the Vector Table location add offsetaddress ------------------*/

    #ifdefVECT_TAB_SRAM

    SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;/* Internal SRAM */

    #else

    SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;/* Internal FLASH */

    #endif

     

    直接修改

    #define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field.

    This valuemust be a multiple of 0x200. */

    #define VECT_TAB_OFFSET 0x10000 /*!< Vector Table base offsetfield.

    This valuemust be a multiple of 0x200. */

     

     

    2.关于IAP程序与APP程序keil中的设置

    Stm32的flash都是从0x8000000开始的,结束地址看片子的flash大小

    Stm32的sram都是从0x2000000开始的,结束地址看片子的sram大小

     

    IAP程序基本默认就行,跟普通程序一样

    在APP程序中需要设置一下偏移量

     

    默认的条件下,图中IROM1的起始地址(Start)一般为0X08000000,大小(Size)为0X100000,即从0X08000000开始的1M空间为我们的程序存储(因为我们的STM32F4的FLASH大小是1M)。而图中,我们设置起始地址(Start)为0X08010000,即偏移量为0X10000(64K字节),因而,留给APP用的FLASH空间(Size)只有0X100000-0X10000=0XF0000(960K字节)大小了。设置好Start和Szie,就完成APP程序的起始地址设置。

    这里的64K字节,需要大家根据Bootloader程序大小进行选择,比如我们本章的Bootloader程序为22K左右,理论上我们只需要确保APP起始地址在Bootloader之后,并且偏移量为0X200的倍数即可(相关知识,请参考:http://www.openedv.com/posts/list/392.htm)。这里我们选择64K(0X10000)字节,留了一些余量,方便Bootloader以后的升级修改。

    注意:设置的起始地址要与程序中设置的中断向量表的偏移量对应起来(如果给IAP程序64k的空间则APPkeil中起始地址为0x8010000相应的程序中中断向量偏移0x10000)我用的1M flash大小的片子。。具体的大小设置,看自己的片子。。

    ,不过也需要注意,保证偏移量为 0X200 的倍数(我们这里为 0X1000)。
     
    展开全文
  • 中断向量表的重映设

    2018-01-17 16:25:00
     上电时,程序首先在BootLoader中运行,此时的中断向量表在flash的起始地址,即:0x0800 0000,当程序需要从BootLoader跳转的App中执行的时候,需要把中断向量表重映设到APP的起始部分,例如:0x0800 1000....
  • 程序是怎么运行的简单说一下,复位之后,总是从地址0x04拿到复位代码的起始地址,以及从地址0x0取堆栈指针,开始执行复位程序。这个0x04地址里面存的东西就是很关键的东西,大白话讲,它就是程序的开头索引。目前STM...
  • ARM Cortex-M架构的芯片的中断向...ARM Cortex-M手册规定在片上闪存起始地址处需要有一个有效的中断向量表。芯片上电或复位后首先从中向量表中读出入口函数地址和栈指针。将入口函数地址和栈指针装载入寻址寄存器...
  • 因为之前写个stm32的IAP升级程序,所以我总结了做IAP升级的三个主要的难点...2、如何配置程序的起始地址 3、如何从IAP跳转到APP程序 4、使用库函数要注意的地方(防止被坑) 说文章的时候我已经完成了一个最简单的I...
  • STM32F07CBT6中断向量表的重映射 最近有用到STM32fF07CBT6的芯片,发现这个芯片中断向量表的重新映射跟其他的芯片不同。 比如说需要偏移到0x8005000这个地址 然而这个芯片需要用到上面的方法0x20000000 是SRAM起始...
  • STM32F0xx IAP实现之中断向量表重定义

    万次阅读 2014-11-29 21:38:55
    在STM32F103等cortex-m3/m4内核的单片机上可以通过设置SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;该寄存器的值来实现中断向量表的重定义。但在STM32F0xx系列以cortex-m0为内核的...1、将中断向量表放入到RAM的起始地址
  • 对于支持重映射中断向量表的硬件,检查存储中断向量表起始地址的寄存器的值是否正确 当你在程序中对向量表重新进行了映射时,检查起始地址的合法性与复制区域大小,可以读取复制完成后的新中断向量表的首尾中,...

空空如也

空空如也

1 2 3 4 5 ... 10
收藏数 185
精华内容 74
关键字:

中断向量表起始地址