【S5PV210】 | 按键和CPU的中断系统

S5PV210 | 按键和CPU的中断系统


时间:2024年3月17日14:04:27

目录

[TOC]

1.参考

1.项目管理

2.x210bv3s: ARM Cortex-A8 (s5pv210)的开发与学习 硬件版本:(九鼎)X210BV3S 20160513

3.知识星球 | 深度连接铁杆粉丝,运营高品质社群,知识变现的工具

4.按键—朱老师物联网大课堂_四引脚按键 可以分成2对吗-CSDN博客

5.项目目录预览 - mark-down-s5pv210 - GitCode

6.x210bv3s电路原理图

7.【S5PV210】 | 按键和CPU的中断系统-CSDN博客

2.原理

在这里插入图片描述


在这里插入图片描述

对应GPIO口默认硬件上拉,有按键按下时对应的IO口变为低电平。

我们可以将对应GPIO口设置为输入,检测对应的电平即可。

3.DataSheet查询

在这里插入图片描述

1向量中断控制器

1.1向量中断控制器概述

S5PV210中的中断控制器由四个向量中断控制器(VIC),ARM PrimeCell组成PL192和四个TrustZone中断控制器(TZIC)SP890。
菊花链式连接了四个TZIC和四个VIC,以支持多达93个中断源。 TZIC提供软件TrustZone设计中与安全中断系统的接口。 它提供对nFIQ中断和在系统(VIC)非安全侧屏蔽来自中断控制器的中断源。 使用后者产生nIRQ信号。
为了从非安全中断源生成nFIQ,TZIC0从非安全中断控制器获取nNSFIQIN信号。

1.1.1向量中断控制器的主要功能

•支持93个向量IRQ中断
•固定硬件中断优先级
•可编程中断优先级
•支持硬件中断优先级屏蔽
•可编程中断优先级屏蔽
•生成IRQFIQ
•产生软件中断
•测试寄存器
•原始中断状态
•中断请求状态
•支持特权模式以限制访问

1.2中断源

S5PV210支持中断源,如下表所示

在这里插入图片描述

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

1.3功能说明

当用户清除待处理的中断时,用户必须将0写入所有VICADDRESS寄存器(VIC0ADDRESS
VIC1ADDRESSVIC2ADDRESSVIC3ADDRESS

1.4寄存器描述

详见数据手册

4.代码编写

裸机代码07-key_int · x210bv3s/v210_NoOs - 码云 - 开源中国 (gitee.com)

int.c

/*******************************************************************
 *   > File Name: int.c
 *   > Author: fly
 *   > Mail: lf.ye@samoon.net
 *   > Create Time: 2020年08月07日 星期五 14时01分36秒
 *================================================================*/
#include "int.h"
#include "stdio.h"

void reset_exception(void)
{
    printf("reset_exception.\n\r");
}

void undef_exception(void)
{
    printf("undef_exception.\n\r");
}

void soft_int_exception(void)
{
    printf("soft_int_exception.\n\r");
}

void prefetch_exception(void)
{
    printf("prefetch_exception.\n\r");
}

void data_exception(void)
{
    printf("data_exception.\n\r");
}

// 主要功能:绑定第一异常向量表;禁止所有中断;选择所有中断类型为IRQ;
// 清除VICnADDR为0
void system_init_exception(void)
{
    // 第一阶段处理,绑定异常向量表
    r_exception_reset = (unsigned int)reset_exception;
    r_exception_undef = (unsigned int)undef_exception;
    r_exception_soft_int = (unsigned int)soft_int_exception;
    r_exception_prefetch = (unsigned int)prefetch_exception;
    r_exception_data = (unsigned int)data_exception;
    r_exception_irq = (unsigned int)IRQ_handle;
    r_exception_fiq = (unsigned int)IRQ_handle;

    // 初始化中断控制器的基本寄存器
    intc_init(); 
}

// 清除需要处理的中断的中断处理函数的地址
void intc_clearvectaddr(void)
{
    // VICxADDR:当前正在处理的中断处理函数的地址
    VIC0ADDR = 0;
    VIC1ADDR = 0;
    VIC2ADDR = 0;
    VIC3ADDR = 0;
}

// 初始化中断控制器
void intc_init(void)
{
    // 禁止所有中断
    // 为什么在中断初始化之初要禁止所有中断?
    // 因为中断一旦打开,因为外部或者硬件自己的原因产生中断后一定会寻找isr(interrupt service routines:中断服务程序)
    // 而我们可能认为自己用不到这个中断就没有提供isr,这是它自动拿到的就是乱码
    // 则程序很可能跑飞,所以不用的中断一定要关掉。
    // 一般的做法是先全部关掉,然后再逐一打开自己感兴趣的中断。一旦打开
    // 就必须给这个中断提供相应的isr并绑定好。
    VIC0INTENCLEAR = 0xffffffff;
    VIC1INTENCLEAR = 0xffffffff;
    VIC2INTENCLEAR = 0xffffffff;
    VIC3INTENCLEAR = 0xffffffff;

    // 选择中断类型为IRQ
    VIC0INTSELECT = 0x0;
    VIC1INTSELECT = 0x0;
    VIC2INTSELECT = 0x0;
    VIC3INTSELECT = 0x0;

    // 清VICxADDR
    intc_clearvectaddr();
}

// 绑定我们写的isr到VICnVECTADDR寄存器
// 绑定过之后我们就把isr的地址交给硬件了,剩下的我们不用管,硬件会自己处理
// 等发生相应中断的时候,我们直接到相应的VICnADDR中去取isr地址即可。
// 参数:intnum是int.h定义的物理中断号,handler是函数指针,就是我们写的isr

// VIC0VECTADDR定义为VIC0VECTADDR0寄存器的地址,就相当于是VIC0VECTADDR0~31这个
// 数组(这个数组就是一个函数指针数组)的首地址,然后具体计算每一个中断的时候
// 只需要首地址+偏移量即可。
void intc_setvectaddr(unsigned long intnum, void (*handler)(void))
{
    // VIC0
    if(intnum < 32)
    {
        *((volatile unsigned long *)(VIC0VECTADDR + 4 *(intnum - 0))) = (unsigned)handler;
    }
    // VIC1
    else if(intnum < 64)
    {
        *((volatile unsigned long *)(VIC1VECTADDR + 4 *(intnum - 32))) = (unsigned)handler;
    }
    // VIC2
    else if(intnum < 96)
    {
        *((volatile unsigned long *)(VIC2VECTADDR + 4 *(intnum - 64))) = (unsigned)handler;
    }
    // VIC3
    else
    {
        *((volatile unsigned long *)(VIC3VECTADDR + 4 *(intnum - 96))) = (unsigned)handler;
    }

    return;
}

// 使能中断
// 通过传参的intnum来使能某一个具体的中断源,中断号在int.h中定义,是物理中断号
void intc_enable(unsigned long intnum)
{
    unsigned long temp;
    // 确定intnum在哪个寄存器的哪一位
    // <32就是0~31,必然在VIC0
    if(intnum < 32)
    {
        temp = VIC0INTENABLE;
        temp |= (1<<intnum);    // 如果是第一种设计必须位操作,第二种设计可以直接写。

        VIC0INTENABLE  = temp;
    }
    else if(intnum < 64)
    {
        temp = VIC1INTENABLE;
        temp |= (1 << (intnum - 32));
        VIC1INTENABLE = temp;
    }
    else if(intnum < 96)
    {
        temp = VIC2INTENABLE;
        temp |= (1 << (intnum - 64));
        VIC2INTENABLE = temp;
    }
    else if(intnum < NUM_ALL)
    {
        temp = VIC3INTENABLE;
        temp |= (1 << (intnum - 96));
        VIC3INTENABLE = temp;
    }
    // NUM_ALL : enable all interrupt
    else
    {
        VIC0INTENABLE = 0xffffffff;
        VIC1INTENABLE = 0xffffffff;
        VIC2INTENABLE = 0xffffffff;
        VIC3INTENABLE = 0xffffffff;
    }
}

// 禁止中断
// 通过传参的intnum来禁止某一个具体的中断源,中断号在int.h中定义,是物理中断号
void intc_disable(unsigned long intnum)
{
    unsigned long temp;

    if(intnum < 32)
    {
        temp = VIC0INTENCLEAR;
        temp |= (1<<intnum);
        VIC0INTENCLEAR = temp;
    }
    else if(intnum < 64)
    {
        temp = VIC1INTENCLEAR;
        temp |= (1<<(intnum - 32));
        VIC1INTENCLEAR = temp;
    }
    else if(intnum < 96)
    {
        temp = VIC2INTENCLEAR;
        temp |= (1<<(intnum - 64));
        VIC2INTENCLEAR = temp;
    }
    else if(intnum < NUM_ALL)
    {
        temp = VIC3INTENCLEAR;
        temp |= (1<<(intnum - 96));
        VIC3INTENCLEAR = temp;
    }
    // NUM_ALL : disable all interrupt
    else
    {
        VIC0INTENCLEAR = 0xffffffff;
        VIC1INTENCLEAR = 0xffffffff;
        VIC2INTENCLEAR = 0xffffffff;
        VIC3INTENCLEAR = 0xffffffff;
    }

    return;
}

// 通过读取VICnIRQSTATUS寄存器,判断其中哪个有一位为1,来得知哪个VIC发生中断了
unsigned long intc_getvicirqstatus(unsigned long ucontroller)
{
    if(ucontroller == 0)
        return VIC0IRQSTATUS;
    else if(ucontroller == 1)
        return VIC1IRQSTATUS;
    else if(ucontroller == 2)
        return VIC2IRQSTATUS;
    else if(ucontroller == 3)
        return VIC3IRQSTATUS;
    else
    {}
    return 0;
}

// 真正的中断处理程序。意思就是说这里只考虑中断处理,不考虑保护/恢复现场
void irq_handler(void)
{
    printf("irq_handler.\n\r");
    // SoC支持很多个(在低端CPU例如2440中有30多个,在210中有100多个)中断
    // 这么多中断irq在第一个阶段走的是一条路,都会进入到irq_handle来
    // 我们在irq_handler中要去区分究竟是哪个中断发生了,然后再去调用该中断
    // 对应的isr。

    // 虽然硬件已经自动帮我们把isr放入了VICnADDR中,但是因为有4个,所以我们
    // 必须先软件去检查出来到底是哪一个VIC中断,也就是isr到底在哪个VICADDR寄存器中
    unsigned long vicaddr[4] = {VIC0ADDR, VIC1ADDR, VIC2ADDR, VIC3ADDR};
    int i = 0;
    void (*isr)(void) = NULL;

    for(i = 0; i< 4; i++)
    {
        // 发生一个中断时,4个VIC中有3个是全0,1个的其中1位不是0
        if(intc_getvicirqstatus(i) != 0)
        {
            isr = (void(*)(void))vicaddr[i];
            break;
        }
    }

    (*isr)();   // 通过函数指针来调用函数
}

key.c

/*******************************************************************
 *   > File Name: key.c
 *   > Author: fly
 *   > Mail: XXXXXXXX@icode.com
 *   > Create Time: 2020年12月07日 星期一 19时52分42秒
 ******************************************************************/
#include "key.h"
#include "uart.h"
#include "int.h"
#include "printf.h"

// -------------------中断方式处理按键-------------------------------
// 以中断方式来处理按键的初始化
void key_init_interrupt(void)
{
	// 1.外部中断对应的GPIO模式设置
	rGPH0CON |= 0xFF << 8;		// GPH0_2/GPH0_3设置为外部中断模式
	rGPH2CON |= 0xFFFF << 0;	// GPH2_0/1/2/3共4个引脚设置为外部中断模式

	// 2.中断触发模式设置
	rEXT_INT_0_CON &= ~(0xFF<<8);			// bit8~15全部清零
	rEXT_INT_0_CON |= ((2<<8) | (2<<12));	// EXT_INT2和EXT_INT3设置为下降沿触发
	rEXT_INT_2_CON &= ~(0xFFFF<<0);
	rEXT_INT_2_CON |= ((2<<0) | (2<<4) | (2<<8) | (2<<12));

	// 3.中断允许
	rEXT_INT_0_MASK &= ~(0x03<<2);
	rEXT_INT_2_MASK &= ~(0x0F<<0);

	// 4.清挂起,清除是写1,
	rEXT_INT_0_PEND |= (0x03<<2);
	rEXT_INT_2_PEND |= (0x0F<<0);
}

// EINT2通道对应的按键,就是GPH0_2引脚对应的按键,
// 就是开发板上标了LEFT的那个按键
void isr_eint2(void)
{
	// 真正的isr应该做2件事情。
	// 第一,中断处理代码,就是真正干活的代码
	printf("isr_eint2_LEFT.\n\r");
	uart2_printf("isr_eint2_LEFT.\n\r");
	// 第二,清除中断挂起
	rEXT_INT_0_PEND |= (1<<2);
	intc_clearvectaddr();
}

void isr_eint3(void)
{
	// 真正的isr应该做2件事情。
	// 第一,中断处理代码,就是真正干活的代码
	printf("isr_eint3_DOWN.\n\r");
	uart2_printf("isr_eint3_DOWN.\n\r");
	// 第二,清除中断挂起
	rEXT_INT_0_PEND |= (1<<3);
	intc_clearvectaddr();
}

void isr_eint16171819(void)
{
	// 第一,中断处理代码;
	// 因为EINT16~31是共享中断,所以
	// 要在这里再次去区分具体是哪个子中断
	if(rEXT_INT_2_PEND & (1 << 0))
	{
		printf("eint16_UP.\n\r");
		uart2_printf("eint16_UP.\n\r");
	}
	if(rEXT_INT_2_PEND & (1 << 1))
	{
		printf("eint17_RIGHT.\n\r");
		uart2_printf("eint17_RIGHT.\n\r");
	}
	if(rEXT_INT_2_PEND & (1 << 2))
	{
		printf("eint18_BACK.\n\r");
		uart2_printf("eint18_BACK.\n\r");
	}
	if(rEXT_INT_2_PEND & (1 << 3))
	{
		printf("eint19_MENU.\n\r");
		uart2_printf("eint19_MENU.\n\r");
	}

	// 第二,清除中断挂起
	rEXT_INT_2_PEND |= (0x0F << 0);
	intc_clearvectaddr();
}

void tester_key_int(void)
{
	key_init_interrupt();
	// 如果程序要使用中断,就要调用中断初始化来
	// 初步初始化中断控制器
	system_init_exception();

	// 绑定isr到中断控制器
	intc_setvectaddr(KEY_EINT2, isr_eint2);
	intc_setvectaddr(KEY_EINT3, isr_eint3);
	intc_setvectaddr(KEY_EINT16_19, isr_eint16171819);

	// 使能中断
	intc_enable(KEY_EINT2);
	intc_enable(KEY_EINT3);
	intc_enable(KEY_EINT16_19);
}

5.拓展

NA

相关推荐

  1. k8sPVPVC存储介绍

    2024-03-17 16:08:03       20 阅读
  2. 按键驱动中断方式按键驱动

    2024-03-17 16:08:03       12 阅读
  3. [xboard]ok210-3 S5PV210光盘资料与功能测试

    2024-03-17 16:08:03       17 阅读
  4. 【K8S系列】深入解析K8SPV PVC

    2024-03-17 16:08:03       12 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-17 16:08:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-17 16:08:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-17 16:08:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-17 16:08:03       20 阅读

热门阅读

  1. 修改Docker 默认存储路径,镜像容器移动到新路径

    2024-03-17 16:08:03       19 阅读
  2. 【Docker】Kong 容器化部署及配置参数说明

    2024-03-17 16:08:03       17 阅读
  3. centos7网络命令:ping、dig、nsloopup、tcpdump

    2024-03-17 16:08:03       20 阅读
  4. 【Python】pymysql库的介绍及用法

    2024-03-17 16:08:03       23 阅读
  5. Python面向对象编程:入门篇(类和对象)

    2024-03-17 16:08:03       22 阅读
  6. 华为机试真题练习汇总(41~50)

    2024-03-17 16:08:03       20 阅读
  7. 客户端渲染与服务端渲染(2)

    2024-03-17 16:08:03       17 阅读
  8. linux ---vim的基本使用

    2024-03-17 16:08:03       18 阅读
  9. 前端面试练习24.3.16

    2024-03-17 16:08:03       22 阅读
  10. 速盾cdn:cdn关闭后多长生效?

    2024-03-17 16:08:03       20 阅读
  11. 【TypeScript系列】Iterators 和 Generators

    2024-03-17 16:08:03       20 阅读