嵌入式学习笔记: Cortex-A8 外部中断

时间:2021-04-06 18:50:56

以此作为笔记,自己巩固也供大家学习,不足之处,轻拍。


整个过程需要参考对照s5pv210说明手册、电路图底板图以及核心板电路图

百度云盘:
说明手册 s5pv210_UM_REV1.1.pdf
核心板电路图 210kfb-core-v11.pdf
底板电路图 210KFBDBV1.1.pdf

A、外部中断

一、一句话:

学习过程所使用的芯片是s5pv210,该芯片*有128个中断源,这些中断源又分别分配到4组不同的向量终端控制器 VIC0-VIC3

二、简构原理

为什么叫“简构原理”,我这里是想我们在学习之前,先从概念构思一边,如果我们设计出了一个中断机制会怎么样让别人使用起来方便一些,我也是第一次接触,所以在我学习的时候我是这样想的,这是我自己的一种思路,下面是我的思考内容

当设备在稳定运行过程中,突然产生一个中断信号告诉机器马上执行另一件事,那程序不得不放下目前正在进行的工作,去完成中断信号命令的任务。

这里我们可以知道当被命令中断当前任务,执行其它任务完成后,我们的设备并不是进入等待状态,它得回来接着把之前的任务完成。所以,在进入另一项任务之前,需要对现目前工作状态进行保存

在执行中断任务的时候,程序是不知道要执行什么任务的,所以这个任务我们得告诉他,这里就要初始化注册一个中断函数

我还要给定一个中断产生的条件,开发板上有按钮,我就假定按钮按下的时候让它中断去执行一个函数,这里就要初始化一个按键,设置外部中断为按键产生的中断

好了,我大概能想到的就是这些,接下来我边查手册,一边写一个简单的按键中断

三、初步探索

我们从简单的开始设置

1、设置一个按键产生中断,先从电路图中找到按键电路,在

(210KFBDBV1.1.pdf手册第4页)
嵌入式学习笔记: Cortex-A8 外部中断

(可以看到电路图上有8个按键,从K2-K9,但是开发板上实际有9个按键,其中有一个为复位按键,所以这里不用理会K1)

图示看到按键K2接通的引脚标注为KP_COL0

2、打开核心板电路图查询引脚标注对应的引脚号

搜索”KP_COL”
(210kfb-core-v11.pdf 第2页)
嵌入式学习笔记: Cortex-A8 外部中断

搜索到结果可以看到引脚为GPH2_*
其中GPH2_*这一组有8个引脚,对应编号从0-7,实际上的按键只有GPH2_0-GPH2_3四个引脚,如图黑色方框内的内容
其它四个按键属于GPH3_*的前四个引脚控制

找到引脚号,现在就开始查询怎么设置和控制这些引脚。

3、打开芯片手册–S5PV210_UM_REV1.1.pdf

搜索 “GPH2”
(S5PV210_UM_REV1.1.pdf 第328页)
嵌入式学习笔记: Cortex-A8 外部中断
看它的说明告诉我们的信息:

GPH2通过4个寄存器控制,这四个寄存器分别是GPH2CON、GPH2DAT、GPH2PUD、GPH2DRV
其中GPH2PUD、GPH2DRV我们可以不用先不用管,GPH2DAT我们也用不到,不过我这里也说一下,我们大致浏览一下表格的内容,看看可以获得哪些信息,浏览一遍328页-329也的内容

嵌入式学习笔记: Cortex-A8 外部中断

我们至少可以知道这些内容:
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]的寄存器信息

嵌入式学习笔记: Cortex-A8 外部中断

1) EXT_INT_2_CON —外部中断寄存器16-23的配置寄存器(336页)

嵌入式学习笔记: Cortex-A8 外部中断
EXT_INT_2_CON寄存器有32个bit位,每4个bit位的低三位设置外部中断的触发方式,共8个外部中断EXT_INT[16-23],
其中的控制内容包括触发方式:
a、电平触发(高电平001,低电平000)
b、边沿触发(上升沿011、下降沿010)
c、两种方式都允许触发100

2) EXT_INT_2_FLTCON* —外部中断寄存器16-23的滤波器配置寄存器(345页)

3) EXT_INT_2_MASK —外部中断屏蔽寄存器(349页)

嵌入式学习笔记: Cortex-A8 外部中断
只使用8个bit位,其它bit位都预留,分别设置EXT_INT[16]-[23]
0表示使能中断,1表示屏蔽中断

4) EXT_INT_2_PEND —外部中断挂起寄存器(351页)
嵌入式学习笔记: Cortex-A8 外部中断
只使用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部分
如下图:
嵌入式学习笔记: Cortex-A8 外部中断
如图所示,我们需要在每一个VIC*VECTADDR*中配置一个中断入口地址,其实就是中断函数,可以理解为这是一个现成的指针,需要指向一个函数的地址,在中断产生时,就跳转到函数地址去执行

继续往下翻阅手册会发现在564页有这么一句话
嵌入式学习笔记: Cortex-A8 外部中断
中断挂起时,用户必须清空所有向量中断控制器的入口地址

到这一步我们还不能写代码,我们继续往下翻阅手册到565页
嵌入式学习笔记: Cortex-A8 外部中断
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

多有不足,欢迎交流指正。

博客的文章都会发到个人订阅号上,欢迎关注
嵌入式学习笔记: Cortex-A8 外部中断