前言
- 本日记记录使用中断的过程,以GPIO Interrupt Demo记录中断使用流程
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
- 记录使用过一个中断的过程
流程
BD设计
参考这一部分第一篇日记链接: 1 使用EMIO
SDK设计
/*
* emio-interrupt.c: simple test application
*
* This application configures UART 16550 to baud rate 9600.
* PS7 UART (Zynq) is not initialized by this application, since
* bootrom/bsp configures it to baud rate 115200
*
* ------------------------------------------------
* | UART TYPE BAUD RATE |
* ------------------------------------------------
* uartns550 9600
* uartlite Configurable only in HW design
* ps7_uart 115200 (configured by bootrom/bsp)
*/
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xil_exception.h"
#include "xscugic.h"
#include "xgpiops.h"
#define printf xil_printf
#ifndef GPIO_DEVICE_ID
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#endif
#ifndef INTR_DEVICE_ID
#define INTR_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#endif
#define PL_KEY_INTR XPAR_XGPIOPS_0_INTR // 可以设置为121,表示第一个中断ID
// #define PL_KEY1_INTR XPAR_XGPIOPS_0_INTR+1 // 如果是有两个中断,表示中断ID 加 1就行,三个四个也是如此
// PL端GPIO从78号开始,顺序分配就行,与VIVADO中进行的引脚约束的顺序无关
#define PL_LED (78) /* The pin connected to the LED */
#define PL_KEY (79) /* The pin connected to the pushbutton sw14 */
XGpioPs Gpio;
XScuGic Intc;
int IntrInitFunction(XScuGic *instancePtr, u16 DeviceId, XGpioPs *instanceGpio);
void GpioHandler(void *CallBackRef);
int count = 0;
int led_status = 0;
int main()
{
int Status;
/*
* Initialize the GPIO
*/
printf("Begin initial GPIO\n\r");
XGpioPs_Config *ConfigPtr;
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
if (ConfigPtr == NULL) {
return XST_FAILURE;
}
Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Set the direction for the LED pin to be an output
* Set the output enable for the LED pin
* Set the initial calue for the LED pin to be off
*/
XGpioPs_SetDirectionPin(&Gpio, PL_LED, 1);
XGpioPs_SetOutputEnablePin(&Gpio, PL_LED, 1);
XGpioPs_WritePin(&Gpio, PL_LED, 0);
/*
* Set the direction for the PL_KEY pin to be an input
* Set the interrupt type rising for the PL_KEY pin
* Set the interrupt enable for the PL_KEY pin
*/
XGpioPs_SetDirectionPin(&Gpio, PL_KEY, 0);
XGpioPs_SetIntrTypePin(&Gpio, PL_KEY, XGPIOPS_IRQ_TYPE_EDGE_FALLING); // 设置输入IO为中断类型
XGpioPs_IntrEnablePin(&Gpio, PL_KEY); // 使能
printf("End initial GPIO\n\r");
Status = IntrInitFunction(&Intc, INTR_DEVICE_ID, &Gpio);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
return 0;
}
/* 初始化并建立中断函数 */
int IntrInitFunction(XScuGic *instancePtr, u16 DeviceId, XGpioPs *instanceGpio)
{
int status;
XScuGic_Config *IntrConfig;
IntrConfig = XScuGic_LookupConfig(INTR_DEVICE_ID);
if (IntrConfig == NULL) {
return XST_FAILURE;
}
status = XScuGic_CfgInitialize(instancePtr, IntrConfig, IntrConfig->CpuBaseAddress);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
XScuGic_SetPriorityTriggerType(instancePtr, PL_KEY_INTR, 0x10, 0x1); /* set pl_key failing sensitive*/
status = XScuGic_Connect(instancePtr, PL_KEY_INTR, (Xil_InterruptHandler)GpioHandler, (void *)instanceGpio);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
XScuGic_Enable(instancePtr, PL_KEY_INTR);
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, instancePtr);
Xil_ExceptionEnable();
return XST_SUCCESS;
}
void GpioHandler(void *CallBackRef)
{
XGpioPs *GpioPtr = (XGpioPs *)CallBackRef;
int key_value = XGpioPs_IntrGetStatusPin(GpioPtr, PL_KEY);
if ((key_value))
{
printf("get interrupt counts: %d \r\n", count);
XGpioPs_WritePin(GpioPtr, PL_LED, led_status);
led_status = ~led_status;
count += 1;
}
XGpioPs_IntrClearPin(GpioPtr, PL_KEY);
}
-
关与XScuGic_SetPriorityTriggerType(instancePtr, PL_KEY_INTR, 0x10, 0x1); /* set pl_key failing sensitive*/函数
- 第一个参数:中断实例化指针
- 第二个参数:中断ID, 这里就是PL_KEY_INTR对应的宏定义ID号就是121
- 第三个参数:中断优先级,只能值8的整数倍,越小优先级越高
- 第三个参数:中断触发类型
- 0x01: 高电平触发
- 0x11: 上升沿触发
-
关于XScuGic_Connect(instancePtr, PL_KEY_INTR, (Xil_InterruptHandler)GpioHandler, (void *)instanceGpio);函数
- 第一个参数:中断实例化指针
- 第二个参数:中断ID, 这里就是PL_KEY_INTR对应的宏定义ID号就是121
- 第三个参数:中断回调函数,这里的函数名就是GpioHandler,(Xil_InterruptHandler)是一个指针类型进行类型转换
- 第三个参数:中断回调参考实例,可以是中断实例化指针,但一般是需要中断回调函数中使用的实例化指针
-
关于回调函数GpioHandler
void GpioHandler(void *CallBackRef) { XGpioPs *GpioPtr = (XGpioPs *)CallBackRef; int key_value = XGpioPs_IntrGetStatusPin(GpioPtr, PL_KEY); if ((key_value)) { printf("get interrupt counts: %d \r\n", count); XGpioPs_WritePin(GpioPtr, PL_LED, led_status); /* 控制LED状态变化 */ led_status = ~led_status; count += 1; } XGpioPs_IntrClearPin(GpioPtr, PL_KEY); /* 清除中断 */ }
- 参数:固定格式,对应的就是XScuGic_Connect第三个参数:中断回调参考实例,可以是中断实例化指针,但一般是需要中断回调函数中使用的实例化指针
- 获得按键的值
- 执行对应的操作
- 清除中断,便于下次中断触发
- 关于XGpioPs_IntrGetStatusPin函数,就是封装的读对应GPIO寄存器的值 ,只是进行了一些封装使读写更加安全。
-
关于异常
Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, instancePtr); Xil_ExceptionEnable();
- 需要初始化并设置 ARM 处理器的异常处理功能。
- ARM 处理器支持 7种异常情况:复位、未定义指令、软件中断、指令预取中止、数据中止、中断请求(IRQ)和快速中断请求(FIQ)。
- ARM 处理器支持的每种异常也都有自己的 ID 标识,其中 XIL_EXCEPTION_ID_INT 用于标识中断请求(IRQ)异常。
- 通 过 调 用 函 数 Xil_ExceptionRegisterHandler( XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler) XScuGic_InterruptHandler, &scugic_inst )来给 IRQ 异常注册处理程序,它会将中断控制器 GIC 的中断处理程序与 ARM 处理器中的硬件中断处理逻辑连接起来。
- 另外还要通过 Xil_ExceptionEnable()函数使能 IRQ 异常。