ARM基础--基于Exynos4412的轮询和中断

本文介绍了CPU与硬件的三种交互方式:轮询、中断和DMA,重点讲解了基于中断的按键实验和ARM的中断处理机制,包括A9中断控制器的组成部分和工作原理,以及中断控制器编程和中断处理程序的编写。此外,还涉及了ARM处理器的异常处理流程。
摘要由CSDN通过智能技术生成

目录

CPU与硬件的交互方式

基于轮询的按键实验

中断控制器概念

中断控制器用到的寄存器详解

中断控制器编程

ARM的异常处理机制

中断处理程序


CPU与硬件的交互方式

        1.轮询:CPU执行程序时不断地询问硬件是否需要其服务,若需要则给予其服务,若不需要一段时间后再次询问,周而复始。

        2.中断: CPU执行程序时若硬件需要其服务,对应的硬件给CPU发送中断信号,CPU接收到中断信号后将当前的程序暂停下来,转而去执行中断服务程序,执行完成后再返回到被打断的点继续执行。

        3.DMA:硬件产生数据后,硬件控制器可将产生的数据直接写入到存储器中,整个过程无需CPU的参与。

基于轮询的按键实验


#include "exynos_4412.h"
void delay(unsigned int time)
{
	while(time --);
}
int main()
{
    // 设置GPIO为输入。
    GPX1.CON = GPX1.CON & (~(0xF << 4));
    while(1)
    {
        // 判断X1端口为低电平
        if(!(GPX1.DAT & (1<<1)))
        {
			delay(1000);
            printf("Key2 Pressed\n");
			while(!(GPX1.DAT & (1<<1)));
        }
        else
        {
            
        }
    }
	return 0;
}

基于中断的按键实验


#include "exynos_4412.h"
 
int main()
{
    GPX1.CON = GPX1.CON | (0xF << 4);
    EXT_INT41_CON = EXT_INT41_CON & (~(0x7 << 4)) | (0x2 << 4);
    EXT_INT41_MASK = EXT_INT41_MASK & (~(1 << 1));
 
	return 0;
}

中断控制器概念

A9中断控制器是指ARM Cortex-A9处理器内置的中断控制器,主要负责管理所有的中断请求,包括设备中断和软件中断。A9中断控制器包括两个模块:GIC Distributor和GIC CPU Interface。

  1. GIC Distributor

GIC Distributor是中断分发器,用于管理所有中断源,包括外设中断和软件中断,并将这些中断请求分发给GIC CPU Interface。GIC Distributor可以识别每个中断请求的优先级,并通过轮询、中断请求锁定和转发等机制来确保高优先级的中断请求能够优先处理。

  1. GIC CPU Interface

GIC CPU Interface是CPU接口,用于将中断请求送到CPU核心,并进行中断优先级判断和中断屏蔽等操作。它可以对每个CPU内核进行独立的中断屏蔽和中断优先级设置,从而保证系统中各个中断请求的处理顺序和优先级。

A9中断控制器支持多种中断信号源,包括硬件设备中断、软件中断、中断请求片段(SGI)等。除此之外,它还支持多种触发模式,包括边沿触发和电平触发等。在系统运行过程中,A9中断控制器提供了丰富的中断处理机制,包括自动中断屏蔽、中断向量表、多级中断处理、中断请求共享等,为系统提供了高效、灵活、可靠的中断处理功能。

SGI:软中断,不是ARM架构里的那个SWI,这个是多核处理器之间用的比较多,一般操作系统内核中会使用。

PPI:私有外设中断

SPI:共享外设中断可以发送给任何一个CPU去执行。

中断控制器用到的寄存器详解

ICDDCR:中断总开关

ICDISER:每个中断的小开关,我们要打开57号中断的开关

ICDIPTR:确定我们的57号中断发送给哪个CPU处理,暂时只能是CPU0

ICCICR:中断控制器和CPU之间的接口

中断控制器编程

#include "exynos_4412.h"
 
int main()
{
    GPX1.CON = GPX1.CON | (0xF << 4);
    EXT_INT41_CON = EXT_INT41_CON & (~(0x7 << 4)) | (0x2 << 4);
    EXT_INT41_MASK = EXT_INT41_MASK & (~(1 << 1));
    
    ICDDCR = ICDDCR | 1;
    ICDISER.ICDISER1 = ICDISER.ICDISER1 | (1 << 25);
    ICDIPTR.ICDIPTR14 = ICDIPTR.ICDIPTR14 & (~(0xFF << 8)) | (0x01 << 8);
    CPU0.ICCICR = CPU0.ICCICR | 1;
 
 
	return 0;
}

ARM的异常处理机制

处理器在正常执行程序的过程中可能会遇到一些不正常的事件发生,这时处理器就要将当前的程序暂停下来转而去处理这个异常的事件。异常事件处理完成之后再返回到被异常打断的点,继续执行程序。

不同的处理器对异常的处理的流程大体相似,但是不同的处理器在具体实现的机制上有所不同;比如处理器遇到哪些事件认为是异常事件遇到异常事件之后处理器有哪些动作、处理器如何跳转到异常处理程序如何处理异常、处理完异常之后又如何返回到被打断的程序继续执行等我们将这些细节的实现称为处理器的异常处理机制。

ARM异常源
    FIQ                                          快速中断请求引脚有效 

    IRQ                                          外部中断请求引脚有效

    Reset                                       复位电平有效

    Software Interrupt                    执行swi指令

    Data Abort                               数据终止

    Prefetch Abort                         指令预取终止

    Undefined Instruction              遇到不能处理的指令

中断处理程序

修改启动文件

.text
.global _start
_start:
    /*
     * Vector table
     */ 
    b reset
    b .
    b .
    b .
    b .
    b .
    //IRQ
    b irq_handler
    b .

reset:
    /*
     * Set vector address in CP15 VBAR register
     */ 
    ldr    r0, =_start
    mcr    p15, 0, r0, c12, c0, 0    @Set VBAR

    /*
     * Set the cpu to SVC32 mode, Disable FIQ/IRQ
     */  
    mrs r0, cpsr
    bic r0, r0, #0x1f
    orr    r0, r0, #0xd3
    msr    cpsr ,r0

    /*
     * Defines access permissions for each coprocessor
     */  
    mov    r0, #0xfffffff
    mcr    p15, 0, r0, c1, c0, 2      

    /*
     * Invalidate L1 I/D                                                                                                                   
     */
    mov    r0, #0                    @Set up for MCR
    mcr    p15, 0, r0, c8, c7, 0    @Invalidate TLBs
    mcr    p15, 0, r0, c7, c5, 0    @Invalidate icache
    
    /*
     * Set the FPEXC EN bit to enable the FPU
     */ 
    mov r3, #0x40000000
    fmxr FPEXC, r3
    
    /*
     * Disable MMU stuff and caches
     */
    mrc    p15, 0, r0, c1, c0, 0
    bic    r0, r0, #0x00002000        @Clear bits 13 (--V-)
    bic    r0, r0, #0x00000007        @Clear bits 2:0 (-CAM)
    orr    r0, r0, #0x00001000        @Set bit 12 (---I) Icache
    orr    r0, r0, #0x00000002        @Set bit 1 (--A-) Align
    orr    r0, r0, #0x00000800        @Set bit 11 (Z---) BTB
    mcr    p15, 0, r0, c1, c0, 0

    /*
     * Initialize stacks                                                                                                                  
     */
init_stack:     
    /*svc mode stack*/
    msr cpsr, #0xd3
    ldr sp, _stack_svc_end

    /*undef mode stack*/
    msr cpsr, #0xdb
    ldr sp, _stack_und_end

    /*abort mode stack*/    
    msr cpsr,#0xd7
    ldr sp,_stack_abt_end

    /*irq mode stack*/    
    msr cpsr,#0xd2
    ldr sp, _stack_irq_end
    
    /*fiq mode stack*/
    msr cpsr,#0xd1
    ldr sp, _stack_fiq_end
    
    /*user mode stack, enable FIQ/IRQ*/
    msr cpsr,#0x10
    ldr sp, _stack_usr_end

    /*Call main*/
    b main
//IRQ异常处理程序
irq_handler:
    //跳转修复
    sub lr, lr, #4

    //R0-R12 IRQ模式和USER模式是同一组
    stmfd sp!, {r0-r12,lr}
    //处理异常
    bl do_irq

    //异常返回
    ldmfd sp!,{r0-r12,pc}^


_stack_svc_end:      
    .word stack_svc + 512
_stack_und_end:      
    .word stack_und + 512
_stack_abt_end:      
    .word stack_abt + 512
_stack_irq_end:      
    .word stack_irq + 512
_stack_fiq_end:
    .word stack_fiq + 512
_stack_usr_end:      
    .word stack_usr + 512

.data
stack_svc:      
    .space 512
stack_und:
    .space 512
stack_abt:      
    .space 512
stack_irq:      
    .space 512
stack_fiq:      
    .space 512

定义异常处理函数

#include "exynos_4412.h"
void do_irq()
{
    unsigned int IrqNum;
    IrqNum = CPU0.ICCIAR & 0x3FF;
    switch(IrqNum)
    {
        case 0:
            //0号中断处理程序
            break;
        case 1:
            break;
        case 57:
    		printf("KEY3 pressed\n");
    		//清除中断挂起
   	 		EXT_INT41_PEND = (1 << 1);
            break;
        case 159:
            break;
        default:
            break;
    }
 
}

启动中断处理程序

#include "exynos_4412.h"
void do_irq()
{
    unsigned int IrqNum;
    IrqNum = CPU0.ICCIAR & 0x3FF;
    switch(IrqNum)
    {
        case 0:
            //0号中断处理程序
            break;
        case 1:
            break;
        case 57:
    		printf("KEY2 pressed\n");
    		//清除中断挂起
   	 		EXT_INT41_PEND = (1 << 1);
            //将当前中断号写回中断控制器
            //告知中断处理完成
            CPU0.ICCEOIR = CPU0.ICCEOIR & (~(0x3FF)) | 57;
            break;
        case 159:
            break;
        default:
            break;
    }
 
}
 
void delay(unsigned int time)
{
	while(time --);
}
 
int main()
{
    GPX1.CON = GPX1.CON | (0xF << 4);
    EXT_INT41_CON = EXT_INT41_CON & (~(0x7 << 4)) | (0x2 << 4);
    EXT_INT41_MASK = EXT_INT41_MASK & (~(1 << 1));
    
    ICDDCR = ICDDCR | 1;
    ICDISER.ICDISER1 = ICDISER.ICDISER1 | (1 << 25);
    ICDIPTR.ICDIPTR14 = ICDIPTR.ICDIPTR14 & (~(0xFF << 8)) | (0x01 << 8);
    CPU0.ICCICR = CPU0.ICCICR | 1;
 
	GPX2.CON = GPX2.CON & (~(0xF << 28)) | (0x1 << 28);
	GPX1.CON = GPX1.CON & (~(0xF)) | (0x1);
	GPF3.CON = GPF3.CON & (~(0xFF << 16)) | (0x11 << 16);
 
	while(1)
	{
		GPX2.DAT = GPX2.DAT | (1 << 7);
		delay(1000000);
		GPX2.DAT = GPX2.DAT & (~(1 << 7));
		delay(1000000);
		GPX1.DAT = GPX1.DAT | 1;
		delay(1000000);
		GPX1.DAT = GPX1.DAT & (~1);
		delay(1000000);	
		GPF3.DAT = GPF3.DAT | (1 << 4);
		delay(1000000);
		GPF3.DAT = GPF3.DAT & (~(1 << 4));
		delay(1000000);
		GPF3.DAT = GPF3.DAT | (1 << 5);
		delay(1000000);
		GPF3.DAT = GPF3.DAT & (~(1 << 5));
		delay(1000000);	
			
	}
 
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值