S5P4418裸机开发(十二):IRQ (按键中断) & 串口中断

S5P4418 64个中断源,按键的GPIO口是GPIOB28-30,中断号为54;

Interrupt Controller相关寄存器

在这里插入图片描述

寄存器 功能
VICIRQSTATUS R,相关位为1表示该IRQ中断发生且未被屏蔽
VICFIQSTATUS R,相关位为1表示该FIQ中断发生且未被屏蔽
VICRAWINTR R,表示屏蔽之前的中断状态
VICINTSELECT 选择中断请求类型
VICINTENABLE 写1中断使能
VICINTENCLEAR 写1中断失能
VICSOFTINT 软中断失能,我理解为可以模拟按键
VICSOFTINTCLEAR 软中断失能
VICPROTECTION 使能或失能Protection mode
VICSWPRIORITYMASK 某些优先级的中断是否屏蔽
VICVECTPRIORITYDAISY 设置中断优先级
VICVECTADDR0-31 表示各个中断源的ISR(Interrupt service routine)
VICVECTPRIORITY0 各个中断源的优先级
VICADDRESS 中断发生时,对应的ISR函数地址会复制到这个寄存器中
VICPERIPHID0-4 返回固定的值
VICPCELLID1-4 返回固定的值

GPIO Controller中相关寄存器

寄存器 功能
GPIOxOUTENB 写0设置输入模式
GPIOxDETMODE0-1 设置事件检测方式,也可以说中断触发方式
GPIOxDETMODEEX 事件检测方式的扩展位
GPIOxINTENB 中断使能
GPIOxDET 检测模式下1表示事件发生,Set “1” to clear the relevant bit. GPIOx[31:0] is used as a Pending register when an interrupt occurs.
GPIOxDETENB detected mode使能与使能

中断配置与处理流程

  • CPSRI位清0,允许IRQ中断
  • 设置检测方式,使能IO口检测,GPIOxDETMODE,GPIOxDETENB
  • 使能IO口中断,GPIOxINTENB
  • 选择IO口中断类型,VICINTSELECT
  • 设置中断处理函数地址,VICVECTADDR
  • 使能中断,VICINTENABLE

当中断发生后,跳到异常向量表,CPSRI位会被置1,硬件将优先级最高的中断ISR地址放到了VICADDRESS中。

IRQ模式只能被FIQ模式打断,FIQ模式下谁也打不断。所以这款芯片没有中断嵌套的情况。

  • 设置返回地址,保存现场
  • 进入IRQ后取VICADDRESS的值,进入中断处理函数
  • 通过GPIOxDET判断是哪个引脚发生了中断
  • 退出中断函数时,将GPIOxDET的值写回GPIOxDET以清除相应位,否则会重复进去ISR
  • 最后向VICADDRESS中写任意值,清除当前中断

使能GPIO外部中断

// 首先要修改CPSR寄存器,允许IRQ中断
void exti_init(){		// 配置中断
    // K1 GPIOB28; K2 GPIOB29; K3 GPIOB30; 按下为低电平

    GPIOBALTFN1 &= ~((3 << 24) | (3 << 26) | (3 << 28));    // 交替函数功能选择
    GPIOBALTFN1 |= ((1 << 24) | (1 << 26) | (1 << 28));

    GPIOBOUTENB &= ~((1 << 24) | (1 << 26) | (1 << 28));    // 输入模式
    
    GPIOBDETMODEEX &= ~((1 << 30) | (1 << 29) | (1 << 28));
    GPIOBDETMODE1 &= ~((3 << 28) | (3 << 26) | (3 << 24));
    GPIOBDETMODE1 |= ((2 << 28) | (2 << 26) | (2 << 24));   // 下降沿触发
    GPIOBDETENB |= ((1 << 30) | (1 << 29) | (1 << 28));     // 事件检测使能   

    GPIOBINTENB |= ((1 << 30) | (1 << 29) | (1 << 28));     // 中断使能

    VICINTENCLEAR_CH1 = 0xFFFFFFFF;
    VICINTSELECT_CH1 &= ~(1 << 22);     // IRQ
    VICVECTADDR_GPIOB = (u32)exti54_ISR;
    VICINTENABLE_CH1 = (1 << 22);
    // VICSOFTINT_CH1 = (1 << 22);      // 生成软中断,相当于模拟按键
}

void exti54_ISR(){		// ISR
    print_cpsr();

    if(GPIOBDET & (1 << 28)){		// 按下k1点亮led1
        led1_on();
    }
    if(GPIOBDET & (1 << 29)){		// 按下k2点亮led2
        led2_on();
    }
    if(GPIOBDET & (1 << 30)){		// 按下k3熄灭led
        led1_off();
        led2_off();
    }

    GPIOBDET = GPIOBDET;    	// 相当于清除挂起寄存器
    VICADDRESS_CH1 = 0x0;		// 必须清除
}
// .starts 启动文件中保护和恢复现场的操作
_irq:
    sub	lr, lr, #4
    stmdb sp!, {r0-r12, lr}
    sub r0, lr, #4		// 传参
    bl except_irq
    ldmia sp!, {r0-r12, pc}^
void except_irq(u32 addr){
    printf("[%x] Triggered IRQ exceptions\r\n", addr);
    ((void (*)(void))VICADDRESS_CH1)();     // 具体的中断函数
}

编译烧写上电,死活进不了IRQ,纠结了几天,了解到还有一个叫GIC的东西。
在这里插入图片描述

帖子面向Cortex-A9的ucos移植 中有这样一句话

因此,ICCICR寄存器的地址为0XF0000000+0X100,往这个地址写0则绕过GIC,这样,多核处理器的中断就跟我们以前用的单核没有区别了。

不纠结那么多,先出效果再说;

#define GICC_CTLR			    __REG(0xF0000100 + 0x00)

void other_init(){
    // cpsie i
    __asm__(
        "MRS r0, cpsr\n"
        "BIC r0, r0, #(1 << 7)\n"
        "MSR cpsr, r0\n"
    );  // 开启IRQ
    
    GICC_CTLR = 0;      // 绕过GIC
}

编译烧写上电,OK。成功进入IRQ模式;
下一贴纠结GIC;

顺便把串口也改成中断模式

在这里插入图片描述

    // 配置中断
    UARTIMSC |= (1 << 4);

    VICINTENCLEAR_CH0 = (1 << 7);
    VICINTSELECT_CH0 &= ~(1 << 7);     // IRQ
    VICVECTADDR_UART0 = (u32)uart0_ISR;
    VICINTENABLE_CH0 = (1 << 7);

工程文件

8_extint_key

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章