时间:2020-11-21 11:03
人气:
作者:admin
引言
随着深度学习和5G的应用,对FPGA的功能要求越来越多。因此近几年FPGA大厂纷纷将自己的器件集成了更多的内核,比如赛灵思的zynq系列就集成了arm,GPU,PCIE,射频处理模块等等,用于满足各种各样的需求。出身FPGA的工程师们也必须拥抱这些变化,不仅仅要精通FPGA开发,还需要了解其他方面的知识。比如基于zynq的开发者,就需要了解arm,linux驱动以及linux系统。做深度学习加速的还需要了解深度学习网络以及网络压缩等知识。学习这些知识会让你的眼界更加开阔,会站得高看得远,在开始一项任务的时候不再是盲人摸象,而是高瞻远瞩,把握全局。
这是我介绍linux系统和驱动的第4篇文章,如有不恰当的地方欢迎指正,因为本人也是处于学习入门阶段。三人行,必有我师焉。讨论的多了,问题也就清晰了。这一篇主要介绍按键驱动的编写,了解中断的处理过程,以及设备树的修改。
1. vivado工程搭建
工程搭建很简单,就是配置完zynq核的外设后,增加一个axi_gpio模块,作为外部按键的接口。虽然按键并不是直接连接到arm的IO上,但是axi_gpio也被映射到zynq系统的内存空间中,linux驱动通过读写key对应的映射内存来控制和检测。要检测到key被按下我们必须开启中断,因此axi_gpio模块设置如下图。Address editor是gpio的对应的内存空间。Zynq已经为不同外设类型分配了可选的内存映射,通常工程建立完后,由软件工具自行分配就好了。如果一些外设内存有冲突,是无法生成hdf的。



配置完成后,进行管脚约束,然后综合实现,生成bit文件。再导出hdf文件,打开SDK来生成fsbl,u-boot还使用前几篇介绍驱动中的u-boot。U-boot通常不会因为驱动的新增而修改。但是由于增加了key按键,我们需要去设备树中修改对应的配置。
具体如何修改设备树,可以到linux驱动文件夹Documentation/devicetree中去寻找对应的外设文件,其中有设备树修改的介绍。Gpio的修改可以到gpio文件夹下的gpio-zynq.txt查看。其基本形式为:
gpio@e000a000 { #gpio-cells = <2>;
compatible = "xlnx,zynq-gpio-1.0";
clocks = <&clkc 42>;
gpio-controller;
interrupt-parent = <&intc>;
interrupts = <0 20 4>;
interrupt-controller;
#interrupt-cells = <2>;
reg = <0xe000a000 0x1000>; };
其中compatible主要是用于linux驱动去匹配设备树中相应的节点,后面我们会介绍,这个名字和那一块程序有关。主要是配置中断,其中interrupts-cell指定了interrupts有多少个属性。Interrupts的第一个属性是中断类型,第二个是中断号,最后一个表示触发类型:高电平触发、低电平触发、上升沿触发和下降沿触发四种类型。Interrupt-parent是中断所属的中断控制器。我们在SDK中产生了设备树,我们看到按键的相应节点位于amba_pl节点下,其中amba_pl是PL端的总线节点,而amba是PS端的总线节点,修改pl.dtsi中的gpio内容:

我们改了compitable的内容,同时要关注inerrupts,xlnx,all-inputs,xlnx,gpio-width这些属性。Gpio-width是宽度,all-inputs是表示为输入。
设备树修改完后就可以编译设备树文件,然后用fsbl,u-boot,设备树来制作boot.bin了。放到SD卡,启动linux系统。接下来进入关键环节,key驱动的编写。
2. 按键驱动代码剖析
对于一个刚刚入门的人来说,其实了解了驱动的基本框架就好了。每个驱动都按照它的框架进行编写和修改。能理解驱动的各个模块功能,在驱动调试或者编写中就能有的放矢。一个简单的驱动的构成也很复杂,代码也很多,篇幅有限,我只介绍主要部分。
1)platform框架
Platform是一种虚拟的平台,提供了驱动和具体硬件交互的接口。Platform_device类似于虚拟的总线,IIC,LCD,GPIO等外设都可以看做platform_device,通过它可以遍历所有的总线设备,而对应的驱动就是platform_driver。基本流程是:先注册platform_device,再注册platform_driver,然后匹配设备和驱动,最后注册整个驱动。
在linux3以前的版本,需要定义platform_device结构体,然后通过platform_device_register函数来注册设备。但是linux3.0以后出现了设备树,内核函数of_platform_default_populate_init会在内核启动后遍历设备树,自动注册每个节点对应的设备。因此只需要修改设备树参数就行了。首先看这个结构体:
static const struct of_device_id key_of_match[] __devinitdata={
{.compatible="xlnx,gpio-keys",},
{/*end of list*
Fidus Sidewinder-100集成PCIe NVMe 控制系统,有