以此作为笔记,自己巩固也供大家学习,不足之处,轻拍。
整个过程需要参考对照s5pv210说明手册、电路图底板图以及核心板电路图
百度云盘:
说明手册 s5pv210_UM_REV1.1.pdf
核心板电路图 210kfb-core-v11.pdf
底板电路图 210KFBDBV1.1.pdf
A、外部中断
一、一句话:
学习过程所使用的芯片是s5pv210,该芯片*有128个中断源,这些中断源又分别分配到4组不同的向量终端控制器 VIC0-VIC3
二、简构原理
为什么叫“简构原理”,我这里是想我们在学习之前,先从概念构思一边,如果我们设计出了一个中断机制会怎么样让别人使用起来方便一些,我也是第一次接触,所以在我学习的时候我是这样想的,这是我自己的一种思路,下面是我的思考内容
当设备在稳定运行过程中,突然产生一个中断信号告诉机器马上执行另一件事,那程序不得不放下目前正在进行的工作,去完成中断信号命令的任务。
这里我们可以知道当被命令中断当前任务,执行其它任务完成后,我们的设备并不是进入等待状态,它得回来接着把之前的任务完成。所以,在进入另一项任务之前,需要对现目前工作状态进行保存
在执行中断任务的时候,程序是不知道要执行什么任务的,所以这个任务我们得告诉他,这里就要初始化注册一个中断函数
我还要给定一个中断产生的条件,开发板上有按钮,我就假定按钮按下的时候让它中断去执行一个函数,这里就要初始化一个按键,设置外部中断为按键产生的中断
好了,我大概能想到的就是这些,接下来我边查手册,一边写一个简单的按键中断
三、初步探索
我们从简单的开始设置
1、设置一个按键产生中断,先从电路图中找到按键电路,在
(210KFBDBV1.1.pdf手册第4页)
(可以看到电路图上有8个按键,从K2-K9,但是开发板上实际有9个按键,其中有一个为复位按键,所以这里不用理会K1)
图示看到按键K2接通的引脚标注为KP_COL0
2、打开核心板电路图查询引脚标注对应的引脚号
搜索”KP_COL”
(210kfb-core-v11.pdf 第2页)搜索到结果可以看到引脚为GPH2_*
其中GPH2_*这一组有8个引脚,对应编号从0-7,实际上的按键只有GPH2_0-GPH2_3四个引脚,如图黑色方框内的内容
其它四个按键属于GPH3_*的前四个引脚控制找到引脚号,现在就开始查询怎么设置和控制这些引脚。
3、打开芯片手册–S5PV210_UM_REV1.1.pdf
搜索 “GPH2”
(S5PV210_UM_REV1.1.pdf 第328页)
看它的说明告诉我们的信息:GPH2通过4个寄存器控制,这四个寄存器分别是GPH2CON、GPH2DAT、GPH2PUD、GPH2DRV
其中GPH2PUD、GPH2DRV我们可以不用先不用管,GPH2DAT我们也用不到,不过我这里也说一下,我们大致浏览一下表格的内容,看看可以获得哪些信息,浏览一遍328页-329也的内容我们至少可以知道这些内容:
1、GPH2CON寄存器有32个bit位,其中每4个bit位控制一个引脚GPH2_*(0-7)
2、GPH2CON的每4个bit位控制的内容包括input、output、KP_COL、EXT_INT
3、GPH2DAT有8个bit位当GPH2CON寄存器配置类型为input时,通过此寄存器输出,每一个bit位控制一个GPH2_*(0-7)可以看到当GPH2CON[0]的4个bit位配置为1111时,表示外部中断16号寄存器(EXT_INT->>external interrupt)
接下来继续搜索EXT_INT_[16],我们把有关的寄存器全部都看一遍
四、外部中断寄存器
1、有关控制外部中断EXT_INT[16]的寄存器信息
1) EXT_INT_2_CON —外部中断寄存器16-23的配置寄存器(336页)
EXT_INT_2_CON寄存器有32个bit位,每4个bit位的低三位设置外部中断的触发方式,共8个外部中断EXT_INT[16-23],
其中的控制内容包括触发方式:
a、电平触发(高电平001,低电平000)
b、边沿触发(上升沿011、下降沿010)
c、两种方式都允许触发1002) EXT_INT_2_FLTCON* —外部中断寄存器16-23的滤波器配置寄存器(345页)
略
3) EXT_INT_2_MASK —外部中断屏蔽寄存器(349页)
只使用8个bit位,其它bit位都预留,分别设置EXT_INT[16]-[23]
0表示使能中断,1表示屏蔽中断4) EXT_INT_2_PEND —外部中断挂起寄存器(351页)
只使用8个bit位,其它bit位都预留,分别设置EXT_INT[16]-[23]
0表示没有发生中断,1表示产生了中断。
这个寄存器可以看作一个状态寄存器,在程序运行过程中,通过读取这里的值可以判断中断是否发生,这里需要手动清零,并且,这里是置1清零
上述的滤波器我们不使用,只需要使用其它三项就可以。
2、向量中断控制器 559-563页
这部分内容里我们获取到的信息如下:
1) 这个芯片里有4个向量中断控制器(VECTORED INTERRUPT CONTROLLER),VIC0-VIC3
2) 每个控制器有32个中断源
3) 每个中断控制器负责的内容不同
4) 我们所需要的EXT_INT[16]属于控制器VIC0部分
如下图:
如图所示,我们需要在每一个VIC*VECTADDR*中配置一个中断入口地址,其实就是中断函数,可以理解为这是一个现成的指针,需要指向一个函数的地址,在中断产生时,就跳转到函数地址去执行继续往下翻阅手册会发现在564页有这么一句话
中断挂起时,用户必须清空所有向量中断控制器的入口地址到这一步我们还不能写代码,我们继续往下翻阅手册到565页
1.4 REGISTER DESCRIPTION
1.4.1 REGISTER MAP
VIC0IRQSTATUS —指定IRQ状态寄存器 (普通中断)
VIC0FIQSTATUS —指定FRQ状态寄存器 (快速中断)
VIC0RAWINTR —指定Raw中断状态寄存器
VIC0INTSELECT —指定中断选择寄存器
VIC0INTENABLE —指定中断使能寄存器其中前三个状态寄存器,后面两个是需要我们给定初始化的寄存器
我们之前知道向量中断控制器有4个,每一个控制器控制32个中断寄存器,所以我们在这里VIC0INTSELECT需要选择我们需要用到的中断寄存器进行操作,同时也要对应的中断寄存器使能产生中断VIC0INTENABLE
如果看到这里基本明白的话,下面就可以开始写代码了,我这里有以汇编和C语言为例
本例代码已传码云
码云:https://git.oschina.net/wangsansan/ARM-learn.git
所需要的头文件请自行下载
main.c
#include "stdio.h" //printf scanf ....
#include "s5pv210.h" //寄存器
void EINT16_31_Interrupt(void)
{
if(rEXT_INT_2_PEND & 1)
{
rEXT_INT_2_PEND|=1;
printf("KEY2 Down\r\n");
}
rVIC0ADDRESS = 0;
rVIC1ADDRESS = 0;
rVIC2ADDRESS = 0;
rVIC3ADDRESS = 0;
}
void KEY_Init(void)
{
/* 初始化按键2为外部中断16 */
rGPH2CON |=0xF;
/* 配置外部中断16为下降沿触发 */
rEXT_INT_2_CON &=~0x07;
rEXT_INT_2_CON |= 0x02;
/* 允许外部中断16产生中断 */
rEXT_INT_2_MASK&=~1;
/* 清零外部中断16中断标志位,在ARM系列芯片当中都是写1清零*/
rEXT_INT_2_PEND|=1;
/* 安装一个外部中断16中断服务函数 */
rVIC0VECTADDR16=(unsigned int)EINT16_31_Interrupt;
/* 设置VIC0通道16的中断类型为IRQ中断 */
rVIC0INTSELECT &=~(1<<16);
/* 使能VIC0通道16的产生中断*/
rVIC0INTENABLE |=(1<<16);
}
int main(void)
{
KEY_Init();
printf("This is key2 irq\r\n");
while(1)
{
}
return 0;
}
以下是汇编
start.S
#define rVIC0IRQSTATUS 0xF2000000
#define rVIC0ADDRESS 0xF2000F00
.text
.extern main
.extern uart_init
.global _start
_start:
@使能IRQ中断
mrs r1,cpsr //r1=cpsr
bic r1,#0x80 //r1&=~(1<<7)
msr cpsr,r1 //cpsr=r1
@安装处理IRQ异常的函数到0xD0037418地址处
ldr r0,=HandlerIRQ
ldr r1,=0xD0037418
str r0,[r1]
@uart_init();
bl uart_init
@main;
bl main
halt:
b halt
@while(1)
HandlerIRQ:
@因为发生异常的时候,CPU自动将PC-4的值放到lr当中
@while(1)
sub lr,lr,#4
@保护现场
stmfd sp!,{r0-r12,lr}
@设置恢复现场的地址给到lr,因为中断服务函数完成之后,会使用到lr寄存器
ldr lr,=return_irq
@判断中断源
ldr r0,=rVIC0IRQSTATUS
ldr r1,[r0]
cmp r1,#0
bne vic0_handler
return_irq:
ldmfd sp!,{r0-r12,pc}^ //^,SPSR的值手动恢复到CPSR当中
vic0_handler:
@获取当前有效的中断服务函数地址
ldr r0,=rVIC0ADDRESS
ldr pc,[r0]
.end
多有不足,欢迎交流指正。
博客的文章都会发到个人订阅号上,欢迎关注