前言
电脑环境和开发板环境都已经搭建完成,下面要做的就是运行第一个APP和驱动程序,达到嵌入式入门。
第一个APP:Hello Word
(1)代码编写
#include <stdio.h>
int main(void)
{
printf("Welcome to Linux\n");
printf("Hello Word\n");
return 0;
}
(2)在Ubuntu下编译
arm-linux-gnueabihf-gcc -o hello hello.c
(3)拷贝到NFS目录
cp hello /home/ww/nfs_rootfs
此处是将hello.c文件建立并编译在共享文件夹下
(4)通过NFS下载到开发板上
1)VMware NAT方式
假设Windows IP为192.168.1.100,在开发板上执行以下命令(注意:必须指定port为2049、 mountport为9999):
mount -t nfs -o nolock,vers=3,port=2049,mountport=9999 192.168.1.100:/home/ww/nfs_rootfs /mnt
cp /mnt/hello ./hello
2)VMware桥接方式
假设Ubuntu IP为192.168.10.128,在开发板上执行以下命令:
mount -t nfs -o nolock,vers=3 192.168.10.128:/home/ww/nfs_rootfs /mnt
cp /mnt/hello ./hello
补充:
mobaxterm软件在复制过长的命令行时,出现覆盖的情况解决方法:
在log显示窗口右键 -> change terminal settings… ->Implict LF in every CR
(5)运行
添加可执行权限
chmod +x hello
运行
./hello
第一个驱动程序:moudle_test
该实验参考朱有鹏老师的驱动开发
驱动开发得到的.ko文件必须与开发板上的内核同出一门,否则不能安装,出现报错信息:insmod:ERROR:coud not insert XXXX.ko:Invalid module format
1、运行在Ubuntu进行实验观察
(1)代码编写
module_test.c文件
#include <linux/module.h>
#include <linux/init.h>
// 模块安装函数
static int __init chrdev_init(void)
{
printk(KERN_INFO "chrdev_init helloword init\n");
return 0;
}
// 模块卸载函数
static void __exit chrdev_exit(void)
{
printk(KERN_INFO "chrdev_exit helloworld exit\n");
}
module_init(chrdev_init);
module_exit(chrdev_exit);
// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE("GPL"); // 描述模块的许可证,这个许可证最好不要少,否则会出现莫名其妙的错误。
MODULE_AUTHOR("aston"); // 描述模块的作者
MODULE_DESCRIPTION("module test"); // 描述模块的介绍信息
MODULE_ALIAS("alias xxx"); // 描述模块的别名信息
Makefile文件
KERN_VER = $(shell uname -r)
KERN_DIR = /lib/modules/$(KERN_VER)/build
obj-m += module_test.o
all:
make -C $(KERN_DIR) M=`pwd` modules
cp:
cp *.ko /home/ww/nfs_rootfs
.PHONY: clean
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
(2)编译
进入到Makefile和module_test.c这两个文件的文件夹目录
cd /mnt/hgfs/share/x210v3/5.2.1
make all
(加图)
(3)安装、查看、卸载
查看驱动信息
modinfo module_test.ko
查看已安装的驱动
lsmod
安装 module_test 驱动
insmod module_test.ko
再次查看已安装驱动,观察 module_test 驱动是否安装
lsmod
卸载 module_test 驱动
rmmod module_test
再次查看已安装驱动,观察module_test 驱动是否卸载
lsmod
2、运行在开发板进行实验观察
因为该驱动是运行在开发板上,故要使用开发板上的内核进行驱动编译。之前使用BSP时,已经编译好kernel,因此只需将Makefile中内核的路径修改为
KERN_DIR = /x210v3_bsp/qt_x210v3/kernel
(1)代码编写
module_test.c文件不变和上面相同,只需要修改Makefile文件。
Makefile文件
KERN_VER = $(shell uname -r)
#修改为开发板的linux内核的源码树目录
KERN_DIR = /x210v3_bsp/qt_x210v3/kernel
obj-m += module_test.o
all:
make -C $(KERN_DIR) M=`pwd` modules
cp:
cp *.ko /home/ww/nfs_rootfs
.PHONY: clean
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
对make -C $(KERN_DIR) M=pwd
modules语句解释:
该命令是make modules命令的扩展,-C选项的作用是指将当前的工作目录转移到指定的目录,即(KDIR)目录,程序到(pwd)当前目录查找模块源码,将其编译,生成.ko文件
(2)下载内核和根文件系统到开发板,并下载 .ko 文件测试
1)直接使用fastboot下载kernel和根文件系统,用NFS下载 .ko 文件到开发板测试
编译kernel和根文件系统并下载
进入BSP路径下
cd /x210v3_bsp/qt_x210v3
生成zImage-qt
./mk -k
生成rootfs文件夹
./mk -r
生成ext3格式的rootfs镜像
./mk -re
使用fastboot指令将 zImage-qt 和 rootfs_qt4.ext3 下载到开发板上。
编译module_test,将.ko放入NFS共享目录
进入到Makefile和module_test.c这两个文件的文件夹目录
cd /mnt/hgfs/share/x210v3/5.2.1
make all
make cp
通过NFS传输 .ko 文件到开发板
NAT模式
假设Windows IP为192.168.1.100,在开发板上执行以下命令(注意:必须指定port为2049、 mountport为9999):
mount -t nfs -o nolock,vers=3,port=2049,mountport=9999 192.168.1.100:/home/ww/nfs_rootfs /mnt
桥接模式
假设Ubuntu IP为192.168.10.128,在开发板上执行以下命令:
mount -t nfs -o nolock,vers=3 192.168.10.128:/home/ww/nfs_rootfs /mnt
安装、查看、卸载
查看已安装的驱动
lsmod
安装 module_test 驱动
insmod module_test.ko
再次查看已安装驱动,观察 module_test 驱动是否安装
lsmod
卸载 module_test 驱动
rmmod module_test
再次查看已安装驱动,观察module_test 驱动是否卸载
lsmod
2)使用TFTP挂载内核,使用NFS挂载根文件系统和驱动(需要完善)
在uboot倒计时结束前,按回车键进入配置界面。
先设置IP地址
set serverip 192.168.1.141
set gatewayip 192.168.1.1
set netmask 255.255.255.0
配置TFTP
设置bootcmd使开发板通过TFTP下载自己建立的内核源码树编译得到的zImage
set bootcmd 'tftp 0x30008000 zImage;bootm 0x30008000'
配置NFS
设置bootargs使开发板从NFS去挂载rootfs(内核配置记得打开使能nfs形式的rootfs)
setenv bootargs root=/dev/nfs nfsroot=192.168.1.141:/root/porting_x210/rootfs/rootfs ip=192.168.1.10:192.168.1.141:192.168.1.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC2,115200
在内核目录下进行NFS配置
make menueconfig
配置网络部分,主要是使能CONFIG_IP_PNP以在2中能够看到Root file system on NFS选项
Networking support
Networking options
TCP/IP networking
IP: kernel level autoconfiguration
[] IP: DHCP support
[] IP: BOOTP support
配置开启nfs服务
File systems —>
Network File Systems —>
<> NFS client support
[] NFS client support for NFS version 3 [] NFS client support for the NFSv3 ACL protocol extension
[] NFS client support for NFS version 4 (EXPERIMENTAL)
[] NFS client support for NFSv4.1 (DEVELOPER ONLY)
[] Root file system on NFS
重新编译内核
make distclean
make x210ii_qt_defconfig
make -j4
编译module_test,将.ko文件放入NFS共享目录
进入到Makefile和module_test.c这两个文件的文件夹目录
cd /mnt/hgfs/share/x210v3/5.2.1
make all
make cp
安装、查看、卸载
查看已安装的驱动
lsmod
安装 module_test 驱动
insmod module_test.ko
再次查看已安装驱动,观察 module_test 驱动是否安装
lsmod
卸载 module_test 驱动
rmmod module_test
再次查看已安装驱动,观察module_test 驱动是否卸载
lsmod
第一次驱动程序与应用程序结合
驱动程序编写
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/uaccess.h>
int MYMAJOR;
char kbuf[50];//内核空间buf
//上层应用启用该驱动时的打印信息
static int test_open(struct inode *inode, struct file *file)
{
printk("test_open success\n");
return 0;
}
//上层应用关闭该驱动时的打印信息
static int test_close(struct inode *inode, struct file *file)
{
printk("test_close success\n");
return 0;
}
//上层应用传数据到内核空间
static ssize_t test_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
{
if(!copy_from_user(kbuf, buf, size))//写参数到内核驱动
{
printk("test_write success\n");
if(kbuf[0] == '1')
{
printk("write 1 success\n");
}
else if(kbuf[0] == '1')
{
printk("write 0 success\n");
}
else
{
printk("please write '0' or '1'\n");
}
}
else
{
printk("test_write fail\n");
}
return 0;
}
//内核空间传数据到上层应用
static ssize_t test_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
if(!copy_to_user(buf, kbuf, size))//从内核驱动读参数
{
printk("test_read success\n");
}
else
{
printk("test_read fail\n");
}
return 0;
}
//定义文件描述符
static const struct file_operations test_fops = {
.owner = THIS_MODULE,
.open = test_open,
.write = test_write,
.read = test_read,
.release = test_close
};
//驱动注册函数
//test_module为insmod生成的驱动名
static int __init test_init(void)
{
printf("test_init ing\n");
MYMAJOR = register_chrdev(0,"test_module",&test_fops);
if(MYMAJOR < 0)
{
printk("test_init fail\n");
return -EINVAL;
}
else
{
printk("test_init success\n");
return 0;
}
}
//驱动卸载函数
static void __exit test_exit(void)
{
printk("test_exit success\n");
unregister_chrdev(MYMAJOR, "test_module");
}
module_init(test_init);//驱动注册
module_exit(test_exit);//驱动卸载
MODULE_LICENSE("GPL");
MODULE_AUTHOR("WuLi");
Makefile文件编写
KERN_VER = $(shell uname -r)
KERN_DIR = /home/x210v3/kernel/ #目录为kernel的源码树目录
obj-m += module_test.o
all:
make -C $(KERN_DIR) M='pwd' modules
cp:
cp *.ko /home/x210v3/rootfs/customer/
#复制到使用busybox创建的rootfs文件夹
.PHONY: clean
clean:
make -C $(KERN_DIR) M='pwd' modules clean
上层应用程序编写
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define FILE "/dev/module_test"//执行mknod时的名称
char buf[20];//用户空间
int main(void)
{
int fd = -1;
int i = 0;
fd = open(FILE, O_RDWR);
if(fd < 0)
{
printf("open %s fail\n",FILE);
return -1;
}
printf("open %s success\n",FILE);
while(1)
{
memset(buf, 0, sizeof(buf));
printf("Please input on | off | read | quit\n");
scanf("%s",buf);
if(!strcmp(buf, "on"))
{
write(fd, "1", 1);
}
else if(!strcmp(buf, "off"))
{
write(fd, "0", 1);
}
else if(!strcmp(buf, "read"))
{
memset(buf, 0, sizeof(buf));
read(fd, buf, 1);
if(buf[0] == '1')
{
printf("The type is on\n");
}
else if(buf[0] == '1')
{
printf("The type is off\n");
}
else
{
printf("error\n");
}
}
else if(!strcmp(buf, "quit"))
{
break;
}
}
close(fd);
return 0;
}
编译
1。使用Makefile文件编译module_test.c文件生成module_test.ko;
2。使用交叉编译工具链gcc编译module_test_app.c生成可执行文件;
3。将module_test.ko和module_test_app复制到busybox生成的rootfs/customer文件夹中;
4。使用busybox生成rootfs.ext2
烧录测试
通过fastboot更新rootfs
1。通过lsmod查看开发板已安装的驱动
2。insmod module_test.ko
3。lsmod查看module_test.ko是否安装成功
4。cat /proc/devices查看module_test.ko安装后的设备号(设备名为module_test.c文件中register_chrdev注册时的命名)
5。mknod /dev/module_test c 229 0 (mknod (module_test_app.c文件中定义的FILE) c (cat查看后获取的设备号) 0)
6。执行 ./module_test_app 测试
7。测试完成后,先卸载驱动 rmmod module_test
8。再卸载设备 rm -r /dev/module_test