完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一、什么是中断
中断:也称为异步中断。因此它是由其他硬件设备依照 CPU 时钟信号随机产生,即意味着中断能在指令之间发生。 中断又分为外部可屏蔽中断(INTR)和外部非屏蔽中断(NMI),所用I0设备产生的中断请求均引起可屏蔽中断。通过按键可以实现按键中断。 二、如何设置按键中断 1、电路分析 由原理图可知按键S2-EINT0-GPF0 按键S3-EINT2-GPF2按键S4-EINT11-GPG3 按键S5-EINT19-GPG11 2、中断函数编写思路 1、进行初始化设置: { ①设置中断,使器件能发出中断信号 ②设置中断控制器,使他能发出中断信号给CPU ③设置CPU,开中断(CPSR中的I位为中断总开关) } 2、处理时,需分辨中断源 3、处理完需清除中断 以上设置都需要通过设置相关寄存器来设置 三、如何配置寄存器 通过查询手册可知,需要配置下列寄存器 1、设置中断,使器件能发出中断信号 1.1 初始化GPXCON,使按键为中断触发引脚 GPFCON &=~((3<<0)|(3<<4));GPFCON |= ((2<<0)|(2<<4)); //设置S2、S3 GPGCON &=~((3<<6)|(3<<22));GPGCON |= ((2<<22)|(2<<6)); //设置S4、S5 1.2 配置EXTINTn寄存器,外部中断为双边沿触发 EXTINT0 |= ((7<<0)|(7<<8)); //设置 EINT0、EINT2 EXTINT1 |= (7<<12); //设置EINT11 EXTINT2 |= (7<<12); //设置EINT19 3.3 配置EINTMASK寄存器,允许EINT0,EINT2,EINT11,ENIT19向中断控制器发生中断 !其中EINT0-EINT3的中断信号不需要配置,可以直接到达中断控制器! EINTMASK &=~ ((1<<11)|(1<<19)); //使能EINT11,19 2、设置中断控制器,使他能发出中断信号给CPU 分析:中断请求由硬件产生,根据中断源类型分别将中断信号送到SUBSRCPND(SubSourcePending)和SRCPND(SourcePending)寄存器, SUBSRCPND是子中断源暂存寄存器,用来保存子中断源信号,SRCPND是中断源暂存寄存器,用来保存中断源信号。中断信号可通过编程方式屏蔽掉,SUBMASK是子中断源屏蔽寄存器,可以屏蔽指定的子中断信号, MASK功能同SUBMASK用来屏蔽中断源信号。中断分为两种模式:一般中断的和快速中断,MODE是中断模式判断寄存器,用来判断当前中断是否为快速中断,如果为快速中断直接将快速中断信号送给ARM内核,如果不是快速中断,还要将中断信号进行仲裁选择。S3C2440A支持多达60种中断,很有可能多个硬件同时产生中断请求,这时要求中断控制器做出裁决,Priority是中断源优先级仲裁选择器,当多个中断产生时,选择出优先级最高的中断源进行处理,INTPND是中断源结果寄存器,里面存放优先级仲裁出的唯一中断源。 (摘自:https://www.cnblogs.com/mr-raptor/archive/2011/06/20/2347673.html) 在INTERRUPT SUB SOURCES列表里面没有找到EINT0、EINT2、EINT11和EINT19,所以这四者是without sub -register从路线图上看,需要配置SRCPND、INTPND以及使用到相关寄存器。 2.1 SRCPND寄存器 作用:显示哪个中断产生了, 需要清除对应位 清除方式:可以通过将数据写入该寄存器来清除SRCPND寄存器的特定位。它只清除位位置对应于数据中设置为1的SRCPND。 EINT0-BIT[0]EINT2-BIT[2]EINR8_23-BIT[5] 2.2 INTMOD寄存器 作用:设置中断模式为FIQ还是IRQ 默认值为0x00000000,不需要重新设置 2.3 INTMSK寄存器 作用:对应位设置为0,CPU为来自相应中断源的中断请求提供服务 EINT0-BIT[0]EINT2-BIT[2]EINR8_23-BIT[5]INTMSK &=~ ((1<<0)|(1<<2)|(1<<5)); 2.4 INTPND寄存器 作用:显示当前优先级最高的、正在发生的中断, 需要清除对应位 清除方式:可以通过将数据写入该寄存器来清除INTPND寄存器的特定位。它只清除位位置对应于数据中设置为1的INTPND。 EINT0-BIT[0]EINT2-BIT[2]EINT8_23-BIT[5] 2.5 INTOFFSET寄存器 作用:显示IRQ模式的哪个中断请求在INTPND寄存器中,这个位可以通过清除SRCPND和INTPND来自动清除。 EINT0-BIT[0]EINT2-BIT[2]EINT8_23-BIT[5] 提问:如何知道EINT8_23中具体哪一个中断产生? 回答:通过读EINTPEND寄存器的值可以知道。 2.6 EINTPEND寄存器 对应位为1,则发生了中断,为0,则无发生。 3、设置CPU,开中断(CPSR中的I位为中断总开关) 配置CPRS寄存器,使其I位置0bic r0, r0, #(1<<7) /* 清除I位, 使能中断 */msr cpsr, r0 /* 写入值,改变cpsr的值*/ 四、如何在代码中实现 1、新建interrupt.c文件,作为外部中断函数, 功能实现:通过4个按键触发外部中断,控制LED灯的亮灭,编写代码: #include "s3c2440_soc.h" /* EINTPEND,可通过读此寄存器知道EINT4-EINT23哪个发生中断,请中断时可往里面写1 */ /* SRCPND 用来显示哪个中断产生了, 需要清除对应位 * EINT0-BIT[0] * EINT2-BIT[2] * EINR8_23-BIT[5] */ /* INTMOD 用来设置发生中断模式(IRQ和FIQ) * 0-IRQ,1-FIQ,默认为0 */ /* INTMSK 用来屏蔽中断, 1-masked * EINT0-BIT[0] * EINT2-BIT[2] * EINR8_23-BIT[5] */ /* 初始化中断控制器 */ void interrupt_init(void) { INTMSK &=~ ((1<<0)|(1<<2)|(1<<5)); } /* INTPND 用来显示当前优先级最高的、正在发生的中断, 需要清除对应位 * EINT0-BIT[0] * EINT2-BIT[2] * EINR8_23-BIT[5] */ /* INTOFFSET 用来显示INTPND中哪一位被设置为1 * 这个位可以通过清除SRCPND和INTPND来自动清除。 */ /* *初始化按键并将其设置为中断源 *S2:EINT0:GPF0 S3:EINT2:GPF2 S4:EINT11:GPG3 S5:EINT19:GPG11 *设置中断方式:双边触发 */ void key_eint_int(void) { /* *配置按键 *设置寄存器,先请零、后设置 */ GPFCON &=~((3<<0)|(3<<4)); GPFCON |= ((2<<0)|(2<<4)); //设置S2、S3 GPGCON &=~((3<<6)|(3<<22)); GPGCON |= ((2<<22)|(2<<6)); //设置S4、S5 EXTINT0 |= ((7<<0)|(7<<8)); //设置 EINT0、EINT2 EXTINT1 |= (7<<12); //设置EINT11 EXTINT2 |= (7<<12); //设置EINT19 EINTMASK &=~ ((1<<11)|(1<<19)); //使能EINT11,19 /* *设置LED灯 *配置GPF4,5,6为输出口 *先对寄存器CPFCON清0 *后再配置寄存器,是GPF4,5,6为输出口 */ GPFCON &=~ ((3<<8)|(3<<10)|(3<<12)); GPFCON |= ((1<<8)|(1<<10)|(1<<12)); } /* 中断处理函数 * 先分辨中断源,对不同的中断源进行处理 * 后清中断 */ void key_irq_handle(int flag) { unsigned int val = EINTPEND; unsigned int valf = GPFDAT; unsigned int valg = GPGDAT; if (flag == 0) { if (valf & (1<<0)) /* s2 --> gpf6 */ { /* 松开 */ GPFDAT |= (1<<6); } else { /* 按下 */ GPFDAT &= ~(1<<6); } } else if (flag == 2) { if (valf & (1<<2)) /* s3 --> gpf5 */ { /* 松开 */ GPFDAT |= (1<<5); } else { /* 按下 */ GPFDAT &= ~(1<<5); } } else if (flag == 5) { if (val & (1<<11)) /* eint11 */ { if (valg & (1<<3)) /* s4 --> gpf4 */ { /* 松开 */ GPFDAT |= (1<<4); } else { /* 按下 */ GPFDAT &= ~(1<<4); } } else if (val & (1<<19)) /* eint19 */ { if (valg & (1<<11)) { /* 松开 */ /* 熄灭所有LED */ GPFDAT |= ((1<<4) | (1<<5) | (1<<6)); } else { /* 按下: 点亮所有LED */ GPFDAT &= ~((1<<4) | (1<<5) | (1<<6)); } } } EINTPEND = val; } void handle_irq_c(void) { int bit = INTOFFSET; if (bit==0||bit==2||bit==5) { key_irq_handle(bit); } SRCPND = (1< 2.start.S汇编文件代码如下: .text .global _start _start: b reset /* vector 0:reset */ ldr pc, und_addr /* vector 4:und_addr */ ldr pc, swi_addr /* vector 8:swi_addr */ b halt/* vector C:Abort (prefetch) */ b halt/* vector 10:Abort (data) */ b halt/* vector 14:Reserved */ ldr pc, irq_addr/* vector 18:IRQ */ b halt/* vector 1C:FIQ */ und_addr: .word do_und swi_addr: .word do_swi irq_addr: .word do_irq do_und: /* 执行到这里之前: * 1. lr_und保存有被中断模式中的下一条即将执行的指令的地址 * 2. SPSR_und保存有被中断模式的CPSR * 3. CPSR中的M4-M0被设置为11011, 进入到und模式 * 4. 跳到0x4的地方执行程序 */ /* * 1.保存现场 * 2.处理异常 * 3.恢复现场 */ ldr sp, =0x34000000 //und模式下的sp寄存器为该模式下专用寄存器,使用前需要对其进行设置 /* 在进入und模式的时候,查表可知r0-r12寄存器的值可能会被修改,所以需要对其进行保存 */ stmdb sp!, {r0-r12,lr} /* 处理异常函数:把cpsr内的信息放到r0,执行printException */ mrs r0, cpsr ldr r1, =und_string bl printException /* 恢复现场,把spsr寄存器的值传输回cpsr*/ ldmia sp!, {r0-r12,pc}^ und_string: .string "undefined instruction exception" .align 4 do_swi: /* 执行到这里之前: * 1. lr_svc保存有被中断模式中的下一条即将执行的指令的地址 * 2. SPSR_svc保存有被中断模式的CPSR * 3. CPSR中的M4-M0被设置为10011, 进入到svc模式 * 4. 跳到0x8的地方执行程序 */ /* * 1.保存现场 * 2.处理异常 * 3.恢复现场 */ ldr sp, =0x33e00000 //und模式下的sp寄存器为该模式下专用寄存器,使用前需要对其进行设置 /* 在进入und模式的时候,查表可知r0-r12寄存器的值可能会被修改,所以需要对其进行保存 */ stmdb sp!, {r0-r12,lr} mov r4,lr //把lr寄存器下一条即将执行的指令的地址传到r0 /* 处理异常函数:把cpsr内的信息放到r0,执行printException */ mrs r0, cpsr ldr r1, =swi_string bl printException sub r0,r4,#4 //r4地址减四就是swi指令执行地址 bl printSWIVal /* 恢复现场,把spsr寄存器的值传输回cpsr*/ ldmia sp!, {r0-r12,pc}^ swi_string: .string "swi exception" .align 4 do_irq: /* 执行到这里之前: * 1. lr_irq保存有被中断模式中的下一条即将执行的指令的地址 * 2. SPSR_irq保存有被中断模式的CPSR * 3. CPSR中的M4-M0被设置为10010, 进入到und模式 * 4. 跳到0x18的地方执行程序 */ /* * 1.保存现场 * 2.处理异常 * 3.恢复现场 */ ldr sp, =0x33d00000 //und模式下的sp寄存器为该模式下专用寄存器,使用前需要对其进行设置 /* 在进入und模式的时候,查表可知r0-r12寄存器的值可能会被修改,所以需要对其进行保存 */ sub lr,lr,#4 stmdb sp!, {r0-r12,lr} /* 处理中断函数 */ bl handle_irq_c /* 恢复现场,把spsr寄存器的值传输回cpsr*/ ldmia sp!, {r0-r12,pc}^ reset: /* 关闭看门狗 */ ldr r0, =0x53000000 ldr r1, =0 str r1, [r0] /* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */ /* LOCKTIME(0x4C000000) = 0xFFFFFFFF */ ldr r0, =0x4C000000 ldr r1, =0xFFFFFFFF str r1, [r0] /* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8 */ ldr r0, =0x4C000014 ldr r1, =0x5 str r1, [r0] /* 设置CPU工作于异步模式 */ mrc p15,0,r0,c1,c0,0 orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA mcr p15,0,r0,c1,c0,0 /* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) * m = MDIV+8 = 92+8=100 * p = PDIV+2 = 1+2 = 3 * s = SDIV = 1 * FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M */ ldr r0, =0x4C000004 ldr r1, =(92<<12)|(1<<4)|(1<<0) str r1, [r0] /* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定 * 然后CPU工作于新的频率FCLK */ /* 设置内存: sp 栈 */ /* 分辨是nor/nand启动 * 写0到0地址, 再读出来 * 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动 * 否则就是nor启动 */ mov r1, #0 ldr r0, [r1] /* 读出原来的值备份 */ str r1, [r1] /* 0->[0] */ ldr r2, [r1] /* r2=[0] */ cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */ ldr sp, =0x40000000+4096 /* 先假设是nor启动 */ moveq sp, #4096 /* nand启动 */ streq r0, [r1] /* 恢复原来的值 */ bl sdram_init bl copy_to_sdram bl clean_bss /* *复位之后, cpu处于svc模式 *系统先进入用户模式,修改cpsr寄存器的值 *后在swi指令触发异常 */ mrs r0,cpsr /* 读出cpsr的值 */ bic r0, r0, #0xf /* 修改M4-M0为0b10000, 进入usr模式 */ bic r0, r0, #(1<<7) /* 清除I位, 使能中断 */ msr cpsr, r0 /* 写入值,改变cpsr的值*/ /* 设置usr模式下的sp寄存器 */ ldr sp, =0x33f00000 ldr pc, =sdram sdram: bl uart0_init bl print1 /*故意定义一条未定义指令,使cpu进入und模式 */ und_code: .word 0xdeadc0de //word定义的是一变量,会开辟占用内存 bl print2 swi 0x123 /* swi指令,用来触发异常 */ //bl main /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */ ldr pc, =main /* 绝对跳转, 跳到SDRAM */ halt: b halt |
|
|
|
只有小组成员才能发言,加入小组>>
3323 浏览 9 评论
3000 浏览 16 评论
3497 浏览 1 评论
9072 浏览 16 评论
4093 浏览 18 评论
1192浏览 3评论
613浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
603浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2341浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1899浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-29 09:03 , Processed in 1.058443 second(s), Total 78, Slave 59 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号