×
嵌入式 > 嵌入式开发 > 详情

S5PV210的中断应用实例

发布时间:2020-07-10 发布时间:
|

实验程序可以从四个方面设计:一是启动程序的设计,主要是对ARM工作模式的配置和中断服务程序的设计;二是初始化程序,包括S5PV210中断控制器的初始化、GPIO引脚的配置;三是主程序设计;最后编写Makefile,编译生成目标文件。下面就从这四方面编写测试代码以及代码的详解。

1.启动程序start.S

前面已介绍过,S5PV210本身的固化代码(iROM)在上电后配置好IRQ中断的栈,以及系统模式所使用的栈,所以在启动代码中可以不用设置这些栈(如果重新配置也可以),所以实验的启动程序比较简单,主要是当中断发生时先保存现场,跳到中断服务程序执行中断处理,处理结束再恢复现场。具体代码示例如下:

01 .text

02 .global _start/*声明一个全局的标号*/

03 .global IRQ_handle

04_start:

06mrs r0,cpsr

07bic r0,r0,#0x00000080/*使能IRQ中断bit[7]=0 */

08msr cpsr,r0

09bl main

10 halt_loop:

11bhalt_loop/*死循环,不让程序跑飞*/

12

13 IRQ_handle:

14sub lr, lr, #4/*计算返回地址*/

15stmdb sp!, {r0-r12, lr} /*保存用到的寄存器*/

16bl irq_handler/*跳到中断服务函数*/

17ldmia sp!, {r0-r12, pc}^/*中断返回, ^表示将spsr的值复制到cpsr */

2.初始化阶段

初始化阶段重点讲下外部中断控制寄存器的配置方法,以及中断向量控制寄存器的设置,关于LED相关的引脚配置不作重复介绍。

……

08 #define GPH0CON*((volatile unsigned int *)0xE0200C00)

09 #define GPH0DAT*((volatile unsigned int *)0xE0200C04)

10 #define EXT_INT_0_CON*((volatile unsigned int *)0xE0200E00)

11 #define EXT_INT_0_MASK*((volatile unsigned int *)0xE0200F00)

12

13 #define VIC0IRQSTATUS*((volatile unsigned int *)0xF2000000)

14 #define VIC0INTSELECT*((volatile unsigned int *)0xF200000C)

15 #define VIC0INTENABLE*((volatile unsigned int *)0xF2000010)

16 #define VIC0VECTADDR0*((volatile unsigned int *)0xF2000100)

17 #define VIC0VECTADDR1*((volatile unsigned int *)0xF2000104)

18 #define VIC0ADDRESS*((volatile unsigned int *)0xF2000F00)

19

20 extern void IRQ_handle(void);

……

38 //配置中断引脚

39 void init_key(void)

40 {

41//配置GPIO引脚为中断功能

42GPH0CON &= ~(0xFF<<0);

43GPH0CON |= (0xFF<<0); // key1:bit[3:0];key2:bit[7:4]

44//配置EXT_INT[0]、EXT_INT[1]中断为下降沿触发

45EXT_INT_0_CON &= ~(0xFF<<0);

46EXT_INT_0_CON |= 2|(2<<4);

47//取消屏蔽外部中断EXT_INT[0]、EXT_INT[1]

48EXT_INT_0_MASK &= ~0x3;

49 }

50//清中断挂起寄存器

51 void clear_int_pend()

52 {

53EXT_INT_0_PEND |= 0x3; // EXT_INT[0]、EXT_INT[1]

54 }

55 //初始化中断控制器

56 void init_int(void)

57 {

58//选择中断类型为IRQ

59VIC0INTSELECT = ~0x3; //外部中断EXT_INT[0]、EXT_INT[1]为IRQ

60//清VIC0ADDRESS

61VIC0ADDRESS = 0x0;

62//设置EXT_INT[0]、EXT_INT[1]对应的中断服务程序的入口地址

63VIC0VECTADDR0 = (int)IRQ_handle;

64VIC0VECTADDR1 = (int)IRQ_handle;

65//使能外部中断EXT_INT[0]、EXT_INT[1]

66VIC0INTENABLE |= 0x3;

67 }

68 //清除需要处理的中断的中断处理函数的地址

69 void clear_vectaddr(void)

70 {

71VIC0ADDRESS = 0x0;

72 }

73 //读中断状态

74 unsigned long get_irqstatus(void)

75 {

76return VIC0IRQSTATUS;

77 }

3.主程序

开发板上电后就会跳到主程序main执行,主程序main中主要是对各初始化函数的调用,另外main.c中还定义了一个中断处理函数,也就是当相应的中断发生后,CPU需要跳过去执行的具体内容,这里主要是点灯或灭灯。

01 extern void init_leds(void);//其他源文件中定义的函数在此声明

02 extern void clear_int_pend();

03 extern void led1_on_off();

04 extern void led2_on_off();

05 extern void init_key(void);

06 extern void init_int(void);

07 extern void clear_vectaddr(void);

08 extern unsigned long get_irqstatus(void);

09 void irq_handler()

10 {

11volatile unsigned char key_code = get_irqstatus() & 0x3;// VIC0's status

12clear_vectaddr();/*清中断向量寄存器*/

13clear_int_pend();/*清pending位*/

14if (key_code == 1)/* key1 */

15led1_on_off();

16else if (key_code == 2) /* key2 */

17led2_on_off();

18else

19{

20led1_on_off();

21led2_on_off();

22}

23 }

24 int main(void)

25 {

26int c = 0;

27

28init_leds();/*初始化GPIO引脚*/

29init_key();/*初始化按键中断*/

30init_int();/*初始化中断控制器、使能中断*/

31

32while (1);

33 }

4.编写Makefile

01 objs := start.o init.o main.o

02

03 int.bin: $(objs)

04arm-linux-ld -Ttext 0xD0020010 -o int.elf $^

05arm-linux-objcopy -O binary -S int.elf $@

06arm-linux-objdump -D int.elf > int.dis

07

08 %.o : %.c

09arm-linux-gcc -c -O2 $< -o $@

10

11 %.o : %.S

12arm-linux-gcc -c -O2 $< -o $@

13

14 clean:

15rm -f *.o *.elf *.bin *.dis

将以上编写好的源代码上传到宿主机上编译生成可执行的目标文件int.bin,然后烧写到开发板上电测试。

实验最终结果是:当按下“KEY1”,LED1灯会被点亮或熄灭;当按下“KEY2”,LED2灯会被点亮或熄灭。



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
一只老鸟的嵌入式ARM学习心得