嵌入式实验报告 IO口驱动实验.docx
《嵌入式实验报告 IO口驱动实验.docx》由会员分享,可在线阅读,更多相关《嵌入式实验报告 IO口驱动实验.docx(19页珍藏版)》请在冰点文库上搜索。
嵌入式实验报告IO口驱动实验
实验七I/O口驱动实验
一、实验目的:
1、了解PXA270微处理器GPIO的功能
2、熟悉PXA270微处理器GPIO驱动程序的编写方法
3、掌握驱动程序的加载过程和方法
二、实验环境(软件与硬件):
软件环境:
VMwareWorkstation
硬件环境:
pc机、arm机
三、实验过程和结果(包括编写的程序与结果,结果要截图)
第1步:
利用vi编辑器,编写一个xsb_seg.c驱动代码;
(1)增加驱动所需的头文件和变量
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
charLED_MODULE=0;
#defineDEVICE_NAME"xsb_seg"
#defineSEG_CS10x10300000
#defineSEG_CS20x10400000
staticcharLED[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7F,0x6F};
unsignedlong*CS1_Address,*CS2_Address;
structseg
{
charLED1_Val;
charLED2_Val;
charLED3_Val;
charLED4_Val;
charnegative;
};
(2)同时更新所有七段数码光驱动管显示函数
staticvoidUpdateled(structseg*seg_7)
{
unsignedshortbuff=0x00;
buff=seg_7->LED1_Val;
buff=buff|(seg_7->LED2_Val<<8);
writew(buff,CS1_Address);
buff=0x00;
buff=seg_7->LED3_Val;
buff=buff|(seg_7->LED4_Val<<8);
writew(buff,CS2_Address);
return;
}
(3)写具体某位七段数码光驱动管显示函数
voidvalue_seting(structseg*seg_7,charposition,charvalue)
{
if(seg_7->negative==0)
value=~value&~(0x1<<7);
else
value=(0x1<<7)|value;
if(position==1)
seg_7->LED1_Val=value;
elseif(position==2)
seg_7->LED2_Val=value;
elseif(position==3)
seg_7->LED3_Val=value;
elseif(position==4)
seg_7->LED4_Val=value;
}
(4)实现七段数码光驱动写操作函数
staticssize_tXSB_Seg_write(structfile*file,constchar*buffer,size_tcount,loff_t*ppos)
{
inti;
structseg*seg_7=file->private_data;
charled_forall[4];
printk(KERN_EMERG"TheModuleiswritten,XSB_Seg_write\n");
if(count!
=4)
{
printk(KERN_EMERG"thecountofinputisnot4!
!
");
return0;
}
if(copy_from_user(led_forall,buffer,4))
{
for(i=1;i<=4;i++)
{
value_seting(seg_7,i,LED[led_forall[i-1]]);
}
Updateled(seg_7);
}
return0;
}
(5)实现七段数码管驱动IOCTL操作函数
staticintXSB_Seg_ioctl(structinode*ip,structfile*fp,unsignedintcmd,unsignedlongarg)
{
charval=0x00;
structseg*seg_7=fp->private_data;
if(!
arg)
return-EINVAL;
if(copy_from_user(&val,(int*)arg,sizeof(char)))
return-EFAULT;
switch(cmd){
case1:
value_seting(seg_7,1,val);
break;
case2:
value_seting(seg_7,2,val);
break;
case3:
value_seting(seg_7,3,val);
break;
case4:
value_seting(seg_7,4,val);
break;
case0:
seg_7->negative=LED_MODULE;
break;
default:
printk(KERN_EMERG"ioctlparametererror,pleaseinputnumber0-4");
break;
}
Updateled(seg_7);
return0;
}
(6)实现七段数码管驱动打开操作函数
staticintXSB_Seg_open(structinode*inode,structfile*filp)
{
structseg*seg_7;
printk(KERN_EMERG"TheModuleisopen,XSB_Seg_open\n");
seg_7=kmalloc(sizeof(structseg),GFP_KERNEL);
filp->private_data=seg_7;
return0;
}
(7)实现七段数码管驱动释放函数
staticintXSB_Seg_release(structinode*inode,structfile*filp)
{
printk(KERN_EMERG"TheModuleisrelease,XSB_Seg_release\n");
kfree(filp->private_data);
return0;
}
(8)七段数码管驱动文件结构体定义
staticstructfile_operationsEmdoor_fops={
open:
XSB_Seg_open,
write:
XSB_Seg_write,
release:
XSB_Seg_release,
ioctl:
XSB_Seg_ioctl,
owner:
THIS_MODULE,
};
(9)实现七段数码管驱动初始化函数
staticint__initXSB_Seg_init(void)
{
intret;
printk(KERN_EMERG"TheModuleisInit,XSB_Seg_init\n");
CS1_Address=ioremap(SEG_CS1,4);
CS2_Address=ioremap(SEG_CS2,4);
ret=register_chrdev(61,DEVICE_NAME,&Emdoor_fops);
if(ret<0){
printk(DEVICE_NAME"can'tgetmajornumber\n");
returnret;
}
return0;
}
(9)实现七段数码管驱动模块退出函数与模块描述
staticvoid__exitXSB_Seg_exit(void)
{
printk(KERN_EMERG"TheModuleisExit,XSB_Seg_exit\n");
iounmap(CS1_Address);
iounmap(CS2_Address);
unregister_chrdev(61,DEVICE_NAME);
}
module_init(XSB_Seg_init);
module_exit(XSB_Seg_exit);
MODULE_AUTHOR("Ben.li,ben.li@");
MODULE_DESCRIPTION("Thisisa8SegmentLeddriverdemo");
第2步:
利用vi编辑器,编写一个用于编译xsb_seg.c驱动架构Makefile文件;
#Makefileforthe8Segment_LedDriver.#
CFLAGS+=$(DEBFLAGS)-Wall
ifneq($(KERNELRELEASE),)
obj-m:
=xsb_seg.o
else
KERNELDIR?
=/root/work/linux-2.6.22.10
PWD:
=$(shellpwd)
ALL:
$(MAKE)$(CFLAGS)-C$(KERNELDIR)M=$(PWD)modules
endif
clean:
rm–fr*.o*.ko*~core.depend.*.cmd*.mod.c.tmp_versions
第3步:
运行make编译命令,用ls命令查看编译后的结果,在该目录中应生成xsb_seg.ko模块文件,利用file命令查看xsb_seg.ko文件的格式,应为ARM格式的ELF文件。
第4步:
利用vi编辑器在test目录下编译测试驱动的seg_test.c源文件。
/************************************************
*************************************************/
#include
#include
#include
#include
typedefunsignedcharu8;
#defineSEG_DEV"/dev/xsb_seg"
charnumber[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7F,0x6F};
voidclear_led(intfd)
{
inti;
charval=0;
for(i=1;i<=4;i++)
ioctl(fd,i,&val);
sleep
(1);
}
voiddisplay_led(intfd)
{
inti;
charval=0x7f;
for(i=1;i<=4;i++)
ioctl(fd,i,&val);
sleep
(1);
}
voidappear_same(intfd)
{
chari,j,base=0;
for(j=0,base=0;j<=9;j++,base++){
for(i=1;i<=4;i++)
ioctl(fd,i,number+base);
sleep
(1);
}
}
voidappear_roll(intfd)
{
chari,j,base=0;
for(j=0,base=0;j<=9;j++,base++){
for(i=1;i<=4;i++)
ioctl(fd,i,number+(base+i-1)%10);
sleep
(1);
}
}
voiddisplay_menu()
{
printf("*****ChoiceMenu*********\n");
printf("[0]OpenDevice\n");
printf("[1]DisplaySame\n");
printf("[2]RollDisplay\n");
printf("[3]AllDisplay\n");
printf("[4]ClearDisplay\n");
printf("[5]WriteDisplay\n");
printf("[C]CloseDevice\n");
printf("[x]ExitTest\n");
printf("***********************\n");
printf("Pleaseinputyourchoise:
");
}
intmain(intargc,char**argv)
{
intfd=-1;
charch=0x00;
unsignedcharled[4]={2,0,0,8};
display_menu();
while
(1){
ch=getchar();
switch(ch)
{
case'0':
if(fd>0)
printf("##SEGDevicehasbeenopen##%d\n",fd);
else{
fd=open(SEG_DEV,O_RDWR);
if(fd<0)
printf("####SEGDeviceopenFail####\n");
else
printf("####SEGDeviceopenSuccess####%d\n",fd);
}
display_menu();
break;
case'1':
if(fd>0){
appear_same(fd);
clear_led(fd);
}
else
printf("##SEGDeviceisNOTopen##\n");
display_menu();
break;
case'2':
if(fd>0){
appear_roll(fd);
clear_led(fd);
}
else
printf("##SEGDeviceisNOTopen##\n");
display_menu();
break;
case'3':
if(fd>0)
display_led(fd);
else
printf("##SEGDeviceisNOTopen##\n");
display_menu();
break;
case'4':
if(fd>0)
clear_led(fd);
else
printf("##SEGDeviceisNOTopen##\n");
display_menu();
break;
case'5':
if(fd>0)
write(fd,led,4);
else
printf("##SEGDeviceisNOTopen##\n");
display_menu();
break;
case'c':
case'C':
if(fd>0){
clear_led(fd);
sleep
(1);
close(fd);
printf("##SEGDeviceisclosedsuccess##\n");
fd=-1;
}
display_menu();
break;
case'x':
case'X':
if(fd>0){
clear_led(fd);
sleep
(1);
close(fd);
}
exit(0);
break;
}
}
return(0);
}
第5步:
利用vi编辑器,编写一个用于编译seg_test.c的Makefile文件;其中CC=/opt/arm-linux/bin/arm-linux-gcc为交叉编译工具所在的路径位置,INCLUDEDIR=/opt/arm-linux/arm-linux/include为头文件所在的路径
CC=/opt/arm-linux/bin/arm-linux-gcc
INCLUDEDIR=/opt/arm-linux/arm-linux/include
CFLAGS=-I..-I$(INCLUDEDIR)
TARGET_TEST=seg_test
OBJ_TEST=$(TARGET_TEST)
SOURCE_TEST=$(TARGET_TEST).c
ALL:
$(CC)$(CFLAGS)-o$(OBJ_TEST)$(SOURCE_TEST)
clean:
rm-rf$(OBJ_TEST)
第6步:
运行make命令对seg_test.c源代码进行编译,用ls命令查看编译后的结果,利用file命令查看seg_test文件的格式,应为ARM格式的ELF文件。
第7步:
在Linux操作系统下输入minicom,配置串口参数,然后打开EELiod目标平台电源,平台启动后,按CTRL+A,然后按Z,启动串口命令界面,按S键,选择zmodem传输方式;按回车
第8步:
选择PC平台中驱动模块文件xsb_seg.ko和驱动测试文件seg_test,并按回车键。
下载选中的文件,文件下载完毕后按ESC键,退出串口传输,返回目标平台界面。
第9步:
在目标平台终端利用mknod命令建立设备文件节点;并利用insmod命令动态加载驱动模块,同时利用lsmod命令查看驱动模块的加载情况,
第10步:
在目标平台终端运行八段数码驱动测试程序seg_test,在平台终端将显示驱动测试程序菜单。
第11步:
在平台终端显示驱动测试程序菜单输入提示输入数字“0”。
驱动测试程序将通过open函数打开设备文件,同时内核调用驱动程序的xxx_open函数,在平台终端可以查看驱动和测试程序调试输出信息。
第12步:
在平台终端显示驱动测试程序菜单输入提示分别输入数字“1”、“2”、“3”、“4”,查看平台4个7段数码管的显示情况,并分析测试程序通过调用什么函数与驱动进行通信?
第13步:
在平台终端显示驱动测试程序菜单输入提示分别输入数字“5”、查看平台4个7段数码管的显示情况,并分析测试程序通过调用什么函数与驱动进行通信?
第14步:
在平台终端显示驱动测试程序菜单输入提示分别英文字符“C”或“c”,然后再输入“1~5”任何数字,查看测试程序的输出情况,并分析测试程序通过调用什么函数与驱动进行通信?
第15步:
在平台终端显示驱动测试程序菜单输入提示分别英文字符“X”或“x”,退出测试程序。
第16步:
在平台终端输入dmesg命令,查看驱动程序在加载和测试过程中输出消息,并分析驱动代码,查看输出信息。
4、实验总结
在做本次实验过程中,遇到很多问题,例如是pc机跟XSBase270实验开发箱的连接问题,把bootloader烧写到实验箱等等问题,在同学或网上找资料的帮助下,一步一步的把问题慢慢的解决,从而成功的把本次实验做好。