前言
前面先简单介绍这个实验的基本流程,了解了基本背景后,再重点讲解驱动程序的编写特点,以及用户面对Xilinx官方驱动包时如何使用。
一、功能描述
通过MIO实现对LED灯的控制,使其以固定频率闪烁。
二、实验步骤
1、硬件部分
① 创建系统工程
② 创建BD工程
③ 配置zynq IP:配置电压、串口、时钟、GPIO
④ 连线、编译、导出
2、软件部分
① 创建软件工程
② 添加对应驱动的头文件
③ 查看头文件中关于此驱动的相关参数定义和函数定义
④ 查找硬件配置后对应接口模块是否存在
⑤ 初始化一个接口
⑥ 设置GPIO输出方向
⑦ 配置连接LED的那一位GPIO引脚输出
⑧ 循环给定值0和1值给连接LED的GPIO引脚
三、GPIO驱动程序结构性分析
这里使用的是GPIO驱动程序包,所以首先找到相关的头文件。

在include和libsrc中均可以看到

接下来看下这个头文件的结构,都定义了哪些东西,在xgpiops.h头文件中。
首先,定义了中断类型、bank、引脚数目等信息。

其次,定义了两个结构体,一个保存设备号和基地址,用于查找外设GPIO的存在,另一个保存调用GPIO实例所需要的基本信息,用于初始化操作,分别如下:

最后是函数定义,这里主要关注注释部分说明,定义了哪些函数以及函数所在的文件位置信息,方便我们查看和调用。具体表现为:
/* Functions in xgpiops.c */
/* Bank APIs in xgpiops.c */
/* Pin APIs in xgpiops.c */
/* Diagnostic functions in xgpiops_selftest.c */
/* Functions in xgpiops_intr.c */
/* Bank APIs in xgpiops_intr.c */
/* Pin APIs in xgpiops_intr.c */
/* Functions in xgpiops_sinit.c */
四、调用函数实现实验软件功能
按照第二部分说明的软件顺序,首先需要添加头文件,这里需要添加的头文件有:
#include "xgpiops.h"
#include "sleep.h"
之所以需要添加sleep.h头文件,是因为循环点亮LED,中间需要延时操作,方便用户观察亮灭情况。
1、查找和初始化GPIO外设资源
按照Xilinx的套路,首先需要查找GPIO定义,调用函数
XGpioPs_Config *XGpioPs_LookupConfig(u16 DeviceId);
函数位于xgpiops_sinit.c文件中,函数详情:
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;
}
先定义一个XGpioPs_Config类型的指针,准备接收特定设备号下 查找到的基地址;依次循环查表,表以数组的形式存放于xgpiops_g.c中,如下:

当输入的设备号一致时,就将表中的内容一一对应复制给XGpioPs_Config结构体中元素并返回。(设备号device和定义的GPIO驱动个数XPAR_XGPIOPS_NUM_INSTANCES是自动生成,位于xparameters.h文件中)
接下来回到主函数,判断下查找是否成功,返回状态值。
接着初始化外设GPIO,调用初始化函数
s32 XGpioPs_CfgInitialize(XGpioPs *InstancePtr, XGpioPs_Config *ConfigPtr, u32 EffectiveAddr)
初始化函数调用之前,先定义一个XGpioPs结构体类型的指针实例,用于保存初始化后的关于GPIO的参数,这样做的目的可以使用户初始化很多这样的GPIO以便使用。
初始化函数中,在进行一个判断传入的三个参数是否为空后,然后对保存GPIO基本信息的参数进行赋值。赋值操作如下:
InstancePtr->IsReady = 0U;
InstancePtr->GpioConfig.BaseAddr = EffectiveAddr;
InstancePtr->GpioConfig.DeviceId = ConfigPtr->DeviceId;
InstancePtr->Handler = (XGpioPs_Handler)StubHandler;
InstancePtr->Platform = XGetPlatform_Info();
参数分别为:
① 准备信号赋值0,表示暂时没有初始化完成;
② 基地址
③ 设备号
④ 所有状态的处理程序
⑤ 设备数据
接下来,根据设备参数确定初始化结构体中最大引脚数和最大bank数目。

接下来,关闭GPIO所有中断,这里没有使用GPIO的中断功能,最后将初始化完成后的准备信号赋值,表示此次对GPIO的、初始化工作已经完成,可以使用。

回到主函数,根据初始化函数的返回值,同样做一个判断,是否完成初始化工作。
至此,关于外设GPIO的查找和初始化工作已经全部完成,接下来就是功能性程序。
2、设置GPIO输出方向
调用设置GPIO输出方向的函数
void XGpioPs_SetDirectionPin(XGpioPs *InstancePtr, u32 Pin, u32 Direction)
void XGpioPs_SetDirectionPin(XGpioPs *InstancePtr, u32 Pin, u32 Direction)
{
u8 Bank;
u8 PinNumber;
u32 DirModeReg;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Xil_AssertVoid(Pin < InstancePtr->MaxPinNum);
Xil_AssertVoid(Direction <= (u32)1);
/* Get the Bank number and Pin number within the bank. */
XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);
DirModeReg = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +</

最低0.47元/天 解锁文章
446

被折叠的 条评论
为什么被折叠?



