ARM之按键K2触发中断,并在超级终端上打印‘S‘

下降沿触发 过滤器 抖动 中断编号越低优先级越高
需求:按键K2按下  打印一个'S'
看原理图:
1)按键按下(管脚输入电平 高 到 低)
2)UART_RING  GPX1_1(XEINT9)
XEINT9/KP_COL1/ALV_DBG5/GPX1_1(蓝)  UART_RING(红)
外部中断:XEINT9
UART_RING --》GPX1_1-->XEINT9(GPIO设置成中断管脚)
        |-----》外部中断控制器
看芯片手册:GPX1_1
1)GPIO特点之一:控制172个外部中断,所以外部中断控制器也是GPIO
【GPIO】
GPX1CON[1]        [7:4]    0xF = EXT_INT41[1]
【GPIO 外部中断控制器】
观看过滤器(4个): 
EXT_INT41CON
EXT_INT41_FLTCON0
EXT_INT41_MASK
EXT_INT41_PEND

1)EXT_INT41_CON[1]    [6:4]    0x2 = Triggers Falling edge下降沿触发
2)FLTSEL16[1]        [15]    0x0:关闭过滤器、0x1:启动过滤器
FLTSEL16[1]        [14]    0x1:延迟过滤器、0x1:数字过滤器(时钟计数)
延时过滤器:一定时间内只处理一次中断抖动,忽略其他中断(设备自己做)
数字过滤器:设置手动过滤,在 FLTWIDTH16[1] 里面设置
FLTWIDTH16[1]        [13:8]    当 FLTSEL16[1] =0x1时有效,时长=时钟*0xnn
这三者是启动过滤器,延时消除抖动,为了简单便设置默认
3)EXT_INT41_MASK[1]     [1]    0x0:启动中断、0x1:屏蔽中断
4)EXT_INT41_PEND[1]     [1]    0x0:没有发生、0x1:中断发生 
注意:这里中断处理退出后需要将其置为1(写1清理设备),防止将其频繁处理中断

没将'S'写进去,汇编中cpsr的问题
1、由于之前汇编将中断全部屏蔽,所以需要在初始化和main函数中(即切换到用户模式时)将中断启动
2、设置中断处理函数,并给中断分配栈空间
3、纠正处理中断指令返回后的地址
4、设置中断控制器    【中断设备】----【中断控制器】------【CPU】

SGI(软中断) PPI(私有中断) SPI(共享中断)
9.2.2 GIC中断(160个) SPI Port No:这类里面的中断编号  ID:全部中断的中断编号
25 57 EINT[9] 外部中断9
中断优先级0-255 最高:0 最低:255
Distributor(分发器) ->Highest poiority interrupt(根据优先级)->Interface(指定CPU核,可指定一个或者多个)
知道中断流程后,筛选的CPU的寄存器:
ICCICR_CPU0  CPU0的控制寄存器  CPU interface control register  0x10480000 
ICCPMR_CPU0  CPU0的中断优先掩码控制器 Interrupt priority mask register 0x10480004 
ICCBPR_CPU0  CPU0的二进制点寄存器 Binary point register 0x10480008
ICCIAR_CPU0  CPU0的中断接收确认寄存器 Interrupt acknowledge register 0x1048000C
ICCEOIR_CPU0 CPU0的中断完成确认寄存器 End of interrupt register 0x10480010
ICCABPR_CPU0 CP0的别名二进制寄存器 Aliased binary point register 0x1048001C
知道中断流程后,筛选的分发器的寄存器:
ICDDCR      分发器控制寄存器  Distributor control register 0x10490000
ICDICTR      分发器类型控制器  Interrupt controller type register 0x10490004
ICDIIDR      分发器观测寄存器  Distributor implementer identification register 08
ICDISER0_CPU0 中断使能寄存器 Interrupt set-enable register (SGI,PPI) 0x10490100
ICDICER0_CPU0 中断清理寄存器 Interrupt clear-enable register (SGI,PPI) 0x10490180

进一步看CPU寄存器功能筛选寄存器:
ICCICR_CPUn 0x1 使能中断
ICCIAR_CPUn 中断接收确认  ICCEOIR_CPUn  中断完成确认
ICCPMR_CPUn 0xff 掩码,当中断优先级高于该字段表示接口信号的值时,接口发出信号中断到处理器,0-255,255为最低
ICCBPR_CPU0 拆分字段,不需要,筛出 ICCABPR_CPU0同理
进一步看分发器寄存器筛选寄存器:
ICDDCR    0x1 全局启用,用于监控外围中断信号,并将挂起的中断转发到CPU接口
ICDICTR     ICDIIDR  只读的辅助寄存器,筛出
ICDISER_CPU 读取SPI、PPI的每个bit位 1=启用相应中断,启用后可使能
注意:这里设置了五个寄存器,每个中断只占寄存器中的1位,总共160位,1为启用,0为禁用,根据中断编号来确认 25 57 EINT[9],所有这里偏移地址为 0x0104 0x1<<25
【ICDICER_CPU 读取SPI、PPI的每个bit位 1=读取相应中断,启用后禁用 0x0184 0x1<<25】
ICDICPR_CPU 清除挂起位 防止被重复挂起,然后被CPU调用 1:启动 0x284 0x1<<25
ICDIPR14_CPU0 设置中断的优先级 0x0438 [15:8] 0
ICDIPTR14_CPU0    确认中断发送的目标CPU 0bxx1  CPU interface 0 0x0838 [15:8] 0x1
ICDICFR_CPU 设置触发方式,但是是只读寄存器,手册有误,筛去

 Makefile:

all:
	arm-linux-gcc start.S -o start.o -c -g
	arm-linux-gcc uart.c -o uart.o -c -g
	arm-linux-gcc main.c -o main.o -c -g
	arm-linux-ld  main.o uart.o start.o  -o start.elf -Ttest.lds
	arm-linux-objcopy start.elf start.bin -O binary
clean:
	rm *.o *.elf *.bin

start.S:

.globl _start
_start: 
	b	reset
	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

reset:
	/* 设置cpu模式为SVC模式 */
	mrs	r0, cpsr
	bic	r0, r0, #0x1f  
	orr	r0, r0, #0xd3  @11010011
	msr	cpsr,r0

	/* 设置异常向量表起始地址 */
	ldr	r0, =0x41000000
	mcr	p15, 0, r0, c12, c0, 0	@Set VBAR

    /*用户需要设置的初始化*/
    ldr sp, stacktop  /*设置svc sp*/
    sub r6, sp , #64  /*计算user需要指向的栈顶地址*/

    /*切换到irq 模式*/
	mrs	r0, cpsr
	bic	r0, r0, #0x1f  
	orr	r0, r0, #0x12 
	msr	cpsr,r0

    /*给中断分配栈空间*/
    mov sp, r6  /*设置irq sp*/
    sub r6, sp , #64

    /*切换到用户模式*/
	mrs	r0, cpsr
	bic	r0, r0, #0xff /*清零,将中断开启*/ 
	orr	r0, r0, #0x10 
	msr	cpsr,r0

    mov sp, r6  /*设置user sp*/

    /*跳转到应用程序*/
    bl	main

irq_handler:
    /*纠正处理中断指令返回后的地址*/
    sub lr,lr,#4
    stmfd sp!,{r0-r12,lr}
    bl doirq
    ldmfd sp!,{r0-r12,pc}^

stack: .space 64*8
stacktop: .word stack+64*8

test.lds:

ENTRY(_start)
SECTIONS{
	. = 0x41000000;
	.text : {
		start.o(.text)
		*(.text)
	}
	.data : {
		*(.data)
	}
	.bss : {
		*(.bss)	
	}
}

uart.h:

#ifndef __MY_UART__
#define __MY_UART__

void uart_init();
void uart_send(char c);
void uart_str(char* s);

#endif

uart.c:

#define GPA1CON   *(unsigned int volatile*)0x11400020
#define ULCON2    *(unsigned int volatile*)0x13820000
#define UCON2     *(unsigned int volatile*)0x13820004
#define UTRSTAT2     *(unsigned int volatile*)0x13820010
#define UTXH2     *(unsigned int volatile*)0x13820020
#define URXH2     *(unsigned int volatile*)0x13820024
#define UBRDIV2   *(unsigned int volatile*)0x13820028
#define UFRACVAL2 *(unsigned int volatile*)0x1382002c

void uart_init()
{
    GPA1CON = GPA1CON & ~(0xf<<4) | (0x2<<4);
    GPA1CON = GPA1CON & ~(0xf<<0) | (0x2<<0);
    ULCON2 = 0x3; 
    UCON2 = UCON2 & ~0x3f | (0x1<<2)|(0x1<<0); 
    UBRDIV2 = 53;
    UFRACVAL2 = 4;   
}
void uart_send(char c)
{
    while( !(UTRSTAT2&(0x1<<2)) );
    UTXH2 = c;    
}
void uart_str(char* s)
{
    while(*s != '\0')
    {
        uart_send(*s);
        s++;
    }
}
char uart_recv()
{
    while( !(UTRSTAT2&0x1) );
    return (URXH2 & 0xff);
}

main.c:

#include "uart.h"
//GPIO将GPX1_1管脚转换成中断管脚(GPIO控制器)
#define GPX1CON         *(unsigned int volatile*)0x11000C20
//设置中断触发方式寄存器
#define EXT_INT41CON    *(unsigned int volatile*)0x11000E04
//启动中断寄存器
#define EXT_INT41_MASK  *(unsigned int volatile*)0x11000F04
//处理中断后清理中断标签寄存器
#define EXT_INT41_PEND  *(unsigned int volatile*)0x11000F44
//使能中断寄存器 CPU核
#define ICCICR_CPUn     *(unsigned int volatile*)0x10480000 
//中断掩码寄存器,设置中断信号优先级门槛 CPU核
#define ICCPMR_CPUn     *(unsigned int volatile*)0x10480004
//中断接收确认寄存器 CPU核
#define ICCIAR_CPUn     *(unsigned int volatile*)0x1048000c
//中断完成确认寄存器 CPU核
#define ICCEOIR_CPUn    *(unsigned int volatile*)0x10480010
//分发器启用寄存器 分发器
#define ICDDCR          *(unsigned int volatile*)0x10490000
//读取相应中断寄存器,后续可进行使能操作 分发器
#define ICDISER1_CPU0   *(unsigned int volatile*)0x10490104
//设置中断优先级寄存器 分发器
#define ICDIPR14_CPU0   *(unsigned int volatile*)0x10490438
//确认中断发送目标CPU寄存器 分发器
#define ICDIPTR14_CPU0  *(unsigned int volatile*)0x10490838
//清除挂起位寄存器 分发器
#define ICDICPR1_CPU0   *(unsigned int volatile*)0x10490284

void delay()
{
    int t = 0xfffff*3;
    while(t--);
}

void doirq()
{
    //确认接收到中断
    int  irq = ICCIAR_CPUn;
    //进行中断操作,这里是按键发送S
    uart_send('S');    
    //启动中断发生标签清理
    EXT_INT41_PEND = EXT_INT41_PEND | (0x1<<1);
    //清除挂起位寄存器
    ICDICPR1_CPU0 |= 0x1<<25;
    //确认完成中断
    ICCEOIR_CPUn = irq;
}

void gic_init()
{
    //使能中断
    ICCICR_CPUn=0x1;
    //设置中断掩码,
    ICCPMR_CPUn = 0xff;
    //启动分发器,监控外部中断信号,并将挂起的中断转发到CPU接口
    ICDDCR= 0x1;
    //启动查找对应中断的寄存器
    ICDISER1_CPU0 |= 0x1<<25;
    //设置被查找到的中断的优先级为0
    ICDIPR14_CPU0 = ICDIPR14_CPU0 & ~(0xff<<8);
    //确认中断发送的目标的CPU
    ICDIPTR14_CPU0 = ICDIPTR14_CPU0  & ~(0xff<<8) | (0x1<<8);
}

void key_init()
{
    //将GPX1_1管脚转换成中断管脚
    GPX1CON = GPX1CON | (0xf<<4);    
    //设置下降沿触发方式(先清后置)
    EXT_INT41CON = EXT_INT41CON & ~(0x7<<4)|(0x2<<4);
    //启动中断
    EXT_INT41_MASK = EXT_INT41_MASK & ~(0x1<<1);
}

void  main()
{
    //分发器初始化
    gic_init();
    uart_init();
    //设置中断触发方式
    key_init();
    while(1);
}

结果:

## Starting application at 0x41000000 ...
SSSSSSSSSSSSSSSSSSSSSSSSSSS

    1、需求: 按键按下  打印一个'S'
    2、原理图:
        1)按键按下  (管脚输入电平  高  到 低 )
        2)UART_RING--》GPX1_1 --->XEINT9 (GPIO设置成中断管脚)
                          |-------》外部中断控制器
    3、芯片手册:
        【GPIO】
        GPX1CON  [7:4]  0xF = EXT_INT41[1]
        【外部中断控制器 GPIO】
        EXT_INT41_CON  [6:4]  0x2 = Triggers Falling edge
        EXT_INT41_MASK [1]    0x0 = Enables Interrupt
        EXT_INT41_PEND [1]    0x1 
    4、写代码

    【GIC】
    25 57 – EINT[9] 
    【Distributor】
     Enabling the forwarding of interrupts to the CPU interfaces globally. (全局通道 distributor --> face) ICDDCR= 0x1;
     Enabling or disabling each interrupt. (中断使能)   ICDISER1_CPU0 |= 0x1<<25;
     Setting the priority level of each interrupt. (中断优先级 :0)   ICDIPR14_CPU0 [15:8]  0 
     Setting the target processor list of each interrupt. (中断发往的cpu : cpu0 )   ICDIPTR14_CPU0  [15:8]  00000001
     Setting each peripheral interrupt to be level-sensitive or edge-triggered.设置中断触发方式
    (请pending状态)  ICDICPR_CPU0 |= 0x1<<25;
    【cpu interface】
     Enabling the signaling of interrupt requests by the CPU interface.(使能异常) ICCICR_CPUn=0x1;
     Acknowledging an interrupt.   (应答收到了中断)      ICCIAR_CPUn
     Indicating completion of the processing of an interrupt.  (应答中断处理完成)  ICCEOIR_CPUn
     Setting an interrupt priority mask for the processor. (优先级屏蔽码)    ICCPMR_CPUn = 0xff;

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值