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

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

保存, 退出
- 添加创建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


保存,退出
- 编辑用户设备树文件(system-user.dtsi )


设备树和 驱动程序代码中的设置必须一致, 这样系统才能找到驱动程序。
- 编译内核
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 波特率

用户名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

- 设置gpio 口, 点亮led 灯

至此, linux 就可以通过系统命令,设置 gpio(led)了
- Linux 下,应用程序开发
在ubuntu 下创建一个test_func目录, 在test_func 目录下创建fii_dt_app.c 文件

- 编辑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, 可以看到这个程序的使用指南

可根据上述命令选择: 方向寄存器,写操作, 读操作。
- 举例:
./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 状态)
至此,总线设备树驱动程序设计完成。