This article walks through writing a simple device driver as well as adding the FPGA register.
For related subjects, please refer to the SOC Table of Contents.
We will first create a folder titled “work” in our home folder and go into its directory from the terminal.
We will next execute the following two commands to create a new PetaLinux project in the directory.
sptl
petalinux-create -t project --template zynq -n fii-module
Note that we named the project fii-module to match the development board we will be using.
We will then copy the FPGA SDK directory FII_7030.sdk to the work folder we just created and edit fii_module. Use the following command to enter the fii_module project directory:
cd fii-module
Next, we will execute the sptl command, and configure the project by using the following command:
petalinux-config --get-hw-description ~/work/FII_7030.sdk/
We don’t need to make any changes, and we can simply choose < Save > and < Exit >.
Next, we will insert and create the fpga device tree driver by using the following command:
petalinux-create -t modules --name fii-driver
We can now go on to edit the driver by going into the ~/work/fii-module/project-spec/meta-user/recipes-modules/fii-driver/files directory and editing the fii-driver.c file.
Driver Code Download: Simple Character Device Driver
Once the file is open, we will modify it as such:
#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");
When you finish writing the code, please execute the following command to edit the PetaLinux driver settings.
petalinux-config -c rootfs
Once the graphical interface opens, go into modules and include fii-driver by pressing [Y]. Make sure you save and exit when you are finished.
We will then proceed to compile the core by using the following command:
petalinux-build -c kernel
Next, we will use the following command to compile the driver:
petalinux-build -c fii-driver
Now we can go ahead and compile the entire project by using the following command:
petalinux-build
We will now create the project files by executing the following command:
petalinux-package --boot --fsbl ./images/linux/zynq_fsbl.elf --fpga --u-boot --force
We will now copy the BOOT.BIN file and the image.ub file from ~/work/fii-module/images/linux/ to partition 1 of the SD card, which should be the boot partition; and extract rootfs.cpio to the other partition, which should be titled rootfs.
We will also copy the file at ~/work/fii_module/build/tmp/sysroots-components/plnx_zynq7/fii-driver/lib/modules/4.14.0-xilinx-v2018.3/extra/fii-driver.ko to the SD card.
When finished, please plug the SD card into the fii_7030 development board and boot it up. Make sure you are connected to the board via PuTTY. Recall that both the username and the password is root.