文章目录
- 1 实验任务
- 2 系统框图
- 3 软件设计
1 实验任务
本实验任务是通过调用PL端AXI GPIO IP核,使用中断机制,实现PL端按键控制 PS端LED的功能。
2 系统框图
3 软件设计
注意事项:
- AXI GPIO IP核是双沿触发中断,不可设置;
- AXI GPIO IP核的中断使能和中断状态都是以通道为单位。
/***************************** Include Files ********************************/
#include <stdio.h>
#include "xil_exception.h"
#include "xparameters.h"
#include "xgpiops.h"
#include "xgpio.h"
#include "xscugic.h"
#include "xstatus.h"
#include "sleep.h"
/************************** Constant Definitions ****************************/
#define PSGPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#define AXIGPIO_DEVICE_ID XPAR_GPIO_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define AXIGPIO_INTR_ID XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR
#define PS_LED0_GPIO_PIN 0
#define AXIGPIO_CHANNEL1 0x1
/**************************** Type Definitions ******************************/
/***************** Macros (Inline Functions) Definitions ********************/
/************************** Function Prototypes *****************************/
int PsGpioInit(XGpioPs* PsGpioInstPtr);
int AxiGpioInit(XGpio* AxiGpioInstPtr);
int SetupIntrSystem(XScuGic* IntcInstPtr, XGpio* AxiGpioInstPtr, u16 AxiGpioIntrId);
void AxiGpioIntrHandler(void *CallBackRef);
/************************** Variable Definitions ****************************/
XGpioPs PsGpioInst;
XGpio AxiGpioInst;
XScuGic IntcInst;
u32 KeyPress = 0;
/****************************************************************************/
int PsGpioInit(XGpioPs* PsGpioInstPtr)
{
//
int Status;
XGpioPs_Config* PsGpioConfigPtr;
//
PsGpioConfigPtr = XGpioPs_LookupConfig(PSGPIO_DEVICE_ID);
Status = XGpioPs_CfgInitialize(PsGpioInstPtr, PsGpioConfigPtr, PsGpioConfigPtr->BaseAddr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
// 设置输出
XGpioPs_SetDirectionPin(PsGpioInstPtr, PS_LED0_GPIO_PIN, 1);
// 使能输出
XGpioPs_SetOutputEnablePin(PsGpioInstPtr, PS_LED0_GPIO_PIN, 1);
//
return XST_SUCCESS;
}
int AxiGpioInit(XGpio* AxiGpioInstPtr)
{
//
int Status;
XGpio_Config* AxiGpioConfigPtr;
//
AxiGpioConfigPtr = XGpio_LookupConfig(AXIGPIO_DEVICE_ID);
Status = XGpio_CfgInitialize(AxiGpioInstPtr, AxiGpioConfigPtr, AxiGpioConfigPtr->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
// 设置输入
XGpio_SetDataDirection(AxiGpioInstPtr, AXIGPIO_CHANNEL1, 0x1);
// 使能中断
XGpio_InterruptEnable(AxiGpioInstPtr, XGPIO_IR_CH1_MASK);
XGpio_InterruptGlobalEnable(AxiGpioInstPtr);
//
return XST_SUCCESS;
}
/*
* 如何设置AXI GPIO引脚方向
*
* XGpio gpio_instance;
* int channel = 1; // 假设使用通道1
* int bit_to_change = 3; // 假设要修改第3位
*
* // 初始化GPIO
* XGpio_Initialize(&gpio_instance, XPAR_XGPIOPS_0_DEVICE_ID);
*
* // 读取当前方向寄存器的值
* u32 current_direction = XGpio_GetDataDirection(&gpio_instance, channel);
*
// 将第3位设置为输出(0)
* u32 new_direction_output = current_direction & ~(1 << bit_to_change);
* XGpio_SetDataDirection(&gpio_instance, channel, new_direction_output);
*
* // 将第3位设置为输入(1)
* u32 new_direction_input = current_direction | (1 << bit_to_change);
* XGpio_SetDataDirection(&gpio_instance, channel, new_direction_input);
*
*/
int SetupIntrSystem(XScuGic* IntcInstPtr, XGpio* AxiGpioInstPtr, u16 AxiGpioIntrId)
{
//
int Status;
XScuGic_Config* IntcConfigPtr;
// step1. 初始化中断控制器GIC
IntcConfigPtr= XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == IntcConfigPtr) {
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(IntcInstPtr, IntcConfigPtr, IntcConfigPtr->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
// step2. 在处理器中初始化异常处理功能
Xil_ExceptionInit();
// step3. 在处理器中为IRQ中断异常注册处理程序
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, IntcInstPtr);
// step4. 在处理器中使能IRQ中断异常
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
// step5. 在GIC中为外设注册中断处理程序
// XScuGic_Connect函数将中断源(Int_Id)与中断处理程序(Handler)关联起来;当中断发生时,GIC会调用中断处理程序来处理中断
Status = XScuGic_Connect(IntcInstPtr, AxiGpioIntrId, (Xil_ExceptionHandler)AxiGpioIntrHandler, (void *)AxiGpioInstPtr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
// step6. 在GIC中设置外设中断的优先级和触发类型
XScuGic_SetPriorityTriggerType(IntcInstPtr, AxiGpioIntrId, 0xA0, 0x1);
// step7. 在GIC中使能外设中断
XScuGic_Enable(IntcInstPtr, AxiGpioIntrId);
//
return XST_SUCCESS;
}
void AxiGpioIntrHandler(void *CallBackRef)
{
//
XGpio* AxiGpioInstPtr = (XGpio*)CallBackRef;
u32 IntrStatus;
//
IntrStatus = XGpio_InterruptGetStatus(AxiGpioInstPtr);
if (IntrStatus==1)
{
// 禁用中断
XGpio_InterruptDisable(AxiGpioInstPtr, XGPIO_IR_CH1_MASK);
printf("Interrupt Detected.\n");
KeyPress = 1;
}
//
return;
}
int main()
{
//
int Status;
u32 LedValue;
u32 KeyValue;
//
printf("AXI GPIO Interrupt Control LED Test\n");
//
Status = PsGpioInit(&PsGpioInst);
if (Status == XST_FAILURE) {
printf("PS GPIO Init Failed.\n");
}
//
Status = AxiGpioInit(&AxiGpioInst);
if (Status == XST_FAILURE) {
printf("AXI GPIO Init Failed.\n");
}
//
Status = SetupIntrSystem(&IntcInst, &AxiGpioInst, AXIGPIO_INTR_ID);
if (Status == XST_FAILURE) {
printf("Setup Interrupt System Failed.\n");
}
//
while(1)
{
if (KeyPress==1)
{
usleep(200000);
KeyValue = XGpio_DiscreteRead(&AxiGpioInst, AXIGPIO_CHANNEL1);
if ((KeyValue & (1 << 0)) == 0) {
LedValue = ~XGpioPs_ReadPin(&PsGpioInst, PS_LED0_GPIO_PIN);
XGpioPs_WritePin(&PsGpioInst, PS_LED0_GPIO_PIN, LedValue);
}
KeyPress = 0;
XGpio_InterruptClear(&AxiGpioInst, XGPIO_IR_CH1_MASK);
XGpio_InterruptEnable(&AxiGpioInst, XGPIO_IR_CH1_MASK);
}
}
//
return 0;
}