[Linux]异常与中断

[Linux]异常与中断

艾恩凝

2021/4/1

INTRODUCTION

这个部分手册内容也不是很多,大体看了看,主要分为两种模式一种是ARM模式另一种是thumb,对于现在的硬件水平来说thumb可以直接考虑不看,毕竟现在不是内存不够用的时代,能跑linux的性能不会太差。arm4字节,thumb2字节。

关于异常和中断,说白了就是异常,中断也算是异常的一种,就像你在路上正常走着,突然来了个姑娘,你的目光从看路转向了姑娘,这个时候就是异常,或者中断,当处理完了,也就是看完了姑娘之后,你又继续走路,这就是一个完美的中断,程序正常运行来了个突发事故,先处理这个,然后接着继续正常的程序。

详细介绍

yi001.png

上图介绍了这芯片异常的几种模式,用户模式,系统模式,未定义,管理模式,终止模式,中断模式,快中断模式。

yi002.png

上图是对应的寄存器,黑色三角形的是另外单独的寄存器。

yi003.png

这个图则说明了程序状态寄存器的格式,总共32位,中间是保留位,其他都注明了每一位代表的意思。

yi004.png

这个图对应了上一张图后5位,代表了7种不同的模式

yi005.png

上面对应了各种模式地址。

裸板中断LED

 1/* 执行到这里之前:
 2	 * 1. lr_irq保存有被中断模式中的下一条即将执行的指令的地址
 3	 * 2. SPSR_irq保存有被中断模式的CPSR
 4	 * 3. CPSR中的M4-M0被设置为10010, 进入到irq模式
 5	 * 4. 跳到0x18的地方执行程序 
 6	 */
 7
 8	/* sp_irq未设置, 先设置它 */
 9	ldr sp, =0x33d00000
10
11	/* 保存现场 */
12	/* 在irq异常处理函数中有可能会修改r0-r12, 所以先保存 */
13	/* lr-4是异常处理完后的返回地址, 也要保存 */
14	sub lr, lr, #4
15	stmdb sp!, {r0-r12, lr}  
16
17	/* 处理irq异常 */
18	bl handle_irq_c
19
20	/* 恢复现场 */
21	ldmia sp!, {r0-r12, pc}^  /* ^会把spsr_irq的值恢复到cpsr里 */

中断汇编代码

  1
  2/* SRCPND 用来显示哪个中断产生了, 需要清除对应位
  3 * bit0-eint0
  4 * bit2-eint2
  5 * bit5-eint8_23
  6 */
  7
  8/* INTMSK 用来屏蔽中断, 1-masked
  9 * bit0-eint0
 10 * bit2-eint2
 11 * bit5-eint8_23
 12 */
 13
 14/* INTPND 用来显示当前优先级最高的、正在发生的中断, 需要清除对应位
 15 * bit0-eint0
 16 * bit2-eint2
 17 * bit5-eint8_23
 18 */
 19
 20/* INTOFFSET : 用来显示INTPND中哪一位被设置为1
 21 */
 22
 23/* 初始化中断控制器 */
 24void interrupt_init(void)
 25{
 26	INTMSK &= ~((1<<0) | (1<<2) | (1<<5));
 27}
 28
 29/* 初始化按键, 设为中断源 */
 30void key_eint_init(void)
 31{
 32	/* 配置GPIO为中断引脚 */
 33	GPFCON &= ~((3<<0) | (3<<4));
 34	GPFCON |= ((2<<0) | (2<<4));   /* S2,S3被配置为中断引脚 */
 35
 36	GPGCON &= ~((3<<6) | (3<<22));
 37	GPGCON |= ((2<<6) | (2<<22));   /* S4,S5被配置为中断引脚 */
 38
 39
 40	/* 设置中断触发方式: 双边沿触发 */
 41	EXTINT0 |= (7<<0) | (7<<8);     /* S2,S3 */
 42	EXTINT1 |= (7<<12);             /* S4 */
 43	EXTINT2 |= (7<<12);             /* S5 */
 44
 45	/* 设置EINTMASK使能eint11,19 */
 46	EINTMASK &= ~((1<<11) | (1<<19));
 47}
 48
 49/* 读EINTPEND分辨率哪个EINT产生(eint4~23)
 50 * 清除中断时, 写EINTPEND的相应位
 51 */
 52
 53
 54void key_eint_irq(int irq)
 55{
 56	unsigned int val = EINTPEND;
 57	unsigned int val1 = GPFDAT;
 58	unsigned int val2 = GPGDAT;
 59
 60	if (irq == 0) /* eint0 : s2 控制 D12 */
 61	{
 62		if (val1 & (1<<0)) /* s2 --> gpf6 */
 63		{
 64			/* 松开 */
 65			GPFDAT |= (1<<6);
 66		}
 67		else
 68		{
 69			/* 按下 */
 70			GPFDAT &= ~(1<<6);
 71		}
 72
 73	}
 74	else if (irq == 2) /* eint2 : s3 控制 D11 */
 75	{
 76		if (val1 & (1<<2)) /* s3 --> gpf5 */
 77		{
 78			/* 松开 */
 79			GPFDAT |= (1<<5);
 80		}
 81		else
 82		{
 83			/* 按下 */
 84			GPFDAT &= ~(1<<5);
 85		}
 86
 87	}
 88	else if (irq == 5) /* eint8_23, eint11--s4 控制 D10, eint19---s5 控制所有LED */
 89	{
 90		if (val & (1<<11)) /* eint11 */
 91		{
 92			if (val2 & (1<<3)) /* s4 --> gpf4 */
 93			{
 94				/* 松开 */
 95				GPFDAT |= (1<<4);
 96			}
 97			else
 98			{
 99				/* 按下 */
100				GPFDAT &= ~(1<<4);
101			}
102		}
103		else if (val & (1<<19)) /* eint19 */
104		{
105			if (val2 & (1<<11))
106			{
107				/* 松开 */
108				/* 熄灭所有LED */
109				GPFDAT |= ((1<<4) | (1<<5) | (1<<6));
110			}
111			else
112			{
113				/* 按下: 点亮所有LED */
114				GPFDAT &= ~((1<<4) | (1<<5) | (1<<6));
115			}
116		}
117	}
118
119	EINTPEND = val;
120}
121
122
123void handle_irq_c(void)
124{
125	/* 分辨中断源 */
126	int bit = INTOFFSET;
127
128	/* 调用对应的处理函数 */
129	if (bit == 0 || bit == 2 || bit == 5)  /* eint0,2,eint8_23 */
130	{
131		key_eint_irq(bit); /* 处理中断, 清中断源EINTPEND */
132	}
133
134	/* 清中断 : 从源头开始清 */
135	SRCPND = (1<<bit);
136	INTPND = (1<<bit);
137}
138
139

CONCLUSION

等着定时器最后熟悉完,裸板就算是基本结束了,正式进入linux


    


公众号'艾恩凝'
个人公众号
个人微信
个人微信
    吾心信其可行,
          则移山填海之难,
                  终有成功之日!
                                  ——孙文
    评论
    0 评论
avatar

取消