location驱动包_Zynq SDK 驱动探求(三):论一个外设驱动的全部身家·Xilinx SDK 驱动源码结构...

f3d96fbd25b9f03eecdc91d67859a908.png
Processor is ready. Configure programable logic.
在新专栏 Rapid TCP/IP on Zynq 中,将围绕 Xilinx Zynq 系列芯片,从 SDK 驱动,PS-PL 协同加速,嵌入式协议栈 LWIP 分析以及 TCP/IP 硬件加速等方面,一起探求可灵活配置,软件定义,硬件加速的 TCP/IP 协议栈的实现。

在 Xilinx SDK 驱动中,每个外设都拥有许多源文件,一个个家财万贯。本文将以私有定时器为例,做一个香港小报记者,一一盘点驱动大佬们的身家。

Location,Location

全部的 SDK 驱动源代码位于赛灵思安装源目录

/SDK/2018.3(SDK版本)/data/embeddedsw/XilinxProcessorIPLib/drivers/ 中。

每个文件夹中存放着一个外设驱动, PS 和 PL 的外设驱动兼有。

ccc1278af2476025d6a3af68c8564e88.png

3000 多个文件夹,岂不是有 3000 多个外设,疯了疯了。其实也没有这么多,以中断控制器 scugic 为例,这里包括了外设驱动的 6 个版本,所以外设没这么多,估摸着也就千八百个。所有提供的历史版本都可以在 BSP 设置中切换使用。

d1edb7969771001814b9bc0fe91163fe.png

当你新建一个 SDK 工程的时候,一般都会同时新建一个 BSP,BSP 名为板级支持包,BSP 根据选择的硬件平台,统一管理所有启用的外设驱动函数库,以及包括 LwIP 等第三方函数库。

值得注意的是:所谓驱动管理,就是将硬件平台需要的外设源代码复制到当前 BSP 的目录下。也就是说如果需要修改源代码,需要到 SDK 的路径中修改,对于某个 BSP 代码的修改只对当前 BSP 有效。

我们首先新建一个 BSP 来看看 BSP 的结构。

456ed850e98ebe1573cc84dd98fba7d3.png

BSP 分为两个部分:文档源码

BSP Doucumentation 中是外设驱动的文档,双击某个外设即可用打开包括外设驱动概述,API等的文档,以网页的形式。在之后的文章中,我们可能会分析一下文档的重点区域。

源码都位于 ps7_cortexa9_0 目录下,包括头文件,函数库源码,编译完的函数库,编译函数库的 Makefile 文件以及概述 BSP 信息的 system.mss 文件。Makefile 用于执行将所有的外设驱动函数库源代码编译为 libxil.a 。

d6d4bfb5e8d27b8e2be7f3c77359bacf.png

所以定时器身家几何?

终于来到了本文的主要部分,定时器的源代码有哪些文件?

05f4dfa44ab32cc87fe8bf90dd4cd474.png

在 libsrc/scutimer 下的 src 目录中,共有 7 个文件,基本上所有的外设都是同样的设定,所以了解定时器之后,所有外设的源文件结构也就大抵明了。

xscutimer_selftest.c :

仅包括一个外设自测试函数 XScuTimer_SelfTest ,通过对外设寄存器进行读写一致性测试判断外设是否已经就绪。通过测试函数可以发现外设初始化失败,外设寄存器基址有误等错误。

xscutimer_sinit.c:

仅包括外设配置查找函数 XScuTimer_LookupConfig,将外设 ID 对应的硬件配置以外设配置结构体的形式返回。外设的硬件信息来自于 vivado 生成并导致出至 SDK 的硬件平台信息。这个函数在上一篇文章中进行了详细的讨论。

ljgibbs:Zynq SDK 驱动探求(二):外设,从初始化到干活​zhuanlan.zhihu.com
b1074b4ac96373d6f7c1a99fc54db0d8.png

xscutimer_g.c:

本文件为通过硬件信息生成的硬件外设 ID 于寄存器基址映射表数组。数组中每个位置存放有一个外设配置结构体。XScuTimer_LookupConfig 正是通过匹配 ID 的方式获得对应的外设配置结构体。

/*

xscutimer.c:

本文件中定义了定时器初始化,启动,写入/读取定时器等外设配置控制函数。这些函数体中通过 XScuTimer_ReadReg/XScuTimer_WriteReg 函数访问寄存器,完成相应的外设控制和配置操作。

但值得注意的是,xscutimer.c 中仅包括了部分外设管理配置函数,其余的函数以宏定义的形式分别定义于 xscutimer.h 以及 xscutimer_hw.h 等头文件中。这不禁让人发问:为什么有的函数定义在源文件中,而有些只能以宏定义的形式蜗居于头文件中?是什么让 Xilinx 的程序员厚此薄彼,到底是人性的沦丧还是道德的沉沦?(xilinx 程序员们你们好,手动狗头)

对此问题,我只发现了问题的表面现象,那就是在 xscutimer.c 中定义的函数对传入参数进行了检查,而 xscutimer.h 和 xscutimer_hw.h 中宏定义的函数则不检查参数。看来是xscutimer.c 中定义的函数比较关键吧,命比较贵,惹不起。

xscutimer.h

作为主要的头文件,定义了外设的数据结构,包括最重要的两个结构体:XScuTimer_Config,XScuTimer。分别为外设配置结构体,用于存储外设的硬件信息;外设实例结构体,用于存储外设具体的配置参数。

还定义了我们上述讨论的外设配置函数,以及声明了 xscutimer.c 中定义的函数,做了一个头文件应该做的。

xscutimer_hw.h

该文件的描述中是这么说的:This file contains the hardware interface to the Timer. 定义了寄存器的地址偏移,寄存器位的 mask ,定义了寄存器操作函数 XScuTimer_ReadReg/XScuTimer_WriteReg ,这都非常合理地实现了一个硬件接口的工作,专注于寄存器访问。

但还定义了外设配置函数是什么鬼情况?比如:

#define XScuTimer_SetLoadReg(BaseAddr, Value)				

即定义了写寄存器函数,又定义了调用写寄存器函数的外设配置函数。这样层级不就全乱了,定义硬件结构的初衷也不存在了啊。外设配置函数就应该定义在 xscutimer.c/h 中啊,然后调用 xscutimer_hw.h 中的寄存器操作函数啊。

冷静了一下,打开了别的外设 xyyyy_hw.h 文件观察了一下:我只能说大部分的外设驱动代码遵从了分层的概念:只在 xyyyy_hw.h 文件中定义了读写寄存器操作,但有一小部分外设驱动还定义了外设配置函数。

然后又冷静了一下:发现了 xscutimer_hw.h 中函数的特点,那就是以外设基址作为参数,而 xscutimer.c/h 中的函数,则以外设实例结构体作为参数,接收参数后再从中取出外设基址。所以这是出于什么考虑呢,暂时不清楚。

对此我只能说两点:一,作为一个外设驱动库,统一,分层的源码文件架构应该是必须的。二,读写寄存器操作其实没有必要再每个外设中定义,因为不同的外设实质上都使用统一的方式访问寄存器,即下层的 Xil_In32/ Xil_Out32 函数,完全可以抽象出一个寄存器层次。

#define XScuWdt_ReadReg(BaseAddr, RegOffset)		

至于 Makefile 我很想强行分析一下,无奈之前学的语法已经基本上忘了,但应该会在后续的文章中专门分析 SDK 中外设驱动的编译过程。

结语

至此,本文分析了 SDK 中外设源码存放的路径,BSP 的组成以及以定时器为例,分析了外设的源文件的组成与功能。此外,还对 Xilinx SDK 的设计提出了一点小疑问。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值