作者:Wilson Qiu,Xilinx工程師
ZYNQ對Memory的操作
參考工程見“ZYBO_Memory_GPIO_Interrupt_demo.xpr”。
ZYNQ有專用的DDR Controller接口,如果外部硬件連接了DDR器件,于是在ZYNQ Processing System中正確配置了相應的信號和參數后,DDR就可以成為ZYNQ的內存,在SDK中可以直接使用memcpy、memset以及類似的函數對于Memory空間進行操作。
Step1:查看ZYBO的原理圖,找到相應的配置。ZYBO原理圖中與DDR相關的部分如圖 49所示。
圖 49
于是得到兩個信息,第一個所使用的芯片是MT41J128M16JT-125,第二個是兩片DDR3顆粒是通過位拼接完成的,也就是數據位寬為32bit。
Step2:在Block Design中對DDR部分的參數進行配置。
圖 50
Step3:完成Block Design設計,產生Bitstream,導入SDK。
圖 51
Step4:在SDK中編寫Memory測試代碼。
#include #include #include "platform.h" #include "xil_printf.h" #include "xil_types.h" #include "xil_io.h" int main() { u32 test_src[100]; int i; int readback; init_platform(); u32 *result = (u32*) malloc(sizeof(u32) * 100); if (result) { memset(result, 0, sizeof(u32) * 100); } else { return 0; } for(i=0;i<99;i++) { test_src[i]=i; } memcpy(result,test_src,100 * sizeof(u32)); for(i=0;i<100;i++) { readback = Xil_In32(result+i);
其中特別需要學習的就是malloc與memcpy的使用方法。
ZYNQ中MIO/EMIO GPIO的使用
參考工程見“ZYBO_Memory_GPIO_Interrupt_demo.xpr”。
MIO是PS端的外部引腳,共有54個;EMIO是PL端的外部引腳,共有64個。ZYNQ支持通過配置將PS的控制器信號通過EMIO輸出,例如PS自帶的UART Controller,如果正常選擇引腳只能選擇MIO引腳輸出,但是通過設置可以選擇連接到EMIO引腳。同時EMIO引腳也可以作為PS端的擴展引腳,即經過擴展PS一共可以控制118個引腳。
該例程演示將4個EMIO設置為PS的擴展引腳,這4個EMIO連接著LED。于是,與“將用戶邏輯設計封裝成IP”中的實驗相比,同樣是控制外部4個LED,就不需要另外設計一個邏輯模塊,并封裝成IP作為PS的外設了,可以直接通過SDK的程序進行控制。
注意:
1. 用于擴展GPIO的EMIO和用于擴展外設的EMIO是完全獨立的,GPIO的EMIO共有64個,由2個bank組成,如圖 52所示。
圖 52
2. EMIO的內部排序按照EMIO54、EMIO55... ... EMIO117,以此類推。有了EMIO的編號之后就與內部控制EMIO的寄存器一一對應;而EMIO在外部與外部引腳的對應關系又是可以通過管腳約束進行更改的。于是可以得出:不能通過EMIO的外部引腳的關系確定其內部寄存器的地址。工具對于EMIO GPIO的連接關系是按照從EMIO54開始依次向上排列。
Step1:在Block Design中加入ZYNQ7 Processing System,在ZYNQ7 Processing System配置中添加EMIO GPIO,如圖 53所示。通過設置EMIO GPIO Width來選擇擴展EMIO GPIO的個數,此時就完成了與內部寄存器之間的對應關系,規則就是從EMIO54開始向上排列。
圖 53
Step2:將ZYNQ的EMIO連接到外部引腳。右擊生成的GPIO信號,點擊Make External。
圖 54
Step3:約束EMIO與外部引腳Pad的對應關系以及EMIO的電平標準。
方法有兩種:
第一種是通過XDC約束文件進行約束,需要先將Block Design生成HDL Wrapper,這樣才能知道其引腳名稱。
圖 55
第二種方法就是Open Elaborated Design,在GUI中設置電平和引腳。
圖 56
Step4:完成Block Design的綜合、實現、生成Bitstream并導入SDK。
Step5:SDK中完成代碼的編寫,EMIO的代碼編寫需要包含的庫文件是"xgpiops.h"。
#include "xgpiops.h" static XGpioPs emio; #define EMIO_54 54 #define EMIO_55 55 #define EMIO_56 56 #define EMIO_57 57 int main() { //定義GPIOPS型指針,用于初始化時綁定硬件 XGpioPs_Config *ConfigPtrPS; init_platform(); //初始化GPIOPS,將ConfigPtrPS與硬件綁定 ConfigPtrPS = XGpioPs_LookupConfig(0); XGpioPs_CfgInitialize(&emio, ConfigPtrPS, ConfigPtrPS- > BaseAddr); //設置EMIO的方向,并使能EMIO XGpioPs_SetDirectionPin(&emio, EMIO_54, 1); XGpioPs_SetOutputEnablePin(&emio, EMIO_54, 1); XGpioPs_SetDirectionPin(&emio, EMIO_55, 1); XGpioPs_SetOutputEnablePin(&emio, EMIO_55, 1); XGpioPs_SetDirectionPin(&emio, EMIO_56, 1); XGpioPs_SetOutputEnablePin(&emio, EMIO_56, 1); XGpioPs_SetDirectionPin(&emio, EMIO_57, 1); XGpioPs_SetOutputEnablePin(&emio, EMIO_57, 1); while(1) { // 向EMIO寫入數據,即驅動EMIO引腳 XGpioPs_WritePin(&emio, EMIO_54, 0x0); XGpioPs_WritePin(&emio, EMIO_55, 0x0); XGpioPs_WritePin(&emio, EMIO_56, 0x0); XGpioPs_WritePin(&emio, EMIO_57, 0x0); usleep(200000); XGpioPs_WritePin(&emio, EMIO_54, 0x1); XGpioPs_WritePin(&emio, EMIO_55, 0x1); XGpioPs_WritePin(&emio, EMIO_56, 0x1); XGpioPs_WritePin(&emio, EMIO_57, 0x1); usleep(200000); } cleanup_platform(); return 0; }
Step6:如果需要將EMIO作為輸入端口,只需要將IO的方向設置為input。對于IO,作為輸出的時候需要Enable,但是作為輸入是永遠使能的,不需要額外的Enable。具體代碼如圖 57所示。
圖 57
補充說明:
MIO和EMIO都屬于PS的GPIO,用于指示的變量類型為XGpioPs;而使用AXI_GPIO外設的GPIO,由于是屬于PL的,所以指示這些IO的變量類型為XGpio。
MIO和EMIO的控制對于SDK是完全相同的,其地址偏移量也是排在一起的,MIO從0排到53,EMIO接著從54開始。示例代碼中顯示的是EMIO作為輸出和MIO作為輸入,只需要將引腳編號的宏定義改為需要的MIO或者EMIO編號即可使用。
在硬件配置時MIO的配置方法與EMIO有所不同,EMIO的配置如圖 53所示。而MIO由于不像EMIO,外部管腳是確定的,所以可以在ZYNQ7 Processing System配置時同時完成屬性以及電平的設置,如圖 58所示。
圖 58
ZYNQ中Interrupt使用
參考工程見“ZYBO_Memory_GPIO_Interrupt_demo.xpr”。
ZYNQ中的中斷管理是通過Generic Interrupt Controller(GIC)完成的。
任何的中斷功能都需要兩步,第一步是配置相應的中斷,第二步是設置中斷觸發之后的服務函數。
配置相應中斷分以下幾個步驟:
1. 使能相應的功能,例如GPIO中斷需要首先使能和配置GPIO;Timer中斷需要首先使能和配置Timer;
圖 59
2. 初始化并配置使能GIC,還要使能異常處理。第1步中的操作對于每個中斷源來說都不相同,但是這一步的配置對于不同中斷源而言是類似的。不同之處在于有一個參數:中斷ID,即例子中的52是變化的,52是GPIO的中斷號,其他中端需要使用不同的ID。該值可以在UG585中斷的相關章節查詢到,如圖 61所示。
另一個區別就是XScuGic_Connect時的服務子函數不同。
圖 60
圖 61
3. 編寫中斷服務函數,需要注意的是進入服務函數后首先需要禁止中斷,保證在處理中斷時不會再次因觸發中斷而程序跳轉;另外就是需要清除中斷標志位,否則會不斷觸發中斷。
圖 62
源代碼見附件。
ZYNQ CPU內部任何有定時器,在Vivado的ZYNQ配置中無需任何操作就可以在SDK中直接使用。與GPIO中斷類似,Timer的中斷也包含相同的幾步操作,下面給出各個階段的代碼片段,完整代碼見附件。
1. 初始化Timer。
圖 63
2. 初始化GIC,設置中斷服務函數入口。
圖 64
3. 配置Timer工作模式,導入計數初值,使能中斷。
圖 65
4. 編寫中斷服務函數,進入中斷后首先Disable中斷,清楚中斷標志位;然后進行中斷處理;退出中斷服務函數前重新使能中斷。
圖 66
Appendix 1: 配套工程
編輯:hfy
-
DDR
+關注
關注
11文章
712瀏覽量
65401 -
Zynq
+關注
關注
10文章
610瀏覽量
47208 -
memcpy
+關注
關注
0文章
9瀏覽量
2834 -
malloc
+關注
關注
0文章
52瀏覽量
73
發布評論請先 登錄
相關推薦
評論