location驱动包_Zynq SDK 驱动探求(三):论一个外设驱动的全部身家·Xilinx SDK 驱动源码结构...
在新專欄 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 的外設驅動兼有。
3000 多個文件夾,豈不是有 3000 多個外設,瘋了瘋了。其實也沒有這么多,以中斷控制器 scugic 為例,這里包括了外設驅動的 6 個版本,所以外設沒這么多,估摸著也就千八百個。所有提供的歷史版本都可以在 BSP 設置中切換使用。
當你新建一個 SDK 工程的時候,一般都會同時新建一個 BSP,BSP 名為板級支持包,BSP 根據選擇的硬件平臺,統一管理所有啟用的外設驅動函數庫,以及包括 LwIP 等第三方函數庫。
值得注意的是:所謂驅動管理,就是將硬件平臺需要的外設源代碼復制到當前 BSP 的目錄下。也就是說如果需要修改源代碼,需要到 SDK 的路徑中修改,對于某個 BSP 代碼的修改只對當前 BSP 有效。
我們首先新建一個 BSP 來看看 BSP 的結構。
BSP 分為兩個部分:文檔與源碼。
BSP Doucumentation 中是外設驅動的文檔,雙擊某個外設即可用打開包括外設驅動概述,API等的文檔,以網頁的形式。在之后的文章中,我們可能會分析一下文檔的重點區域。
源碼都位于 ps7_cortexa9_0 目錄下,包括頭文件,函數庫源碼,編譯完的函數庫,編譯函數庫的 Makefile 文件以及概述 BSP 信息的 system.mss 文件。Makefile 用于執行將所有的外設驅動函數庫源代碼編譯為 libxil.a 。
所以定時器身家幾何?
終于來到了本文的主要部分,定時器的源代碼有哪些文件?
在 libsrc/scutimer 下的 src 目錄中,共有 7 個文件,基本上所有的外設都是同樣的設定,所以了解定時器之后,所有外設的源文件結構也就大抵明了。
xscutimer_selftest.c :
僅包括一個外設自測試函數 XScuTimer_SelfTest ,通過對外設寄存器進行讀寫一致性測試判斷外設是否已經就緒。通過測試函數可以發現外設初始化失敗,外設寄存器基址有誤等錯誤。
xscutimer_sinit.c:
僅包括外設配置查找函數 XScuTimer_LookupConfig,將外設 ID 對應的硬件配置以外設配置結構體的形式返回。外設的硬件信息來自于 vivado 生成并導致出至 SDK 的硬件平臺信息。這個函數在上一篇文章中進行了詳細的討論。
ljgibbs:Zynq SDK 驅動探求(二):外設,從初始化到干活?zhuanlan.zhihu.comxscutimer_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 的設計提出了一點小疑問。
總結
以上是生活随笔為你收集整理的location驱动包_Zynq SDK 驱动探求(三):论一个外设驱动的全部身家·Xilinx SDK 驱动源码结构...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 向上造型和向下造型_盆景造型大全——造型
- 下一篇: 信用卡逾期被停用怎么办 及时还款最重要