嵌入式快速入门学习笔记-第一个APP和驱动程序

前言

电脑环境和开发板环境都已经搭建完成,下面要做的就是运行第一个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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值