目录
- Zynq UltraScale+ MPSoC Linux下EMIO-GPIO驱动
- 1、MPSOC GPIO简介
- 2、vivado中EMIO配置
- 3、EMIO设备树修改
Zynq UltraScale+ MPSoC Linux下EMIO-GPIO驱动
声明:本文是学习赛灵思 Zynq UltraScale+ MPSoC 5EV过程中写的笔记,便于以后复习,参考《 ug1144-petalinux-tools-reference-guide》、《ug1085》、黑金Zynq UltraScale+ MPSoC 5EV开发板资料。
1、MPSOC GPIO简介
MPSOC
的GPIO
是有 6 个BANK
;如下图;BANK0
有 26 个信号,控制 MIO[0:25]
,BANK1
有 26 个信号,控制 MIO[26:51]
,BANK2
有 26 个信号,控制 MIO[52:77]
,MIO
总共有 78 个引脚,也就是诸如 SPI,I2C,USB,SD
等 PS端外设接口;
BANK3~BANK5
总共能控制 96 个 PL
端引脚,注意每一组都有三个信号,输入EMIOGPIOI
,输出 EMIOGPIOO
,输出使能 EMIOGPIOTN
,类似于三态门,共 288 个信号。
可以连接到 PL
端引脚,通过 PS
端控制。
2、vivado中EMIO配置
使用PL
端的emio
需要在vivado
中进行约束;如需要将BANK4
中的AA13
引脚设置为EMIO1
则需要在vivado
的XDC
文件中做如下约束
set_property PACKAGE_PIN AA13 [get_ports {emio_tri_io[1]}]
作用:将AA13约束为EMIO1;在zynqmpsoc中emio的编号是从78开始的,所以emio1对应的就是78+1 = 79。
3、EMIO设备树修改
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
/{
/* ps端 MIO*/
ledps{
compatatible = "led-ps";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_led_default>;
led-gpios = <&gpio 78 GPIO_ACTIVE_HIGH>;
};
keypl{
compatible = "keypl";
/* 79-emio引脚 GPIO_PULL_UP-GPIO属性 上拉输入 */
key-gpios = <&gpio 79 GPIO_PULL_UP>;
};
};
/* SD */
&sdhci1 {
disable-wp;
no-1-8-v;
};
/* USB */
&dwc3_0 {
status = "okay";
dr_mode = "host";
};
&gpio {
status = "okey";
};
&pionctrl0 {
status = "okey";
pinctrl_led_default:led-default{
mux {
groups = "gpio0_78_grp";
function = "gpio0";
};
conf {
pins = "EMIO78";
bias-disable;
slew-rate = <SLEW_RATE_SLOW>;
io-standard = <IO_STANDARD_LVCMOS18>;
};
};
};
在设备树中 emio 不需要配置pinctrl,直接使用gpio子系统即可。
驱动程序编写 key.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/ide.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#define CHAR_DEV_NAME "pl_key_dev"
/* 定义key设备结构体 */
struct key_dev{
dev_t devid;
struct cdev cdev;
struct class *class;
struct device *device;
struct device_node *nd;
struct gpio_desc *gpio_d;
struct semaphore lock;
};
static struct key_dev key_char = {
.cdev = {
.owner = THIS_MODULE,
},
};
/* 打开设备 */
static int key_open(struct inode *inode_p,struct file *file_p)
{
int ret = 0;
ret = down_interruptible(&key_char.lock);
if(ret)
{
printk("%s wait resource break\n", CHAR_DEV_NAME);
ret = -1;
}
else
{
printk("char dev open\n");
}
return ret;
}
/* 从设备读取数据 */
static int key_read(struct file *file_p, char __user *buf, size_t len, loff_t *loff_t_p)
{
int ret = 0;
unsigned char state = 0;
if(0 == gpiod_get_value(key_char.gpio_d))
{
medlay(50);
while(0 == gpiod_get_value(key_char.gpio_d));
state = 1;
ret = copy_to_user(buf,&state,sizeof(state));
}
else
{
ret = copy_to_user(buf, &state,sizeof(state));
}
return ret;
}
/* 关闭/释放设备 */
static int key_release(struct inode *inode_p, struct file *file_p)
{
up(&key_char.lock);
printk("char dev release\n");
return 0;
}
/* 设备操作函数 */
static struct file_operations key_fops = {
.owner = THIS_MODULE,
.open = key_open,
.read = key_read,
//.write = key_write,
.release = key_release,
};
/* 驱动初始化函数 */
static int __init key_drv_init(void)
{
int ret = 0;
ret = alloc_chrdev_region(&key_char.devid,0,1,CHAR_DEV_NAME);
if(ret < 0)
{
goto err;
}
cdev_init(&key_char.cdev.&key_fops);
ret = cdev_add(&key_char.cdev,key_char.devid,1);
if(ret < 0)
{
goto err;
}
key_char.class = class_create(THIS_MODULE,CHAR_DEV_NAME);
if(IS_ERR(key_char.class))
{
ret = PTR_ERR(key_char.class);
goto err;
}
key_char.device = device_create(key_char.class,NULL,key_char.devid,NULL,CHAR_DEV_NAME);
if(IS_ERR(key_char.device))
{
ret = PTR_ERR(key_char.device);
goto err;
}
key_char.device->of_node = of_find_node_path("/keypl");
key_char.gpio_d = gpio_get_index(key_char.device,"key",0,GPIO_IN);
gpiod_direection_input(key_char.gpio_d);
sema_init(&key_char.lock,1);
err:
return ret;
}
static void __exit key_drv_exit(void)
{
gpio_put(key_char.gpio_d);
cdev_del(&key_char.cdev);
device_destroy(key_char.class,key_char.devid);
class_destroy(key_char.class);
unregister_chrdev_region(key_char.devid,1);
}
module_init(key_drv_init);
module_exit(key_drv_exit);
MODULE_AUTHOR("kevin");
MODULE_ALIAS("emio_key");
MODULE_DESCRIPTION("EMIO KEY driver");
MODULE_VERSION("v1.0");
MODULE_LICENSE("GPL");
应用程序:Emio_Key_Test.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int mian(int argc, char *argv[])
{
int fd_led,fd_key;
int ret;
unsigned int key_value = 0;
fd_key = opne("/dev/pl_key_dev", O_RDWR);
if(fd_key < 0)
{
printf("file /dev/pl_key_dev open failed\r\n");
return -1;
}
fd_led = open("/dev/led_dev", O_RDWR);
if(fd_led < 0)
{
printf("file /dev/led_dev open failed\r\n");
return -1;
}
while(1)
{
ret = read(fd_key,&key_value, sizeof(key_value));
if(ret < 0)
{
printf("read failed\r\n");
break;
}
if(1 == key_value)
{
printf("key pushed\n");
led_value = !led_value;
ret = write(fd_led,&led_value,sizeof(led_value));
if(ret < 0)
{
printf("write failed\r\n");
break;
}
}
}
close(fd_key);
close(fd_led);
return 0;
}
测试
修改设备树后重新编译petalinux
,并打包生成BOOT.bin
文件,烧录到SD
卡中
petalinux-build
petalinux-package --boot --u-boot --fsbl --force
进入板载Linux系统中,加载led
和key
两个驱动文件
insmod pl-key.ko
insmod ps-led.ko
运行./Emio_Key_Test
printf("请关注微信公众号:Kevin的学习站,关于AUTSAR和自动驾驶嵌入式相关的文章!")
赛灵思-Zynq UltraScale+ MPSoC学习笔记汇总