當下最火的是AI,Machine Learning, Embedded Vision。FPGA老酒新裝,在這個圈子里也可以摻和摻和。而談到linux,這里從事傳統(tǒng)嵌入式開發(fā)的朋友不在少數(shù),八成都在謀求轉(zhuǎn)型,尋個風口。急人所求,本篇軟文以一個簡單的實例來介紹一下FPGA的嵌入式linux里應用。隱去過多設計細節(jié),重過程體驗。新客們可以看個熱鬧,F(xiàn)PGA老玩家可以就此貴安。
這里的UIO即Userspace I/O,本文中UIO泛指UIO設備和UIO驅(qū)動。它在Linux kernel的世界里比較小眾,主要是只一些定制設備和相應的驅(qū)動。UIO內(nèi)核驅(qū)動指負責將中斷和設備內(nèi)存暴露給用戶空間,再由UIO用戶態(tài)驅(qū)動(Application)來實現(xiàn)具體的業(yè)務,隨心所欲的玩。學術(shù)點叫做高度定制化,柔性設計。那怎么和FPGA扯上了關系?是的,F(xiàn)PGA在硬件世界里也是隨心所欲的玩,這一硬一軟還真是登對,在一起啊在一起。
本實驗工程利用Xilinx Zynq UtralScale+(MPSoC)ZCU102嵌入式評估板上實現(xiàn)多個UIO,借助Xilinx的工具完成硬件工程和linux BSP的開發(fā),最后通過測試應用程序完成測試。
ZCU102上的MPSOC集成固化了四核ARMCortex-A53,雙核Cortex-R5以及Mali-400 MP2 GPU,這部分官方稱為PS(processor system)。另外一部分就是FPGA,即PL(programming logical)。PS端實現(xiàn)控制,PL用來實現(xiàn)應用加速,兩者通過AXI連接。跑這個小實驗,呵呵,大材小用。只是本人手頭正好有這個板子不得不裝。筒子們可以去買了個ZYBO, ZED的板子試試身手。
實驗報告
實驗人員:
實驗時間:
實驗材料:
Xilinx Vivado 2017.2
硬件工程設計工具
有免費版本
Petalinux 2017.2
Linux BSP開發(fā)工具(基于yocto)
免費
ZCU102 EVB final v1.0
高端開發(fā)板一枚
收費,貴
PC
電腦一臺
要快一點,空間大一點
硬件設計
建立Vivado工程,適配ZCU102 EVB。通過IP Integrator加入PS,在PL側(cè)加入5個UIO輸入,其中1個是GPIO模塊(包含中斷輸出和設備內(nèi)存),另外4個是PIN連接到ZCU102 EVB上的DIP開關,作為中斷輸入通過一個concat IP連接到PS的ps_pl_irq管腳。
板級細節(jié)請參考[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
寫好約束文件,
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庫,加上可以上天的智能連接。有點數(shù)字電路設計的基礎,很快就能完成這個小設計。整個設計如下圖。點贊!
軟件設計
這里用到Xilinx針對Linux BSP開發(fā)的Petalinux。它基于Yocto,加入Xilinx的Layers實現(xiàn)硬件工程的導入,將復雜的Yocto的設計流程打包簡化,支持一定的用戶自定義功能,如QEMU仿真運行,增加out-of-tree的驅(qū)動,Device tree修改,應用程序編譯打包,等等。這里簡單展示一下具體的命令過程。
$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側(cè)的dtsi文件生成與./components/plnx_workspace/device-tree-generation/pl.dtsi
這里只有GPIO UIO。PIN UIO因為不是IP,所以相關信息無法由工具自動生成。所以要做如下修改,
1.修改GPIO UIO設備端點
a)將中斷號改為93
b)將compatible改成“generic-uio” //我們后面要用Linux自帶的UIO_PDRV_GENIRQ驅(qū)動
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.
有兩個方法來適配UIO端點和 UIO_PDRV_GENIRQ 驅(qū)動
1. bootargs use“uio_pdrv_genirq.of_id=generic-uio”,可以通過DTS定義。
2. 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卡用于啟動。
測試
這里引用下關于uio_pdrv_genirq驅(qū)動的介紹
https://01.org/linuxgraphics/gfx-docs/drm/driver-api/uio-howto.html
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.
在結(jié)合驅(qū)動代碼./drviver/uio/uio_pdrv_genirq.c)可知,每個UIO設備會有對應的/dev/uioX的設備節(jié)點。用戶態(tài)驅(qū)動程序的讀操作會阻塞直到UIO硬件中斷發(fā)生。UIO的中斷處理程序uio_pdrv_denirq_handler()會關閉該硬件中斷。用戶態(tài)驅(qū)動程序需要通過write函數(shù)來觸發(fā)uio_pdrv_genirq_irqcontrol()以完成中斷的使能和關閉。代碼如下,
啟動內(nèi)核及加載uio_pdrv_genirq驅(qū)動
檢查/proc/interrupts
細心的你一定發(fā)現(xiàn)了一個坑,少了2個UIO中斷(IRQ122和IRQ124),原來是硬件不支持Edge falling和Level Low的觸發(fā)模式。kernel log如下。
測試DIP UIO方法一
通過撥動2個DIP,觀察到
2個DIP中斷發(fā)生了,可是不論怎么再撥動DIP開關,始終是1。上文鋪過,這個中斷在驅(qū)動的中斷處理程序里會被關掉,需要通過應用程序調(diào)用write()來打開。這里有個easy way,使用萬能的echo命令“echo 0x1 > /dev/uioX”,再配合DIP可以觸發(fā)多次中斷。
測試DIP UIO方法二
前面的方法比較low,這里有稍微高級的享受。寫個簡單的用戶態(tài)驅(qū)動程序,上代碼。
借助petalinux提供的交叉編譯工具編譯出bin文件,拷貝到啟動SD卡。
運行測試程序并配合DIP開關進程測試。(為了更好的體現(xiàn)測試運行情況,在UIO內(nèi)核驅(qū)動里增加了irqcontrol的調(diào)用打?。?/p>
測試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驅(qū)動會將設備內(nèi)存(寄存器)空間枚舉出來,由用戶態(tài)驅(qū)動程序通過mmap導出進行讀寫控制。參見AXI_GPIO IP的文檔pg144-axi-gpio.pdf,其寄存器如下。
測試應用程序會通過設置GIER和IP_IER來使能中斷。上代碼。
測試過程
或許你覺得這么貼圖代碼不厚道而不能施展復制黏貼大法,可不知我拙與WORD,沒try出好排版。莫急莫急,這里有GIT,https://gitenterprise.xilinx.com/AlexHe/UIO_Linux_Demo
硬件資源文件和Image,測試代碼一個都不能少,統(tǒng)統(tǒng)獻上。
實驗結(jié)論
UIO這種可高度自定義的設備結(jié)合Xilinx的MPSoC可以實現(xiàn)非常靈活的應用。Xilinx提供的完備的工具集,給用戶帶來了高效的開發(fā)體驗。本例雖然簡單,但Xilinx所推崇的All Programming的概念和實際的FPGA加速應用的的確確是建立在這些軟硬件協(xié)同技術(shù)之上。
作者簡介:
何曄:做過學生也做過老師又做了學生后錯入了IT門。接觸linux也有十來個年頭,輾轉(zhuǎn)于各種驅(qū)動開發(fā),無一精通。在AMD就職期間,曾提交過少量的xHCI和ACPI的patch,算是在linux內(nèi)核留下點印記?,F(xiàn)就職于Xilinx,從事與嵌入式FPGA的應用支持。FPGA的使用經(jīng)驗滿打滿算也不過半年,斗膽寫下此篇分享一下經(jīng)驗,也是自己一個小小設計的總結(jié)。其中謬誤,望指正并諒解。
參考文獻
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
評論