前言
- 主要记录的还是中断的使用,因为我认为中断在我后面的设计中将会发挥它的重要性,同时设计慢慢会倾向于PL端设计,使用的是AXI GPIO IP进行写一个小的demo,因为之前做了有将近几年记得FPGA设计(如果本科瞎搞的也算的话,吹个牛:本科的fpga实验课每次都是第一个提前下课的),
PL 对 PS中断
IRQ NAME | IRQ Number | Bits | Required Type | Description |
---|---|---|---|---|
PL_PS_Group0 | 121:128 | 7,8 | rising edge/high level | PL to PS interrupt signals 0 to 7.(3) |
PL_PS_Group1 | 136:143 | 8 | rising edge/high level | PL to PS interrupt signals 8 to 15.(3) |
- ZCU106开发版对应的SOC支持两组PL to PS中断(共16个中断)
- group0: 中断号为121–128,8个中断
- group1: 中断号为136–143,8个中断
如何使用
- 如果使能了IRQ0:第一组PL to PS中断
- PL端对PS端产生多个中断,默认从ID 121开始分配
- 第一个中断的ID:121
- 第一个中断的ID:122
- …累加但第一组最大ID不超过128
- 记录使用过一个中断的过程
设计流程
最后结果
- zcu106开发版,sw15 pushbutton每按下一次,打印一次结果,LED也变换状态
设计流程
BD设计
- pl_ps_irq 的位宽是自动拓展的,可以单击以下 Validate Design 就会自动拓展。
- 因为要对引脚进行约束,需要将GPIO和GPIO2端口导出
引脚约束
参考手册UG244,在这边日记中也有说明1 使用EMIO
set_property PACKAGE_PIN AL11 [get_ports LED_tri_io]
set_property PACKAGE_PIN AL10 [get_ports BUTTON_tri_io]
set_property IOSTANDARD LVCMOS18 [get_ports LED_tri_io]
set_property IOSTANDARD LVCMOS18 [get_ports BUTTON_tri_io]
# bit compress
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]
SDK 设计
初始
#include "xparameters.h"
#include "xgpio.h"
#include "xil_exception.h"
#include "xscugic.h"
#include "xil_printf.h"
#include "sleep.h"
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID // define the General interrupt controller device ID
#define GPIO_DEVICE_ID XPAR_AXI_GPIO_0_DEVICE_ID // define the PL Slide GPIO device ID
#define INTC_GPIO_INTERRUPT_ID XPAR_FABRIC_GPIO_0_VEC_ID // define the AXI GPIO interrupt ID
#define printf xil_printf
/* 对应的AXI GPIO 两个通道*/
#define LED_CHANNEL 1
#define BUTTON_CHANNEL 2
XGpio Gpio; // The instance of the GPIO Driver
XScuGic Intc; // The instance of the Interrupt Controller Driver
主函数
int main()
{
int Status;
Status = InitAxiGpio(&Gpio, GPIO_DEVICE_ID); /* 初始化AXI GPIO */
if (Status != XST_SUCCESS)
{
return XST_FAILURE;
}
Status = InitIntrp(&Intc, &Gpio, INTC_DEVICE_ID, INTC_GPIO_INTERRUPT_ID);
if (Status != XST_SUCCESS)
{
return XST_FAILURE;
}
return XST_SUCCESS;
}
AXI-GPIO初始化
- AXI-GPIO属于PL端资源,使用的是XGpio函数
int InitAxiGpio(XGpio *GpioInstancePtr, u16 GpioDeviceId)
{
int Status;
Status = XGpio_Initialize(GpioInstancePtr, GPIO_DEVICE_ID);
if (Status != XST_SUCCESS)
{
return XST_FAILURE;
}
/* Set channle 1 as led output */
XGpio_SetDataDirection(GpioInstancePtr, LED_CHANNEL, 0x0); // Set the LED channel tristate buffer to be output
XGpio_DiscreteWrite(GpioInstancePtr, LED_CHANNEL, 0x0); // Turn off the LEDs
/* Set cahnnle 2 as button input and intr*/
XGpio_SetDataDirection(GpioInstancePtr, BUTTON_CHANNEL, 0x1); // Set the push button channel tristate buffer to be input
XGpio_InterruptEnable(GpioInstancePtr, BUTTON_CHANNEL); // Enable the interrupt for the push buttons
XGpio_InterruptGlobalEnable(GpioInstancePtr); // Enable global interrupt
return XST_SUCCESS;
}
中断初始化
- 初始化中断
- 初始化并注册中断异常
- 建立中断
int InitIntrp(XScuGic *IntcInstancePtr, XGpio *GpioInstancePtr, u16 IntcDeviceId, u16 IntrId)
{
int Status;
XScuGic_Config *IntcConfig;
IntcConfig = XScuGic_LookupConfig(IntcDeviceId);
if (NULL == IntcConfig)
{
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS)
{
return XST_FAILURE;
}
/* 初始化并注册中断异常 */
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, IntcInstancePtr);
Xil_ExceptionEnable();
/* 设置中断优先级和中断触发方式 */
XScuGic_SetPriorityTriggerType(IntcInstancePtr, IntrId, 0x10, 0x3);
/* 建立中断 */
Status = XScuGic_Connect(IntcInstancePtr, IntrId, (Xil_ExceptionHandler)IntrHandler, (void *)GpioInstancePtr);
if (Status != XST_SUCCESS)
{
return XST_FAILURE;
}
XScuGic_Enable(IntcInstancePtr, IntrId);
return XST_SUCCESS;
}
void IntrHandler(void *CallBackRef)
{
XGpio *GpioInstancePtr = (XGpio *)CallBackRef;
// Clear the interrupt status to allow future interrupts
XGpio_InterruptClear(GpioInstancePtr, BUTTON_CHANNEL);
// 去抖
usleep(20000);
if (XGpio_DiscreteRead(GpioInstancePtr, BUTTON_CHANNEL) & 0x1)
{
led_status = ~led_status;
XGpio_DiscreteWrite(GpioInstancePtr, LED_CHANNEL, led_status);
printf("Button pressed, LED status: %d\r\n", led_status);
}
// Re-enable the interrupt
XGpio_InterruptEnable(GpioInstancePtr, BUTTON_CHANNEL);
}
相关解释
-
关与XScuGic_SetPriorityTriggerType()函数
XScuGic_SetPriorityTriggerType(IntcInstancePtr, IntrId, 0x10, 0x3);
- 第一个参数:中断实例化指针
- 第二个参数:中断ID, 这里就是PL_KEY_INTR对应的宏定义ID号就是121
- 第三个参数:中断优先级,只能值8的整数倍,越小优先级越高
- 第三个参数:中断触发类型
- 0x01: 高电平触发
- 0x11: 上升沿触发
-
关于关于XScuGic_Connect函数
XScuGic_Connect(IntcInstancePtr, IntrId, (Xil_ExceptionHandler)IntrHandler, (void *)GpioInstancePtr);
- 第一个参数:中断实例化指针
- 第二个参数:中断ID, 这里就是PL_KEY_INTR对应的宏定义ID号就是121
- 第三个参数:中断回调函数,这里的函数名就是IntrHandler,(Xil_InterruptHandler)是一个指针类型进行类型转换
- 第三个参数:中断回调参考实例,可以是中断实例化指针,但一般是需要中断回调函数中使用的实例化指针
-
关于回调函数IntrHandler
void IntrHandler(void *CallBackRef) { XGpio *GpioInstancePtr = (XGpio *)CallBackRef; // Clear the interrupt status to allow future interrupts XGpio_InterruptClear(GpioInstancePtr, BUTTON_CHANNEL); // 去抖 usleep(20000); if (XGpio_DiscreteRead(GpioInstancePtr, BUTTON_CHANNEL) & 0x1) { led_status = ~led_status; XGpio_DiscreteWrite(GpioInstancePtr, LED_CHANNEL, led_status); printf("Button pressed, LED status: %d\r\n", led_status); } // Re-enable the interrupt XGpio_InterruptEnable(GpioInstancePtr, BUTTON_CHANNEL); }
- 清除中断
- 执行处理函数
- 写LED通道控制LED状态
- 使能中断
-
关于异常
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, IntcInstancePtr);
Xil_ExceptionEnable();
-
ARM 处理器支持 7种异常情况:复位、未定义指令、软件中断、指令预取中止、数据中止、中断请求(IRQ)和快速中断请求(FIQ)。
-
ARM 处理器支持的每种异常也都有自己的 ID 标识,其中 XIL_EXCEPTION_ID_INT 用于标识中断请求(IRQ)异常。
-
通 过 调 用 函 数 Xil_ExceptionRegisterHandler( )来给 IRQ 异常注册处理程序,它会将中断控制器 GIC 的中断处理程序与 ARM 处理器中的硬件中断处理逻辑连接起来。
- XIL_EXCEPTION_ID_INT:异常中断ID,系统给出
- XScuGic_InterruptHandler:要注册的异常处理函数
- IntcInstancePtr : 中断实例化指针- 另外还要通过 Xil_ExceptionEnable()函数使能 IRQ 异常。
-
使能异常中断