历史上的今天
返回首页

历史上的今天

今天是:2024年09月13日(星期五)

正在发生

2021年09月13日 | S3c2440ARM异常与中断体系详解7---按键中断程序示例完善

2021-09-13 来源:eefocus

首先main.c中

我们初始化中断控制器

初始化中断源


假设按键按键就会产生中断,CPU就会跳到start.S 执行


.text

.global _start


_start:

b reset  /*vector 0 一上电复位,是从0地址开始执行,跳到reset*/

ldr pc, und_addr /*vector 4 如果发生未定义指令异常,硬件就会在自动跳转0x04地址未定义指令异常处,执行do_und*/

    ldr pc,swi_addr /* vector 8 : swi */

在这里插入图片描述

IRQ模式的话跳到0x00000018地方


.text

.global _start


_start:

b reset  /*vector 0 一上电复位,是从0地址开始执行,跳到reset*/

ldr pc, und_addr /*vector 4 如果发生未定义指令异常,硬件就会在自动跳转0x04地址未定义指令异常处,执行do_und*/


/*假设一上电从0地址开始执行,reset,做一系列初始化之后

     *故意加入一条未定义指令

     */

    /*1 添加swi指令*/ 

    ldr pc,swi_addr /* vector 8 : swi */

    b halt          /* vector c : abort */

    b halt          /* vector 10: abort */

    b halt          /* vector 14: reserve */

    ldr pc,irq_addr /* vector 18: IRQ */

irq_addr:

.word do_irq 

do_irq:


/*1、保护现场 2、处理异常 3、恢复现场*/


/*   1、保护现场(硬件自动完成)

*

* 执行到这里之前:

* 1. lr_irq保存有被中断模式中的下一条即将执行的指令的地址

* 2. SPSR_irq保存有被中断模式的CPSR

* 3. CPSR中的M4-M0被设置为10011, 进入到svc模式

* 4. 跳到0x8的地方执行程序 

*/


/*需要从新设置sp栈,指向某一块没有使用的地址*/

/* sp_svc未设置, 先设置它 */


ldr sp,=0x33d00000 /*指向SDRAM的一块内存上*/


/* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */

/* 发生异常时,当前被中断的地址会保存在lr寄存器中 先减后存*/

/* lr是异常处理完后的返回地址, 也要保存 */


sub lr,lr,#4           /* IRQ处理完后的返回地址 -4 由手侧可知 */

stmdb sp!,{r0-r12,lr}  /* 先减后存 */


/* 2、处理irq异常(一般是中断处理函数) */


bl handle_irq_c


/*    3、恢复现场    */

ldmia sp!,{r0-r12,pc}^ /* ^ 会把spsr_svc的值恢复到cpsr里 */  

在这里插入图片描述

中断处理函数的书写:

首先,读EINTPEND分辨哪个EINT产生(eint4~23)清除中断时, 写EINTPEND的相应位

在这里插入图片描述

/* 3、中断处理函数 */

void handle_irq_c(void)

{

/*1 分辨中断源 */

    /*读INTOFFSET在芯片手册里找到这个寄存器,它里面的值表示INTPND中哪一位被设置成1*/

    int bit = INTOFFSET;


    /*2 调用对应的处理函数 */

    if (bit == 0 || bit == 2 || bit == 5)  /* 对应eint0,2,eint8_23 */

    {

        /*我们会调用一个按键处理函数*/

        key_eint_irq(bit); /* 处理中断, 清中断源EINTPEND */

    }


    /*3 清中断 : 从源头开始清

     *先清除掉中断源里面的某些寄存器

     *再清 SRCPND

     *再清 INTPND

     */

    SRCPND = (1<    INTPND = (1<

}

void key_eint_irq(int irq)

{

    unsigned int val = EINTPEND;

    unsigned int val1 = GPFDAT;

    unsigned int val2 = GPGDAT;


    if (irq == 0) /* eint0 : s2 控制 D12 */

    {

        if (val1 & (1<<0)) /* s2 --> gpf6 */

        {

            /* 松开 */

            GPFDAT |= (1<<6);

        }

        else

        {

            /* 按下 */

            GPFDAT &= ~(1<<6);

        }


    }

    else if (irq == 2) /* eint2 : s3 控制 D11 */

    {

        if (val1 & (1<<2)) /* s3 --> gpf5 */

        {

            /* 松开 */

            GPFDAT |= (1<<5);

        }

        else

        {

            /* 按下 */

            GPFDAT &= ~(1<<5);

        }


    }

    else if (irq == 5) /* eint8_23, eint11--s4 控制 D10, eint19---s5 控制所有LED */

    {

        if (val & (1<<11)) /* eint11 */

        {

            if (val2 & (1<<3)) /* s4 --> gpf4 */

            {

                /* 松开 */

                GPFDAT |= (1<<4);

            }

            else

            {

                /* 按下 */

                GPFDAT &= ~(1<<4);

            }

        }

        else if (val & (1<<19)) /* eint19 */

        {

            if (val2 & (1<<11))

            {

                /* 松开 */

                /* 熄灭所有LED */

                GPFDAT |= ((1<<4) | (1<<5) | (1<<6));

            }

            else

            {

                /* 按下: 点亮所有LED */

                GPFDAT &= ~((1<<4) | (1<<5) | (1<<6));

            }

        }

    }


    EINTPEND = val;

}


上传代码编译执行

烧写看是否可以使用

回顾中断处理流程


我们start.s

一上电从

_start:

运行

做一些初始化工作


reset:

    /* 关闭看门狗 */

    ldr r0, =0x53000000

    ldr r1, =0

    str r1, [r0]


    /* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */

    /* LOCKTIME(0x4C000000) = 0xFFFFFFFF */

    ldr r0, =0x4C000000

    ldr r1, =0xFFFFFFFF

    str r1, [r0]


    /* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */

    ldr r0, =0x4C000014

    ldr r1, =0x5

    str r1, [r0]


    /* 设置CPU工作于异步模式 */

    mrc p15,0,r0,c1,c0,0

    orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA

    mcr p15,0,r0,c1,c0,0


    /* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 

     *  m = MDIV+8 = 92+8=100

     *  p = PDIV+2 = 1+2 = 3

     *  s = SDIV = 1

     *  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M

     */

    ldr r0, =0x4C000004

    ldr r1, =(92<<12)|(1<<4)|(1<<0)

    str r1, [r0]


    /* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定

     * 然后CPU工作于新的频率FCLK

     */


    /* 设置内存: sp 栈 */

    /* 分辨是nor/nand启动

     * 写0到0地址, 再读出来

     * 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动

     * 否则就是nor启动

     */

    mov r1, #0

    ldr r0, [r1] /* 读出原来的值备份 */

    str r1, [r1] /* 0->[0] */ 

    ldr r2, [r1] /* r2=[0] */

    cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */

    ldr sp, =0x40000000+4096 /* 先假设是nor启动 */

    moveq sp, #4096  /* nand启动 */

    streq r0, [r1]   /* 恢复原来的值 */


    bl sdram_init

    //bl sdram_init2     /* 用到有初始值的数组, 不是位置无关码 */


    /* 重定位text, rodata, data段整个程序 */

    bl copy2sdram


    /* 清除BSS段 */

    bl clean_bss


    /* 复位之后, cpu处于svc模式

     * 现在, 切换到usr模式

     */

    mrs r0, cpsr         /* 读出cpsr */

    bic r0, r0, #0xf     /* 修改M4-M0为0b10000, 进入usr模式 */

    bic r0, r0, #(1<<7)  /* 清除I位, 使能中断 */

    msr cpsr, r0


    /* 设置 sp_usr */

    ldr sp, =0x33f00000


    ldr pc, =sdram

sdram:

    bl uart0_init


    bl print1

    /* 故意加入一条未定义指令 */

und_code:

    .word 0xdeadc0de  /* 未定义指令 */

    bl print2


    swi 0x123  /* 执行此命令, 触发SWI异常, 进入0x8执行 */


    //bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */

    ldr pc, =main  /* 绝对跳转, 跳到SDRAM */


halt:

    b halt


//让后设置CPSR开中断

//让后调到mian函数,做一些中断初始化


int main(void)

{

    led_init();

    interrupt_init();  /* 初始化中断控制器 */

    key_eint_init();   /* 初始化按键, 设为中断源 */


    puts("nrg_A = ");

    printHex(g_A);

    puts("nr");

/*让后在main函数里一直循环输出串口*/

    while (1)

    {


        putchar(g_Char);

        g_Char++;


        putchar(g_Char3);

        g_Char3++;

        delay(1000000);

    }


//这个时候按下按键就会产生中断,让后进入start.s

//跳到0x18 irq模式


ldr pc, irq_addr /* vector 0x18 : irq */


它是一条读内存的执行,从这里读地址赋给pc


irq_addr:

    .word do_irq


就跳到sdram执行do_irq函数

do_irq:

    /* 执行到这里之前:

     * 1. lr_irq保存有被中断模式中的下一条即将执行的指令的地址

     * 2. SPSR_irq保存有被中断模式的CPSR

     * 3. CPSR中的M4-M0被设置为10010, 进入到irq模式

     * 4. 跳到0x18的地方执行程序 

     */


    /* sp_irq未设置, 先设置它 */

    ldr sp, =0x33d00000


    /* 保存现场 */

    /* 在irq异常处理函数中有可能会修改r0-r12, 所以先保存 */

    /* lr-4是异常处理完后的返回地址, 也要保存 */

    sub lr, lr, #4

    stmdb sp!, {r0-r12, lr}  


    /* 处理irq异常 */

    bl handle_irq_c


    /* 恢复现场 */


它怎么处理

/* 读EINTPEND分辨率哪个EINT产生(eint4~23)

 * 清除中断时, 写EINTPEND的相应位

 */


void key_eint_irq(int irq)

{

    unsigned int val = EINTPEND;

    unsigned int val1 = GPFDAT;

    unsigned int val2 = GPGDAT;


    if (irq == 0) /* eint0 : s2 控制 D12 */

    {

        if (val1 & (1<<0)) /* s2 --> gpf6 */

        {

            /* 松开 */

            GPFDAT |= (1<<6);

        }

        else

        {

推荐阅读

史海拾趣

Blue Creation公司的发展小趣事

Blue Creation公司在电子行业的起步并不顺利,一度面临资金短缺和技术瓶颈。然而,公司创始人凭借对技术的深厚理解,带领团队开发出一款革命性的电源管理技术。这项技术不仅大幅提高了电子设备的续航能力,还降低了能耗,迅速赢得了市场的青睐。随着技术的不断迭代和完善,Blue Creation逐渐在电子行业崭露头角。

中微股份(Cmsemicon)公司的发展小趣事

2019年,中微股份(Cmsemicon)迎来了又一个重要时刻——成为科创板首批上市公司之一。这一荣誉不仅是对公司过去成绩的肯定,也为公司的未来发展提供了更多的资金支持。上市以来,公司充分利用资本市场的优势,加大研发投入,推动技术创新和产品升级。同时,公司还积极拓展国际市场,提升品牌影响力。

Ecera Comtek Corp公司的发展小趣事

在竞争激烈的电子行业中,Ecera Comtek Corp公司意识到只有不断创新才能在市场中立足。于是,公司加大了研发投入,引进了一批高端技术人才。经过长时间的研发,Ecera Comtek Corp公司成功研发出了一种新型的信号处理技术,大大提高了无线通信设备的传输速度和稳定性。这一技术突破迅速引起了市场的关注,Ecera Comtek Corp公司的产品在市场上受到了热烈的欢迎,公司的销售额也实现了快速增长。

倍思特(BEST)公司的发展小趣事

随着公司实力的不断增强,Ecera Comtek Corp公司开始寻求更广阔的发展空间。公司决定进军国际市场,拓展海外业务。然而,国际市场的竞争更加激烈,Ecera Comtek Corp公司面临着来自全球各地的强大竞争对手。为了应对这一挑战,Ecera Comtek Corp公司加强了与国际合作伙伴的联系,共同研发新产品,开拓新市场。同时,公司还加大了对海外市场的宣传力度,提高了品牌的知名度和美誉度。经过几年的努力,Ecera Comtek Corp公司的产品逐渐在国际市场上获得了认可,海外业务也取得了显著的进展。

台湾岱恩(DAIN)公司的发展小趣事

在竞争激烈的电子行业中,Ecera Comtek Corp公司意识到只有不断创新才能在市场中立足。于是,公司加大了研发投入,引进了一批高端技术人才。经过长时间的研发,Ecera Comtek Corp公司成功研发出了一种新型的信号处理技术,大大提高了无线通信设备的传输速度和稳定性。这一技术突破迅速引起了市场的关注,Ecera Comtek Corp公司的产品在市场上受到了热烈的欢迎,公司的销售额也实现了快速增长。

BNS Solutions公司的发展小趣事

随着技术的不断进步,BNS Solutions公司意识到,要想在竞争激烈的电子行业中保持领先地位,必须不断拓展市场并寻求战略合作。于是,公司开始积极拓展国内外市场,与多家知名企业和机构建立了紧密的合作关系。通过合作,BNS Solutions公司不仅获得了更多的资源和支持,还成功将产品推广到了更广泛的市场领域。同时,公司还积极参与行业交流活动,不断提升自身在行业内的影响力和地位。

问答坊 | AI 解惑

关于直插LED与SMDLED和大功率LED的投资分析

关于直插LED与SMDLED和大功率LED的投资分析 因近段时间有很多朋友问关于投资以上三类型的LED,个人仅发表一些看法: 1.直插LED投资发展最快的几年是在02年至05年(相信这时候开厂的已经赚的盆满钵满了);凡有钱的都做直插的LED了,并且现在有很 ...…

查看全部问答>

windowsXP DDK 如何连接一个中断?(KInterrupt?)

我只找到了KInterrupt这个类:但是问题出现如下 KInterrupt::Initialize 两种 格式 FORM 2: (WDM) VOID    Initialize(    KIRQL irql,    ULONG vector,    KINTERRUPT_MODE Mode,     ...…

查看全部问答>

求一份WtpTool Download完整原版代码

marvell的cpu智能机板子,要做一个自己的下载工具 email:killbug2004@gmail.com 另外麻烦讲一下基于usb下载的流程 中间有个VerifyImage不懂,文件下载id设置也不太清楚 谢谢达人…

查看全部问答>

关于VHDL程序设计的三个问题~请教!!!

1。在仿真中,有些非端口信号,例如SIGNAL ,VARIABLE,在node finder的 all list中 还是没有,没法建立它们的仿真波形,该怎么办,而且有的SIGNAL可以看到,有的看不到,这是为什么?(QUARTUSII) 2。在PROCESS中,这个PROCESS是 TYPE state IS ...…

查看全部问答>

A/D转换位数和分辨率

我正要做一个项目,输入信号是±4V,显示范围是0---99999,要求输入信号变化时,显示数据的最后一个位的最小变化是一个字。 即00001-00002---00003向这样的趋势变化,请问我要选择几位的A/D芯片呢,是怎样计算出来的呢? 还请指教!!!…

查看全部问答>

求51+sl811读写U盘的源程序+原理图

在网上有下了《51+sl811读写U盘的源程序+原理图》的原代码,但找不到原理图,请问哪位大哥有可以寄一份给我,或告知下载地址。谢谢! 我邮箱是: power_wjc@163.com…

查看全部问答>

[求助]请问大家一个关于视频的问题

我用1394转接卡接一个摄像头,然后在屏幕上实时的显示摄像头拍得图像,但是在启动初始化的时候(大概10次中有1次),显示在屏幕上的图像错位了,图像的1/3跑到下面去了,而且一直保持这样,要让图像正常只能重启,有人说是同步问题,但我觉得不像, ...…

查看全部问答>

我编译binutils到ARM上用,可是没有make过,请帮忙看一下!!

我先是 ./configure -target=arm-linux生成 Makefile 然后执行 make ,提示如下: // 我查了一下 regex.c中定义了个 char *malloc(); 在stdlib.h中void *malloc (size_t __size),我用的是gcc编译器,如果函数重载c++也可以通过 make[1]: Leav ...…

查看全部问答>

SWIM+STLINK连接不成功

STLINK 与STM8连接不成功。附图:硬件连接有问题吗?或者是STVP的配置有问题。 现在不是下载或者调试问题,而是STLINK识别不到有STM8S的存在:can not connect the device (当时的消息栏忘记抓图了) 初次使用STM8S(具体型号是STM8S103F3P ...…

查看全部问答>

讨论一个功耗问题

msp430的功耗非常低。如果用msp430+分段式LCD显示屏做一个小电子钟,这样两节南孚电池能用多久。…

查看全部问答>