ZYNQ7000-AXI GPIO详解
參考:PG144 - AXI GPIO v2.0 Product Guide (v2.0)
一. AXI GPIO的概念與作用
AXI GPIO是ZYNQ PL部分的一個IP軟核,此IP核提供AXI-Lite Master接口轉GPIO的功能,且一個AXI-Lite Master通過AXI interconnect可以與多個AXI GPIO IP核相連,如下圖所示。也就是說PS部分通過GP接口以及AXI GPIO IP核可實現(xiàn)多個GPIO,一個GP接口最多可以接幾個AXI GPIO IP核我不知道,手冊中沒寫,我這里接了4個沒什么問題。.
我們知道ZYNQ的PS可通過EMIO來使用PL部分的引腳實現(xiàn)GPIO功能,但當使用的引腳很多時,PS程序中控制引腳方向、中斷等將變得繁瑣,這時如果使用PS的GP接口(AXI3 Master)接口通過AXI Interconnect連接AXI GPIO IP核,就可以在PS部分通過更簡單的程序方便地控制眾多PL引腳實現(xiàn)GPIO功能。
所以,從功能上來說,PS通過EMIO還是AXI GPIO來實現(xiàn)GPIO沒有區(qū)別,都能輸入/輸出以及產(chǎn)生中斷,但AXI GPIO在多引腳時在程序的復雜度方面有一定優(yōu)勢。
二. AXI GPIO IP核設置與使用
2.1 AXI GPIO的最大工作時鐘頻率
需要注意,AXI GPIO的AXI-Lite接口的時鐘頻率,超頻可能會導致此IP核無法正常工作。
2.2 AXI GPIO設置
AXI GPIO IP核默認為單通道,可選GPIO寬度為1~32,可設置GPIO方向(注意如果在這里設置了All Input/Output,那么在PS程序中就無需再設置GPIO方向,設置了也無效,建議不要在這里設置,通過PS程序去設置,保持靈活性),可設置輸出默認值與三態(tài)默認值。
可勾選Enable Dual Channel,打開雙通道。
可勾選Enable Interrupt,打開GPIO中斷功能,此中斷屬于PL對PS的中斷,所以需要連接到ZYNQ7核的IRQ_F2P端口,如下圖所示。
因為使用了AXI接口,我們知道AXI是讀寫數(shù)據(jù)的,它必須對應存儲器(RAM,DDR等),所以在設置好IP核并連線完成后,需要對每個AXI GPIO的S_AXI進行存儲器地址映射,規(guī)定S_AXI去讀寫哪個地址段。
打開Address Editor窗口,右擊選擇Assign All即可。
效果如下圖。
這里需要說明,因為在PS的庫函數(shù)中對多個AXI GPIO的情況是有排序的(在xparameters.h中每個AXI GPIO對應不同的ID,如下圖),我們需要知道PL的Block Design中哪個AXI GPIO對應PS庫中的AXI GPIO 0,哪個對應AXI GPIO 1。
這里的排序依據(jù)是ip核的名稱,與同GP0接口相連還是GP1接口相連沒有關系,PS并不區(qū)分axi gpio與哪個GP相連。axi_gpio_0會被設為ID 0,ID從0開始向后排,若不存在axi_gpio_0,則axi_gpio_1會被設為ID 0,以此類推。
明白PL中的axi gpio與PS庫函數(shù)中的ID的對應關系是重要的,它幫助我們對引腳命名,以及在PS中操作我們想操作的GPIO。
2.3 關于AXI GPIO中斷的細節(jié)
注意:
1.AXI GPIO只能使能整個通道中斷,而無法像EMIO一樣單獨使能通道中某個引腳的中斷,當使能某個通道中斷后,該通道所有輸入引腳均能產(chǎn)生中斷信號,效果完全相同。
一種可行的將中斷固定到引腳的辦法是設置通道中其它引腳為輸出,輸出引腳無法產(chǎn)生中斷,中斷就相當于固定到了唯一的輸入引腳上,
2.因為AXI GPIO中斷屬于IRQ_F2P,而IRQ_F2P的中斷類型只能設置為上升沿或者高電平,而不能是下降沿或者低電平。如下圖(參考ug585 Table7-4)。
三. 在PS中控制AXI GPIO輸入、輸出與中斷
3.1 AXI GPIO作為輸入輸出使用,不使用中斷
步驟:初始化AXI GPIO -> 設置AXI GPIO方向 -> 讀/寫AXI GPIO
#include "xgpio.h" #include "sleep.h"#define AXIGPIO_CHANNEL_1 1U #define AXIGPIO_CHANNEL_2 2UXGpio axiGpio0; XGpio axiGpio1;int main(void) {// 初始化AXI GPIOXGpio_Initialize(&axiGpio0, XPAR_GPIO_0_DEVICE_ID);XGpio_Initialize(&axiGpio1, XPAR_GPIO_1_DEVICE_ID);// 設置AXI GPIO的方向,對應位為0表示輸出,為1表示輸入XGpio_SetDataDirection(&axiGpio0, AXIGPIO_CHANNEL_1, 0x0); // 設置axiGpio0的通道1為全輸出XGpio_SetDataDirection(&axiGpio1, AXIGPIO_CHANNEL_2, 0xFFFF0000); // 設置axiGpio1的通道2高16位輸入,低16位輸出u32 axiGpio1_ch2_data = 0;while(1){sleep(1);XGpio_DiscreteWrite(&axiGpio0, AXIGPIO_CHANNEL_1, 0x3); // 向axiGpio0的通道1的第0位和第1位寫1axiGpio1_ch2_data = XGpio_DiscreteRead(&axiGpio1, AXIGPIO_CHANNEL_2); // 讀取axiGpio1的通道2的值,輸出引腳也可讀sleep(1);}return 0; }3.2 使用AXI GPIO中斷
步驟:初始化AXI GPIO -> 打開系統(tǒng)的中斷處理功能 -> 初始化中斷控制器 -> 設置中斷優(yōu)先級與類型,關聯(lián)中斷處理函數(shù) -> 使能中斷
#include "xgpio.h" #include "xscugic.h" #include "xil_exception.h" #include "sleep.h"#define AXIGPIO_CHANNEL_1 1U #define AXIGPIO_CHANNEL_2 2U#define AXIGPIO_IRQ_TYPE_HIGH 1U #define AXIGPIO_IRQ_TYPE_PEDGE 3U#define AXIGPIO_IRQ_PRIORITY 128UXGpio axiGpio0; XScuGic scuGic;void axiGpio0_Handler(void *CallbackRef);int axiGpio0_intrFlag = 0;int main(void) {// 初始化AXI GPIOXGpio_Initialize(&axiGpio0, XPAR_GPIO_0_DEVICE_ID);// 打開系統(tǒng)的中斷處理功能Xil_ExceptionInit(); // 初始化異常句柄,只在很早版本的bsp中需要,此處為了兼容性保留Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &scuGic);Xil_ExceptionEnable(); // 使能系統(tǒng)中斷// 初始化中斷控制器XScuGic_Config *scuGicConfig;scuGicConfig = XScuGic_LookupConfig(XPAR_XSCUTIMER_0_DEVICE_ID); // 根據(jù)器件ID查找配置XScuGic_CfgInitialize(&scuGic, scuGicConfig, scuGicConfig->CpuBaseAddress);// 設置對應ID中斷的的優(yōu)先級與觸發(fā)類型XScuGic_SetPriorityTriggerType(&scuGic, XPAR_FABRIC_GPIO_0_VEC_ID, AXIGPIO_IRQ_PRIORITY, AXIGPIO_IRQ_TYPE_HIGH);// 連接中斷ID與中斷服務函數(shù)XScuGic_Connect(&scuGic, XPAR_FABRIC_GPIO_0_VEC_ID, (Xil_InterruptHandler)axiGpio0_Handler, &axiGpio0);// 啟用對應中斷ID的中斷源XScuGic_Enable(&scuGic, XPAR_FABRIC_GPIO_0_VEC_ID);// 啟動AXI GPIO中斷XGpio_InterruptGlobalEnable(&axiGpio0);// 使能對應通道的中斷XGpio_InterruptEnable(&axiGpio0, AXIGPIO_CHANNEL_1);while(1){sleep(1);if (axiGpio0_intrFlag){xil_printf("This is axiGpio0 interrupt!");axiGpio0_intrFlag = 0; // 復原中斷標志XGpio_InterruptEnable(&axiGpio0, AXIGPIO_CHANNEL_1); // 重新使能中斷}sleep(1);}return 0; }void axiGpio0_Handler(void *CallbackRef) {XGpio *axiGpioPtr = (XGpio *)CallbackRef;axiGpio0_intrFlag = 1;// 關閉中斷XGpio_InterruptDisable(axiGpioPtr, AXIGPIO_CHANNEL_1);// 清除中斷寄存器,不清除無法再次進入中斷XGpio_InterruptClear(axiGpioPtr, AXIGPIO_CHANNEL_1); }總結
以上是生活随笔為你收集整理的ZYNQ7000-AXI GPIO详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何加快Vivado的编译速度
- 下一篇: ZYNQ7000-GPIO EMIO中断