按键中断实验:
实验内容:
通过简单事例说明s5p6818处理器的GIC中断处理的应用,设置key2按键连接的引脚为中断模式,当识别按键被按下时进入相应的中断处理函数
实验目的:
熟悉开发环境的使用
掌握s5p6818处理器的中断过程及编程。
实验平台:
FS_6818开发平台,Ubuntu,secureCRT。
实验6-按键中断实验
- 分析电路图
- 分析芯片手册
分析芯片手册的GPIO章节。
GPIOxOUTENB:GPIOx引脚输出使能寄存器
GPIOxDETMODE0/1:GPIOx引脚事件检查模式寄存器
中断的触发方式:低电平,高电平,下降沿,上升沿
GPIOxINTENB:GPIOx引脚中断使能寄存器
GPIOxDET:GPIOx引脚事件检测寄存器
GPIOxALTFN0/1:GPIOx引脚复用功能选择寄存器
GPIOxDETMODEEX:GPIOx引脚事件检查外部寄存器
GPIOxDETENB:GPIOx引脚检测使能寄存器
- GPIOB8引脚设置为GPIO功能 GPIOBALTFN0
- 设置GPIOB8引脚位输入功能 GPIOBOUTENB
3》 设置GPIOB8引脚的中断的触发方式(下降沿触发)
GPIOxDETMODE0/1
GPIOxDETMODEEX
4》设置中断使能寄存器 GPIOxINTENB
5》事件检测寄存器:GPIOxDET
作用:中断挂起的标志位,当读GPIOx引脚对应的位为1,表示中断发生。
在相应的位写1,可以清除中断挂起标志位,可以接收下一次中断。
6》使能GPIOx引脚检测使能寄存器 GPIOxDETENB
GIC章节分析:
1》GICD_CTRL:GICD全局使能寄存器
2》GICD_ISENABLER:中断设置使能寄存器
GIC支持16个SGI,16个PPI,128个SPI,总计160个中断信号。
而GICD_ISENABLERn寄存器中每一位管理着一个中断号,
一个寄存器最多管理32个中断号,所以需要5个这样的寄存器,
管理160个中断号。
我们需要找到86中断号对应着5个ISENABLERn寄存器中的
哪个寄存器,以及这个寄存器的哪1位。
GICD_ISENABLER2[22] = 0b1
86 / 32 = 2…22
3》GICD_IPRIORITYRn (n = 0 to 39) 中断信号优先级设置寄存器
而GICD_IPRIORITYRn寄存器中每8位管理着一个中断号,
一个寄存器最多管理4个中断号,所以需要40个这样的寄存器,
管理160个中断号。
我们需要找到86中断号对应着40个GICD_IPRIORITYRn寄存器中的哪个寄存器,
以及这个寄存器的哪8位。
GICD_IPRIORITYR21[23:16] = 86;
- 4 = 21…2
4》GICD_ITARGETSRn中断目标分配寄存器
而GICD_ITARGETSRn寄存器中每8位管理着一个中断号,
一个寄存器最多管理4个中断号,所以需要40个这样的寄存器,
管理160个中断号。
我们需要找到86中断号对应着40个GICD_ITARGETSRn寄存器中的哪个寄存器,
以及这个寄存器的哪8位。
GICD_ITARGETSRn21[23:16] = 0x1;
86 / 4 = 21…2
5》GICD_ICPENDERn:中断挂起标志位清除寄存器
而GICD_ICPENDERn寄存器中每一位管理着一个中断号,
一个寄存器最多管理32个中断号,所以需要5个这样的寄存器,
管理160个中断号。
我们需要找到86中断号对应着5个GICD_ICPENDERn寄存器中的
哪个寄存器,以及这个寄存器的哪1位。
GICD_ICPENDER2[22] = 0b1
6》GICC_CTRL:GICC中断使能寄存器
7》GICC_PMR:中断优先级屏蔽寄存器
8》GICC_IAR:中断应答寄存器
9》GICC_EOIR:中断结束寄存器
- 编写代码
main.c
#include "led.h"
#include "pwm.h"
#include "delay.h"
#include "uart0.h"
#include "wdt.h"
#include "adc.h"
#include "key.h"
int main()
{
hal_led_init();
hal_uart_init();
hal_gpio_init();
hal_gic_init();
Tri_String("KEY Interrupt Test\n");
while(1)
{
// 按键中断到来,
// 打断当前正在处理的程序
// 进入中断处理程序
// 需要了解:异常的处理过程。
}
return 0;
}
key.c
#include "key.h"
void hal_gpio_init(void)
{
// 1. 设置GPIOB8引脚为GPIO功能 GPIOBALTFN0
GPIOB.ALTFN0 &= (~(0x3 << 16));
// 2. 设置GPIOB8引脚为输入功能 GPIOBOUTENB
GPIOB.OUTENB &= (~(0x1 << 8));
// 3. 设置GPIOB8引脚的中断触发方式:下降沿触发
// GPIOBDETMODE0 GPIOBDETMODEEX
GPIOB.DETMODE0 &= (~(0x3 << 16));
GPIOB.DETMODE0 |= (0x2 << 16);
GPIOB.DETMODEEX &= (~(0x1 << 8));
// 4. 设置GPIOB8引脚中断使能寄存器 GPIOBINTENB
GPIOB.INTENB |= (0x1 << 8);
// 5. 设置GPIOB8引脚的检测使能寄存器 GPIOBDETENB
GPIOB.DETENB |= (0x1 << 8);
// 1. 设置GPIOB16引脚为GPIO功能 GPIOBALTFN1
GPIOB.ALTFN1 &= (~(0x3 << 0));
GPIOB.ALTFN1 |= (0x2 << 0);
// 2. 设置GPIOB16引脚为输入功能 GPIOBOUTENB
GPIOB.OUTENB &= (~(0x1 << 16));
// 3. 设置GPIOB16引脚的中断触发方式:下降沿触发
// GPIOBDETMODE1 GPIOBDETMODEEX
GPIOB.DETMODE1 &= (~(0x3 << 0));
GPIOB.DETMODE1 |= (0x2 << 0);
GPIOB.DETMODEEX &= (~(0x1 << 16));
// 4. 设置GPIOB16引脚中断使能寄存器 GPIOBINTENB
GPIOB.INTENB |= (0x1 << 16);
// 5. 设置GPIOB16引脚的检测使能寄存器 GPIOBDETENB
GPIOB.DETENB |= (0x1 << 16);
}
void hal_gic_init(void)
{
// GICD
// 1. 设置GICD层86号对应的中断使能寄存器 GICD_ISENABLER2[22]
GICD_ISENABLER.ISENABLER2 |= (0x1 << 22);
// 2. 设置中断优先级寄存器 GICD_IPRIORITYR21[23:16]
GICD_IPRIORITYR.IPRIORITYR21 &= (~(0xFF << 16));
GICD_IPRIORITYR.IPRIORITYR21 |= (86 << 16);
// 3. 设置中断目标分配寄存器 GICD_ITARGETSR21[23:16]
GICD_ITARGETSR.ITARGETSR21 &= (~(0xFF << 16));
GICD_ITARGETSR.ITARGETSR21 |= (0x1 << 16);
// 4. 设置GICD层全局中断使能寄存器 GICD_CTRL[0]
GICD_CTRL |= (0x1);
// GICC
// 5. 设置GICC层中断全局使能寄存器 GICC_CTRL[0]
GICC_CTRL |= (0x1);
// 6. 设置GICC层中断屏蔽寄存器 GICC_PMR[7:0]
GICC_PMR |= (0xFF);
}
do_irq.c
// irq类型中断处理程序的入口
#include "s5p6818.h"
#include "delay.h"
void do_irq(void)
{
int irq_num;
// 获取中断号 GICC_IAR[9:0]
irq_num = GICC_IAR & 0x3FF;
switch(irq_num) {
case 86:
//86号中断处理程序
printf("KEY Interrupt Number = %d\n",irq_num);
if (GPIOB.DET & (0x1 << 8)) {
// 按键按下
while(!(GPIOB.PAD & (1 << 8))) {
delay_ms(10); // 去抖动
// 松手检测
while(!(GPIOB.PAD & (1 << 8)));
printf("KEY VOL+\n");
}
// 清除GPIO层中断挂起标志位 GPIOBDET
GPIOB.DET |= (0x1 << 8);
} else if (GPIOB.DET & (0x1 << 16)) {
while(!(GPIOB.PAD & (1 << 16))) {
delay_ms(10);
while(!(GPIOB.PAD & (1 << 16)));
printf("KEY VOL-\n");
}
// 清除GPIO层中断挂起标志位 GPIOBDET
GPIOB.DET |= (0x1 << 16);
}
// 清除GICD层中断挂起标志位 GICD_ICPENDER2[22]
GICD_ICPENDER.ICPENDER2 |= (0x1 << 22);
break;
case 87:
//87号中断处理程序
break;
// ....
}
// 清除GICC层中断号 GICC_EOIR[9:0]
GICC_EOIR = (GICC_EOIR & (~0x3FF)) | irq_num;
}
key.h
#ifndef __KEY_H__
#define __KEY_H__
#include "s5p6818.h"
void hal_gpio_init(void);
void hal_gic_init(void);
#endif //__KEY_H__
- 下载调试