ZYNQ中的UIO驱动和中断程序学习【Xilinx-Petalinux学习】_uio 及其中断(3)

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

Set the bank voltage for IO Bank 35 to 1.8V by default.

set_property IOSTANDARD LVCMOS33 [get_ports -of_objects [get_iobanks 35]];

set_property IOSTANDARD LVCMOS25 [get_ports -of_objects [get_iobanks 35]];
#set_property IOSTANDARD LVCMOS18 [get_ports -of_objects [get_iobanks 35]];


在Diagram中点击下图中的Run Connection Automation,可以配置对应开发板默认的Zynq设置。   
 ![这里写图片描述](https://img-blog.csdn.net/20170823145011470?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdmFjYWpr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)


弹出界面后点击OK。   
 vivado将自动创建reset、interconnector的IP并进行连接   
 ZCU102   
 ![这里写图片描述](https://img-blog.csdn.net/20170823145043724?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdmFjYWpr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)


ZedBoard   
 ![这里写图片描述](https://img-blog.csdn.net/20170823145053346?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdmFjYWpr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)


不用太关心Zynq或ZynqMP的具体配置和连接方式,我们直接使用这个工程就好了。


然后进行常规的操作



Generate Output Products
Create HDL Wrapper
Generate Bitstream
File -> Export -> Export Hardware(Include bitstream)
File -> Launch SDK


最终在工程目录下的\*.sdk中生成了config\_mpsoc\_wrapper\_hw\_platform\_0文件夹,里面包含了PetaLinux需要的hdf文件和FPGA配置的bit文件。


**注意:**到这里还没有结束,下面的步骤可以防止PetaLinux编译是的错误问题。   
 错误描述是fsbl或pmu-firmware在PetaLinux编译时出错,我自己感觉这是软件的bug或者是我的电脑网络不太好的问题。


解决的方法自己在Xilinx SDK中独立编译fsbl和pmufw的可执行文件。(pmufw只针对ZynqMP)


在操作方式如下图,分别建立fsbl和pmufw工程,工程代码下一个界面中的templates里选择对应的即可   
 ![这里写图片描述](https://img-blog.csdn.net/20170823145103917?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdmFjYWpr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)   
 ![这里写图片描述](https://img-blog.csdn.net/20170823145111240?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdmFjYWpr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)


这样在*.sdk/fsbl/Debug 和*.sdk/pmufw/Debug中就分别得到了fsbl.elf和pmufw.elf两个可执行文件,我们在后面生成boot.bin时候需要使用到。


## PetaLinux工程


将前面的config\_mpsoc\_wrapper\_hw\_platform\_0文件夹复制到虚拟机中。   
 创建PetaLinux工程



$ systemctl start tftp.socket
$ systemctl start tftp.service
$ source /opt/pkg/petalinux/settings.sh
$ petalinux-create -t project --template zynqMP -n zcu102-pl2ps_irq
$ cd zcu102-pl2ps_irq/
$ petalinux-config --get-hw-description …/config_mpsoc_wrapper_hw_platform_0/


在petalinux-config中取消fsbl和pmufw的编译,取消它们的勾选   
 ![这里写图片描述](https://img-blog.csdn.net/20170823145119329?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdmFjYWpr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)


保存并退出petalinux-config。


配置kernel打开UIO中断的支持



$ petalinux-config -c kernel
Device Drivers —>
Userspace I/O drivers —>
< > generic Hilscher CIF Card driver
Userspace I/O platform driver with generic IRQ handling


![这里写图片描述](https://img-blog.csdn.net/20170823145130130?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdmFjYWpr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)


编译出设备树文件



$ petalinux-build -c device-tree


中间有可能出现错误,一种情况是缺少libstdc++和glibc-devel,使用下面命令安装



yum install libstdc++.i686
yum install glibc-devel.i686


还有一种情况就是在上面Vivado工程中提到的我们需要自己生成fsbl和pmufw文件,否则有时候会错误。当然我们刚才在petalinux-config中已经取消了它们的编译,这里应该不会出现这种情况。


在文件./components/plnx\_workspace/device-tree-generation/pl.dtsi 中可以查看PL侧的设备树信息,里面包含了axi\_gpio\_0的设备树,需要用到。


打开文件./project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi   
 我们需要修改的设备树信息必须放在这个文件中才能有效,其他位置修改是不支持的。


**注意:**   
 假如需要添加其他自定义设备树文件,如直接从Xilinx提供的开发板BSP中会有对应板子的dtsi文件,首先需要在system-user.dtsi中加入文本   
 /include/ “board-conf.dtsi”   
 其次需要修改./project-spec/meta-user/recipes-bsp/device-tree/device-tree-generation\_%.bbappend 这个文件,加入文本   
 file://board-user.dtsi \   
 两个必须同时修改了,才有效果,否则会出错说找不到文件。


下面我们来往system-conf.dtsi中加信息。   
 ZCU102



/include/ “system-conf.dtsi”
/ {
amba_pl@0 {
#address-cells = <2>;
#size-cells = <2>;
compatible = “simple-bus”;
ranges ;
gpio@a0000000 {
#gpio-cells = <2>;
#interrupt-cells = <2>;
compatible = “generic-uio”;
gpio-controller ;
interrupt-controller ;
interrupt-parent = <&gic>;
interrupts = <0 93 4>;
reg = <0x0 0xa0000000 0x0 0x10000>;
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 2>;
    };

    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 8>;
    };
};

chosen {        
    bootargs = "earlycon clk_ignore_unused uio_pdrv_genirq.of_id=generic-uio";
    stdout-path = "serial0:115200n8";
};

};

&uart1
{
status = “disabled”;
};


ZedBoard



/include/ “system-conf.dtsi”
/ {
amba_pl {
#address-cells = <1>;
#size-cells = <1>;
compatible = “simple-bus”;
ranges ;

    gpio@41200000 {
        #gpio-cells = <2>;
        #interrupt-cells = <2>;
        compatible = "generic-uio";
        gpio-controller ;
        interrupt-controller ;
        interrupt-parent = <&intc>;
        interrupts = <0 33 4>;
        reg = <0x41200000 0x10000>;
        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 = <&intc>;
        interrupts = <0 29 1>;
    };

    uio@1 {
        compatible = "generic-uio";
        status = "okay";
        interrupt-controller;
        interrupt-parent = <&intc>;
        interrupts = <0 30 2>;
    };

    uio@2 {
        compatible = "generic-uio";
        status = "okay";
        interrupt-controller;
        interrupt-parent = <&intc>;
        interrupts = <0 31 4>;
    };

    uio@3 {
        compatible = "generic-uio";
        status = "okay";
        interrupt-controller;
        interrupt-parent = <&intc>;
        interrupts = <0 32 8>;
    };
};

chosen {
    bootargs = "console=ttyPS0,115200 earlyprintk uio_pdrv_genirq.of_id=generic-uio";
    stdout-path = "serial0:115200n8";
};

};


两个板子的内容不太一样,跟ZynqMP和Zynq的区别有关系,在这里不用太去考虑。只考虑dtsi文件中相同的地方。


首先因为我们四个中断号都没有硬件IP,所以PetaLinux并没有在pl.dtsi中给他们生成设备树信息,所以我们需要受动添加,如



uio@0 {
compatible = “generic-uio”;
status = “okay”;
interrupt-controller;
interrupt-parent = <&intc>;
interrupts = <0 29 1>;
};


看interrupts = <0 29 1> 这个信息。   
 29代表了中断号,这个中断号是系统硬件中断号减去32得到的,1代表中断类型为上升沿触发。具体的可以去网上查一下。


看amba\_pl下gpio@***\*\****中,跟PL.dtsi不同,将compatible的”xlnx,xps-gpio-1.00.a”改为了”generic-uio”,这样就将此axi\_gpio\_0改为了UIO的驱动类型。


看chosen的bootargs中增加了”uio\_pdrv\_genirq.of\_id=generic-uio”。


ZynqMP和Zynq的一个区别需要注意,ZynqMP的interrupt-parent指向的是&gic,而Zynq指向了&intc。其实可以再看看其他的dtsi文件,可以发现,intc其实也是指向了cpu的gic,所以说实际上是一样的,并没有使用PL侧的INTC IP核中断。


ZynqMP还需要将uart1的status设置为disabled,不进行这个配置的话,系统会卡死在下面的log处



[ 0.008300] Console: colour dummy device 80x25
[ 0.012558] console [tty0] enabled
[ 0.015924] bootconsole [cdns0] disabled


将uart1 disabled掉就可以正常启动了。具体原因不太清楚,在这里就先这样处理了。在ug1209中的说明也中关闭了uart1。


下面就可以进行编译了



$ petalinux-build


系统生成了新的文件目录/images/linux,将之前使用Xilinx SDK生成的fsbl.elf和pmufw.elf复制到到这个文件夹中。   
 生成boot.bin



//对于Zynq
$ petalinux-package --boot --fsbl=./images/linux/fsbl.elf --fpga --u-boot --force
//对于ZynqMP
$ petalinux-package --boot --fsbl=./images/linux/fsbl.elf --fpga --atf --pmufw --u-boot

//保存pre-built
$ petalinux-package --prebuilt --fpga ./images/linux/zed_video_wrapper.bit --force


将/images/linux目录下的boot.bin和image.ub复制到SD卡上,插到ZCU102上,启动板子。


输入用户名root,密码root   
 查看uio设备是否正常   
 ![这里写图片描述](https://img-blog.csdn.net/20170823145143693?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdmFjYWpr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)


发现少了两个uio   
 看前面的系统log,发现下降沿触发和低电平触发中断不可用,SW1和SW3不能用   
 ![这里写图片描述](https://img-blog.csdn.net/20170823145150835?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdmFjYWpr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)


只有AXI GPIO,SW0,SW2的中断可用   
 ![这里写图片描述](https://img-blog.csdn.net/20170823145158433?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdmFjYWpr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)


向上拨动SW0和SW2   
 ![这里写图片描述](https://img-blog.csdn.net/20170823145204833?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdmFjYWpr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)


再次拨动开关不能计数   
 是因为uio的终端处理函数被关闭了,需要调用write来重新打开


可以查看内核中的源码uio\_pdrv\_genirq.c和介绍<https://01.org/linuxgraphics/gfx-docs/drm/driver-api/uio-howto.html>   
 ![这里写图片描述](https://img-blog.csdn.net/20170823145217556?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdmFjYWpr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)


何晔老师写到



> 
> 在结合驱动代码./drviver/uio/uio\_pdrv\_genirq.c)可知,每个UIO设备会有对应的/dev/uioX的设备节点。用户态驱动程序的读操作会阻塞直到UIO硬件中断发生。UIO的中断处理程序uio\_pdrv\_denirq\_handler()会关闭该硬件中断。用户态驱动程序需要通过write函数来触发uio\_pdrv\_genirq\_irqcontrol()以完成中断的使能和关闭。
> 
> 
> 


使用echo 0x1 > /dev/uio1来写入,重新开启uio中断。   
 ![这里写图片描述](https://img-blog.csdn.net/20170823145229963?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdmFjYWpr/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)


从何老师那里拷贝过来了两个测试代码,pin-uio-test.c和gpio-uio-test.c。对gpio-uio-test.c进行了修改,看了看LED灯的测试。


pin-uio-test.c



/*

  • 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':

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

int err;

printf("pin UIO test.\n");
while((c = getopt(argc, argv, "d:io:h")) != -1) {
    switch(c) {
    case 'd':

[外链图片转存中…(img-5ymHgF6R-1715845207492)]
[外链图片转存中…(img-up6ka0S4-1715845207492)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值