异常与中断

听了韦老师的异常与中断,这大节课。大概思想很清晰,但让我自己写代码,铁定写不出来的,还是有点迷糊。我暂且把自己理解的部分记录下来,以后完全理解再来修改此文。 异常发生并处理的框架流...

听了韦老师的异常与中断,这大节课。大概思想很清晰,但让我自己写代码,铁定写不出来的,还是有点迷糊。我暂且把自己理解的部分记录下来,以后完全理解再来修改此文。

异常发生并处理的框架流程图

attachments-2020-05-d19O6kba5eb3f685a9549.png


异常处理流程(硬件):

发生异常:

(1).把下一条指令的地址保存再LR寄存器当中(即LR_异常=被中断模式的下一条指令地址)

(2).SPSR_异常=CPSR

(3).修改CPSR的M4~M0,进入异常模式

(4).跳到向量表

离开异常:

(1).从异常模式返回去(PC=LR_异常-offset),offset据情况而定,不同异常值也不同

(2).CPSR=SPSR_异常模式(之前保存的)

(3).清中断

通过看电路图和芯片手册来观察引脚

如图1所示,为按键的引脚和led灯的引脚,可以观察得到我们用到的引脚分别为

按键相关:EINT0、EINT2、EINT11、EINT19

led相关:nLED_1、nLED_2、nLED_4

attachments-2020-05-uwmnh9US5eb3fc2c22fe3.png

                                                             图1

顺藤摸瓜,根据按键的引脚来进入2440的芯片手册。可以发现,我们走的是下面这条分支(without sub -register、)

attachments-2020-05-N91g7s3c5eb3fd6622c3b.png接下来我们来初始化中断控制器

INTMSK中关于按键的寄存器如下,由以上分析可知,我们需要设置第0、2、5位引脚为0

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

attachments-2020-05-Nv0g0Dpa5eb401ae042da.png

初始化按键、设为中断源。涉及到的寄存器为GPFCON、EXTINT0、EXTINT1、EXTINT2、EINTMASK

	/* 配置GPIO为中断引脚 */
	GPFCON &= ~((3<<0) | (3<<4));
	GPFCON |= ((2<<0) | (2<<4));   /* S2,S3被配置为中断引脚 */

	GPGCON &= ~((3<<6) | (3<<22));
	GPGCON |= ((2<<6) | (2<<22));   /* S4,S5被配置为中断引脚 */

attachments-2020-05-NE7XWbut5eb4033fb9d69.pngattachments-2020-05-ODWzlj065eb403d936192.png

	/* 设置中断触发方式: 双边沿触发 */
	EXTINT0 |= (7<<0) | (7<<8);     /* S2,S3 */
	EXTINT1 |= (7<<12);             /* S4 */
	EXTINT2 |= (7<<12);             /* S5 */

attachments-2020-05-7FTS2Bd55eb404960d59e.pngattachments-2020-05-pVcWDUXp5eb404ac06f5b.pngattachments-2020-05-tyWVwPzO5eb404c33f9ee.png



根据EINTPEND的引脚值来判断eint11、eint19

attachments-2020-05-xsB5sq8a5eb40970526d0.png

核心代码

start.S

.text
.global _start
_start:
b reset          /* vector 0 : reset */
ldr pc, irq_addr /* vector 0x18 : irq */
irq_addr:
.word 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

/* 恢复现场 */
ldmia sp!, {r0-r12, pc}^  /* ^会把spsr_irq的值恢复到cpsr里 */
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
ldr pc, =main  /* 绝对跳转, 跳到SDRAM */
halt:
b halt

interrupt.c

void interrupt_init(void)
{
	INTMSK &= ~((1<<0) | (1<<2) | (1<<5));
}

/* 初始化按键, 设为中断源 */
void key_eint_init(void)
{
	/* 配置GPIO为中断引脚 */
	GPFCON &= ~((3<<0) | (3<<4));
	GPFCON |= ((2<<0) | (2<<4));   /* S2,S3被配置为中断引脚 */

	GPGCON &= ~((3<<6) | (3<<22));
	GPGCON |= ((2<<6) | (2<<22));   /* S4,S5被配置为中断引脚 */
	

	/* 设置中断触发方式: 双边沿触发 */
	EXTINT0 |= (7<<0) | (7<<8);     /* S2,S3 */
	EXTINT1 |= (7<<12);             /* S4 */
	EXTINT2 |= (7<<12);             /* S5 */

	/* 设置EINTMASK使能eint11,19 */
	EINTMASK &= ~((1<<11) | (1<<19));
}

/* 读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
		{
			/* 按下 */
			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;
}


void handle_irq_c(void)
{
	/* 分辨中断源 */
	int bit = INTOFFSET;

	/* 调用对应的处理函数 */
	if (bit == 0 || bit == 2 || bit == 5)  /* eint0,2,eint8_23 */
	{
		key_eint_irq(bit); /* 处理中断, 清中断源EINTPEND */
	}

	/* 清中断 : 从源头开始清 */
	SRCPND = (1<<bit);
	INTPND = (1<<bit);	
}
main.c

#include "s3c2440_soc.h"
#include "uart.h"
#include "init.h"

char g_Char = 'A';
char g_Char3 = 'a';
const char g_Char2 = 'B';
int g_A = 0;
int g_B;

int main(void)
{
	led_init();
	interrupt_init();  /* 初始化中断控制器 */
	key_eint_init();   /* 初始化按键, 设为中断源 */
	
	puts("\n\rg_A = ");
	printHex(g_A);
	puts("\n\r");

	while (1)
	{

		putchar(g_Char);
		g_Char++;

		putchar(g_Char3);
		g_Char3++;
		delay(1000000);
	}

	
	return 0;
}

0 条评论&回复

请先 登录 后评论
Litchi_Zheng
Litchi_Zheng

5 篇文章

作家榜 »

  1. 百问网-周老师 18 文章
  2. st_ashang 14 文章
  3. 渐进 12 文章
  4. zxq 11 文章
  5. helloworld 8 文章
  6. 谢工 5 文章
  7. Litchi_Zheng 5 文章
  8. 星星之火 5 文章