MPSOC上PS和PL基于UIO的中断(linux)
2020.09.12
软件平台:
Vivado 2018.3
PetaLinux 2018.3
Ubuntu16.04.6真机
硬件平台:
ZCU102 (ZynqMP)
Vivado框图如下
管脚约束如下,对照原理图选择sw13的低4位
然后编译vivado生成bit并且导出hdf文件,
petalinux创建以及编译的流程参考上一篇
MPSOC上PS和PL基于bram进行数据交互(linux)
这里需要注意的一点,由于uio部分petalinux不会自动生成节点,所以需要手动在system-user.dtsi添加对应的dts描述
首先修改project-spec/meta-user/recipes-bsp/device-tree/device-tree.bbappend如下
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
SRC_URI_append ="\
file://system-user.dtsi \
file://pl.dtsi \
"
然后修改system-user.dtsi如下
/include/ "system-conf.dtsi"
#include "pl.dtsi"
/ {
chosen {
bootargs = "earlycon clk_ignore_unused uio_pdrv_genirq.of_id=generic-uio";
stdout-path = "serial0:115200n8";
};
};
接下来就是创建一个pl.dtsi文件
如下
/*
* CAUTION: This file is automatically generated by Xilinx.
* Version:
* Today is: Sat Sep 12 04:53:17 2020
*/
/ {
amba_pl: amba_pl@0 {
#address-cells = <2>;
#size-cells = <2>;
compatible = "simple-bus";
ranges ;
axi_bram_ctrl_0: axi_bram_ctrl@b0000000 {
clock-names = "s_axi_aclk";
clocks = <&clk 71>;
compatible = "xlnx,axi-bram-ctrl-4.1";
reg = <0x0 0xb0000000 0x0 0x1000>;
xlnx,bram-addr-width = <0xa>;
xlnx,bram-inst-mode = "EXTERNAL";
xlnx,ecc = <0x0>;
xlnx,ecc-onoff-reset-value = <0x0>;
xlnx,ecc-type = <0x0>;
xlnx,fault-inject = <0x0>;
xlnx,memory-depth = <0x400>;
xlnx,rd-cmd-optimization = <0x0>;
xlnx,read-latency = <0x1>;
xlnx,s-axi-ctrl-addr-width = <0x20>;
xlnx,s-axi-ctrl-data-width = <0x20>;
xlnx,s-axi-id-width = <0x1>;
xlnx,s-axi-supports-narrow-burst = <0x1>;
xlnx,select-xpm = <0x1>;
xlnx,single-port-bram = <0x1>;
};
axi_gpio_0: gpio@a0000000 {
//#gpio-cells = <3>;
#gpio-cells = <2>;
#interrupt-cells = <2>;
clock-names = "s_axi_aclk";
clocks = <&clk 71>;
//compatible = "xlnx,axi-gpio-2.0", "xlnx,xps-gpio-1.00.a";
compatible = "generic-uio";
gpio-controller ;
interrupt-controller ;
interrupt-names = "ip2intc_irpt";
interrupt-parent = <&gic>;
interrupts = <0 93 4>;
reg = <0x0 0xa0000000 0x0 0x1000>;
xlnx,all-inputs = <0x0>;
xlnx,all-inputs-2 = <0x0>;
xlnx,all-outputs = <0x1>;
xlnx,all-outputs-2 = <0x0>;
xlnx,dout-default = <0x00000000>;
xlnx,dout-default-2 = <0x00000000>;
xlnx,gpio-width = <0x8>;
xlnx,gpio2-width = <0x20>;
xlnx,interrupt-present = <0x1>;
xlnx,is-dual = <0x0>;
xlnx,tri-default = <0xFFFFFFFF>;
xlnx,tri-default-2 = <0xFFFFFFFF>;
};
uio@0 {
compatible = "generic-uio";
status = "okay";
interrupt-controller;
interrupt-parent = <&gic>;
interrupts = <0 89 1>;
};
uio@1 {
compatible = "generic-uio";
status = "okay";
interrupt-controller;
interrupt-parent = <&gic>;
interrupts = <0 90 1>;
};
uio@2 {
compatible = "generic-uio";
status = "okay";
interrupt-controller;
interrupt-parent = <&gic>;
interrupts = <0 91 4>;
};
uio@3 {
compatible = "generic-uio";
status = "okay";
interrupt-controller;
interrupt-parent = <&gic>;
interrupts = <0 92 4>;
};
psu_ctrl_ipi: PERIPHERAL@ff380000 {
compatible = "xlnx,PERIPHERAL-1.0";
reg = <0x0 0xff380000 0x0 0x80000>;
};
psu_message_buffers: PERIPHERAL@ff990000 {
compatible = "xlnx,PERIPHERAL-1.0";
reg = <0x0 0xff990000 0x0 0x10000>;
};
};
};
~
由于mpsoc的uio中断只支持上升沿和高电平,所以interrupts最后一个参数只能是1或者4,1代表上升沿,4代表高电平.
接下来编译petalinux并且打包BOOT.BIN,拷贝BOOT.BIN和image.ub到sd卡,上电启动开发板
启动linux之后,我们首先看一下uio的对应关系
我现在要测试sw13的GPIO_DIP_SW0,也就是/dev/uio2设备节点,如下图
我来回拨动了9次开关,产生了9次上升沿中断.
测试代码如下
/*
* This application reads/writes GPIO devices with UIO.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
void usage(void)
{
printf("*argv[0] -d <UIO_DEV_FILE>\n");
printf(" -d UIO device file. e.g. /dev/uio0");
return;
}
int main(int argc, char *argv[])
{
int c;
int fd;
char *uiod;
unsigned i = 0;
unsigned icount;
int irq_on = 1;
int err;
printf("pin UIO test.\n");
while((c = getopt(argc, argv, "d:io:h")) != -1) {
switch(c) {
case 'd':
uiod=optarg;
break;
case 'h':
usage();
return 0;
default:
printf("invalid option: %c\n", (char)c);
usage();
return -1;
}
}
/* Open the UIO device file */
fd = open(uiod, O_RDWR);
if (fd < 1) {
perror(argv[0]);
printf("Invalid UIO device file:%s.\n", uiod);
usage();
return -1;
}
for(i = 0; ; ++i) {
/* Print out a message, for debugging. */
if (i == 0)
fprintf(stderr, "Started uio test driver.\n");
else
fprintf(stderr, "Interrupts: %d\n", icount);
/* enable IRQ, trigger the irqcontrol of driver */
write(fd, &irq_on, sizeof(irq_on));
/* Here we got an interrupt from the
device. Do something to it. */
err = read(fd, &icount, 4);
if (err != 4) {
perror("uio read:");
break;
}
}
return 0;
}
~
关于UIO的详细文档链接 https://01.org/linuxgraphics/gfx-docs/drm/driver-api/uio-howto.html