linux userspace 编译,何晔: 当ZYNQ遇到Linux Userspace I/O(UIO)

原创 何晔 Linux阅码场 2017-08-12

作者简介

何晔:做过学生也做过老师又做了学生后错入了IT门。接触linux也有十来个年头,辗转于各种驱动开发,无一精通。在AMD就职期间,曾提交过少量的xHCI和ACPI的patch,算是在linux内核留下点印记。现就职于Xilinx,从事与嵌入式FPGA的应用支持。FPGA的使用经验满打满算也不过半年,斗胆写下此篇分享一下经验,也是自己一个小小设计的总结。其中谬误,望指正并谅解。

25ca40d75f460fd21ff20b1f69090f78.png

欢迎您给Linuxer投稿,作品一旦录取,获得任意在售技术图书,随便您自己挑,征稿细节: Linuxer-"Linux开发者自己的媒体"首月稿件录取和赠书名单

装B一点可以叫《UIO在FPGA上的实现和应用》。本文出于草根,还是装C吧。

当下最火的是AI,Machine Learning, Embedded Vision。FPGA老酒新装,在这个圈子里也可以掺和掺和。而谈到linux,这里从事传统嵌入式开发的朋友不在少数,八成都在谋求转型,寻个风口。急人所求,本篇软文以一个简单的实例来介绍一下FPGA的嵌入式linux里应用。隐去过多设计细节,重过程体验。新客们可以看个热闹,FPGA老玩家可以就此贵安。

这里的UIO即Userspace I/O,本文中UIO泛指UIO设备和UIO驱动。它在Linux kernel的世界里比较小众,主要是只一些定制设备和相应的驱动。UIO内核驱动指负责将中断和设备内存暴露给用户空间,再由UIO用户态驱动(Application)来实现具体的业务,随心所欲的玩。学术点叫做高度定制化,柔性设计。那怎么和FPGA扯上了关系?是的,FPGA在硬件世界里也是随心所欲的玩,这一硬一软还真是登对,在一起啊在一起。

本实验工程利用Xilinx Zynq UtralScale+(MPSoC)ZCU102嵌入式评估板上实现多个UIO,借助Xilinx的工具完成硬件工程和linux BSP的开发,最后通过测试应用程序完成测试。

ZCU102上的MPSOC集成固化了四核ARMCortex-A53,双核Cortex-R5以及Mali-400 MP2 GPU,这部分官方称为PS(processor system)。另外一部分就是FPGA,即PL(programming logical)。PS端实现控制,PL用来实现应用加速,两者通过AXI连接。跑这个小实验,呵呵,大材小用。只是本人手头正好有这个板子不得不装。筒子们可以去买了个ZYBO, ZED的板子试试身手。

实验报告

实验人员:本人

实验时间:几天前

实验材料:

Xilinx Vivado 2017.2

硬件工程设计工具

有免费版本

Petalinux 2017.2

Linux BSP开发工具(基于yocto)

免费

ZCU102 EVB final v1.0

高端开发板一枚

收费,贵

PC

电脑一台

要快一点,空间大一点

硬件设计

建立Vivado工程,适配ZCU102 EVB。通过IP Integrator加入PS,在PL侧加入5个UIO输入,其中1个是GPIO模块(包含中断输出和设备内存),另外4个是PIN连接到ZCU102 EVB上的DIP开关,作为中断输入通过一个concat IP连接到PS的ps_pl_irq管脚。

板级细节请参考[1]UG1182,芯片资料参考[2]UG1085

IRQ source

Trigger type

IRQ number

Board Info

pl_irq_er

edge rising

121

SW13.8, DIP0

pl_irq_ef

edge falling

122

SW13.7, DIP1

pl_irq_lh

level high

123

SW13.6, DIP2

pl_irq_ll

level low

124

SW13.5, DIP3

axi_gpio_1

N/A

125

写好约束文件,

569c072445c943b91c657599b55a9db0.png

set_property PACKAGE_PIN AN13 [get_ports pl_irq_ll]

set_property IOSTANDARD LVCMOS33 [get_portspl_irq_ll]

set_property PACKAGE_PIN AM14 [get_ports pl_irq_lh]

set_property IOSTANDARD LVCMOS33 [get_portspl_irq_lh]

set_property PACKAGE_PIN AP14 [get_ports pl_irq_ef]

set_property IOSTANDARD LVCMOS33 [get_portspl_irq_ef]

set_property PACKAGE_PIN AN14 [get_ports pl_irq_er]

set_propertyIOSTANDARD LVCMOS33 [get_ports pl_irq_er]

Vivado的图形化的模块设计,丰富的IP库,加上可以上天的智能连接。有点数字电路设计的基础,很快就能完成这个小设计。整个设计如下图。点赞!

32c556bafbda94197b2594b9b93a0bdb.png

软件设计

这里用到Xilinx针对Linux BSP开发的Petalinux。它基于Yocto,加入Xilinx的Layers实现硬件工程的导入,将复杂的Yocto的设计流程打包简化,支持一定的用户自定义功能,如QEMU仿真运行,增加out-of-tree的驱动,Device tree修改,应用程序编译打包,等等。具体信息请移步https://www.xilinx.com/products/design-tools/embedded-software/petalinux-sdk.html

这里简单展示一下具体的命令过程。

$petalinux-create -t project --template zynqMP -n zcu102-pl2ps_irq

$cd ./ zcu102-pl2ps_irq

$petalinux-config --get-hw-description

$petalinux-config -c kernel

Enable UIO_PDRV_GENIRQ driver

CONFIG_UIO=y

# CONFIG_UIO_CIF is not set

CONFIG_UIO_PDRV_GENIRQ=y

$petalinux-build -c device-tree

PL侧的dtsi文件生成与./components/plnx_workspace/device-tree-generation/pl.dtsi

67418c75c6e4d42efd536aeefbe63dad.png

这里只有GPIO UIO。PIN UIO因为不是IP,所以相关信息无法由工具自动生成。所以要做如下修改,

1.修改GPIO UIO设备端点

a)将中断号改为93

b)将compatible改成“generic-uio” //我们后面要用Linux自带的UIO_PDRV_GENIRQ驱动

2.增加DIP UIO端点

a)将compatible改成“generic-uio”

b)依次设置中断值89到93

c)按照每个DIP PIN的interrupt trigger type设置属性值

*DTS里的中断号与硬件中断号有32的offset。

Petalinux提供了自定义DTS文件./project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi,将以上修改定义到system-user.dtsi.

96476f710d57d8374800f437e2cd252c.png

有两个方法来适配UIO端点和 UIO_PDRV_GENIRQ 驱动

bootargs use“uio_pdrv_genirq.of_id=generic-uio”,可以通过DTS定义。

insmod uio_pdrv_genirq.ko of_id=generic-uiowhen install the driver

修改完后,编译出Image.

$petalinu-build

$cd ./images/linux

$petalinux-package --boot--fsbl zynqmp_fsbl.elf --fpga --atf --pmufw --u-boot --force

将生成的BOOT.bin(bootloader)和image.ub(FIT uImage)拷贝到SD卡用于启动。

测试

Using uio_pdrv_genirq for platform devices

Especially in embedded devices, you frequently find chips where the irq pin is tied to its own dedicated interrupt line. In such cases, where you can be really sure the interrupt is not shared, we can take the concept of uio_pdrv one step further and use a generic interrupt handler. That’s what uio_pdrv_genirq does.

The setup for this driver is the same as described above for uio_pdrv, except that you do not implement an interrupt handler. The .handler element of struct uio_info must remain NULL. The .irq_flags element must not contain IRQF_SHARED.

You will set the .name element of struct platform_device to "uio_pdrv_genirq" to use this driver.

The generic interrupt handler of uio_pdrv_genirq will simply disable the interrupt line using disable_irq_nosync(). After doing its work, userspace can reenable the interrupt by writing 0x00000001 to the UIO device file. The driver already implements an irq_control() to make this possible, you must not implement your own.

Using uio_pdrv_genirq not only saves a few lines of interrupt handler code. You also do not need to know anything about the chip’s internal registers to create the kernel part of the driver. All you need to know is the irq number of the pin the chip is connected to.

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

1d18f75b9879532f73390dd1a61a2cf5.png

启动内核及加载uio_pdrv_genirq驱动

d83390965fc9e2d89a4e77d6027b6a92.png

检查/proc/interrupts

f4eadd418811b83793b25312c6ee37aa.png

细心的你一定发现了一个坑,少了2个UIO中断(IRQ122和IRQ124),原来是硬件不支持Edge falling和Level Low的触发模式。kernel log如下。

aed65e141661dc4158b4f462acfaf096.png

测试DIP UIO方法一

通过拨动2个DIP,观察到

8ec2012b932d30835266a76ccd380992.png

2个DIP中断发生了,可是不论怎么再拨动DIP开关,始终是1。上文铺过,这个中断在驱动的中断处理程序里会被关掉,需要通过应用程序调用write()来打开。这里有个easy way,使用万能的echo命令“echo 0x1 > /dev/uioX”,再配合DIP可以触发多次中断。

66bf05190dc6a12fa674d2b850b10725.png

测试DIP UIO方法二

前面的方法比较low,这里有稍微高级的享受。写个简单的用户态驱动程序,上代码。

d6d5d2a233dcee0442466af6f9e1b8d6.png

25f981b192c42d419ddcdf9e56919dd6.png

借助petalinux提供的交叉编译工具编译出bin文件,拷贝到启动SD卡。

运行测试程序并配合DIP开关进程测试。(为了更好的体现测试运行情况,在UIO内核驱动里增加了irqcontrol的调用打印)

695dab50a21b836509328c88d0ce7142.png

测试GPIO UIO

This test application mmap out the registers fromhardware to user space. Then enable all the IRQ bits in GIER and IP_IERregisters and dump out all the registers’ values. Please refer topg144-axi-gpio.pdf for the IP.

UIO驱动会将设备内存(寄存器)空间枚举出来,由用户态驱动程序通过mmap导出进行读写控制。参见AXI_GPIO IP的文档pg144-axi-gpio.pdf,其寄存器如下。

bdb984d584d09083bfb0f740aaa2811f.png

测试应用程序会通过设置GIER和IP_IER来使能中断。上代码。

3f3dbfbc9ed72ebae9ab306ed5505dcc.png

3ed944509d50bc3ff9396dad48579139.png

测试过程

0b39c6049a28526c7db96ae1e5218245.png

或许你觉得这么贴图代码不厚道而不能施展复制黏贴大法,可不知我拙与WORD,没try出好排版。莫急莫急,这里有GIT,https://gitenterprise.xilinx.com/AlexHe/UIO_Linux_Demo

硬件资源文件和Image,测试代码一个都不能少,统统献上。酸爽否?

实验结论

UIO这种可高度自定义的设备结合Xilinx的MPSoC可以实现非常灵活的应用。Xilinx提供的完备的工具集,给用户带来了高效的开发体验。本例虽然简单,但Xilinx所推崇的All Programming的概念和实际的FPGA加速应用的的确确是建立在这些软硬件协同技术之上。忘周知!

参考文献

The Userspace I/O HOWTO https://01.org/linuxgraphics/gfx-docs/drm/driver-api/uio-howto.html

[Xilinx]

[1] UG1182 - ZCU102 Board User Guide

[2] UG1085 - Zynq UltraScale+ MPSoC Technical Reference Manual

[3] UG1144 - PetaLinux Tools Documentation: Reference Guide

[4] UG940 - Vivado Design Suite Tutorial: Embedded Processor HardwareDesign

[5] PG144 - AXI GPIO v2.0 Product Guide

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值