iTop-4412 裸机程序(二十)- 按键中断Demo

目录

  • 0.源码
  • 1. 中断初始化
  • 2. 中断回调
  • 3 start.S


上篇博文介绍了按键的轮询处理方式,本篇介绍按键的中断方式。

0.源码

GitHub:https://github.com/Kilento/4412NoOS

1. 中断初始化

void interrupt_init(void)
{
    /* 中断处理:
     * <1> IRQ模式: 中断irq引脚, 中断GIC
     * <2> GIC中断:中断号ID
     *      Key2: GPX1_1/XEINT9
     *      (1) Page 752: EINT9  ---> 中断ID: 57
     *      (2) GPX1_1 配置成中断功能: 0xF
     *      (3) GPX1_1 禁止上拉和下拉 PUD[3:2]
     *      (4) EXT_INT41CON[1] : 0x2 ---> 下降沿触发中断falling edge
     *      (5) EXT_INT41_MASK[1]: 0x0 ---> Enables Interrupt
     * <3> GIC 配置:
     *      (1) ICCICR_CPU0[0] : 0x1048_0000 :   1 ---> enable
     *      (2) ICDDCR:   0x1049_0000 :  1 ---> enable
     *      (3) ICCPMR_CPU0[7:0]:  0x1048_004 :  255屏蔽优先级
     *           ICDIPR_CPU0  偏移57个字节(每个中断占一个字节), 默认0,最高优先级
     *      (4) ICCIAR_CPU0[9:0]: 0x1048_000C:  中断ID
     *      (5) 结束中断
     *      (6) ICDISER_CPU0[57]:   Set-Enable Interrupt 1
     *      (7)  ICDIPTR_CPU:   选择该中断递送给哪一个CPU
     *
     * <4> 中断清除
     *      (1) EXT_INT41_PEND[1]:  0
     *      (2)  (4) ICCICPR_CPU0
     *      (3)  (5) ICCEOIR_CPU0[9:0]: 0x1048_0010: 回写ID给GIC
     */

    printf("interrupt_init\n");
    /*
        GPX1_1 - HOME - EXT_INT41[1] - EINT[9] - SPI(25) - ID(57)
        GPX1_2 - BACK - EXT_INT41[2] - EINT[10] - SPI(26) - ID(58)
        GPX3_3 - SLEEP - EXT_INT43[3] - EINT[27] - SPI(32) - ID(64)
        GPX2_0 - VOL- - EXT_INT42[0] - EINT[16] - SPI(32) - ID(64)
        GPX2_1 - VOL+ - EXT_INT42[1] - EINT[17] - SPI(32) - ID(64)
    */

    ICDDCR = 1;               // 使能中断分配器
    ICDISER1_CPU0 |= 1 << 25; // 57/32 = 1...25
    // ICDISER1_CPU0 |= 1 << 26; // 58/32 = 1...26
    // ICDISER2_CPU0 |= 1 << 0;  // 64/32 = 2...0
    // 设置SPI[25]/ID[57]由哪个cpu处理,当前设置为cpu0的irq中断
    ICDIPTR14_CPU0 |= 1 << 8;
    ICCPMR_CPU0 = 0xff;
    ICCICR_CPU0 = 1;

    return;
}

2. 中断回调

void irq_exception(void)
{
    int irq_num = 0;
    int key_id = 0;

    led_ctrl(0, 0);
    led_ctrl(1, 1);

    irq_num = ICCIAR_CPU0 & 0x3ff;
    printf("%d\n", irq_num);
    switch (irq_num)
    {
	    case 57:
	    {
	        key_id = KEY_HOME;
	        EXT_INT41_PEND |= (0x1 << 1); // 清GPIO中断标志位
	        put_key_value(key_id);
	        break;
	    }
	    default:
	    {
	        printf("unknown irq number=%d", irq_num);
	        break;
	    }
    }

    ICCEOIR_CPU0 = (ICCEOIR_CPU0 & (~0x3FF)) | irq_num; // 清cpu中断标志

    return;
}

3 start.S


init_stack:     
    /*svc mode stack*/
    msr cpsr, #0xd3
    ldr sp, _stack_svc_end

    /*undef mode stack*/
    msr cpsr, #0xdb
    ldr sp, _stack_und_end

    /*abort mode stack*/    
    msr cpsr,#0xd7
    ldr sp,_stack_abt_end

    /*irq mode stack*/    
    msr cpsr,#0xd2
    ldr sp, _stack_irq_end
    
    /*fiq mode stack*/
    msr cpsr,#0xd1
    ldr sp, _stack_fiq_end
    
    /*user mode stack, enable FIQ/IRQ*/
    msr cpsr,#0x10
    ldr sp, _stack_usr_end

    /*Call main*/
	ldr pc, = main 	/* 使用长加载进行地址跳转,不能再使用 bl 进行跳转 */
b .

irq_handler:
    /* 中断程序执行时,会自动将当前pc指针地址存入 lr 寄存器中 */
	sub  lr,lr,#4  /* 由于 armv7 使用两级流水线,PC 指针地址= 当前执行指令地址 + 8,当前中断处理程序地址 = pc - 4 */
	stmfd sp!,{r0-r12,lr} /* 将所有寄存器(r0-r12, lr)的值按顺序存储到当前栈顶位置 */
	bl irq_exception  /* 跳转到中断程序  */
	ldmfd sp!,{r0-r12,pc}^ /* 中断返回程序会从栈中弹出之前存储的所有寄存器的值,并跳转回原来的程序入口地址 */

_stack_svc_end:      
    .word stack_svc + 512
_stack_und_end:      
    .word stack_und + 512
_stack_abt_end:      
    .word stack_abt + 512
_stack_irq_end:      
    .word stack_irq + 512
_stack_fiq_end:
    .word stack_fiq + 512
_stack_usr_end:      
    .word stack_usr + 512

.data
stack_svc:      
    .space 512
stack_und:
    .space 512
stack_abt:      
    .space 512
stack_irq:      
    .space 512
stack_fiq:      
    .space 512

stack_usr:      
    .space 512

2024年02月13日

Kilento

你可能感兴趣的:(Exynos4412,exynos)