实验删减版.docx
《实验删减版.docx》由会员分享,可在线阅读,更多相关《实验删减版.docx(17页珍藏版)》请在冰点文库上搜索。
![实验删减版.docx](https://file1.bingdoc.com/fileroot1/2023-5/8/f1d270f6-5ac0-4944-b9d0-120cc3a3bf3e/f1d270f6-5ac0-4944-b9d0-120cc3a3bf3e1.gif)
实验删减版
实验三中断实验
一、实验目的
1.了解中断的作用;
2.掌握嵌入式系统中断的处理流程;
3.掌握ARM中断编程。
二、实验内容
1.编写中断处理程序,处理外部中断;
三、预备知识
1.了解ADT集成开发环境的基本功能;
2.了解中断的作用以及处理过程。
四、实验设备
1.JX44B0教学实验箱;
2.ADTIDE集成开发环境;
3.串口线一根。
五、基础知识
1.中断的基本概念
CPU与外设之间传输数据的控制方式通常有三种:
查询方式、中断方式和DMA方式。
DMA方式将在后续实验中说明。
查询方式的优点是硬件开销小,使用起来比较简单。
但在此方式下,CPU要不断地查询外设的状态,当外设未准备好时,CPU就只能循环等待,不能执行其它程序,这样就浪费了CPU的大量时间,降低了CPU的利用率。
为了解决这个矛盾,通常采用中断传送方式:
即当CPU进行主程序操作时,外设的数据已存入输入端口的数据寄存器;或端口的数据输出寄存器已空,由外设通过接口电路向CPU发出中断请求信号,CPU在满足一定的条件下,暂停执行当前正在执行的主程序,转入执行相应能够进行输入/输出操作的子程序,待输入/输出操作执行完毕之后CPU再返回并继续执行原来被中断的主程序。
这样CPU就避免了把大量时间耗费在等待、查询状态信号的操作上,使其工作效率得以大大地提高。
能够向CPU发出中断请求的设备或事件称为中断源。
系统引入中断机制后,CPU与外设(甚至多个外设)处于“并行”工作状态,便于实现信息的实时处理和系统的故障处理。
中断方式的原理示意图如下所示。
图5-6中断处理示意图
1)中断响应
中断源向CPU发出中断请求,若优先级别最高,CPU在满足一定的条件下,可以中断当前程序的运行,保护好被中断的主程序的断点及现场信息。
然后,根据中断源提供的信息,找到中断服务子程序的入口地址,转去执行新的程序段,这就是中断响应。
CPU响应中断是有条件的,如内部允许中断、中断未被屏蔽、当前指令执行完等。
2)中断服务子程序
CPU响应中断以后,就会中止当前的程序,转去执行一个中断服务子程序,以完成为相应设备的服务。
中断服务子程序的一般结构如下图所示。
图5-7中断服务子程序处理流程
a.保护现场(由一系列的压栈指令完成)。
目的是为了保护那些与主程序中有冲突的寄存器,(如R0,R1,R2等),如果中断服务子程序中所使用的寄存器与主程序中所使用的寄存器等没有冲突的话,这一步骤可以省略。
b.中断处理,中断处理程序在检查到相应的中断源后,调用对应的中断处理程序完成。
c.恢复现场并返回(由一系列的出栈指令完成)。
是与保护现场对应的,但要注意数据恢复的次序,以免混乱。
由于中断服务子程序需要打断主程序的执行,因此其处理应该及时完成,较长时间的延时将导致系统性能严重下降。
2.S3C44B0中断控制器
S3C44B0的中断控制器包括四类寄存器:
中断控制寄存器、中断模式寄存器、中断状态寄存器、中断屏蔽寄存器。
2.1中断控制寄存器
该控制寄存器是处理器总的中断控制,包括中断模式是矢量模式还是非矢量模式,是否使能IRQ模式的中断,是否使能FIQ模式的中断,具体说明如下:
表5-12中断控制寄存器
2.2中断状态寄存器
该寄存器由于检查中断来源,该寄存器是只读属性的。
表5-13中断状态寄存器
2.3中断模式寄存器
用于设置相应中断的工作模式,是IRQ模式还是FIQ模式。
表5-14中断模式寄存器
2.4中断屏蔽寄存器
表5-15中断屏蔽寄存器
2.5中断清除寄存器
中断处理之后需要清除相应的标志位,中断清除寄存器地址如下:
表5-16中断清除寄存器
3.实验说明
S3C44B0处理器的中断处理与其他CPU的处理模式基本上是一致的,只是由于它引入了几种不同的处理器模式,使中断处理变得更加容易。
其典型的步骤如下:
1)保存现场:
当系统出现中断时,处理器首先要做的就是保存现场,这一过程包括:
保存当前的PC值到lr中,保存当前的程序运行状态到spsr中。
值得注意的就是由于ARM7采用3级流水线结构,此时的PC值实际上等于当前指令地址加上8(ARM指令时),所以返回时还需要将保存的PC值减4。
2)模式切换:
当处理器完成现场保护后,就进入中断模式,并将PC值置为一个固定的值0X00000018,这也就是IRQ模式的中断入口地址。
在中断模式下,有两个独立的寄存器R13、R14,这样可以便于中断程序使用自己特有的堆栈。
但这样随之而来产生一个问题,就是中断处理时堆栈溢出保护的问题,需要我们认真地估计堆栈的大小,同时在中断处理时也要尽量减少函数调用的层次,否则将产生一些不可预知的错误。
3)获取中断源:
所有的IRQ中断都从0X00000018开始执行,通常在该地址处放一条跳转指令,进一步跳到我们的中断程序中。
4)处理中断:
并在中断程序中需要进一步获取中断源,即谁引发了该中断,然后通过查表获取相应中断的处理程序入口,并调用对应的函数;
5)中断返回,恢复现场:
在返回时需要恢复处理器模式,包括恢复中断处理用到的所有寄存器、恢复被中断时的程序运行状态到CPSR,并跳转到被中断的主程序。
下图为JX44B0教学系统中处理外部中断0的流程:
图5-8JX44B0中断处理示意图
中断的入口代码(汇编代码):
0X00000018:
LDRpc,=0X0C000020
……
0X0C000020:
bHandlerIRQ
HandlerIRQ:
subsp,sp,#4/*为中断分发例程入口地址预留栈空间*/
stmfdsp!
{r0}/*保存R0*/
ldrr0,=HandleIRQ/*将中断分发例程入口地址指针保存到R0中*/
ldrr0,[r0]/*将中断分发例程入口地址保存到R0中*/
strr0,[sp,#4]/*将中断分发例程入口地址保存到预留的堆栈空间*/
ldmfdsp!
{r0,pc}/*将R0和中断分发例程入口地址出栈,这条指令也*/
/*实现了一个跳转*/
上述代码实际上就是一个三级跳,即从FLASH中跳到了RAM的中断入口,然后又从中断入口跳到中断分发例程入口。
在此我们有一个前提条件,即必须在HandleIRQ地址处保存正确的分发例程入口地址,如使用下面代码后IsrIRQ就是中断分发例程:
ldrr0,=HandleIRQ
ldrr1,=IsrIRQ
strr1,[r0]
中断分发例程可以采用汇编语言和C语言两种格式编写,下面将分别列出这两种方式。
1、用汇编代码编写的中断分发例程:
IsrIRQ:
/*usingI_ISPRregister.*/
sublr,lr,#4
stmfdsp!
{lr}/*保存中断返回的PC值*/
stmfdsp!
{r0-r4}/*备份寄存器R0-R4*/
subsp,sp,#4/*为PC预留栈空间*/
stmfdsp!
{r8-r9}/*备份寄存器R8-R9*/
ldrr9,=I_ISPR/*读取中断状态*/
ldrr9,[r9]
cmpr9,#0x0/*检查中断状态*/
beqi2
movr8,#0x0/*R8保存中断表的偏移*/
i0:
/*逐位检查中断状态*/
movsr9,r9,lsr#1
bcsi1/*如果该位等于1,则处理这一中断*/
addr8,r8,#4/*修改当前的中断偏移*/
bi0/*处理下一比特*/
i1:
ldrr9,=HandleADC/*HandleADC位于中断向量表起始位置,我们将该地址用作是中断向量表的基地址*/
addr9,r9,r8/*计算入口地址指针:
中断基地址加上偏移*/
ldrr9,[r9]/*从地址向量表中获取入口地址*/
strr9,[sp,#8]/*将入口地址保存到堆栈,并移动堆栈指针*/
movlr,pc/*保存当前PC*/
ldmfdsp!
{r8-r9,pc}/*调用中断例程*/
ldmfdsp!
{r0-r4,pc}^/*中断返回,并恢复中断前的处理器模式*/
i2:
ldmfdsp!
{r8-r9}/*如果当前没有任何中断,直接返回*/
addsp,sp,#4/*移动堆栈指针,该空间由第4句指令预留*/
ldmfdsp!
{r0-r4,pc}^/*中断返回,并恢复中断前的处理器模式*/
2、用C代码编写的中断分发例程:
如果采用GNU编译器,需要将该函数定义为中断类型,使用关键字:
__attribute__((interrupt("IRQ")))。
如下所示代码为C语言的IsrIRQ实现:
typedef(*ISR_ROUTINE_ENTRY)(void);
voidIsrIRQ()__attribute__((interrupt("IRQ")));
voidIsrIRQ()
{
intcount=0;
unsignedintisr_pending;
unsignedintisr_mask=0x00000001;
unsignedintisr_mask_set=rINTMSK;/*读取中断掩码*/
ISR_ROUTINE_ENTRYisr_routine_entry=(ISR_ROUTINE_ENTRY)0x0;
isr_pending=(rINTPND&~isr_mask_set);/*读取中断状态*/
/*查表*/
while(isr_mask)
{
if(isr_pending&isr_mask)
{
/*找到中断源,获取中断例程入口地址*/
isr_routine_entry=(ISR_ROUTINE_ENTRY)(*(int*)(HandleADC+count));
break;
}
count+=4;
isr_mask<<=1;
}
/*调用中断服务例程*/
if(isr_routine_entry)(*isr_routine_entry)();
}
中断处理例程(该函数无需定义为中断类型)
voidEINT0_Isr()
{
rI_ISPC=BIT_EINT0;/*清除中断标志*/
……
}
中断向量表中各个中断的偏移:
表5-17中断向量表中各个中断的偏移
中断源
向量表的偏移
ADC(AD转换中断)
0X20
RTC(实时时钟中断)
0X24
……
六、实验步骤
1.参照模板工程interrupt(modules\interrupt\interrupt.apj),新建一个工程interrupt,添加相应的文件,并修改interrupt的工程设置;
2.创建interrupt.c并加入到工程interrupt中;
3.编写中断分发例程IsrIRQ;
4.注册外部中断0处理函数ext0_int_isr;
5.实现外部中断0处理函数ext0_int_isr,在其中实现LED开关功能;
6.编译interrupt;
7.下载程序并运行,按下按键EXTINT0将引发一次外部中断,并在中断处理函数中开关灯。
七、实验报告要求
1.中断处理的主要步骤有哪些?
试说明每一步的主要工作。
2.说明S3C44B0非矢量中断与矢量中断的区别;
3.简述S3C44B0非矢量中断的处理步骤。
实验二BootLoader编写实验
一、实验目的
1.了解BootLoader在嵌入式系统中的作用;
2.掌握BootLoader的编写。
二、实验内容
1.在BootLoader中实现程序的下载,程序的执行。
三、预备知识
1.了解BootLoader在嵌入式系统中的作用;
2.了解BootLoader的功能组成;
3.了解BootLoader的编写办法。
四、实验设备
1.JX44B0–1教学实验箱;
2.ADT1000仿真器和ADTIDE集成开发环境。
五、基础知识
1.BootLoader的概念
BootLoader是系统加电后运行的第一段软件代码。
回忆一下PC的体系结构我们可以知道,PC机中的引导加载程序由BIOS(其本质就是一段固件程序)和位于硬盘MBR中的引导程序一起组成。
BIOS在完成硬件检测和资源分配后,将硬盘MBR中的引导程序读到系统的RAM中,然后将控制权交给引导程序。
引导程序的主要运行任务就是将内核映象从硬盘上读到RAM中,然后跳转到内核的入口点去运行,也即开始启动操作系统。
而在嵌入式系统中,通常并没有像BIOS那样的固件程序(有的嵌入式系统也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由BootLoader来完成。
比如在一个基于ARM7TDMIcore的嵌入式系统中,系统在上电或复位时都从地址0x00000000开始执行,而在这个地址处安排的通常就是系统的BootLoader程序。
简单地说,BootLoader就是在操作系统内核或用户应用程序运行之前运行的一段小程序。
通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图(有的CPU没有内存映射功能如S3C44B0),从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核或用户应用程序准备好正确的环境。
对于一个嵌入式系统来说,可能有的包括操作系统,有的小型系统也可以只包括应用程序,但是在这之前都需要BootLoader为它准备一个正确的环境。
通常,BootLoader是依赖于硬件而实现的,特别是在嵌入式领域,为嵌入式系统建立一个通用的BootLoader是很困难的。
当然,我们可以归纳出一些通用的概念来,以便我们了解特定BootLoader的设计与实现。
✧BootLoader的移植和修改
每种不同的CPU体系结构都有不同的BootLoader。
除了依赖于CPU的体系结构外,BootLoader实际上也依赖于具体的嵌入式板级设备的配置,比如板卡的硬件地址分配,RAM芯片的类型,其他外设的类型等。
这也就是说,对于两块不同的嵌入式板而言,即使它们是基于同一种CPU而构建的,如果他们的硬件资源和配置不一致的话,要想让运行在一块板子上的BootLoader程序也能运行在另一块板子上,也还是需要作一些必要的修改。
✧BootLoader的安装
系统加电或复位后,所有的CPU通常都从CPU制造商预先安排的地址上取指令。
比如,S3C44B0在复位时都从地址0x00000000取它的第一条指令。
而嵌入式系统通常都有某种类型的固态存储设备(比如:
ROM、EEPROM或FLASH等)被安排这个起始地址上,因此在系统加电后,CPU将首先执行BootLoader程序。
也就是说对于基于S3C44B0的这套系统,我们的BootLoader是从0地址开始存放的,而这块起始地址需要采用可引导的固态存储设备如FLASH。
✧用来控制BootLoader的设备或机制
串口通讯是最简单也是最廉价的一种双机通讯设备,所以往往在BootLoader中主机和目标机之间都通过串口建立连接,BootLoader程序在执行时通常会通过串口来进行I/O,比如:
输出打印信息到串口,从串口读取用户控制字符等。
当然如果认为串口通讯速度不够,也可以采用网络或者USB通讯,那么相应的在BootLoader中就需要编写各自的驱动。
✧BootLoader的启动过程
多阶段的BootLoader能提供更为复杂的功能,以及更好的可移植性。
从固态存储设备上启动的BootLoader大多都是2阶段的启动过程,也即启动过程可以分为stage1和stage2两部分。
✧BootLoader的操作模式
大多数BootLoader都包含两种不同的操作模式:
"启动加载"模式和"下载"模式,这种区别仅对于开发人员才有意义。
但从最终用户的角度看,BootLoader的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别。
启动加载(Bootloading)模式:
这种模式也称为"自主"(Autonomous)模式。
也即BootLoader从目标机上的某个固态存储设备上将操作系统加载到RAM中运行,整个过程并没有用户的介入。
这种模式是BootLoader的正常工作模式,因此在嵌入式产品发布的时侯,BootLoader显然必须工作在这种模式下。
下载(Downloading)模式:
在这种模式下,目标机上的BootLoader将通过串口连接或网络连接等通信手段从主机下载文件,比如:
下载应用程序、数据文件、内核映像等。
从主机下载的文件通常首先被BootLoader保存到目标机的RAM中,然后再被BootLoader写到目标机上的固态存储设备中。
BootLoader的这种模式通常在系统更新时使用。
工作于这种模式下的BootLoader通常都会向它的终端用户提供一个简单的命令行接口。
在教学系统中提供的BootLoader中没有实现自主模式,可以通过修改代码来实现该功能。
✧BootLoader与主机之间进行文件传输所用的通信设备及协议
最常见的情况就是,目标机上的BootLoader通过串口与主机之间进行文件传输,传输可以简单的采用直接数据收发,当然在串口上也可以采用xmodem/ymodem/zmodem协议以及在以太网上采用TFTP协议。
此外,在论及这个话题时,主机方所用的软件也要考虑。
比如,在通过以太网连接和TFTP协议来下载文件时,主机方必须有一个软件用来的提供TFTP服务。
2.BootLoader的主要任务与典型结构框架
从操作系统的角度看,BootLoader的总目标就是正确地调用内核来执行。
另外,由于BootLoader的实现依赖于CPU的体系结构,因此大多数BootLoader都分为stage1和stage2两大部分。
依赖于CPU体系结构的代码,比如设备初始化代码等,通常都放在stage1中,而且通常都用汇编语言来实现,以达到短小精悍的目的。
而stage2则通常用C语言来实现,这样可以实现复杂的功能,而且代码会具有更好的可读性和可移植性。
BootLoader的stage1通常包括以下步骤(以执行的先后顺序):
∙硬件设备初始化。
∙为加载BootLoader的stage2准备RAM空间。
∙拷贝BootLoader的stage2到RAM空间中。
∙设置好堆栈。
∙跳转到stage2的C入口点。
BootLoader的stage2通常包括以下步骤(以执行的先后顺序):
∙初始化本阶段要使用到的硬件设备。
∙调用应用程序或启动内核。
3.实验说明
图8-1Stage1初始化流程图
stage1的功能:
RAM初始化,设置各个部件的时钟和片选,将BootLoader拷贝到RAM中,设置堆栈,调用Stage2。
注意:
在本阶段,特别是在堆栈设置之前,进行函数调用(也有些汇编子程序不需要使用堆栈)或者使用堆栈保存数据将产生不可预知的结果;
stage2的功能:
初始化串口,显示菜单,通过菜单获取用户输入,并执行相应的操作。
图8-2Stage2流程
BootLoader更新程序的流程图
通过BootLoader更新程序的流程。
注意为了使用Bootloader更新FLASH中的程序,需要首先将Bootloader搬迁到RAM中运行。
图8-3下载并更新BootLoader流程
六、实验步骤
1.参照模板工程bootloader(modules\bootloader\bootloader.apj),新建一个工程bootloader,添加相应的文件,并修改bootloader的工程设置;
2.编写Stage1硬件初始化代码;
3.编写Stage2程序,实现从串口下载程序并烧写到FLASH中;
4.运行下载的程序;
5.检查运行结果。
七、实验报告要求
1、Bootloader在嵌入式系统中的作用是什么,它的基本功能包括那些?
2、简述典型Bootloader的框架;