此文章介绍了如何在 Ubuntu 中编写一个简单字符设备驱动程序。
相关参考文章:SOC 教学教案
先进入 Ubuntu 并在主目录 home 下创建一个名为 work 的文件夹。在终端中进入此文件夹后,运行以下命令创建一个新的 PetaLinux 工程。
sptl
petalinux-create - t project --template zynq -n fii-module
注意我们将其命名为了 fii-module,与我们使用的开发板相符。
接下来我们将把 FPGA SDK 目录 FII_7030.sdk 拷贝到我们刚创建的 work 文件夹并编辑 fii_module。我们将使用一下命令进入 fii_module 工程目录。
cd fii-module
接下来我们将运行 sptl 命令并且使用以下命令编辑工程。
petalinux-config --get-hw-description ~/work/FII_7030.sdk/
我们不需要修改任何配置,直接关闭打开的窗口。
下面我们将使用以下命令填入并创建 fpga 设备树驱动。
petalinux-create -t modules --name fii-driver
接下来我们可以进入 ~/work/fii-module/project-spec/meta-user/recipes-modules/fii-driver/files 目录下通过编辑 fii-driver.c 文件编辑驱动。
文件打开后,我们将以此修改:
#include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> /* for put_user */ #include <asm/errno.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_device.h> //#include <linix/of_platform.h> /* 0x43c0_0000 + 4 = value 0x43c0_0000 + 8 = direction */ #define DEVICE_NAME "fii-module" #define CLASS_NAME "fii-module_class" static int major; static struct class *swled_class; static unsigned int *gpio_data; static unsigned int *gpio_dir ; static int swled_open(struct inode* node,struct file* filp){ unsigned int gpio_base = (0x43c00000); gpio_data = ioremap(gpio_base,8); if(gpio_data){ printk("kernel: ioremap(0x%08x)=0x%08x \n",gpio_base,gpio_data); } else{ return -EINVAL; } gpio_dir = gpio_data + 1; printk("kernel: gpio_data address = 0x%08x \n", gpio_data); printk("kernel: gpio_dir address = 0x%08x \n", gpio_dir); return 0; } int swled_release(struct inode *inode, struct file *filp) { // MOD_DEC_USE_COUNT; iounmap(gpio_data); return 0; } /* 0x43c0_0000 + 0 = value 0x43c0_0000 + 4 = direction */ static ssize_t swled_read(struct file *filp, char *buf, size_t size, loff_t *offset) { unsigned char val[32]; unsigned int temp; unsigned int *addr_p; int i = 0, cnt; printk("kernel: swled_read start.... size = %d\n", size); cnt = size; addr_p = gpio_data; temp = *addr_p ; for(i = 0; i < cnt/4; i++ ) { val[i*4 + 3] = temp & 0xff; val[i*4 + 2] = (temp >> 8) & 0xff; val[i*4 + 1] = (temp >> 16) & 0xff; val[i*4 + 0] = (temp >> 24) & 0xff; addr_p ++; temp = *addr_p; } if(i % 4 == 1) { val[i*4 + 0] = temp & 0xff; } if(i % 4 == 2) { val[i*4 + 1] = temp & 0xff; val[i*4 + 0] = (temp >> 8) & 0xff; } if(i % 4 == 3) { val[i*4 + 2] = temp & 0xff; val[i*4 + 1] = (temp >> 8) & 0xff; val[i*4 + 0] = (temp >> 16) & 0xff; } copy_to_user(buf, val, cnt); return cnt; } static ssize_t swled_write(struct file * filp, const char __user *buf, size_t size, loff_t * offset) { unsigned char val[32]; unsigned int temp = 0; unsigned int * addr_p; int i,cnt; memset(val,0,32); addr_p = gpio_data; printk("kernel: swled_write start.... size = %d\n", size); copy_from_user(&val, buf, size); cnt = size - 1; printk("kernel: val[0] = 0x%08x \n", val[0]); if(val[0] == 'w') { temp = val[2]; temp = temp << 8 | val[3]; temp = temp << 8 | val[4]; temp = temp << 8 | val[5]; *addr_p = temp; printk("kernel: gpio_data = 0x%08x \n", temp); } else if(val[0] == 'd') { addr_p ++; temp = val[2]; temp = temp << 8 | val[3]; temp = temp << 8 | val[4]; temp = temp << 8 | val[5]; *addr_p = temp; printk("kernel: gpio_dir = 0x%08x \n", temp); } else { printk("kernel: invalid parameter \n"); } return size; } static struct file_operations swled_oprs = { .owner = THIS_MODULE, .open = swled_open, .write = swled_write, .read = swled_read, .release= swled_release, }; static int swled_init(void){ /* register device */ /* * * int register_chrdev (unsigned int major, * const char *name, * struct file_operations*fops); * * major => 0, automatic mode; others major device ID */ major=register_chrdev(0, DEVICE_NAME, &swled_oprs); if (major < 0) { printk ("Registering the character device failed with %d\n", major); return major; } swled_class = class_create(THIS_MODULE, CLASS_NAME); device_create(swled_class, NULL, MKDEV(major,0), NULL, DEVICE_NAME); return 0; } static void swled_exit(void){ unregister_chrdev(major, DEVICE_NAME); device_destroy(swled_class,MKDEV(major,0)); class_destroy(swled_class); }; module_init(swled_init); module_exit(swled_exit); MODULE_LICENSE("GPL");
代码写完后请运行以下指令编辑 PetaLinux 驱动配置。
petalinux-config -c rootfs
图形界面打开后,进入 modules 并按下 [Y] 选择包含 fii-driver。退出前不要忘记保存。
接下来我们将使用以下命令编译内核。
petalinux-build -c kernel
接下来我们将使用以下命令编译驱动。
petalinux-build -c fii-driver
使用以下命令编译整个工程:
petalinux-build
我们现在可以通过执行以下命令创建工程文件:
petalinux-package --boot --fsbl --fpga --u-boot --force
我们将把 ~/work/fii-module/images/linux/ 中的 BOOT.BIN 和 image.ub 文件拷贝到 SD 卡的 boot 启动分区中,并把 rootfs.cpio 解压到 rootfs 分区中。
我们也将把 ~/work/fii_module/build/tmp/sysroots-components/plnx_zynq7/fii-driver/lib/modules/4.14.0-xilinx-v2018.3/extra/fii-driver.ko 文件拷入到 SD 卡中。
拷贝完之后请把 SD 卡插入 fii_7030 开发板并启动系统,并通过 PuTTY 建立连接。注意用户名和密码都是 root。
目前主要是在录制RISC-V 课程和verilog 教学课程, 之后我们会录制zynq petalinux 相关的课程。也会在网站上通知大家的
老师什么时候开视频课程呀