學(xué)習(xí)內(nèi)容
使用SDK和提供的API進(jìn)行初始化GPIO,并驅(qū)動led和btn進(jìn)行操作,實現(xiàn)led呼吸燈效果,串口讀取btn的值。
開發(fā)環(huán)境
vivado 18.3 && SDK 開發(fā)板 pynq-z2
原理講解
- gpio可以看做一個外設(shè),用于對器件的引腳作觀測(input)以及控制(output)
- MIO 是將PS的外設(shè)和靜態(tài)存儲器接口的訪問多路復(fù)用到PS的引腳上。
- 當(dāng)我們的PS端的MIO不夠用時候,我們可以在搭建硬件平臺時候進(jìn)行設(shè)計,將我們的PL端口的引腳定義拓展為EMIO然后被PS正常驅(qū)動。
- gpio 被分為了4個bank bank0和bank1通過MIO連接到PS的引腳,bank2和bank3通過EMIO連接到PL
這里給出GPIO的一個寄存器的結(jié)構(gòu)圖,方便我們從底層更加深入了解gpio的具體配置的一個狀態(tài)
圖片的上半部分表示的是和IO的中斷功能有關(guān)的寄存器,本節(jié)主要關(guān)注下面的部分。 通過閱讀UG585,我們可以知道寄存器組的不同功能: - DATA_RO:用來反映引腳的功能狀態(tài)
- DATA:當(dāng)GPIO信號被配置為輸出時,這個寄存器控制要輸出的值。該寄存器的所有32位同時寫入。
- MASK_DATA_LSW: 用于屏蔽DATA的低16位
- MASK_DATA_MSW: 用于屏蔽DATA的高16位
- DIRM:用于控制IO引腳作為輸入還是輸出。0關(guān)閉輸出驅(qū)動,1打開輸出驅(qū)動
- OEN:當(dāng)IO配置為輸出時,用于控制打開或者關(guān)閉輸出使能。0關(guān)閉使能,1進(jìn)行使能
硬件平臺搭建
同樣和前面相似,我們先添加IP ZYNQ7,然后進(jìn)行IP配置,選中uart sd gpio
EMIO的 gpio
APB AP transaction error, DAP status f0000021 問題解決方法
我們可以簡單的理解為zynq這個芯片是由這樣幾部分組成,ddr區(qū),PS區(qū),PL區(qū)。DDR區(qū)是存儲區(qū),包括我們的芯片運行SDK的程序時候也是下載到這里。所以在我們沒有對應(yīng)我們的板子配置好DDR時,會碰到這個錯誤信息 ==“APB AP transaction error, DAP status f0000021”== 這也是可以定位到我們在配置ddr信息時候沒有和開發(fā)板匹配,這里我進(jìn)行操作的時候,我是添加了對應(yīng)的板卡信息,ddr自動連線的時候會有一個加載預(yù)配置。 pynq板卡信息會自動幫你配置ddr的信息,這里我貼出pynqz2的ddr的具體信息,需要更改的地方我會標(biāo)記指出:
EMIO和MIO的區(qū)別
前面提到了zynq7000的大致劃區(qū),在ps區(qū),也就是我們的arm核這里,一般都是引出了54個管腳進(jìn)行開發(fā),也就是我們在ZYNQ7的ip里在MIO config的可以配置的那些,這就是MIO我們可以針對這54個管腳進(jìn)行配置自己想要的功能,一般不同的板卡會對應(yīng)設(shè)計SD UART USB GPIO接口什么的,方便用戶進(jìn)行PS端的單獨調(diào)試學(xué)習(xí),那么,對于FPGA的PL端的引腳我們可以不可以進(jìn)行PS操作調(diào)用呢?答案是肯定的!這就提到了EMIO的概念 EMIO的E就是 external的意思,也就是我們可以管腳定義了FPGA端的管腳進(jìn)行擴展給PS端進(jìn)行操作。 配置完成后如圖:
然后我們可以輸出生成頂層文件了
因為這里是用的EMIO,我們不能忘記新建約束文件進(jìn)行管腳分配:
set_property -dict { PACKAGE_PIN R14 IOSTANDARD LVCMOS33 } [get_ports { GPIO0_tri_io[0] }]; #IO_L6N_T0_VREF_34 Sch=led[0]
set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { GPIO0_tri_io[1] }]; #IO_L4P_T0_35 Sch=btn[0]
set_property -dict { PACKAGE_PIN D20 IOSTANDARD LVCMOS33 } [get_ports { GPIO0_tri_io[2] }]; #IO_L4N_T0_35 Sch=btn[1]
最后綜合生成bit流,導(dǎo)出硬件,launch SDK
SDK軟件部分
運行SDK新建helloworld工程(不再多說,看前文),這里貼出SDK的main代碼:
#include
#include "platform.h"
#include "xil_printf.h"
#include "xgpiops.h"
#include "xparameters.h"
#define GPIO_ID XPAR_PS7_GPIO_0_DEVICE_ID
#define LED0 54
#define BTN0 55
#define BTN1 56
static XGpioPs GpioPs;
static XGpioPs_Config *XGpioPs_Cfg;
int initGpio();
int main()
{
u32 led = 0;
int i,j;
init_platform();
initGpio();
while(1){
for(i=0;i<1000;i++){
for(j=0;j<1000;j++){
usleep(1);
if(iBaseAddr);
if( status != XST_SUCCESS){
return XST_FAILURE;
}
XGpioPs_SetDirectionPin(&GpioPs,LED0,0x01);
XGpioPs_SetOutputEnablePin(&GpioPs,LED0,0x01);
XGpioPs_SetDirectionPin(&GpioPs,BTN0,0x00);
XGpioPs_SetOutputEnablePin(&GpioPs,BTN0,0x00);
XGpioPs_SetDirectionPin(&GpioPs,BTN1,0x00);
XGpioPs_SetOutputEnablePin(&GpioPs,BTN1,0x00);
}
部分代碼解釋
#include "xgpiops.h"
#include "xparameters.h"
#define GPIO_ID XPAR_PS7_GPIO_0_DEVICE_ID
#define LED0 54
#define BTN0 55
#define BTN1 56
這里的XPAR_PS7_GPIO_0_DEVICE_ID可以在 "xparameters.h" 尋到,對于LED0 BTN0 BTN1的定義,正是因為前文提到的EMIO的概念,直接PS課操作的管腳54個,是從MIO 0 -- MIO 53 所以這里的EMIO的擴展引腳編號就是54往后,從GPIO0_tri_io 0 依次往后進(jìn)行編號,也可以理解為管腳號。
int initGpio(){
int status;
XGpioPs_Cfg = XGpioPs_LookupConfig(GPIO_ID);
status = XGpioPs_CfgInitialize(&GpioPs,XGpioPs_Cfg,XGpioPs_Cfg->BaseAddr);
if( status != XST_SUCCESS){
return XST_FAILURE;
}
XGpioPs_SetDirectionPin(&GpioPs,LED0,0x01);
XGpioPs_SetOutputEnablePin(&GpioPs,LED0,0x01);
XGpioPs_SetDirectionPin(&GpioPs,BTN0,0x00);
XGpioPs_SetOutputEnablePin(&GpioPs,BTN0,0x00);
XGpioPs_SetDirectionPin(&GpioPs,BTN1,0x00);
XGpioPs_SetOutputEnablePin(&GpioPs,BTN1,0x00);
}
初始化函數(shù)同前文iic的配置,和keil開發(fā)32的流程類似,聲明結(jié)構(gòu)體進(jìn)行初始化,然后設(shè)置GPIO的方向,輸入還是輸出模式。