S3C2440中断
韦东山老师一期中断课程学习:
总结:
程序启动后工作流程,程序从0地址开始执行Reset --》 重定位 --》ldr pc,=main [绝对跳转到SDRAM中执行main()函数],main函数中调用各种函数(初始化函数)。
根据S3C2440的Exception Vectors可以知道, 当发生中断时,CPU运行程序跳转到0X18的地方执行指令,该处我们存放中断处理相关内容,CPU运行相应中断内容{保存现场、处理异常(中断)【分辨中断源、调用相应函数】、恢复现场}。
Exception Vectors 如下:
启动文件Start.S程序如下:
.text
.global _start _start:
b reset /* vector 0 : reset */
ldr pc, und_addr /* vector 4 : und */
ldr pc, swi_addr /* vector 8 : swi */
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:
/* 执行到这里之前:
* 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, #
stmdb sp!, {r0-r12, lr} /* 处理irq异常 */
bl handle_irq_c /* 恢复现场 */
ldmia sp!, {r0-r12, pc}^ /* ^会把spsr_irq的值恢复到cpsr里 */ reset:
/* 关闭看门狗 */
ldr r0, =0x53000000
ldr r1, =
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,,r0,c1,c0,
orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA
mcr p15,,r0,c1,c0, /* 设置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, =(<<)|(<<)|(<<)
str r1, [r0] /* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定
* 然后CPU工作于新的频率FCLK
*/ /* 设置内存: sp 栈 */
/* 分辨是nor/nand启动
* 写0到0地址, 再读出来
* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
* 否则就是nor启动
*/
mov r1, #
ldr r0, [r1] /* 读出原来的值备份 */
str r1, [r1] /* 0->[0] */
ldr r2, [r1] /* r2=[0] */
cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */
ldr sp, =0x40000000+ /* 先假设是nor启动 */
moveq sp, # /* 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, #(<<) /* 清除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
在分析中断处理函数handle_irq_c()时,我们发现如果中断源过多发生的时候,中断处理函数每次都要重新添加,而且显得不简洁。
正常我们在定义中断处理函数时候代码如下:
void handle_irq_c(void)
{
/* 分辨中断源 */
int bit = INTOFFSET; /* 调用对应的处理函数 */
if (bit == 0 || bit == 2 || bit == 5) /* eint0,2,eint8_23 */
{
key_eint_irq(bit); /* 处理中断, 清中断源EINTPEND */
}
else if (bit == 10)
{
timer_irq();
} /* 清中断 : 从源头开始清 */
SRCPND = (<<bit);
INTPND = (<<bit);
}
通过学习可以知道一种思想:定义一个函数指针数组,将所有中断函数存在一个数组中,在写某个初始化中断函数的时候,我们将相应的中断函数存到我们定义的函数指针数组中,然后当处理中断函数工作时,即运行数组中相应的中断函数。
以按键中断点亮LED及定时器中断循环点亮LED为例:
相应代码如下:
[interrupt.c]
#include "s3c2440_soc.h" typedef void(*irq_func)(int);
irq_func irq_array[32]; /* SRCPND 用来显示哪个中断产生了, 需要清除对应位
* bit0-eint0
* bit2-eint2
* bit5-eint8_23
*/ /* INTMSK 用来屏蔽中断, 1-masked
* bit0-eint0
* bit2-eint2
* bit5-eint8_23
*/ /* INTPND 用来显示当前优先级最高的、正在发生的中断, 需要清除对应位
* bit0-eint0
* bit2-eint2
* bit5-eint8_23
*/ /* INTOFFSET : 用来显示INTPND中哪一位被设置为1
*/ #if 0
/* 初始化中断控制器 */
void interrupt_init(void)
{
INTMSK &= ~((<<) | (<<) | (<<));
INTMSK &= ~(<<); /* enable timer0 int */
}
#endif /* 读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 == ) /* eint0 : s2 控制 D12 */
{
if (val1 & (<<)) /* s2 --> gpf6 */
{
/* 松开 */
GPFDAT |= (<<);
}
else
{
/* 按下 */
GPFDAT &= ~(<<);
} }
else if (irq == ) /* eint2 : s3 控制 D11 */
{
if (val1 & (<<)) /* s3 --> gpf5 */
{
/* 松开 */
GPFDAT |= (<<);
}
else
{
/* 按下 */
GPFDAT &= ~(<<);
} }
else if (irq == ) /* eint8_23, eint11--s4 控制 D10, eint19---s5 控制所有LED */
{
if (val & (<<)) /* eint11 */
{
if (val2 & (<<)) /* s4 --> gpf4 */
{
/* 松开 */
GPFDAT |= (<<);
}
else
{
/* 按下 */
GPFDAT &= ~(<<);
}
}
else if (val & (<<)) /* eint19 */
{
if (val2 & (<<))
{
/* 松开 */
/* 熄灭所有LED */
GPFDAT |= ((<<) | (<<) | (<<));
}
else
{
/* 按下: 点亮所有LED */
GPFDAT &= ~((<<) | (<<) | (<<));
}
}
} EINTPEND = val;
} void handle_irq_c(void)
{
/* 分辨中断源 */
int bit = INTOFFSET; /* 调用对应的处理函数 */
irq_array[bit](bit); /* 清中断 : 从源头开始清 */
SRCPND = (<<bit);
INTPND = (<<bit);
} void register_irq(int irq, irq_func fp)
{
irq_array[irq] = fp; INTMSK &= ~(1<<irq);
} /* 初始化按键, 设为中断源 */
void key_eint_init(void)
{
/* 配置GPIO为中断引脚 */
GPFCON &= ~((<<) | (<<));
GPFCON |= ((<<) | (<<)); /* S2,S3被配置为中断引脚 */ GPGCON &= ~((<<) | (<<));
GPGCON |= ((<<) | (<<)); /* S4,S5被配置为中断引脚 */ /* 设置中断触发方式: 双边沿触发 */
EXTINT0 |= (<<) | (<<); /* S2,S3 */
EXTINT1 |= (<<); /* S4 */
EXTINT2 |= (<<); /* S5 */ /* 设置EINTMASK使能eint11,19 */
EINTMASK &= ~((<<) | (<<)); register_irq(0, key_eint_irq);
register_irq(2, key_eint_irq);
register_irq(5, key_eint_irq);
}
[timer.c]
#include "s3c2440_soc.h" void timer_irq(void)
{
/* 点灯计数 */
static int cnt = ;
int tmp; cnt++; tmp = ~cnt;
tmp &= ;
GPFDAT &= ~(<<);
GPFDAT |= (tmp<<);
} void timer_init(void)
{
/* 设置TIMER0的时钟 */
/* Timer clk = PCLK / {prescaler value+1} / {divider value}
= 50000000/(99+1)/16
= 31250
*/
TCFG0 = ; /* Prescaler 0 = 99, 用于timer0,1 */
TCFG1 &= ~0xf;
TCFG1 |= ; /* MUX0 : 1/16 */ /* 设置TIMER0的初值 */
TCNTB0 = ; /* 0.5s中断一次 */ /* 加载初值, 启动timer0 */
TCON |= (<<); /* Update from TCNTB0 & TCMPB0 */ /* 设置为自动加载并启动 */
TCON &= ~(<<);
TCON |= (<<) | (<<); /* bit0: start, bit3: auto reload */ /* 设置中断 */
register_irq(10, timer_irq);
}
S3C2440中断的更多相关文章
- s3c2440中断控制器操作
一.ARM中断体系结构 arm有7中异常工作模式 用户模式.快中断模式.管理模式.数据访问终止模式.中断模式.系统模式.未定义指令终止模式. 几种模式有什么不同呢, 1.不同的寄存器 2.不同的权限 ...
- S3C2440 中断相关寄存器小探
========================================== 转载时请注明出处和作者联系方式 文章出处:http://blog.csdn.net/longintchar 作者联 ...
- (6)s3c2440用I2C接口访问EEPROM
在前面阅读理解了I2C的官方协议文档后,就拿s3c2440和EEPROM来验证一下. 本来是想用s3c2440的SDA和SCL管脚复用为GPIO来模拟的,但在没有示波器的情况下搞了一周,怎么都出不来, ...
- JZ2440 裸机驱动 第9章 中断体系结构
本章目标: 了解ARM体系CPU的7种工作模式 了解S3C2410/S3C2440中断体系结构 掌握S3C2410/S3C2440的中断服务程序的编写方法 9.1 S3C241 ...
- LCD实验学习笔记(八):中断
s3c2440有60个中断源(其中15个为子中断源). 31个32位的通用寄存器,6个程序状态寄存器.有6种工作模式(系统/用户模式,快中断模式,管理模式,数据访问中止模式,中断模式,未定指令中止模式 ...
- u-boot中断功能初步分析之---------按键中断
作者:彭东林 邮箱:pengdonglin137@163.com QQ: 405728433 以前一直有个疑问,在U-boot下到底能不能使用中断,为了验证这个问题,于是乎,昨天晚上我在自己的 TQ2 ...
- 基于mini2440的uboot移植(一)
一.移植环境 虚拟机:ubuntu12.04 uboot源码:u-boot-2008.10.tar.bz2 交叉编译:arm-linux-gcc-4.4.3 简单的记录下编译uboot的过程,要想具体 ...
- GNU μC/OS-II 在 S3C2440 上中断的实现
上一篇文章介绍了S3c2440的中断体系结构,今天我们来分析一下GNU-uC/OS-II在S3c2440上中断的实现. 首先找到IRQ的中断的向量,位于 2440init.S : OK ,我们通过名字 ...
- s3c2440——按键中断
s3c2440的异常向量表: IRQ中断地址是0x18.所以,根据之前的异常处理方式,我们编写启动文件: 为什么需要lr减4,可以参考这篇文章:http://blog.csdn.net/zzsfqiu ...
随机推荐
- PayPal加密证书.pem的生成
How do I create a public certificate for use with PayPal Encrypted Website Payments? Before you ca ...
- UIWebView 设置背景为透明
UIWebView的背景怎样设置成为透明? [webview setBackgroundColor:[UIColor clearColor]]; [webview setOpaque:NO]; 两句代 ...
- POJ-3268-最短路(dijkstra算法)
Silver Cow Party Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 12494 Accepted: 5568 ...
- React Native 中的component 的生命周期
React Native中的component跟Android中的activity,fragment等一样,存在生命周期,下面先给出component的生命周期图 getDefaultProps ob ...
- Java知识总结---整合SpringMVC+Mybatis+Spring(二)
在如今的Java Web开发过程中,各种各样框架层出不穷.在工作中,框架的使用也越来越频繁. 今天介绍一下如今比較流行的SpringMVC.Mybatis和Spring框架.学习一下怎样在项目中使用它 ...
- 一次次迭代 百度语音生成 api 字幕 语音的同步性 关键
发音字符 数一样 D:\myv\semHAND9myuid1523961381.avi 0.7053863117786668 --------------- 深圳市雅超服饰有限公司是一家专业设计制作高 ...
- hbase查询_Phoenix及hbase repl命令行两种方式
一.Phoenix(jdbc)登陆 1.cd /home/mr/phoenix/bin(此路径每个环境里面有可能不一样)2../sqlline.py localhost 二.shell repl Hb ...
- 【SQL Server】SQL触发器经验详解
[SQL Server]SQL触发器经验详解 | 浏览: 4314 | 更新: 2013-01-07 15:33 25 11 全文阅读分步阅读 加入杂志 步骤 1 2 3 4 5 6 7 8 ...
- [POI 2007] Zap
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1101 [算法] 首先 , 问题可以转化为求GCD(x,y) = 1,x <= ...
- C++11 function使用
function是一组函数对象包装类的模板,实现了一个泛型的回调机制. 引入头文件 #include <functional>using namespace std;using names ...