历史上的今天
返回首页

历史上的今天

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

正在发生

2021年09月06日 | S3C2440 按键中断

2021-09-06 来源:eefocus

中断也是一种异常,但中断较为复杂一点,除了一般异常的处理流程


保护现场

处理 (handle_irq_c )

判断中断源 [INTOFFSET]

跳到中断处理函数 (key_action)[EINTPEND]

清除中断 [SRCPND] [INTBEND]

恢复现场

当然还有寄存器设置函数 key_enit_init [EXTINTn] [EINTPEND]


更为甚者,我们可以来参考手册上的流程图

这里是引用

对于我们的按键中断来讲,都是without sub-register。


寄存器

使用什么外设,其实都是和寄存器打交道。那么,这次又和哪些寄存器打交道呢。


总中断寄存器

[INTMASK] Determine which interrupt source is masked.

The masked interrupt source will not be

serviced.(需要设置,在 register_irq 里设置)

[INTBEND] Indicate the interrupt request status.(需要清零, handle_irq_c )

[INTOFFSET] Indicate the IRQ interrupt request source(只读, handle_irq_c )

[SRCPND] Indicate the interrupt request status.(需要清零, handle_irq_c )

INTMSK 寄存器 中断屏蔽寄存器,置1是屏蔽中断源,置0是使能,默认是全部屏蔽,所以需要设置。


地址:0X4A000008

[0] : EINT0 = 0x0(S2 - EINT0)

[2] : EINT2 = 0x0(S3 ~ EINT2)

[5] : EINT8_23 = 0x0(S4 ~ EINT11,S5 ~ EINT19)

即 [0X4A000008] &= ((0<<0) | (0<<2) | (0<<5))

INTPND 寄存器 Indicate the interrupt request status.


地址: 0X4A000010

表明被请求了的寄存器

[0] : EINT0 (S2 - EINT0)

[2] : EINT2 (S3 ~ EINT2)

[5] : EINT8_23 (S4 ~ EINT11,S5 ~ EINT19)

INTOFFSET 寄存器 Indicate the IRQ interrupt request source


地址:0x4A000014

只读寄存器

0 : EINT0 (S2 - EINT0)

2 : EINT2 (S3 ~ EINT2)

5 : EINT8_23 (S4 ~ EINT11,S5 ~ EINT19)

SRCPND寄存器 Indicate the interrupt request status.

一共32位代表不同的中断,置0是关闭中断,置1是使能中断


地址: 0X4A000000

[0] : EINT0 = 0x1(S2 - EINT0)

[2] : EINT2 = 0x1(S3 ~ EINT2)

[5] : EINT8_23 = 0x1(S4 ~ EINT11,S5 ~ EINT19)

外部(按键)中断设置

[EXTINT0] / [EXTINT1] / [EXTINT2]

External interrupt control register 0 / 1 / 2(需要设置, key_enit_init )

[EINTMASK] External interrupt mask register (需要设置, key_enit_init )

[EINTPEND] External interrupt pending register(需要清零, key_action)

EXTINT0 寄存器 External interrupt control register 0


地址:0x56000088

[2:0] :EINT0 = 0x111(11x = Both edge triggered)

[10:8]:EINT2 = 0x111(11x = Both edge triggered)

EXTINT1 寄存器 External interrupt control register 1

地址:0x5600008c


[14:12] :EINT11 = 0x111(11x = Both edge triggered)

EXTINT2 寄存器 External interrupt control register 2

地址:0x56000090


[14:12] :EINT19 = 0x111(11x = Both edge triggered)

EINTMASK 寄存器 外部中断屏蔽寄存器,置1是屏蔽中断源,置0是使能,默认是全部屏蔽,所以需要设置。


地址:0x560000a4(External interrupt mask register )

[11] :EINT11 = 0x0

[19] :EINT19 = 0x0

EINTPEND 寄存器 判断哪个中断发生


地址:0x560000a8(External interrupt pending register)

逐一对应

中断流程

首先是按键中断的各种寄存器初始化,这个真少不了。


/* 初始化按键中断 */

void key_eint_init()


{

/* 初始化按键寄存器

* 设置GPFCON的GPF0/2、GPG3/11为中断引脚 

*  按键寄存器 

* C_S2 ~ 0  ~ GPF0 

* C_S3 ~ 4  ~ GPF2 

* C_S4 ~ 6  ~ GPG3 

* C_S5 ~ 22 ~ GPG11 

* D_S2 ~ 0  ~ GPF0 

* D_S3 ~ 2  ~ GPF2 

* D_S4 ~ 3  ~ GPG3 

* D_S5 ~ 11 ~ GPG11 

*/

GPFCON &= ~((3< GPGCON &= ~((3<

GPFCON |=  ((2< GPGCON |=  ((2<

/* EXTINT0 寄存器 External interrupt control register 0

- 地址:0x56000088

- [2:0]  :EINT0 = 0x111(11x = Both edge triggered)

- [10:8] :EINT2 = 0x111(11x = Both edge triggered)


* EXTINT1 寄存器 External interrupt control register 1

* 地址:0x5600008c

- [14:12] :EINT11 = 0x111(11x = Both edge triggered)


* EXTINT2 寄存器 External interrupt control register 2

* 地址:0x56000090

- [14:12] :EINT19 = 0x111(11x = Both edge triggered)

 

* EINTMASK 寄存器 I/O中断屏蔽寄存器,置1是屏蔽中断源,置0是使能,默认是全部屏蔽,所以需要设置。

- 地址:0x560000a4(External interrupt mask register ) 

- [11] :EINT11 = 0x0

- [19] :EINT19 = 0x0

*/

EXTINT0 |= ((7<<0) | (7<<8)); /* s2, s3*/

EXTINT1 |= ((7<<12)); /* s4 */

EXTINT2 |= ((7<<12)); /* s5 */


EINTMASK &= ~((1<<11) | (1<<19)); /* 使能外部中断,关闭屏蔽信号 */


register_irq(0, key_irq);

register_irq(2, key_irq);

register_irq(5, key_irq);

}


一按下按键,硬件处理,首先就会跳到向量组 vector 0x18,通过汇编跳到 do_irq, 在这里完成保护现场和恢复现场,处理异常跳到c函数 handle_irq_c 。


do_irq:

/* 重要!栈未设置,需要重新设置,指向一个不会被用到的地方 */

ldr sp, =0x33d00000


/* 保护现场 */

sub lr, lr, #4 //根据lr恢复规则,异常前的lr-4 = 异常后的lr

stmdb sp!, {r0-r12, lr} //目前位置 lr 里面有被打断前的下一条将要执行的指令,所以也要保存

/* 处理异常 */

bl handle_irq_c


/* 恢复现场 */

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


来到函数 handle_irq_c,做三个动作,分别是分辨中断源和清除中断,处理中断通过 irq_array[bit](bit) 语句跳转,这个其实是函数指针,in this case,处理函数是 key_action,里面就可以处理按键按下后的事情,整个中断流程至此。


typedef void(*irq_func)(int);

irq_func irq_array[32];


void handle_irq_c()

{

/* 分辨中断源 */


/*INTOFFSET 寄存器** Indicate the IRQ interrupt request source

- 地址:0x4A000014

    只读寄存器

- 0 : EINT0 (S2 - EINT0)

  - 2 : EINT2 (S3 ~ EINT2)

  - 5 : EINT8_23 (S4 ~ EINT11,S5 ~ EINT19)

  */

int bit = INTOFFSET; //读出来是哪个中断



/* 处理中断 */

irq_array[bit](bit);


/* 清除中断 */

SRCPND = (1< INTPND = (1<}


还有一个问题没解决 irq_array[bit](bit) 怎么指向 key_irq ?


我们搞一个函数,注册中断函数 ,在里面顺便设置中断屏蔽


/* 注册中断的指针函数, 附加使能总中断

 * irq - 第几个处理函数,fp - 传入的中断处理函数

 */

void register_irq(int irq, irq_func fp)

{


irq_array[irq] = fp;


/* [INTMSK] 寄存器  中断屏蔽寄存器

* 置1是屏蔽中断源,置0是使能,默认是全部屏蔽,所以需要设置。

- 地址:0X4A000008

- [0] : EINT0 = 0x0(S2 - EINT0)

- [2] : EINT2 = 0x0(S3 ~ EINT2)

- [5] : EINT8_23 = 0x0(S4 ~ EINT11,S5 ~ EINT19)

-  即 [0X4A000008] &= ((0<<0) | (0<<2) | (0<<5))

*/

INTMSK &= ~(1<}


相关代码

中断初始化(总/外部中断)


/* 初始化中断控制器 */

void interrput_init()

{

/* SRCPND寄存器 Indicate the interrupt request status.

* 一共32位代表不同的中断,置0是关闭中断,置1是使能中断

- 地址: 0X4A000000

- [0] : EINT0 = 0x1(S2 - EINT0)

- [2] : EINT2 = 0x1(S3 ~ EINT2)

- [5] : EINT8_23 = 0x1(S4 ~ EINT11,S5 ~ EINT19)

 

* INTMSK 寄存器  中断屏蔽寄存器

* 置1是屏蔽中断源,置0是使能,默认是全部屏蔽,所以需要设置。

- 地址:0X4A000008

- [0] : EINT0 = 0x0(S2 - EINT0)

- [2] : EINT2 = 0x0(S3 ~ EINT2)

- [5] : EINT8_23 = 0x0(S4 ~ EINT11,S5 ~ EINT19)

-  即 [0X4A000008] &= ((0<<0) | (0<<2) | (0<<5))

*/


INTMSK &= ~((1<<0) | (1<<2) | (1<<5));

 

}


按键中断处理

/* 按键处理函数,包括按键处理

irq - 0 : EINT0 (S2 - EINT0)

irq - 2 : EINT2 (S3 ~ EINT2)

irq - 5 : EINT8_23 (S4 ~ EINT11,S5 ~ EINT19)


*/

int key_action(int irq)

{

unsigned int val = EINTPEND;



/* S2-GPF0 、 S3-GPF2 、 S4 - GPG3

* S2~GPF6、S3~GPF5、S4~GPF4

* 如果按键对应DAT寄存器是零,即按键按下,反之 

*/


/* S2控制LED3 */

if (irq == 0)

{

if (GPFDAT&(1< GPFDAT |=  (1< }

else{

GPFDAT &= ~(1< }

}

/* S3控制LED2 */

else if (irq == 2)

{

if (GPFDAT&(1< GPFDAT |=  (1< }

else{

GPFDAT &= ~(1< }

}


/* S4控制LED1 */

else if (irq == 5)

{

if (val & (1<<11))

{

if (GPGDAT&(1< GPFDAT |=  (1< }

else{

GPFDAT &= ~(1<

}

else if (val & (1<<19))

{


if (GPGDAT&(1< GPFDAT |=  ((1< }

else{

GPFDAT &= ~((1< }

}


}

EINTPEND = val; //清除外部中断

}


void handle_irq_c()

{

/* 分辨中断源 */



/*INTOFFSET 寄存器** Indicate the IRQ interrupt request source

- 地址:0x4A000014

    只读寄存器

- 0 : EINT0 (S2 - EINT0)

  - 2 : EINT2 (S3 ~ EINT2)

  - 5 : EINT8_23 (S4 ~ EINT11,S5 ~ EINT19)

  */

int bit = INTOFFSET; //读出来是哪个中断



/* 处理中断 */

if(bit == 0 || bit == 2 || bit == 5)

key_action(bit);


/* 清除中断 */

SRCPND = (1< INTPND = (1<}


汇编

_start:

b reset /* 0x30000000 */

// ldr pc, =do_und /* 0x30000004 */

ldr pc, und_addr

ldr pc, swi_addr

b halt /* vector 0x0c : prefetch aboot */

b halt /* vector 0x10 : data abort */

b halt /* vector 0x14 : reserved */

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

b halt /* vector 0x1c : fiq */

……

do_irq:

/* 重要!栈未设置,需要重新设置,指向一个不会被用到的地方 */

ldr sp, =0x33d00000


/* 保护现场 */

sub lr, lr, #4 //根据lr恢复规则,异常前的lr-4 = 异常后的lr

stmdb sp!, {r0-r12, lr} //目前位置 lr 里面有被打断前的下一条将要执行的指令,所以也要保存

/* 处理异常 */

bl handle_irq_c


/* 恢复现场 */

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

推荐阅读

史海拾趣

Discera公司的发展小趣事

在成功进入军用市场后,Discera公司开始将目光投向更广阔的商用市场。他们积极与各大电子厂商合作,推广自己的CMOS MEMS谐振器产品。随着技术的不断普及和成本的降低,越来越多的商用电子产品开始采用Discera的谐振器产品,公司的市场份额也逐步扩大。

苏州锋驰(Feng)公司的发展小趣事
能够提供恒定的电流输出,确保负载器件在不同工作条件下得到稳定的电流供应。
Horn公司的发展小趣事

在追求经济效益的同时,Horn公司也注重可持续发展。公司积极采用环保材料和绿色生产工艺,减少对环境的影响。此外,Horn公司还注重人才培养和团队建设,为公司的长期发展奠定了坚实的人才基础。展望未来,Horn公司将继续秉承“创新、质量、服务”的企业理念,致力于成为切削工具行业的领导者,为全球客户提供更加优质的产品和服务。

Dino-Lite公司的发展小趣事

Dino-Lite公司自创立之初,就专注于数字显微镜技术的研发与创新。公司研发团队不断探索新技术,将传统显微镜与现代数字技术相结合,成功推出了一系列高性能、易用性强的Dino-Lite数字显微镜产品。这些产品以其高清画质、便捷操作和广泛适用性,迅速赢得了市场的认可。

随着技术的不断进步,Dino-Lite公司不断推出新产品,满足了不同行业对数字显微镜的需求。例如,公司针对医疗领域推出了高分辨率、低光环境下的专业显微镜,为医疗诊断和治疗提供了有力支持;同时,针对教育行业推出了性价比高的入门级产品,让更多的学生和老师能够接触和使用到先进的显微镜技术。

诚芯微(CXW)公司的发展小趣事

在2020年,诚芯微与BYD、小米、公牛等知名企业建立了战略合作伙伴关系,共同推动电源芯片在汽车电子、智能家居等领域的应用。通过与这些行业巨头的合作,诚芯微不仅拓展了市场渠道,还提升了品牌影响力。同时,公司还加大了对新能源汽车电源管理芯片的研发力度,为新能源汽车产业的发展提供了有力支持。

巨盛电子(Chesen)公司的发展小趣事

在电子行业,成本控制对于企业的竞争力至关重要。巨盛电子(Chesen)通过优化供应链管理,实现了成本的降低。公司与供应商建立了长期稳定的合作关系,实现了原材料的规模化采购和成本控制。同时,公司还加强了对生产过程的监控和管理,降低了生产过程中的浪费和损耗。这些措施使得巨盛电子在保持产品质量的同时,实现了成本的降低,提高了企业的盈利能力。

问答坊 | AI 解惑

电源产业的发展趋势

[&]纵观当今国内外电源,不难看出显著的特点是:电源门类多,涉及技术相当全面,且技术含量高,但核心技术应是电能变换和功率传递技术,是光、机、电一体化,新能源与高效节能等多个高新技术领域的复合。当今的开关电源门类就是这些技术复合型的 ...…

查看全部问答>

44b0能用IAR编写程序吗

如果用ads开发 是不是每个程序都要用到44b0的启动代码 不同程序启动代码都一样吗 我听说用iar开发不用启动代码   和用keil一样 44b0+iar+jtag 可以吗…

查看全部问答>

有关波特率的知识【很精辟】

一. 波特率   并行通信中,传输速率是以每秒传送多少字节(B / S)来表示。而串行通信中,传输速率在基波传输的情况下(不加调制,以其固有的频率传送)是用每秒钟传送的位数(bit/s)即波特率来表示。因此,1波特=1位/秒。   最常用的标 ...…

查看全部问答>

RELEASETYPE is not set. Using default settings.

今天编译CE5.0内核遇到这么个警告: RELEASETYPE is not set. Using default settings. 结果导致编译出错,而用同样的BSP在我同事的机子上却没事,所以我怀疑是PB出了问题,哪位大侠给指点一下…

查看全部问答>

Unicode问题 进来看看

用c# 调用ril 函数发送at 命令,可是 发送命令貌似发送到底层貌似解码是错的 求高手解释一下  字符串应该怎么重新编码。 …

查看全部问答>

怎么构建PXA270的交叉编译环境

我买了一本书《ARM嵌入式从入门到精通》其中第二章有关于分步构建交叉编译环境的内容,但是按书上说的去做总是有错,已经失败了N次,。。。。…

查看全部问答>

帮忙看一下,输入的信号被忽略了!

程序实现功能如下: 通过clk的脉冲,在recive=0时统计clk的跳变数,达到计时的目的,再把时间通过4个七段数码管显示出来。 程序代码如下: library ieee; use ieee.std_logic_1164.all; entity device is port(clk        ...…

查看全部问答>

我的ZLG M0估计杯具了

今天兴高采烈的在调 PWM程序 弄示波器探头接触引脚的时候 貌似出现了点火花  我也没太在意 出现了波形 可是频率差了点 于是乎准备重新载程序 突然就出现了 我想估计芯片毁了…

查看全部问答>

BIOS\"任务\"对象的问题.

请教各位:      在BIOS中,我用TSK0调用函数test(),硬件中断INT1调用T0ISR().运行程序后,程序一直进入T0ISR(),而不调用\\"任务\\"对象.不应该是在两次中断之间的时间里,会调用TSK0吗?或者是需要什么API函数调用? 部分程序 ...…

查看全部问答>

AT89C51控制M62429的程序谁有?

AT89C51控制M62429程序中的发送6位数据和发送5位数据子程序我不会作,谁能教教我?…

查看全部问答>