Menu Close

petalinx 下,总线设备树驱动程序的编写

FPGA 硬件设计为axi-lite 的gpio设计完成后,我们也可以在petalinux下设计总线设备树的驱动程序

 

硬件:FII_7030

vivado: 2018.3

petalinux: 2018.3

 

这一节我们讲述总线设备树驱动程序的编写。

  • 进入ubuntu :
  • 安装 petalinux 环境
  • 创建 petalinux 工程:/home/work/ 下

  sptl

petalinux-create -t project –template zynq -n fii-module

 

  • 导入创建fpga 工程中的sdk目录

将fpga 的sdk 工程目录FII_7030.sdk copy 到 ubuntu 的 home/work/ 下

 

  • 编辑fii_module 工程:

     进入fii_module 工程目录: cd fii_module

%title插图%num

执行sptl

 

petalinux-config –get-hw-description ~/work/FII_7030.sdk/

%title插图%num

保存, 退出

 

 

  • 添加创建fpga 自建设备树驱动程序:

   petalinux-create -t modules –name fii-dt-driver

  • 编辑 自建驱动程序:

进入~/work/fii_module/project-spec/meta-user/recipes-modules/fii-dt-driver/files 目录

 

  • 编辑 fii-dt-driver.c 文件

/*************************************************************************************************/

/*  dtpl-swled.c – The simplest kernel module.

 

* Copyright (C) 2013 – 2016 Xilinx, Inc

*

*   This program is free software; you can redistribute it and/or modify

*   it under the terms of the GNU General Public License as published by

*   the Free Software Foundation; either version 2 of the License, or

*   (at your option) any later version.

 

*   This program is distributed in the hope that it will be useful,

*   but WITHOUT ANY WARRANTY; without even the implied warranty of

*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

*   GNU General Public License for more details.

*

*   You should have received a copy of the GNU General Public License along

*   with this program. If not, see <http://www.gnu.org/licenses/>.

 

*/

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/module.h>

#include <linux/slab.h>

#include <linux/io.h>

#include <linux/interrupt.h>

#include <linux/uaccess.h>  /* for put_user */

 

#include <linux/of_address.h>

#include <linux/of_device.h>

#include <linux/of_platform.h>

 

/* Standard module information, edit as appropriate */

MODULE_LICENSE(“GPL”);

MODULE_AUTHOR

    (“FII inc.”);

MODULE_DESCRIPTION

    (“fii-dt-driver – loadable module template generated by petalinux-create -t modules”);

 

#define DRIVER_NAME “fii-dt-driver”

 

#if 0

 

static int fii_dt_driver_dev_init(void)

{

    platform_device_register(&fii_dt_driver_dev);

    return 0;

};

 

 

 

static struct platform_device  fii_dt_driver_dev={

 

    .name           = “fii-dt-driver”,

    .id             = -1,

    .num_resourse   = ARRAY_SIZE(fii_dt_driver_resourse),

    .resourse       = fii_dt_driver_resourse,

    .dev={

        .release    = fii_dt_driver_release,

        .of_match_table = of_match_fii_dt_driver,

    },

 

};

 

Static struct resourse fii_dt_driver_resource[]={

    [0]= {

        .strart     = mx , /* MX  will be replaced byconfig register addrss*/

        .end        = MX+1,

        .flag       = IORESOURCE_MEM,

    },

    //[1]{},

};

 

#endif

 

 

static const struct of_device_id  of_match_fii_dt_driver[] = {

//    {.compatible = “fii,fii-dt-driver”, .data = NULL},

    {.compatible = “fii,fii-dt-driver”, },

    {/*sentinel*/},

};

 

//platform driver

 

static struct class  *fii_dt_driver_class;

 

static unsigned int major;

static unsigned int * gpio_base;

static unsigned int * gpio_data;

static unsigned int * gpio_dir;

 

 

static int fii_dt_driver_init(void);

 

 

 

static int fii_dt_driver_open(struct inode* node,struct file* filp){

 

 

    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;

 

    return 0;

}

 

 

static int fii_dt_driver_release(struct platform_device * dev)

{

    iounmap(gpio_data);

 

    unregister_chrdev(major, “fii-dt-driver”);

    device_destroy(fii_dt_driver_class,MKDEV(major,0));

    class_destroy(fii_dt_driver_class);    

 

    return 0;

}

 

 

 

/*

    0x43c0_0000 + 4 = value

    0x43c0_0000 + 8 = direction

*/

 

static ssize_t fii_dt_driver_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,cnt;

    printk(“kernel: fii-dt-driver read start…. size = %d\n”, size);

//    cnt = size – 1;

    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);

 

//    printk(“val[0] = 0x%x, val[1] = 0x%x, val[2] = 0x%x, val[3] = 0x%x \n”,

//    val[0], val[1], val[2], val[3]);

 

    return cnt;

//    return size;

}

 

 

static ssize_t fii_dt_driver_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: fii-dt-driver 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”);

    }

 

 

 

#if 0

    temp = val[0] & 0xff;

    temp = temp << 8 | (val[1] & 0xff);

    temp = temp << 8 | (val[2] & 0xff);

    temp = temp << 8 | (val[3] & 0xff);

 

    printk(“val[0] = 0x%x, val[1] = 0x%x, val[2] = 0x%x, val[3] = 0x%x \n”,

    val[0], val[1], val[2], val[3]);

 

    *gpio_data = temp;

    printk(“gpio_data = 0x%08x \n”, temp);

 

 

    for(i = 0; i < cnt/4; i++)

    {

        temp = val[i*4 + 0];

        temp = temp << 8 | val[i*4 + 1];

        temp = temp << 8 | val[i*4 + 2];

        temp = temp << 8 | val[i*4 + 3];

 

        *addr_p = temp;

        addr_p ++;

        printk(“kernel: gpio_data[%d] = 0x%08x \n”, i, temp);

    }

 

    if(cnt %4 == 1)    

    {

        temp = val[i*4 + 0];

        *addr_p = temp;

        printk(“kernel: gpio_data[%d] = 0x%08x \n”, i, temp);

    }

    if(cnt %4 == 2)    

    {

        temp = val[i*4 + 0];

        temp = temp << 8 | val[i*4 + 1];

 

        *addr_p = temp;

        printk(“kernel: gpio_data[%d] = 0x%08x \n”, i, temp);

    }

    if(cnt %4 == 3)    

    {

        temp = val[i*4 + 0];

        temp = temp << 8 | val[i*4 + 1];

        temp = temp << 8 | val[i*4 + 2];

 

        *addr_p = temp;

        printk(“kernel: gpio_data[%d] = 0x%08x \n”, i, temp);

    }

 

 

#endif

 

    return size;

}

 

 

 

static struct file_operations fii_dt_driver_oprs = {

 

    .owner      = THIS_MODULE,

    .open       = fii_dt_driver_open,

    .write      = fii_dt_driver_write,

    .read       = fii_dt_driver_read,

//    .release    = fii_dt_driver_release,

};

 

 

static int fii_dt_driver_probe(struct platform_device *pdev)

{

    struct resource *res;

    printk (“kernel: enter fii_dt_driver probe …… \n”);

    printk (“kernel: enter fii_dt_driver probe …… \n”);

    printk (“kernel: enter fii_dt_driver probe …… \n”);

    printk (“kernel: enter fii_dt_driver probe …… \n”);

    printk (“kernel: enter fii_dt_driver probe …… \n”);

    printk (“kernel: enter fii_dt_driver probe …… \n”);

 

    res = platform_get_resource(pdev, IORESOURCE_MEM,0);

 

    if(res){

        gpio_base = res->start;

    }

#if 0

    else

    {

        of_property_read_s32(pdev->dev.of_node,”pin”,&led_pin);//led_pin

    }

 

    if(!led_pin)

    {

        printk(“can not get property for led\n”);

        return -EINVAL;

    }

#endif

//    dtpl_swled_init();

    major=register_chrdev(0, “fii-dt-driver”, &fii_dt_driver_oprs);

    if (major < 0) {

         printk (“Registering the character device failed with %d\n”, major);

        return major;

    }

 

 

    fii_dt_driver_class = class_create(THIS_MODULE, “fii-dt-driver_class”);

    device_create(fii_dt_driver_class,NULL,MKDEV(major,0),NULL,”fii-dt-driver”);

 

    return 0;

}

 

 

 

 

MODULE_DEVICE_TABLE(of, of_match_fii_dt_driver);

 

static struct platform_driver fii_dt_driver_drv = {

    .driver     = {

        .name   = “fii-dt-driver”,

        .owner  = THIS_MODULE,

        .of_match_table = of_match_fii_dt_driver,

//      .of_match_table = of_match_ptr(of_match_fii_dt_driver),

    },

    .probe      = fii_dt_driver_probe,

    .remove     = fii_dt_driver_release,

};

 

static int fii_dt_driver_init(void){       /* register device  */

 

    return platform_driver_register(&fii_dt_driver_drv);

 

}

 

 

static void fii_dt_driver_exit(void){

 

    platform_driver_unregister(&fii_dt_driver_drv);

    return;

};

 

 

//module_platform_driver(fii_dt_driver_drv);

 

 

module_init(fii_dt_driver_init);

module_exit(fii_dt_driver_exit);

 

MODULE_ALIAS(“platform:fii-dt-driver”);

/*************************************************************************************************/

  • 添加petalinux 驱动选项:

petalinux-config -c rootfs

%title插图%num

%title插图%num

保存,退出

  • 编辑用户设备树文件(system-user.dtsi )

%title插图%num

%title插图%num

设备树和 驱动程序代码中的设置必须一致, 这样系统才能找到驱动程序。

 

  • 编译内核

petalinux-build -c kernel

  • 编译驱动

petalinux-build -c fii-dt-driver

  • 编译整个工程:

petalinux-build

  • 制作工程文件

petalinux-package –boot –fsbl ./images/linux/zynq_fsbl.elf –fpga –u-boot –force

  • Copy (~/work/fii_module/images/linux/ 目录下的文件)BIN , image.ub 到SD卡上
  • 将sd卡插入到fii_7030开发板,启动fii_7030 开发板

 

  • 打开windows下的串口终端软件 , 配置串口为115200 波特率

%title插图%num

 

用户名root, 密码 root

 

  • 在串口终端上执行调试命令

cd /mnt

mkdir sd_0

mount /dev/mmcblk0p1 /mnt/sd_0

cd /mnt/sd_0

 

 

 

可以查看一下 /dev 目录下是否已经加载了fii-dt-driver 驱动

ls -l /dev/fii-dt-driver

如果存在, 说明驱动加载成功。

  • 设置方向寄存器

0x4300_0000 = 0 (output);  0x4300_0000 = 1 (最低位 input,其他位是 output);  

 

echo d 0000 > /dev/fii-dt-driver

%title插图%num

 

  • 设置gpio 口, 点亮led 灯

%title插图%num

至此, linux 就可以通过系统命令,设置 gpio(led)了

  • Linux 下,应用程序开发

在ubuntu 下创建一个test_func目录, 在test_func 目录下创建fii_dt_app.c 文件

%title插图%num

  • 编辑fii_dt_app.c文件 (应用程序文件)
  •  

/*************************************************************************************************/

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>   /* File Control Definitions           */

#include <termios.h> /* POSIX Terminal Control Definitions */

#include <unistd.h>  /* UNIX Standard Definitions    */

#include <errno.h>   /* ERROR Number Definitions           */

#include <string.h>

 

// Number of strings in array argv

//int main( int argc,            char *argv[],

//void main(void)

 

static void print_msg(void)

{

    printf(“=============================================================\n”);

    printf(“Usage :\n”);

    printf(“./fii_dt_app.o dir <val> : val : 0 => output; 1 => input\n”);

    printf(“./fii_dt_app.o wr  <val> : val : 0x43c0_0004 address value\n”);

    printf(“./fii_dt_app.o rd        : \n”);

    printf(“=============================================================\n”);

    return;

}

static void func_read(int fd,  int read_cnt)

{

    char rd_buf[32];        /* Buffer to store the data received              */

    int  bytes_read = 0;    /* Number of bytes read by the read() system call */

    unsigned int temp;

 

    printf(“Press ctrl+C to exit \n”);

    tcflush(fd, TCIFLUSH);   /* Discards old data in the rx buffer */

    lseek(fd, 0, SEEK_SET);

 

    bytes_read = read(fd, rd_buf, read_cnt);

    printf(“\n\nBytes Rxed = %d \n”, bytes_read); /* Print the number of bytes read */

 

    temp = rd_buf[0];

    temp = (temp << 8) | rd_buf[1];

    temp = (temp << 8) | rd_buf[2];

    temp = (temp << 8) | rd_buf[3];

 

    printf(“read value = 0x%08x \n”, temp);

 

    temp = rd_buf[4];

    temp = (temp << 8) | rd_buf[5];

    temp = (temp << 8) | rd_buf[6];

    temp = (temp << 8) | rd_buf[7];

 

    printf(“read dir   = 0x%08x \n”, temp);

    printf(“\n +———————————-+\n\n\n”);

 

//    usleep(1000000);

    return;

}

static void func_write(int fd,  char *p)

{

    char wr_buf[32];

    ssize_t bytes_written = 0;

    unsigned int value;

 

    memset (wr_buf, 0x0a, 32);

 

    value = atoi(p);

    printf(“value = %x \n” , value);

 

    wr_buf[0] = ‘w’;

    wr_buf[1] = ‘ ‘;

    wr_buf[2] = value >> 24;

    wr_buf[3] = (value >> 16) & 0xff;

    wr_buf[4] = (value >> 8) & 0xff;

    wr_buf[5] = value & 0xff;

 

    bytes_written = write(fd, wr_buf, 7);

 

    return;

}

static void func_direction(int fd,  char *p)

{

    char wr_buf[32];

    ssize_t bytes_written = 0;

    unsigned int value;

 

    memset (wr_buf, 0x0a, 32);

 

    value = atoi(p);

    printf(“value = %x \n” , value);

 

    wr_buf[0] = ‘d’;

    wr_buf[1] = ‘ ‘;

    wr_buf[2] = value >> 24;

    wr_buf[3] = (value >> 16) & 0xff;

    wr_buf[3] = (value >> 8) & 0xff;

    wr_buf[5] = value & 0xff;

 

    bytes_written = write(fd, wr_buf, 7);

}

int main( int argc, char *argv[])

{

    int fd;/*File Descriptor*/

    unsigned int value = 0;

    char * cmd_p;

 

    /* O_RDWR    – Read/Write access to serial port     */

    /* O_RDONLY  – Read access to serial port           */

    /* O_WRONLY  – Write access to serial port          */

    /* O_NOCTTY  – No terminal will control the process */

    /* Open in blocking mode,read will wait             */

 

    fd = open(“/dev/fii-dt-driver”,O_RDWR );

 

    printf(“\n +———————————-+”);

    printf(“\n |     fii-driver function          |”);

    printf(“\n +———————————-+”);

 

    if(fd == -1) /* Error Checking */

        printf(“\n  Error! in Opening swled  \n”);

    else

        printf(“\n  fii-driver Opened Successfully \n”);

 

    cmd_p = argv[1];

    if(argc == 2)

    {

        if( strcmp (cmd_p , “rd”) == 0 )

        {

            func_read(fd,  8);

            return 0;

        }

        else

        {

            print_msg();

            close(fd); /* Close the serial port */

            return 1;

        }

    }

    else if (argc == 3)

    {

        if( strcmp (cmd_p , “wr”) == 0 )

        {

            func_write(fd, argv[2]);

            close(fd); /* Close the serial port */

            return 0;

        }

        else if( strcmp (cmd_p , “dir”) == 0 )

        {

            func_direction(fd, argv[2]);

            close(fd); /* Close the serial port */

            return 0;

        }

    }

    else

    {

        print_msg();

        close(fd); /* Close the serial port */

        return 1;

    }

 

    return 0;

}

/*************************************************************************************************/

  • Fii_dt_app.c 编译

进入fii_dt_app工程目录

sptl

arm-linux-gnueabihf-gcc fii_dt_app.c -o fii_dt_app.o

生成fii_dt_app.o 文件

    COPY fii_dt_app.o 文件到 sd 卡上

 

  • 系统启动时自动加载fii-dt-driver.ko

 

  • 运行fii_dt_app 软件

在串口终端中执行, ./fii_dt_app.o,  可以看到这个程序的使用指南

%title插图%num

可根据上述命令选择: 方向寄存器,写操作, 读操作。

 

  • 举例:

./fii_dt_app.o dir 0  设置所有gpio 为 output

 

./fii_dt_app.o wr 0  设置最低位gpio 为 0

./fii_dt_app.o wr 7  设置最低三位gpio 为 0

 

./fii_dt_app.o dir 7  设置低三位gpio 为 input

./fii_dt_app.o rd    读取gpio 的值, (用户可以波动switch,查看gpio 状态)

 

至此,总线设备树驱动程序设计完成。

 

Posted in FPGA, Linux内核, Linux开发与应用, SoC, SoC, Verilog, 教材与教案, 驱动开发

发表评论

相关链接