Menu Close

Writing a Simple Device Driver and Adding the FPGA register

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.

Posted in Textbook and Training Project

Related Articles

Leave a Reply

Your email address will not be published.

Leave the field below empty!