ZYNQ-Vitis(SDK)裸机开发之(五)PL端AXI GPIO的使用

14 篇文章 5 订阅
8 篇文章 2 订阅

目录

一、ZYNQ中PL端AXI GPIO简介

1.AXI GPIO IP核介绍

二、搭建Block Design

1.添加AXI GPIO的IP核

2.Block Design连线设计

三、编写Vitis工程

1.AXI GPIO Vitis操作说明

2. 添加AXI GPIO操作代码


例程开发环境:

SOC芯片:ZYNQ7020

开发环境:Vivado2020.2,Vitis2020.2

目前网上对于AXI GPIO的详细使用方法介绍的很少,基本都是一个通道一个IO,或者几个IO,统一进行配置,并没有对不同bit的不同操作进行深入的讲解,因此才写了本篇文章,也是希望大家学习过程中少走一些弯路,坑我都替你们踩过了。

  • 一、ZYNQ中PL端AXI GPIO简介

1.AXI GPIO IP核介绍

每个AXI GPIO IP核具有两个通道GPIO和GPIO2,添加IP后,默认只开启通道1,如果使用双通道,则勾选上Enable Dual Channel

每个通道具有32bit的可控制IO,每个bit可控制一个IO的输入或输出,在IP核中可以将整个通道32bit全部设置成输入模式或者输出模式

GPIO Width:选择需要使用几个bit的IO;

Default Output Value:32个bit上电后默认输出值,也可在Vitis中通过代码配置

Default Tri State Value:32个bit的IO默认方向模式,FFFFFFFF即全部是输入模式

如果需要使用AXI GPIO的中断输入,则需要勾选上Enable Interrupt,并将irpt中断引脚连接到PS端,用于PS端读取中断状态进行控制

  • 二、搭建Block Design

本项目工程是在ZYNQ-Vitis(SDK)裸机开发之(一)串口实验工程基础上开发的,一些block design的设计方法,Vitis工程的建立方法等,均在该篇文章中进行了详细的讲解,大家可以去参考:

ZYNQ-Vitis(SDK)裸机开发之(一)串口收发使用:PS串口+PL串口、多个串口使用方法

1.添加AXI GPIO的IP核

在原有串口工程基础上添加AXI GPIO的IP核

右击block design空白处,点击Add IP,弹出窗口中输入AXI GPIO,双击添加即可

添加后,按照如下配置

在这里我需要使用两个IO,因此只需要使用通道1,并且在通道1中GPIO Width只需要填2个即可;其中bit0作为蜂鸣器的输出控制IO,bit1作为按键输入读取IO,由于不知道外部按键何时会被按键,因此需要通过中断来检测外部按键的状态,将Enable Interrupt勾选上,点击OK。

2.Block Design连线设计

AXI GPIO IP核添加后,按照下图进行连线,通过concat将AXI GPIO的中断信号连接到PS端

输出产品

生成顶层文件

在xdc文件中添加AXI GPIO引脚的约束,我这里将bit0约束到蜂鸣器,将bit1约束到外部按键

最后综合、实现、生成bit文件。

  • 三、编写Vitis工程

1.AXI GPIO Vitis操作说明

/*

 * AXI GPIO使用说明:

 * 1.每个AXI GPIO IP核有两个通道,在vivado中搭建block design时可以选择启用哪个通道,或者两个通道都启用

 * 2.如果要使用AXI GPIO中断功能,在在vivado中搭建block design时需要将中断使能勾选上

 * 3.AXI GPIO每个通道具有32个bit的可控IO,每个IO,即每个bit均可进行配置操作

 * 4.设置输出方向、设置IO值以及读取IO值时,操作对象均是对应每个bit,而不是每个通道,每个bit都可以单独设置

 * 5.设置中断启动、关闭时,是对每个通道进行操作,例如打开中断是直接打开一整个通道,也就是32bit的IO全部的中断全部打开,无法单独对某一bit进行中断配置

 * 6.该代码实现AXI GPIO读取按键中断输出,然后打开蜂鸣器,按键一次,打开蜂鸣器,再按键一次,关闭蜂鸣器,蜂鸣器:channel1bit0,按键:channel1bit1

 */

2. 添加AXI GPIO操作代码

头文件axi_gpio_hdl.h:

  1. 定义一些位操作的接口,因为AXI GPIO的官方接口都是按整个通道进行读写操作的,但是一个通道有32bit的IO,因此需要在自己代码中再将IO操作封装一层,细化到按bit操作
  2. 定义AXI GPIO设备ID号、中断ID号、通道号、通道中使用的bit号等
  3. 定义高低电平的枚举
  4. 定义AXI GPIO操作配置的结构体实例
  5. 声明AXI GPIO驱动初始化、中断初始化、中断处理、写操作、读操作的方法

具体头文件代码如下:

/*!
    \file    axi_gpio_hdl.h
    \brief   firmware functions to manage intr
    \version 2024-03-12, V1.0.0
	\author  tbj
*/

#ifndef AXI_GPIO_HDL_H
#define AXI_GPIO_HDL_H

#include "crc_cal.h"
#include "xgpio.h"

#ifdef __cplusplus
 extern "C" {
#endif

//位操作定义
#define SETBIT(x,y)  x|=(1<<y)  //把x中的第y位置1,从0开始数
#define CLRBIT(x,y)  x&=~(1<<y)  //把x中的第y位置0,从0开始数
#define RESERVEBIT(x,y) x^=(1<<y)  //把x中的第y位取反,从0开始数
#define GETBIT(x,y)  ((x)>>(y)&1)  //获取x中第y位的值,移位运算符的优先级大于逻辑按位运算符优先级

//AXI_GPIO设备ID
#define AXI_GPIO_DEVICE_ID 		XPAR_AXI_GPIO_0_DEVICE_ID
//AXI_GPIO中断ID
#define AXI_GPIO_INT_ID 		XPAR_FABRIC_GPIO_0_VEC_ID
//AXI_GPIO使用的通道号(一个AXI_GPIO一共两个通道,每个通道有32bit I/O 可控)
#define AXI_GPIO_CHANNEL1 		XGPIO_IR_CH1_MASK
//定义外设连接AXI GPIO对应哪个bit
#define AXI_GPIO_BEEP			0
#define AXI_GPIO_KEY			1

typedef enum{
	AXI_GPIO_VALUE_OFF = 0,
	AXI_GPIO_VALUE_ON,
}AXI_GPIO_VALUE;

//PL端 AXI GPIO 驱动实例
XGpio axi_gpio;

//AXI GPIO外设初始化函数
int axi_gpio_init(XGpio *axi_gpio_ptr, u8 channel_num, u32 direction);
//AXI GPIO中断初始化函数
int axi_gpio_intr_init(XScuGic *gic_inst_ptr, XGpio *axi_gpio_ptr, u16 AXI_GpioIntrId);
//AXI GPIO输入中断处理函数
void axi_gpio_key_Intr_Hander(void *CallBackRef);

//读取AXI GPIO相应通道值
u8 axi_gpio_read(XGpio *axi_gpio_ptr, u8 channel_num, u8 gpio_bit);
//设置AXI GPIO相应通道值
void axi_gpio_write(XGpio *axi_gpio_ptr, u8 channel_num, u8 gpio_bit, u8 gpio_bit_val);

#ifdef __cplusplus
}
#endif

#endif /* AXI_GPIO_HDL_H */

源文件axi_gpio_hdl.c:

  1. 对头文件中AXI GPIO驱动初始化、中断初始化、中断处理、写操作、读操作的方法进行实现

具体代码如下:

/*!
    \file    axi_gpio_hdl.c
    \brief   firmware functions to manage axi_gpio
    \version 2024-04-11, V1.0.0
	\author  tbj
*/

/*
 * AXI GPIO使用说明:
 * 1.每个AXI GPIO IP核有两个通道,在vivado中搭建block design时可以选择启用哪个通道,或者两个通道都启用
 * 2.如果要使用AXI GPIO中断功能,在在vivado中搭建block design时需要将中断使能勾选上
 * 3.AXI GPIO每个通道具有32个bit的可控IO,每个IO,即每个bit均可进行配置操作
 * 4.设置输出方向、设置IO值以及读取IO值时,操作对象均是对应每个bit,而不是每个通道,每个bit都可以单独设置
 * 5.设置中断启动、关闭时,是对每个通道进行操作,例如打开中断是直接打开一整个通道,也就是32bit的IO全部的中断全部打开,无法单独对某一bit进行中断配置
 * 6.该代码实现AXI GPIO读取按键中断输出,然后打开蜂鸣器,按键一次,打开蜂鸣器,再按键一次,关闭蜂鸣器,蜂鸣器:channel1bit0,按键:channel1bit1
 */

#include "axi_gpio_hdl.h"

/* @brief:初始化GPIO外设
 * @param:AXI GPIO对象指针
 * @param:AXI GPIO通道号
 * @param:AXI GPIO通道输入输出方向
 * @return:初始化结果
 */
int axi_gpio_init(XGpio *axi_gpio_ptr, u8 channel_num, u32 direction)
{
	int Status;

	//初始化 PL端 AXI GPIO 驱动
	Status = XGpio_Initialize(axi_gpio_ptr, AXI_GPIO_DEVICE_ID);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	//设置 AXI GPIO通道方向
	XGpio_SetDataDirection(axi_gpio_ptr, channel_num, direction);

	return XST_SUCCESS;
}


/* @brief:初始化AXI GPIO的中断
 * @param:中断控制器对象指针
 * @param:AXI GPIO对象指针
 * @param:AXI GPIO中断号
 * @return:初始化结果
 */
int axi_gpio_intr_init(XScuGic *gic_inst_ptr, XGpio *axi_gpio_ptr, u16 AXI_GpioIntrId)
{
	//设置中断优先级和中断触发方式,0x01高电平中断,0x02是总触发中断,0x03是上升沿儿中断
	XScuGic_SetPriorityTriggerType(gic_inst_ptr, AXI_GpioIntrId, 0xA0, 0x01);
	//关联中断 ID 和中断处理函数
	XScuGic_Connect(gic_inst_ptr, AXI_GpioIntrId,
					(Xil_ExceptionHandler) axi_gpio_key_Intr_Hander, (void *) axi_gpio_ptr);

	//使能来自于 axi_Gpio 器件的中断
	XScuGic_Enable(gic_inst_ptr, AXI_GpioIntrId);
	//使能AXI GPIO通道1的中断
	XGpio_InterruptEnable(axi_gpio_ptr, AXI_GPIO_CHANNEL1);
	//使能全局中断-AXI GPIO中断依赖于全局中断
	XGpio_InterruptGlobalEnable(axi_gpio_ptr);

	return XST_SUCCESS;
}

/* @brief:AXI GPIO中断处理函数
 * @param:回调指针
 * @return:初始化结果
 */
void axi_gpio_key_Intr_Hander(void *CallBackRef){

	//记录上次蜂鸣器状态
	static u8 beep_value_temp = 0;
	//本次配置蜂鸣器的状态
	u8 beep_value = 0;
	XGpio *axi_gpio_ptr = (XGpio *)CallBackRef;

	usleep(20000); //延时 20ms,按键消抖
	//通过读取AXI GPIO channel1的bit1来判断按键有没有被按下
	if (axi_gpio_read(axi_gpio_ptr, AXI_GPIO_CHANNEL1, AXI_GPIO_KEY) == 0) {
		beep_value = RESERVEBIT(beep_value_temp, 0);
		//改变蜂鸣器状态
		axi_gpio_write(axi_gpio_ptr, AXI_GPIO_CHANNEL1, AXI_GPIO_BEEP, beep_value);
		XGpio_InterruptDisable(axi_gpio_ptr, AXI_GPIO_CHANNEL1);
	}
	//清除中断并重新使能中断
	XGpio_InterruptClear(axi_gpio_ptr, AXI_GPIO_CHANNEL1);
	XGpio_InterruptEnable(axi_gpio_ptr, AXI_GPIO_CHANNEL1);
}


/* @brief:读取AXI GPIO相应通道值
 * @param:AXI GPIO对象指针
 * @param:AXI GPIO通道号
 * @param:AXI GPIO需要操作的bit
 * @return:返回AXI GPIO对应bit的值
 */
u8 axi_gpio_read(XGpio *axi_gpio_ptr, u8 channel_num, u8 gpio_bit){
	u32 read_val = 0;
	read_val = XGpio_DiscreteRead(axi_gpio_ptr, channel_num);
	return GETBIT(read_val, gpio_bit);
}

/* @brief:设置AXI GPIO相应通道值
 * @param:AXI GPIO对象指针
 * @param:AXI GPIO通道号
 * @param:AXI GPIO需要操作的bit
 * @param:AXI GPIO需要操作的bit写入的值
 * @return:无
 */
void axi_gpio_write(XGpio *axi_gpio_ptr, u8 channel_num, u8 gpio_bit, u8 gpio_bit_val){

	u32 write_val = 0;
	//先读取AXI GPIO整个通道的值,防止写入某一bit将其余bit清除掉
	write_val = XGpio_DiscreteRead(axi_gpio_ptr, channel_num);
	//判断写1还是写0
	if(gpio_bit_val == 1){
		SETBIT(write_val, gpio_bit);
	}else if(gpio_bit_val == 0){
		CLRBIT(write_val, gpio_bit);
	}else{
		;
	}
	//将对应值写入AXI GPIO寄存器
	XGpio_DiscreteWrite(axi_gpio_ptr, channel_num, write_val);
}

最后在main.c中调用AXI GPIO初始化相关功能

int main()
{
	//AXI GPIO测试
#ifdef AXI_GPIO_Test
	//初始化AXI GPIO每个bit的输入输出方向,0:输出,1:输入;0x020即bit0为输出,bit1为输入
	u32 axi_gpio_dir = 0x02;
	axi_gpio_init(&axi_gpio, AXI_GPIO_CHANNEL1, axi_gpio_dir);
	//初始化AXI GPIO中断
	axi_gpio_intr_init(&GicIntrDevice, &axi_gpio, AXI_GPIO_INT_ID);
#endif

	while(1){

	}
    return 0;
}

 创作不易,希望大家点赞、收藏、关注哦!!!ヾ(o◕∀◕)ノ

  • 34
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Xilinx Zynq-7000 AP SoC开发实战指南PDF是面向工程师、研究人员和开发人员的一本指南手册。它提供了丰富的信息和案例研究,帮助用户深入了解Zynq-7000 AP SoC的体系结构和开发方法。本书分为两部分,第一部分介绍了Zynq-7000 AP SoC的基础知识,包括体系结构、处理器和系统构建。第二部分则介绍了Zynq-7000 AP SoC的开发工具和应用。 本书主要围绕Xilinx Zynq-7000 AP SoC,通过实际案例研究来展示如何在各种不同的应用环境中使用该处理器。作者详细介绍了Zynq-7000 AP SoC的硬件架构和软件编程环境,包括系统设计、软件开发和调试等方面。此外,本书还对常见问题进行了解答,并提供了一些技术提示,帮助读者克服各种开发难题。 总之,Xilinx Zynq-7000 AP SoC开发实战指南PDF是一本非常有用的指南手册,适用于那些希望深入了解和使用该处理器的人。它提供了全面的指导和实例,为开发者带来了巨大的帮助。 ### 回答2: Xilinx Zynq-7000 AP SoC是一款嵌入式处理器,其具有ARM芯片和FPGA的功能,提供了计算和处理的高度灵活性。《Xilinx Zynq-7000 AP SoC开发实战指南》PDF介绍了如何使用Xilinx的开发工具和SoC系统来构建嵌入式处理器应用和设计。此外,本书还介绍了Xilinx Zynq-7000 AP SoC的架构和配置,如何设计和测试嵌入式系统,以及如何使用Hardware Abstraction Layer(HAL)API编写应用程序。 在本书中,读者将学习如何使用Vivado设计套件和SDK开发和测试嵌入式处理器应用。作者提供了详细的教程和例子,帮助读者更好地理解如何使用Xilinx工具来设计和部署嵌入式系统。 此外,本书还包含了Xilinx Zynq-7000 AP SoC的详细架构和配置信息,让读者更好地了解此处理器的性能、架构和配置选项。读者可通过本书学习如何配置硬件、配置针脚、使用时钟和中断等功能来实现高度优化的嵌入式系统设计。 《Xilinx Zynq-7000 AP SoC开发实战指南》PDF是一本非常有用的嵌入式系统设计指南,为读者提供了详细的信息和指导,使其能够使用Xilinx的工具和技术来构建高度定制的嵌入式系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

披着假发的程序唐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值