文章目录
- 编译内核
- 拓展一下,如果是其他板子内核编译有几种方式(可以不用看):以下是树莓派板子的内核编译
- 驱动编写框架
- 驱动框架
- 结束
编译内核
编写驱动之前先去官网下载,手册,跳到5.几章先弄好内核编译
照着手册来,没问题。(文章说需要切换清华的源)(我没切换)(反而切换出了很多错误)
http://www.orangepi.cn/html/hardWare/computerAndMicrocontrollers/service-and-support/Orange-Pi-Zero-2.html
必须内核编译,驱动编写,需要一个编译好的内核
编译成功后,看到源码树目录多了vmlinux,失败则无此文件
拓展一下,如果是其他板子内核编译有几种方式(可以不用看):以下是树莓派板子的内核编译
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make bcm2709_defconfig
指定ARM架构 指定编译器 树莓派 主要核心指令
第一种方式:cp 厂家.config .config
第二种方式:make menuconfig 一项项配置,通常是基于厂家的config来配置
第三种方式:完全自己来
编译:
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make -j4 zImage modules dtbs
编译成功后,看到源码树目录多了vmlinux,失败则无此文件
成功后,目标zImage镜像arch/arm/boot底下
打包zImage成树莓派可用的xxx.img
./scripts/mkknlimg arch/arm/boot/zImage ./kernel_new.img
这里作为一个拓展吧,每个内核编译都可能不同,具体找商家手册来看
驱动编写框架
驱动两种加载方式:
- *编译进内核 zImage包含了驱动
- M 模块方式生成驱动文件xxx.ko 系统启动后,通过命令inmosd xxx.ko 加载
驱动框架
#include <linux/fs.h> //file_operations声明
#include <linux/module.h> //module_init module_exit声明
#include <linux/init.h> //__init__exit 宏声明
#include <linux/device.h> //class device 声明
#include <linux/uaccess.h> //copy_from_user的头文件
#include <linux/types.h> //设备号dev_t类型声明
#include <asm/io.h> //ioremap iounmap的头文件static struct class *pin4_class;
static struct device *pin4_class_dev;static dev_t devno; //设备号
static int major =231; //主设备号
static int minor =0; //次设备号
static char *module_name="pin4"; //模块名//ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
static ssize_t pin4_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{printk("pin4_read\n");return 0;
}static int pin4_open(struct inode *inode,struct file *file)
{printk("pin4_open\n"); //内核打印函数,和printf类似return 0;
}static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{printk("pin4_write\n");return 0;
}static struct file_operations pin4_fops = {.owner = THIS_MODULE,.open = pin4_open,.write = pin4_write,.read = pin4_read,
};
//static int __init
static int pin4_drv_init(void)
{int ret;devno = MKDEV(major,minor);ret = register_chrdev(major, module_name,&pin4_fops);pin4_class=class_create(THIS_MODULE,"myfirstdemo");pin4_class_dev =device_create(pin4_class,NULL,devno,NULL,module_name);return 0;
}static void pin4_drv_exit(void)
{device_destroy(pin4_class,devno);class_destroy(pin4_class);unregister_chrdev(major, module_name);
}module_init(pin4_drv_init);
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");
这个框架需要和用户态的open等函数进行配合,需要知道linux内核框图可明白
这里直接放上代码,去和驱动框架进行配合
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{int fd;fd = open("/dev/pin4",O_RDWR);if(fd < 0){printf("open fail\n");}else {printf("open success\n");}fd = write(fd,'1',1);
}
这里俩个文件,放入先放入虚拟机交叉编译。
驱动代码需要内核编译成模块,再用scp上传开发板。
普通代码编译完,也上传到开发板就可以。
编译成模块方法:
使用aarch64-none-linux-gnu-先设置环境变量
cd ~
vi .bashrc
最后一行添加export PATH = $PATH: /……/bin//aarch64-none-linux-gnu-命令所在地位置
(在内核编译完成之后个toolchain文件夹在里面找)
在这个文件夹下,放入你的驱动代码
orangepi-build-main/kernel/orange-pi-4.9-sun50iw9/drivers/char
修改Makefile文件
vi Makefile
添加咱们写的驱动
obj-m +=pin4Dev.o(文件名是啥就写啥后缀为.o即可)
保存退出wq
使用命令编译
回到内核源码这里的路径进行编译
orangepi-build-main/kernel/orange-pi-4.9-sun50iw9
输入命令
ARCH=arm64 CROSS_COMPILE=aarch64-none-linux-gnu- KERNEL=kernel make modules
将.ko文件放到(没有ko就是内核编译有问题,重新编译去)
通过以下命令配合
sudo insmod 文件.ko //加载驱动
//加载驱动以后,在/dev/pin4就会看到//但是此时运行我们的测试代码是打不开的,需要添加权限
sudo chmod 666 /dev/pin4 //所有用户可读可写
./a.out//测试文件,看到打开成功
//如果看不到输出信息可以输入dmesg |grep pin4//可查看内核态输出信息lsmod //查看驱动
sudo rmmod 文件//卸掉驱动
成功;
结束
如有问题欢迎提出,共同进步