AXI GPIO 同意通道混合输入输出中断控制

Haskell
#KEY
set_property IOSTANDARD LVCMOS18 [get_ports {AXI_GPIO_KEY_tri_io[0]}]
set_property PACKAGE_PIN J13 [get_ports {AXI_GPIO_KEY_tri_io[0]}]
set_property IOSTANDARD LVCMOS18 [get_ports {AXI_GPIO_KEY_tri_io[1]}]
set_property PACKAGE_PIN H13 [get_ports {AXI_GPIO_KEY_tri_io[1]}]
#LED
set_property IOSTANDARD LVCMOS18 [get_ports {AXI_GPIO_KEY_tri_io[2]}]
set_property PACKAGE_PIN U21 [get_ports {AXI_GPIO_KEY_tri_io[2]}]
set_property IOSTANDARD LVCMOS18 [get_ports {AXI_GPIO_KEY_tri_io[3]}]
set_property PACKAGE_PIN Y25 [get_ports {AXI_GPIO_KEY_tri_io[3]}]
main.c
cs
#include <stdio.h>
#include "xil_printf.h"
#include "axi_gpio.h"
#include "axi_intr.h"
#include "sleep.h"
u8 led1_flag = 0;
u8 led2_flag = 0;
int main(){
printf("AXI_GPIO_S\r\n");
axi_gpio_config();
intr_config();
// LED_ON;
while(1){
out_axi_gpio(2,led1_flag);
out_axi_gpio(3,led2_flag);
printf("%lx %d %d\r\n",read_axi_reg(),led1_flag,led2_flag);
sleep(1);
AXI_GPIO_INTR(1);
}
return 0;
}
axi_gpio.c
cs
#include <stdio.h> // 标准输入输出函数,用于调试信息输出
#include "xparameters.h" // 硬件系统参数定义,包含基地址和设备ID等
#include "axi_gpio.h" // AXI GPIO寄存器定义,提供底层硬件访问
XGpio AXI_Gpio ;
#define GPIO_CHANNEL1 1 //AXI GPIO 通道号
#define AXI_GPIO_ID XPAR_GPIO_0_DEVICE_ID //AXI GPIO 器件ID
//axi gpio 初始化
void axi_gpio_config(void){
XGpio_Initialize(&AXI_Gpio, AXI_GPIO_ID); //初始化AXI GPIO
XGpio_SetDataDirection(&AXI_Gpio,GPIO_CHANNEL1,0x000000003); //设置对应通道为0011输出输入
LED_OFF;
}
//读取通道当前状态
u32 read_axi_reg(void){
return XGpio_DiscreteRead(&AXI_Gpio,GPIO_CHANNEL1);
}
//输出函数
//bit_pos:要修改的数据位
//value:要修改的数据
void out_axi_gpio(u32 bit_pos,u8 value){
u32 out_data;
out_data = modify_bit(read_axi_reg(),bit_pos,value);
XGpio_DiscreteWrite(&AXI_Gpio,GPIO_CHANNEL1,out_data);
}
/**
* @brief 修改数据的特定位
* @param data 要修改的原始数据
* @param bit_pos 要修改的位位置(0-31,0表示最低位)
* @param value 要设置的值(0或1)
* @return 修改后的数据
*
* @details 此函数通过创建掩码来修改数据的特定位,不影响其他位的值
* 使用示例:modify_bit(0x00000000, 3, 1) 返回 0x00000008(设置第3位为1)
*/
u32 modify_bit(u32 data, u32 bit_pos, u8 value) {
// 创建指定位的掩码:将1左移bit_pos位
// 例如:bit_pos=3 -> mask = 0b00001000 (0x08)
u32 mask = 1U << bit_pos;
if (value) {
// 设置特定位为1:使用OR操作将指定位设为1
data |= mask;
} else {
// 设置特定位为0:使用AND操作与掩码的反码,清除指定位
data &= ~mask;
}
return data;
}
/**
* 获取32位数据中特定位的值
* @param data 原始数据
* @param bit_pos 位位置(0-31,0表示最低位)
* @return 指定位的值(0或1)
*/
u32 get_bit(u32 data, u32 bit_pos) {
// 确保位位置在有效范围内(0-31)
if(bit_pos > 31) return 0;
// 将数据右移,使目标位移动到最低位,然后与1进行与操作
return (data >> bit_pos) & 1;
}
axi_gpio.h
cs
#include <stdio.h>
#include "xparameters.h"
#include "xgpio.h"
extern XGpio AXI_Gpio ;
#define GPIO_CHANNEL1 1 //AXI GPIO 通道号
#define LED_ON XGpio_DiscreteWrite(&AXI_Gpio,GPIO_CHANNEL1,0X0000000F) //控制IO输出1
#define LED_OFF XGpio_DiscreteWrite(&AXI_Gpio,GPIO_CHANNEL1,0X00000003) //控制IO输出0
void axi_gpio_config(void);
u32 read_axi_reg(void);
u32 modify_bit(u32 data, u32 bit_pos, u8 value);
void out_axi_gpio(u32 bit_pos,u8 value);
u32 get_bit(u32 data, u32 bit_pos);
axi_intr.c
cs
#include <stdio.h>
#include "xparameters.h"
#include "xgpio.h"
#include "xil_exception.h"
#include "xscugic.h"
#include "axi_intr.h"
#include "axi_gpio.h"
extern XGpio AXI_Gpio ;
XScuGic Intc ;
#define AXI_GPIO_ID XPAR_GPIO_0_DEVICE_ID //AXI GPIO 器件ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID //中断控制器 器件ID
#define AXI_GPIO_INT_ID XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR //AXI GPIO 中断ID
#define GPIO_CHANNEL1 1 //AXI GPIO 通道号
extern u8 led1_flag;
extern u8 led2_flag;
void intr_config(void){
XGpio_Initialize(&AXI_Gpio, AXI_GPIO_ID); //初始化AXI GPIO
XGpio_SetDataDirection(&AXI_Gpio,GPIO_CHANNEL1,0x00000003); //设置对应通道为输入
SetupInterruptSystem(&Intc,&AXI_Gpio,AXI_GPIO_INT_ID); //设置中断系统
}
void SetupInterruptSystem(XScuGic *GicInstancePtr, XGpio *AXI_Gpio,u16 AXI_GpioIntrId)
{
XScuGic_Config *IntcConfig;
//查找GIC配置信息,进行初始化
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
XScuGic_CfgInitialize(GicInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress);
/*********************************************************************************************************************/
//初始化ARM处理器异常句柄
Xil_ExceptionInit();
//给IRQ异常注册处理程序
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,GicInstancePtr);
//使能处理器中断
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
/*********************************************************************************************************************/
//关联IQC异常处理函数
XScuGic_Connect(GicInstancePtr,AXI_GpioIntrId,(Xil_ExceptionHandler)IntrHandler,(void *)AXI_Gpio);
//使能GIC控制器对应ID中断
XScuGic_Enable(GicInstancePtr, AXI_GpioIntrId);
//设置优先级0xA0 触发类型 0x3边沿触发(上升沿或下降沿)
XScuGic_SetPriorityTriggerType(GicInstancePtr, AXI_GpioIntrId,0xA0, 0x3);
//打开AXI GPIO IP中断使能 通道使能
XGpio_InterruptGlobalEnable(AXI_Gpio);
XGpio_InterruptEnable(AXI_Gpio,0x00000003);
}
void IntrHandler(void){
printf("from intr\r\n");
//关闭AXI GPIO1中断使能
AXI_GPIO_INTR(0);
// //判断AXI KEY
if(get_bit(read_axi_reg(),0) == 0){
led1_flag = !led1_flag;
}
if(get_bit(read_axi_reg(),1) == 0){
led2_flag = !led2_flag;
}
// else;
//清楚中断线
XGpio_InterruptClear(&AXI_Gpio,GPIO_CHANNEL1);
}
axi_intr.h
cs
#include <stdio.h>
#include "xparameters.h"
#include "xgpio.h"
#include "xil_exception.h"
#include "xscugic.h"
void intr_config(void);
void IntrHandler(void);
void SetupInterruptSystem(XScuGic *GicInstancePtr, XGpio *AXI_Gpio,u16 AXI_GpioIntrId);
extern XScuGic Intc ;
extern XGpio AXI_Gpio ;
#define AXI_GPIO_INTR(a) if(a)\
XGpio_InterruptEnable(&AXI_Gpio,0x00000003);\
else XGpio_InterruptDisable(&AXI_Gpio,0x00000000);
实现AXI GPIO[1:0]做输入,中断控制AXI GPIO[3:2]做输出。