前言
xilinx公司在设计这款芯片时就同步编写了ps端的函数库,我们在对zynq这款芯片进行开发,直接调用库函数就可以了。不过比较难过的是,官方虽然编写了函数驱动库,但并没有出版相应的类似于函数指导之类的文档,需要开发者自己去理解这个函数用法,但官方还是有相应的历程,我们可以学历历程来基本掌握这些函数的用法,但并不是很详细,也没有说明文档,需要结合datasheet和其他的文档进行综合理解分析。
首先
gpio有两个重要的数据结构:XGpioPs 和 XGpioPs_Config
typedef struct {
XGpioPs_Config GpioConfig; /**< Device configuration */
u32 IsReady; /**< Device is initialized and ready */
XGpioPs_Handler Handler; /**< Status handlers for all banks */
void *CallBackRef; /**< Callback ref for bank handlers */
u32 Platform; /**< Platform data */
u32 MaxPinNum; /**< Max pins in the GPIO device */
u8 MaxBanks; /**< Max banks in a GPIO device */
} XGpioPs;
typedef struct {
u16 DeviceId; /**< Unique ID of device */
u32 BaseAddr; /**< Register base address */
} XGpioPs_Config;
XGpioPs 结构体里面各个成员变量的大致作用:
1:GpioConfig 是XGpioPs_Config结构体的指针,指向内部成员DeviceId和BaseAddr;这两个成员作用是保存gpio这个设备的Id和基地址,在zynq中任何外设都有一个相应的id和基地址用来识别。
解析一下为什么我们在所有历程中或者别人的工程中看到的id都是0,它只是被用来初始化,表示这个设备在vivado搭建工程环境时我们勾选了这个设备,没有勾选的设备你是在#include "xparameters_ps.h"中找不到相应的id和地址的。
2:IsReady,当设备初始化完成,设备已经准备好
3:Handler ,中断句柄,用于中断读取和写入
4:CallBackRef 中断回调函数,没有用到中断时可不做关心
5:Platform 这个是跟你的开发板硬件平台相关,不做关心
6:MaxPinNum ps端能使用的最大的pin数量,在zynq中为118
7:MaxBanks 在zynq中的io bank数目为4
1:查询函数XGpioPs_LookupConfig()
XGpioPs_Config *XGpioPs_LookupConfig(u16 DeviceId)
{
XGpioPs_Config *CfgPtr = NULL;
u32 Index;
for (Index = 0U; Index < (u32)XPAR_XGPIOPS_NUM_INSTANCES; Index++) {
if (XGpioPs_ConfigTable[Index].DeviceId == DeviceId) {
CfgPtr = &XGpioPs_ConfigTable[Index];
break;
}
}
return (XGpioPs_Config *)CfgPtr;
}
参数:设备id,我们可以在#include "xparameters_ps.h"找到id和地址
/* Definitions for peripheral PS7_GPIO_0 */
#define XPAR_PS7_GPIO_0_DEVICE_ID 0
#define XPAR_PS7_GPIO_0_BASEADDR 0xE000A000
#define XPAR_PS7_GPIO_0_HIGHADDR 0xE000AFFF
每一个设备都有一个唯一的配置表:
XGpioPs_Config XGpioPs_ConfigTable[XPAR_XGPIOPS_NUM_INSTANCES] =
{
{
XPAR_PS7_GPIO_0_DEVICE_ID,
XPAR_PS7_GPIO_0_BASEADDR
}
};
XGpioPs_LookupConfig这个函数就是根据设备id,查找配置表,然后将设备的地址等信息,通过XGpioPs_Config 指针返回。
2:初始化函数XGpioPs_CfgInitialize()
s32 XGpioPs_CfgInitialize(XGpioPs *InstancePtr, XGpioPs_Config *ConfigPtr,
u32 EffectiveAddr)
{
s32 Status = XST_SUCCESS;
u8 i;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(ConfigPtr != NULL);
Xil_AssertNonvoid(EffectiveAddr != (u32)0);
/*
* Set some default values for instance data, don't indicate the device
* is ready to use until everything has been initialized successfully.
*/
InstancePtr->IsReady = 0U;
InstancePtr->GpioConfig.BaseAddr = EffectiveAddr;
InstancePtr->GpioConfig.DeviceId = ConfigPtr->DeviceId;
InstancePtr->Handler = StubHandler;
InstancePtr->Platform = XGetPlatform_Info();
/* Initialize the Bank data based on platform */
if (InstancePtr->Platform == XPLAT_ZYNQ_ULTRA_MP) {
/*
* Max pins in the ZynqMP GPIO device
* 0 - 25, Bank 0
* 26 - 51, Bank 1
* 52 - 77, Bank 2
* 78 - 109, Bank 3
* 110 - 141, Bank 4
* 142 - 173, Bank 5
*/
InstancePtr->MaxPinNum = (u32)174;
InstancePtr->MaxBanks = (u8)6;
} else {
/*
* Max pins in the GPIO device
* 0 - 31, Bank 0
* 32 - 53, Bank 1
* 54 - 85, Bank 2
* 86 - 117, Bank 3
*/
InstancePtr->MaxPinNum = (u32)118;
InstancePtr->MaxBanks = (u8)4;
}
/*
* By default, interrupts are not masked in GPIO. Disable
* interrupts for all pins in all the 4 banks.
*/
for (i=0;i<InstancePtr->MaxBanks;i++) {
XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
((u32)(i) * XGPIOPS_REG_MASK_OFFSET) +
XGPIOPS_INTDIS_OFFSET, 0xFFFFFFFFU);
}
/* Indicate the component is now ready to use. */
InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
return Status;
}
参数1:XGpioPs 结构体指针
参数2:指向XGpioPs_Config 设备指针
参数3:指向设备基地址
**函数功能:**设置一些初始默认值,如:设置io的最大值和bank数,默认关闭中断等等。
使用:
static XGpioPs psGpioInstancePtr;
XGpioPs_Config* GpioConfigPtr;
int xStatus;
GpioConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);
if(GpioConfigPtr == NULL)
return XST_FAILURE;
xStatus = XGpioPs_CfgInitialize(&psGpioInstancePtr,GpioConfigPtr, GpioConfigPtr->BaseAddr);
if(XST_SUCCESS != xStatus)
print(" PS GPIO INIT FAILED \n\r");