轉載請注明出處 :https://www.cnblogs.com/imapla/p/7454973.html
硬件:AM5728開發板;Artix-7開發板
軟件:Linux am57xx-evm 4.4.19;Vivado 2015.2
作者:Imapla
郵箱:hihuanglong@foxmail.com
AM5728外設接口豐富,有V-PORT接口、PCIe、GPMC、USB、UART等等,通常與FPGA之間高速數據通信可以選擇V-PORT、PCIe、GPMC,這里以實現起來最簡單的GPMC為例,實現了從FPGA到AM5728的高速數據搬運。
AM5728的ARM端運行Linux 4.4內核操作系統,通過GPMC接口采用DMA的方式讀取FPGA端的數據,讀取32KB數據大概用了540us,即60MB/s左右的速度,實際上通過配置GPMC接口的時間參數和工作模式,速度還可以更快。
- GPMC接口介紹
GPMC的全稱是 General-Purpose Memory Controller,即通用存儲控制器,是TI的Sitara 系列處理器AM5728用來與外部存儲設備例如NOR FLASH、NAND FLASH、SRAM等等通信的一個接口。這個接口並不是AM5728特有的,在BeagleBone Black、AM33XX等芯片上也有類似接口。
1.1 硬件連接方式
參考SPRUHZ6I 15.4.6.1.2 在AM5728中把GPMC接口配置為異步模式並設置NOR FLASH、非地址數據線復用的模式與FPGA通信,但只用16位數據線,不用地址線,即采用類似於FIFO的方式與FPGA通信。目前實際只使用到了如下I/O口,信號方向如下圖所示。
GPMC_D[15:0]: 16位數據線
GPMC_nCS: 片選信號
GPMC_nOE: 輸出使能時鍾
FPGA_nRST: 用於通知FPGA讀寫指針復位
FPGA_nIRQ: 用於通知ARM讀取一塊數據

1.2 硬件接口協議
采用異步方式讀取,即不使用GPMC_CLK,FPGA端在GPMC_nOE的下降沿把數據送出去。

目前這種工作模式下的GPMC接口,我們只需要關心以下幾個時間:
即CS有效時間,OE有效時間,GPMC讀取數據時間,GPMC單個讀取周期。

- Linux驅動實現
Linux 4.4 版本內核采用設備樹dts的方法編寫驅動,與2.6版本時候有較大區別,4.4版本內核中關於GPMC接口的API幾乎沒有導出,通過API來操作不可行,必須使用編寫設備樹方法。關於設備樹的編譯請參考創龍的用戶手冊。
AM5728的dts文件路徑:linux-4.4.19-g5e4091a-v1.3\arch\arm\boot\dts
內核實現的gpmc驅動在:linux-4.4.19-g5e4091a-v1.3\drivers\memory\omap-gpmc.c
關於 dts 的編程方法可以參考:
https://learn.adafruit.com/introduction-to-the-beaglebone-black-device-tree/overview
以及閱讀Linux內核目錄下的文檔:
Documentation\devicetree\bindings\mtd\gpmc-nor.txt
配置方面主要包括與GPMC相關的7個配置寄存器CONFIG1-CONFIG7,GPMC端口初始化等等。
(1)首先確保在 文件dra7.dtsi中引入了GPMC控制器,如下:

(2)接着在 am57xx-beagle-x15-common.dtsi 加入 GPMC 管腳初始化配置

(3)最后在實現一個自己的GPMC設備節點,其中關鍵的時序參數如下,在這里我們設置GPMC的片選CS6地址為0x10000000,大小為16MB,GPMC的單個讀取周期為30ns。

- 采用DMA傳輸
AM5728帶有System DMA和Enhanced DMA,Linux 4.4 之后內核中 EDMA 相關的API不對外導出,因此暫時只能采用通用的DMA API操作,實現DMA搬運。
需要注意的是,DMA中配置的地址都為物理地址,即DMA傳送到源端為外設的地址即GPMC的物理地址,目的地端為你申請的內存空間物理地址。

- 實驗驗證
(1)使用memread讀取GPMC端口數據
memread中使用mmap方法把GPMC的物理地址0x10000000映射到用戶空間。在用戶空間通過CPU讀取GPMC端口數據,抓取CS6n和OEn的波形如下,目前沒有用到DMA傳送,只是在Linux循環讀取,可以看見每個周期里片選信號CS6n都會維持很長一段高電平的時間,GPMC一次的讀取周期大概為200ns。

通道1為片選信號CS6n,通道2為輸出使能信號OEn
這樣的速率大概只有 16bit / 200ns = 10MB/s
(2)使用DMA傳輸
編譯並使用insmod工具加載DMA驅動edmatest.ko,抓取CS6n和OEn的波形如下,使用DMA傳送,這下讀周期就小了很多了,大概只有30ns,和GPMC參數里設置的完全一致。讀取32KB數據大概用了540us,即60MB/s左右的速度。實際上通過配置GPMC接口的時間參數和工作模式,速度還可以更快。

(3)FPGA端對應的代碼,FPGA端的代碼只要是實現在每個OEn信號下降沿來的時候,把16bit的數據送到GPMC_DATA端口,並自加一次。

(4)Linux端讀取數據並做校驗
校驗通過,說明數據一致性正確!至此AM5728與FPGA通過GPMC接口用DMA實現數據高速傳輸,驗證可行!

- 源代碼下載
設備樹文件:http://deepelec.com/files/dsp/dts.zip
Linux 下 memread 參考代碼:http://deepelec.com/files/dsp/memread.zip
Linux 下 edmatest 參考代碼:http://deepelec.com/files/dsp/edmatest.zip
FPGA端對應代碼比較簡單就不上傳了。
整個實驗過程中涉及到的細節很多,如有錯誤之處請不吝指出!
參考資料:
https://e2e.ti.com/support/arm/sitara_arm/f/791/t/512464
https://e2e.ti.com/support/arm/sitara_arm/f/791/p/315716/1530903#pi316653=1
https://github.com/fpga-logi/logi-kernel/commit/42066f774425afb196dc0f8f1ad40f450da34115
http://valentfx.com/wiki/index.php?title=LOGI_-_BBB_GPMC_Bus-_HW
有任何問題,歡迎加入 TI DSP 技術交流 QQ 群:652563558
