实验七 嵌入式系统驱动实验资料.docx
《实验七 嵌入式系统驱动实验资料.docx》由会员分享,可在线阅读,更多相关《实验七 嵌入式系统驱动实验资料.docx(16页珍藏版)》请在冰豆网上搜索。
实验七嵌入式系统驱动实验资料
实验七ARM9嵌入式系统硬件驱动基础开发实验
【实验目的】
1.掌握嵌入式linux内核的配置编译及移植。
2.掌握ARMlinux驱动程序的开发流程。
【实验内容】
1.常用linux命令的使用
2.嵌入式linux驱动程序开发步骤
3.linux内核配置、编译以及移植
【实验设备】
1.ARM9开发板
2.串口线、USB线
3.PC机(软件:
VMwareWorkstation6.5)
【实验原理】
嵌入式Linux是以Linux为基础的嵌入式作业系统,它被广泛应用在移动电话、个人数字助理(PDA)、媒体播放器、消费性电子产品以及航空航天等领域中。
Linux是开放源代码的操作系统,同时具有体积小、执行速度快、较好的可裁剪性与移植性等特点。
针对ARMCPU开发的具有MMU(MemoryManagementUnit)功能的嵌入式Linux操作系统是ARM平台上操作系统的最佳选择。
通用的基于ARM系统的Linux开发步骤如下:
1)开发目标硬件系统:
如选择微处理器,Flash及其他外设等;
2)建立交叉编译工具:
一般的GCC工具都是针对X86体系的,为了能够生成目标板可执行的代码必须建立交叉编译工具;
3)开发Bootloader:
建立启动系统的主引导程序;
4)移植Linux内核:
如基于ARM的Linux2.4内核移植;
5)开发一个根文件系统:
如yaffs文件系统的制作;
6)开发相关硬件的驱动程序:
如LCD、Keypad等;
7)开发上层的应用程序:
如QTGUI开发。
驱动程序的目的一般式驱动硬件正常工作,所以通常所说的驱动程序都是针对特定的硬件来编写的。
驱动程序既可以工作在有操作系统的环境下,也可以工作在无操作系统的环境中。
通常在做一些简单的硬件控制时,由于功能比较单一,不需要操作系统来管理,所以针对这种情况下的驱动程序相对来说也比较简单,但是作为一个嵌入式系统,他要实现的任务也相对比较多,比较复杂,所以需要有操作系统来对他进行管理。
设备驱动程序是操作系统内核和及其硬件之间的接口。
设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。
Linux下的设备驱动程序是内核的一部分,运行在内核模式。
也就是说,设备驱动程序为内核提供了一个I/O接口,用户使用这个接口实现对设备的操作。
我们在这个实验中主要是将驱动程序的C文件交叉编译后添加进内核,同时,在文件系统中添加驱动测试程序。
最后将生成的系统映像文件烧进开发板中。
对于驱动程序的使用,有静态编译和动态编译两种,静态编译指的是将驱动程序添加到内核中,动态编译是指将驱动程序编译成驱动模块。
我们采用第一种,即静态编译的方式添加驱动程序。
驱动程序的开发步骤如下:
1)首先,用户在自己的驱动程序源文件中定义file_operations结构,并编写出设备需要的各种操作函数,对于设备不需要的操作函数用NULL初始化,这些操作函数将被注册到内核。
当应用程序对相应的设备文件进行操作时,内核会找到相应的操作函数,并进行调用。
如果操作函数使用NULL,操作系统就进行默认的处理。
2)设备驱动程序编写完成后,就可将其添加到linux内核中,这需要修改linux的源码,然后重新配置编译linux内核。
3)编写相应的驱动测试程序,下载到ARM板进行相应驱动的测试。
【实验步骤】
1.打开桌面上的虚拟机软件VMwareWorkstation,用户名为root,密码为123456,即以超级用户的身份登录。
打开终端,学习一下Linux常用命令:
#cd/切换到根目录
#cddir切换到当前目录下的dir目录下
#cd..切换到上一级目录
#ls显示当前目录下的文件列表
#vifile编辑文件file
#tarxzvffile.tgz将文件file解压
#rmfile删除文件
#rm–frdir删除当前目录下叫dir的整个目录
#cpsourcetarget将文件source复制为target,可以指定文件路径
#catfile查看file的内容
#mvfile/dir将当前目录下的file文件移动到dir目录下
还有一些命令会在后面的使用中具体讲解。
2.在终端里进入/opt/FriendlyARM/Nano2410V2目录下,其中有一个kernel文件夹,这就是我们要操作的LINUX的内核。
进入kernel/drivers/char,即内核驱动的字符型设备驱动文件夹,然后ls查看里面的文件列表,其中有一个super2410-leds.c文件,这是一个led驱动程序,但此程序需要修改才能适用于我们的ARM板。
3.输入visuper2410-leds.c,对此文件进行编辑。
在vi编辑器里面默认的是命令模式,键入i就进入了编辑模式。
程序里led_table中定义了四个端口,我们将GPIO_E13改为GPIO_F7,即我们只对板子上的LED2进行操作。
修改之后按Esc回到命令模式,然后输入:
wq保存退出。
4.打开kernel/drivers/char目录下的Makefile文件,即输入viMakefile。
切换到编辑模式,在第199行里输入obj-$(CONFIG_SUPER2410_LEDS)+=super2410-leds.o。
按Esc键,输入:
wq保存退出。
这一步操作时为了在编译内核时将super2410-leds.c编译成super2410-leds.o文件。
5.打开kernel/drivers/char目录下的Config.in文件,即输入viConfig.in。
切换到编辑模式,在第89行里输入dep_tristate‘SupportSuper2410Leds’CONFIG_SUPER2410_LEDS,然后按Esc键,输入:
wq保存退出。
这样在运行menuconfig配置字符设备时就会出现SupportSuper2410Leds的字样,如果选中并编译通过,驱动程序就加到内核中了。
6.返回到/kernel目录下面,输入makemenuconfig,进行内核的配置。
首先找到Characterdevices,回车进入,找到SupportSuper2410Leds(NEW),键入空格选中此项。
然后返回上一级,进入Generalsetup,在TimerandCPUusageLEDS上键入空格,取消选中。
如果选中则两个LED分别用于Timer和CPU,我们的测试程序将看不到效果,故在此处将其取消。
然后保存退出,这时可以进行LINUX内核的编译了。
7.在终端里输入makedep,这一步仅仅在第一次编译时需要,为的是编译时内核知道文件之间的依赖关系;输入makeclean,该命令用于清除以前编译内核时生成的所有目标文件、模块文件和临时文件;输入makezImage,即将内核编译成gzip压缩形式的image。
编译通过后会在目录kernel/arch/arm/boot下生成zImage内核文件。
8.编译好之后,我们查看kernel/drivers/char目录会看到super2410-leds.o文件,如果没有则我们的LED驱动程序没有加入到内核。
另一种方法是在终端里kernel目录下输入catSystem.map|grepleds,如果有matrix4_leds_init、matrix4_leds_ioctl、matrix4_leds_fops(这几个是super2410-leds.c文件里的函数)等,则表明驱动已经正确地加入到了内核。
9.将zImage文件拷贝到/mnt/hgfs/share文件夹里,则在windows下我们可以获得此文件。
下面进行驱动测试程序的操作。
10.在虚拟机的/opt/FrindlyARM/Nano2410V2/examples找到leds文件夹,里面有两个文件,main.c是led的测试程序,Makefile是用来指明编译main.c文件时要用的编译器。
在终端里进入此文件夹,输入make后在该文件下生成一个二进制程序led。
将其重命名为ledtest,拷贝到/opt/FriendlyARM/Nano2410V2/root_qtopia_tp/sbin下。
这个root_qtopia_tp文件夹是我们板子所使用的文件系统。
11.将root_qtopia_tp文件夹拷贝到/opt/FriendlyARM/Nano2410V2/mkyaffs文件夹下,在终端里进入此文件夹,输入命令./mkyaffsimageroot_qtopia_tptest.img。
执行完后在mkyaffs文件夹下会生成test.img文件,这是我们要下载到ARM板子上的文件系统映像文件。
12.将前面的zImage和test.img文件下载到ARM板,然后重新启动,通过windows主机的超级终端进行驱动程序的测试。
13.在windows主机下,打开开始-程序-附件-通讯-超级终端,输入自定义的名称,选择COM口(默认COM1即可),端口设置如下图:
将ARM板上面的COM0和主机的串口用串口线连接,上电后会在超级终端里看到启动信息,当出现“PleasepressEntertoactivethisconsole”时键入回车进入操作系统,如下图
此时可以通过超级终端控制我们的ARM板了。
14.这时候可以看到LED2在闪烁,其控制程序是/etc/rC.d/init.d下面的leds。
输入./ledsstop后,则此程序被结束,LED不再闪烁。
15.进入/sbin,查看文件列表会发现我们添加的驱动测试程序ledtest:
进入/dev会看到我们加入内核的驱动leds(驱动程序super2410-leds.c中定义的驱动名称为leds),如下图:
这时候我们进行驱动程序的测试,输入ledtest11则点亮LED2,输入ledtest10则熄灭LED2。
实现一个简单的linux字符设备驱动
步骤1:
编写驱动程序
1.#include
2.#include
3.#include
4.#include
5.#include
6.#include
7.#include
8.#include
9.#define DEVICE_NAME "cdev_zhangwei"
10.int number_of_devices = 1;
11.struct cdev mydev;
12.dev_t dev = 0;
13.char data[128] = "/0"; // the data of my device
14.struct class *myclass;
15.static int mydev_open(struct inode *inode, struct file *file)
16.{
17. pr_info("mydev driver open!
/n");
18. return 0;
19.}
20.static int mydev_release(struct inode *inode, struct file *file)
21.{
22. pr_info("mydev driver released!
/n");
23. return 0;
24.}
25.ssize_t mydev_write(struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
26.{
27. ssize_t ret = 0;
28. pr_info("mydev_write!
/n");
29. pr_info("writing %d bytes/n", count);
30. if (count > 127)
31. return -ENOMEM;
32. if (count < 0)
33. return -EINVAL;
34. if (copy_from_user(data, buf, count)) {
35. ret = -EFAULT;
36. }
37. else {
38. data[127] = ''/0'';
39. pr_info("kernel received:
%s/n", data);
40. ret = count;
41. }
42. return ret;
43.}
44.static ssize_t mydev_read(struct file* filp, char* buf, size_t len,loff_t* off)
45.{
46. if( copy_to_user(buf,data,len) )
47. {
48. return -EFAULT;
49. }
50.
51. return len;
52.}
53.struct file_operations mydev_fops = {
54. .owner = THIS_MODULE,
55. .open = mydev_open,
56. .read = mydev_read,
57. .write = mydev_write,
58. .release = mydev_release
59.
60.};
61.static int __init mydev_init(void)
62.{
63. int result, error;
64. result = register_chrdev(0, DEVICE_NAME, &mydev_fops);
65. pr_info("udev_cdev:
get major number:
%d/n", result);
66. dev = MKDEV(result, 0);
67. myclass = class_create(THIS_MODULE, "mydev_class");
68. device_create(myclass, NULL, dev, NULL, DEVICE_NAME);
69. return 0;
70.}
71.static void __exit mydev_exit(void)
72.{
73. cdev_del(&mydev);
74. unregister_chrdev_region(dev, number_of_devices);
75. device_destroy(myclass, dev);
76. class_destroy(myclass);
77. pr_info("Goodbye cdev!
/n");
78.}
79.module_init(mydev_init);
80.module_exit(mydev_exit);
81.MODULE_LICENSE("GPL");
82.MODULE_DESCRIPTION("Simple cdev udev driver test");
步骤2:
编译,形成ko文件,然后利用insmod命令插入内核。
(最好利用makefile进行编译,网上有文章专门有介绍)
步骤3:
创建设备节点:
mknod/dev/your_name c 主设备号 次设备号
次设备号这里填0,主设备号可以利用cat/proc/devices查看
步骤4:
编写用户程序(测试咱们的驱动是否可行),如以下代码简单的用gcc命令编译就好了
1.#include
2.#include
3.#include
4.#include
5.#include
6.int main (void)
7.{
8. int fd,len;
9. pid_t pid;
10. char buff[] = "This is from userspace zhangwei fight it!
";
11. char buff_read[100] ;
12. fd = open ("/dev/cdev_zhangwei", O_RDWR);
13. if (fd < 0) {
14. perror("open failed");
15. exit(0);
16. }
17. pid = fork();
18. if(pid>0)
19. {
20. len = write (fd, buff, sizeof(buff));
21. printf ("son Write returns %d/n",len );
22. }
23. else // parent
24. {
25. //waitpid(pid);
26. printf ("read returns %d/n", read(fd,buff_read,len) );
27. printf("buff_read = %s/n",buff_read);
28. }
29. close (fd);
30. return 0;
31.}
到了这里,对字符设备驱动就有一个直观的印象了。
【实验报告要求】
1.将实验中用到的驱动程序及测试程序打印出来附在实验报告中。
2.将实验中用到的Linux基本命令及其作用写在实验报告中。
3.回答实验思考题。
【思考题】
1.分析Linux内核与文件系统之间的关系。
2.简述硬件驱动开发的基本流程。
3.查看本实验中驱动程序的内容,分析其file_operations结构。