嵌入式大作业解析.docx
《嵌入式大作业解析.docx》由会员分享,可在线阅读,更多相关《嵌入式大作业解析.docx(13页珍藏版)》请在冰豆网上搜索。
嵌入式大作业解析
2015嵌入式大作业
一、叙述JTAG接口在嵌入式开发中的作用。
JTAG是一种国际标准测试协议主要用于芯片内部测试,JTAG接口的主要作用如下所述:
◆它最初用来对电路和芯片进行边界扫描测定,它的基本原理是在器件内部定义一个测试是访问口(TestAccessPort),通过JTAG专用的测试工具对器件内部节点进行测试。
通过电路的边界扫描测试技术,用具有边界扫描功能的芯片构成的印制板电路,可通过相应的测试设备检测芯片功能,检测电路连接的正确性同时检测它是否有预定的逻辑功能,从而对这块印制电路进行故障检测和故障定位。
◆JTAG接口可以对目标板进行测试,还可以对目标板系统的存储单元编程,经常通过JTAG接口直接烧写嵌入式系统Flash存储器。
◆JTAG的引脚定义
1.TCK为TAP提供一个独立基本的时钟信号,TAP的所有操作都是通过这个时钟信号来驱动的。
2.TMS用来控制TAP状态机的转换,通过TMS新号可以控制TAP在不同的状态间转换,TMS信号在TCK信号的上升沿有效。
3.TDI是数据输入的接口,所有输入到特定寄存器的数据都要通过TDI一位一位串行输出。
4.TDO数据输出的接口所有从特定寄存器输出的数据都要通过TDO一位一位串行输出。
5.TRST可以用来对TAPController进行复位,该信号线可选,TMS也可以对其进行复位。
6.VTREF接口信号电平参考电压一般直接接V(supply),这个可以用来确定ARM的JTAG的接口逻辑电平。
7.RTCK可选项,由目标端反馈给仿真器的时钟信号,用来同步TCK信号的产生,不使用时直接接地。
8.SystemReset可选项,与目标板上的系统复位信号相连,可以直接对目标系统复位,同时可以检测目标系统的复位情况,为了防止误触发应在目标端加上适当的上位电阻。
9.USER IN用户自定义输入,可以接到一个IO口上,用来接收上位机的控制。
10.USEROUT用户自定义输出,可以接到一个IO口上,用来向上位机反馈一个状态。
二、叙述嵌入式平台的搭建过程,以linux为例。
1)一:
建立宿主机开发环境
建立交叉编译的环境即在宿主机上安装与开发板相应的编译器及库函数,以便能够在宿主机上应用开发工具编译在目标板上运行的Linux引导程序,内核,文件系统和应用程序
交叉编译:
在特殊的环境下,把嵌入式程序代码编译成不同的CPU所对应的机器代码。
开发时使用宿主机上的交叉编译,汇编及链接工具形成可执行的二进制代码(该代码只能在开发板上执行),然后下载到开发板上运行
2)下载和安装arm-Linux-gcc编译工具链
下载最新的arm-Linux-gcc并解压至当前目录下
在系统配置文件profile中设置环境变量方法:
直接在profile文件中加入搜索路径立即使新的环境变量生效:
运行source命令,检查是否将路径加入到path,测试是否安装成功,
编译程序,测试交叉工具链
3)配置超级终端minicomminicom是宿主机与目标板进行通信的终端:
在宿主机Linux终端中输入:
minicom-s或输入minicom然后按ctrl+A+O对超级终端minicom进行配置,再选择串口并配置串口,最后保存即可
4)建立数据共享服务:
NFS服务是Linux系统中经常使用的数据文件共享服务
5)编译嵌入式系统内核:
内核配置,建立依存关系,建立内核
6)制作文件系统
三、给出现今有哪些用于嵌入式开发的芯片名称,他们分是哪些公司的产品?
体系结构是什么?
1)基于32位RISC微处理器芯片的ARM7系列,ARM9系列,ARM9E系列,ARM10E系列都是ARM公司的产品,arm9以上的体系结构是哈佛总线体系结构以下的是冯。
诺依曼体系。
2)TI公司的DSP处理器内核是哈佛总线体系结构。
3)PowerPC公司的芯片,基于RISC结构,是哈佛总线体系结构。
4)MIPS公司的芯片,基于RISC结构,是哈佛总线体系结构。
四、现今较流行的嵌入式操作系统有哪些?
1 VxWork
2 Linux
3 μC/OS-Ⅱ
4 windowsCE
5 Android
五、PXA270嵌入式开发板的接口有哪些?
全双工异步串行口和硬件流控制串行口,10M标准以太网接口10M/100M标准以太网接口,USB接口,红外通讯口,音频接口,存储卡口,视频和触摸屏接口摄像头接口,RTC时钟接口,调试接口,下载接口,电源接口。
六、请写出NorFlash和NandFlash的区别。
Flash是一种非易失闪存,它具有和ROM一样的掉电后数据不会丢失的特性。
它主要分为NorFlash和NandFlash。
他们的主要区别如下所示:
NorFlash
NandFlash
接口时序同SRAM,容易使用
地址/数据线复用,数据位较窄
读取速度较快
读取速度较慢
檫除速度慢,以64-128KB的块为单位
檫除速度快,以8-32KB的块为单位
写入速度慢(因为一般要檫除)
写入速度快
随机存取速度较快,支持XIP(eXecuteInPlace,芯片内执行),适用于代码存储。
在嵌入式系统中,常用于存放引导程序、根文件等
顺序读取速度较快,随机存取速度慢,适用于数据存储(如大容量的多媒体应用)。
在嵌入式系统中,常用于存放用户文件系统等
单片容量较小为1-32MB
单片容量较大为8-128MB,提高了单元密度
最大檫写次数为10万次
最大檫写次数为100万次
七、冯。
诺依曼架构与哈佛架构的区别。
他们的主要区别是计算机的存储结构和总线连接形式不同。
在冯·诺依曼的结构中,存储器内部的数据存储空间和程序存储空间是合在一起的,他们共享存储器总线,即数据和指令在同一条总线上通过时分复用的方式进行传输,这种结构在高速运行时,不能达到同时取指令和取操作数的目的从而形成传输过程的瓶颈。
在哈佛总线体系结构的芯片内部,数据存储空间和程序存储空间是分开的,所以哈佛总线体系在指令执行时可以同时存取指令(来自程序空间)和取操作数(来自数据空间),因此具有更高的执行效率,修正的哈佛总线结构还可以在程序空间和数据空间之间相互传送数据。
(目前大多数DSP和ARM9以上的嵌入式系统微处理器内核都采用哈佛总线体系结构而ARM7采用的则是冯·诺依曼结构)
8、单周期3级流水的情况下,第10个指令周期时,第几条指令执行结束?
三级流水读取指令过程:
⑴取指从存储器装载一条指令
⑵译码识别将要被执行的指令
⑶执行处理指令并将结果写会寄存器
故ARM正在执行第1条指令的同时对第2条指令进行译码,并将第3条指令从存储器中取出。
所以,ARM7流水线只有在取第10条指令时,第7条指令才算完成执行。
九、下面是linux下的一个简单的设备驱动程序,写出linux设备驱动常用的数据结构,同时阅读下面代码,请给出测试程序中的每条语句加以注释。
设备驱动程序Keypad.c的源代码:
#include//最基本的文件,支持动态添加和卸载模块。
HelloWorld驱动要这一个文件就可以了
#include//包含了文件操作相关struct的定义,例如大名鼎鼎的structfile_operations
#include//初始化头文件
#include//轮询文件
#include//对一些特殊类型的定义,例如dev_t,off_t,pid_t.其实这些类型大部分都是unsignedint型通过一连串的typedef变过来的,只是为了方便阅读。
#include//可以在芯片上产生周期性的中断
#include//延时头文件
#include//与处理器相关的硬件
#include//延时头文件
#include//与处理器相关的入口
#defineLEDnKEY_MAJOR251
#defineKEYPAD_NAME"X-Hyper250Keypad"
#defineKEYPAD_VERSION"Version0.1"
#defineEXT_KEY_CSEXT_PORT2//宏定义
#defineEXT_LED_CSEXT_PORT3//宏定义
#defineLED_SHOW10//宏定义
/*EXT_KEY_CS为向外部LED进行数值设定,它定义在其它头文件里*/
voidled_off_on()
{
inti;
EXT_LED_CS=0xff;
for(i=0;i<8;++i)
{
EXT_LED_CS=~((1<
udelay(30000);//调用udelay函数来延迟
}
EXT_LED_CS=0xff;
}
/*应用程序用open来打开设备文件,实际上调用驱动的lednkey_open()函数*/
intlednkey_open(structinode*inode,structfile*filp)//打开设备文件
{
MOD_INC_USE_COUNT;//模块自身通过MOD_INC_USE_COUNT,宏来管理自己被使用的计数。
return(0);/*success*/
}
intlednkey_release(structinode*inode,structfile*filp)//释放设备文件
{
led_off_on();
MOD_DEC_USE_COUNT;
return(0);
}
ssize_tlednkey_read(structfile*filp,char*Putbuf,size_tlength,loff_t*f_pos)//按键读取函数
{
unsignedshortBottonStatus;
unsignedcharBottontmp=0;
inti;
BottonStatus=(EXT_KEY_CS&0xff);/*按键状态*/
for(i=0;i<8;++i)
{
if(((BottonStatus>>i)&1)==0)
Bottontmp=(i+1);
}/*判断哪个按键按下*/
copy_to_user(Putbuf,&Bottontmp,length);/*将数据从内核态拷贝到用户态,这是由定义在里的特殊函数实现在不同的空间传输任意字节的数据*/
returnlength;
}
ssize_tlednkey_write(structfile*filp,constchar*Getbuf,size_tlength,loff_t*f_pos)
{
intnum;
unsignedcharUsrWantLed;
copy_from_user(&UsrWantLed,Getbuf,length);/*将数据从用户态拷贝到核心态*/
num=((UsrWantLed)&0xff);/*确定哪一位要进行设定*/
EXT_LED_CS=~(1<<(num-1));//点亮相应LED灯
return(0);
}
intlednkey_ioctl(structinode*inode,structfile*filp,unsignedintcmd,unsignedlongarg)//lednkey_ioctl接口函数,主要用于获取或者改变正在运行的设备参数
{
switch(cmd)
{
caseLED_SHOW:
{
if(arg)
led_off_on();
break;
}
}
return0;
}
/*以下这些驱动函数是与用户的应用程序里对设备文件操作的函数相对应的*/
structfile_operationslednkey_fops={
open:
lednkey_open,
read:
lednkey_read,
write:
lednkey_write,
ioctl:
lednkey_ioctl,
release:
lednkey_release,
};
staticint_initxhyper250_keypad_init(void)//初始化设备函数,在函数名之前加上这个属性之后,系统会在初始化完成之后丢弃初始化函数,收回它所占用的内存,以减小内核所占用的内存空间,它只对内建的驱动起作用
{
intresult;
result=register_chrdev(LEDnKEY_MAJOR,"lednkey",&lednkey_fops);//向操作系统注册一个主号为251,设备名为"lednkey",并传递设备驱动程序的指针为lednkey_fops(全局变量),其中register_chrdev()是内核提供的函数,作用是完成注册新的字符设备
printf("%s%sinitialized.\n",KEYPAD_NAME,KEYPAD_VERSION);
led_off_on();
return0;
}
staticvoid_exitxhyper250_keypad_exit(void)/*向操作系统卸载设备函数*/
{
unregister_chrdev(LEDnKEY_MAJOR,"lednkey");
led_off_on();
}
module_init(xhyper250_keypad_init);//显式声明初始化设备函数
module_exit(xhyper250_keypad_exit);//显式声明卸载设备函数*/
测试文件的源代码如下:
#include
#include
#include
#include
#include
#include
#defineLED_SHOW10//宏定义
intfd;
staticchar*dev_name="/dev/keypad";
intmain(intargc,char**argv)
{
intdata=0,pre_data;
fd=open(dev_name,O_RDWR);//使用函数open打开设备keypad
if(!
(fd>=0))
{
printf("%sfileopenfailed\n",dev_name);
exit(-1);
}//打开失败,显示出错信息
printf("\nkeypadApp:
pressthepushbuttonseeshowled-ExitCtrl-C\n",dev_name);//打开成功,提示用户输入
ioctl(fd,LED_SHOW,1);//循环显示LED,看LED是否正常
while
(1)
{
do
{
pre_data=data;
read(fd,(char*)&data,sizeof(data));
data=(data&0xff);
}while(data==0);
if(pre_data==0)
{
printf("Write%dLED\n",data);
write(fd,(constchar*)&data,sizeof((constchar)data));//采用忙等待方式扫描用户输入,传递给write函数
}
}
close(fd);//使用函数close关闭设备keypad
return0;
}
常用数据结构:
(1)file_operations结构:
structfile_operations{
structmodule*owner;
loff_t(*llseek)(structfile*,loff_t,int);
ssize_t(*read)(structfile*,char__user*,size_t,loff_t*);
ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*);
ssize_t(*aio_read)(structkiocb*,conststructiovec*,unsignedlong,loff_t);
ssize_t(*aio_write)(structkiocb*,conststructiovec*,unsignedlong,loff_t);
int(*readdir)(structfile*,void*,filldir_t);
unsignedint(*poll)(structfile*,structpoll_table_struct*);
int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);
long(*unlocked_ioctl)(structfile*,unsignedint,unsignedlong);
long(*compat_ioctl)(structfile*,unsignedint,unsignedlong);
int(*mmap)(structfile*,structvm_area_struct*);
int(*open)(structinode*,structfile*);
int(*flush)(structfile*,fl_owner_tid);
int(*release)(structinode*,structfile*);
int(*fsync)(structfile*,structdentry*,intdatasync);
int(*aio_fsync)(structkiocb*,intdatasync);
int(*fasync)(int,structfile*,int);
int(*lock)(structfile*,int,structfile_lock*);
ssize_t(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int);
unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong);
int(*check_flags)(int);
int(*flock)(structfile*,int,structfile_lock*);
ssize_t(*splice_write)(structpipe_inode_info*,structfile*,loff_t*,size_t,unsignedint);
ssize_t(*splice_read)(structfile*,loff_t*,structpipe_inode_info*,size_t,unsignedint);
int(*setlease)(structfile*,long,structfile_lock**);
};
(2)File文件结构
1)fmode_tf_mode;此文件模式通过FMODE_READ,FMODE_WRITE识别了文件为可读的,可写的,或者是二者。
在open或ioctl函数中可能需要检查此域以确认文件的读/写权限,你不必直接去检测读或写权限,因为在进行open/ioctl等操作时内核本身就需要对其权限进行检测。
2)loff_tf_pos;当前读写文件的位置。
为64位。
如果想知道当前文件当前位置在哪,驱动可以读取这个值而不会改变其位置。
对read,write来说,当其接收到一个loff_t型指针作为其最后一个参数时,他们的读写操作便作更新文件的位置,而不需要直接执行filp->f_pos操作。
而llseek方法的目的就是用于改变文件的位置。
3)unsignedintf_flags;文件标志,如O_RDONLY,O_NONBLOCK以及O_SYNC。
在驱动中还可以检查O_NONBLOCK标志查看是否有非阻塞请求。
其它的标志较少使用。
4)structfile_operations*f_op;与文件相关的各种操作。
当文件需要迅速进行各种操作时,内核分配这个指针作为它实现文件打开,读,写等功能的一部分。
filp->f_op其值从未被内核保存作为下次的引用,即你可以改变与文件相关的各种操作,这种方式效率非常高。
5)void*private_data;在驱动调用open方法之前,open系统调用设置此指针为NULL值。
(3)Inode结构
1 dev_ti_rdev;表示设备文件的结点,这个域实际上包含了设备号。
2 structcdev*i_cdev;structcdev是内核的一个内部结构,它是用来表示字符设备的,当inode结点指向一个字符设备文件时,此域为一个指向inode结构的指针。