当前位置: 首页 > news >正文

Zynq(4)MIO中断

在这里插入图片描述

文章目录

  • 1.什么是中断?
  • 2.GPIO中断
  • 3.程序分析
  • 4.传送门

前言: 在前两篇文中,通过HelloWorld例程熟悉Zynq的开发过程;通过读写MIO学习使用外设进一步熟悉开发流程,本文承接上文,介绍Zynq开发中的重要机制——中断,以MIO的中断为例,介绍中断原理,工程搭建步骤,以及程序源码解读。读者通过本文认识重要的交互机制中断,为后续为特定项目场景方案定制提供思路,为深入理解Zynq内部架构提供理论支撑

1.什么是中断?

中断是IO操作的一种方式,也是CPU与外设的一种通信机制,除此之外还有查询、DMA等方式。三者相比各有优缺点,在查询模式下,CPU主动、定时地检查外设的状态,询问外设是否需要进行数据交换。这种方式效率较低,因为CPU在不断地轮询外设时可能浪费大量时间,无法进行其他任务,例如在QT中使用定时器,在定时器到时之后处理某件时间,这个就是查询操作。DMA即Direct Memory Access直接存储访问,是一种允许外设直接访问系统内存,绕过CPU进行数据传输的技术。通过DMA,外设可以自主地将数据从内存中读取或写入内存,而不需要CPU的持续参与。使用DMA可以有效的降低CPU负载,适合在批量数据传输的场景中。Xilinx的PCIE解决方案XDMA IP核就是采用的DMA方式。
而中断(Interrupt)是指在计算机系统中,当外设或其他事件需要CPU的处理时,主动向CPU发出信号,打断当前正在执行的程序,让CPU暂停当前的任务,转而执行一个专门的程序(称为中断服务程序,ISR, Interrupt Service Routine)来处理该事件。处理完中断事件后,CPU会恢复之前的状态,继续执行被中断的任务。例如,在使用电脑时对人们对鼠标的点击,对于CPU来说就是一个异步操作,USB3.0有四种传输模式,鼠标使用的就是USB的中断传输模式。中断可以高效快速的实时响应一些紧急任务例如系统故障报警,温度报警等,或者处理异步事件如按键按下,使用这种方式非常高效,但是当中断越多的时候,相应的中断处理机制就更复杂。
以本文对应例程为例,简要介绍中断相关概念。本文使用中断实现一个简单的功能,PS端一个按键按下的时候点亮PL端一个LED灯。按键按下是本例的异步事件,涉及中断源的概念;点亮LED即为中断来的时候处理的结果,涉及中断服务函数。
在Zynq系统中,可以产生中断的源有很多,PS端各种外设,PL端都可以产生中断,为了能够区分,在CPU与外设之间设置了一个通用中断控制器(General interrupt controller),它用于集中管理从 PS 和 PL 发送到 CPU 的中断,实现中断禁用、屏蔽、优先级分配等功能。当GIC发送给CPU并且CPU处理完该中断后,CPU会告诉GIC中断处理完毕,GIC收到后将该中断取消。
在CPU接收到中断之后,会停下来转而执行中断服务函数去做相应的处理,CPU跳转到中断服务程序是由芯片本身的硬件功能来实现的,而不是由程序员手动操作的。当特定的中断事件发生时,CPU会自动检测到该中断并跳转到预先定义好的中断服务程序的入口地址开始执行。 这个过程是由CPU内部的中断控制器和中断向量表等硬件模块来完成的,程序员只需要在编写程序时设置好中断服务程序的入口地址和相应的中断处理函数即可。zynq是通过将一类外设共享一个中断号的方式,提前写好CPU在收到该类中断时转而执行程序的内存地址,根据这个地址去找相应的处理函数,而用户需要在中断处理函数中区分是具体哪个外设。GPIO(PSMIO/EMIO)就是共享(IRQ ID#58)中断号,在Zynq的APU中将中断分成了三种类型,分别是16 个软件产生的中断(SGI),7 个私有外设中断(PPI),92 个共享外设中断(SPI)。如下图所示除了APU中断控制器还有RPU中断控制器。
在这里插入图片描述

2.GPIO中断

关于GPIO中断的使用,主要还是图中涉及中断的几个寄存器的配置。INT_TYPE控制中断类型是边沿敏感还是电平敏感。INT_POLARITY寄存器控制中断时低有效还是高有效(边沿或电平)。INT_ANY设置是否双边沿中断。通过上述三个寄存器设置触发方式。INT_STAT显示当前中断的位,将1写入指定位可以清除对应中断状态。INT_DIS\INT_EN\INT_MASK是和中断屏蔽的寄存器。
在这里插入图片描述

3.程序分析

Vivado工程中对zynq的配置就是勾选串口,勾选emio,勾选mio,然后添加PL端LED约束生成bit流导出xsa文件即可。

#include "xparameters.h"
#include "xgpiops.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "xplatform_info.h"
#include <xil_printf.h>
#include "sleep.h"#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID      // GPIO 器件 ID#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID  //通用中断控制器 ID#define GPIO_INTERRUPT_ID XPAR_XGPIOPS_0_INTR        //GPIO 中断 ID#define KEY 42 //PS_KEY1 连接到 MIO40#define LED 78 //PS_LED1 连接到 EMIO78#define LED2 79 //PS_LED2 连接到 EMIO79static void intr_handler(void * callback_ref);
int setup_interrupt_system(XScuGic  *gic_ins_ptr, XGpioPs *gpio, u16 GpioIntrId );/**************************Global Variable Definitions ***********************/XGpioPs gpio; ; //PS 端 GPIO 驱动实例XScuGic intc; ; //通用中断控制器驱动实例u32 key_press; ; //KEY 按键按下的标志u32 key_val; ; //用于控制 LED 的键值/************************** Function Definitions *****************************/int main(void){int status;XGpioPs_Config  *ConfigPtr; ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);//根据器件ID查找相应配置信息if (ConfigPtr  ==  NULL){return XST_FAILURE;}XGpioPs_CfgInitialize (&gpio, ConfigPtr,ConfigPtr->BaseAddr );//根据配置信息完成IO初始化和驱动实例初始化XGpioPs_SetDirectionPin (&gpio, KEY , 0 );//设置引脚方向XGpioPs_SetDirectionPin (&gpio,  LED, 1 );XGpioPs_SetDirectionPin (&gpio, LED2,  1 );XGpioPs_SetOutputEnablePin (&gpio,  LED, 1 );  //设置输出引脚使能XGpioPs_SetOutputEnablePin (&gpio,  LED2,  1 );XGpioPs_WritePin (&gpio,LED,  0x0 );    //设置输出引脚输出值XGpioPs_WritePin (&gpio, LED2,  0x1 ); status =setup_interrupt_system (&intc,  &gpio,GPIO_INTERRUPT_ID );//通过IO驱动实例、中断控制器实例建立中断if(status  != XST_SUCCESS) {xil_printf( "Setup interrupt system failed\r\n" );return XST_FAILURE;}//中断触发时,key_press 为 TURE,延时一段时间后判断按键是否按下,是则反转 LEDwhile(1){if (key_press){usleep(20000 );if ( XGpioPs_ReadPin (&gpio,  KEY) == 0) {key_val = ~key_val;XGpioPs_WritePin (&gpio,  LED, key_val );}key_press  = FALSE;XGpioPs_IntrClearPin (&gpio , KEY ); //清除按键 KEY 中断XGpioPs_IntrEnablePin (&gpio , KEY ); //使能按键 KEY 中断}}return XST_SUCCESS;}static void intr_handler(void *callback_ref){XGpioPs  *gpio = (XGpioPs *) callback_ref;if (XGpioPs_IntrGetStatusPin(gpio,  KEY)){//读取 KEY 按键引脚的中断状态,判断是否发生中断key_press= TRUE;XGpioPs_IntrDisablePin(gpio, KEY); //屏蔽按键 KEY 中断,等待中断响应}}int setup_interrupt_system(XScuGic*gic_ins_ptr, XGpioPs *gpio, u16 GpioIntrId){int status;XScuGic_Config *IntcConfig; //中断控制器配置信息IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID );//根据器件ID查找中断控制器配置信息并初始化中断控制器驱动if (  NULL  == IntcConfig ) {return XST_FAILURE;}status = XScuGic_CfgInitialize(gic_ins_ptr, IntcConfig, IntcConfig->CpuBaseAddress );if (status  != XST_SUCCESS){return XST_FAILURE;}Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, gic_ins_ptr );//设置并使能中断异常Xil_ExceptionEnable ();//为中断设置中断处理函数status = XScuGic_Connect(gic_ins_ptr, GpioIntrId,(Xil_ExceptionHandler) intr_handler, (void  *) gpio );if (status  != XST_SUCCESS ) {return status;}XScuGic_Enable(gic_ins_ptr, GpioIntrId);//使能 Gpio器件中断XGpioPs_SetIntrTypePin(gpio,  KEY,  XGPIOPS_IRQ_TYPE_EDGE_FALLING);//设置 KEY 按键的中断类型为下降沿中断XGpioPs_IntrEnablePin(gpio,  KEY );//使能具体引脚 中断return XST_SUCCESS;}

一共有三个函数,一个是主函数main,配置IO的操作和配合中断服务函数对LED操作在主函数中。一个中断配置函数setup_interrupt_system,另一个是中断处理函数intr_handler。Main函数中主要是对IO的相关操作在上篇文章中清楚的描述过了,中断处理函数操作简单,这里着重介绍setup_interrupt_system,它接收三个参数:中断控制器实例指针、GPIO实例指针和GPIO中断ID。status用于保存函数执行状态,在执行结果发生意外时通过串口打印相关错误信息。IntcConfig用于存储中断控制器的配置信息,根据XScuGic_LookupConfig查找到的中断控制器的配置传给IntcConfig,IntcConfig当作参数调用XScuGic_CfgInitialize初始化中断控制器。之后调用Xil_ExceptionRegisterHandler注册中断异常处理程序,使用XScuGic_InterruptHandler来处理中断。Xil_ExceptionEnable();启用异常处理,使系统能响应中断。在Zynq系统中,所有中断(如GPIO中断)和异常(如算术错误)都通过同一个中断控制器来管理。处理器在响应中断时需要知道如何处理这些中断,无论是外部设备产生的中断还是处理器内部产生的异常。调用 Xil_ExceptionEnable() 的目的是使处理器能够响应中断。这个函数会启用全局中断,使得所有配置好的中断(包括刚设置的GPIO中断)能够被处理。Zynq系统有一个中断向量表,存储着各个中断源的处理程序的地址。使能异常处理会让处理器在接收到中断信号时,能够从这个向量表中找到对应的处理程序。XScuGic_Connect将GPIO中断ID与处理函数intr_handler连接起来。需要注意,当中断产生的时候,先进入的是XScuGic_InterruptHandler(这是zynq系统的函数)函数,在该函数中,才进入XScuGic_Connect指定的中断处理函数。然后调用XScuGic_Enable启用中断,设置KEY按键的中断类型为下降沿中断 ,在通过XGpioPs_IntrEnablePin指定哪个引脚的中断即可完成中断配置。需要注意,在接收到中断进入中断处理函数中后,要调用XGpioPs_IntrDisablePin关闭中断等待中断处理结束,在main函数中处理完中断操作后,先清除中断,在使能中断以等待新的中断到来。

4.传送门

  • 我的主页
  • FPGA通信接口专栏汇总导航
  • 上一篇:Zynq(3)使用外设MIO/EMIO
END

🔈文章原创,首发于CSDN论坛。
🔈欢迎点赞❤❤收藏⭐⭐打赏💴💴!
🔈欢迎评论区或私信指出错误❌,提出宝贵意见或疑问❓。


http://www.mrgr.cn/news/57482.html

相关文章:

  • 桌面化学生管理系统的开发(简易版)
  • 深度学习 之 模型部署 使用Flask和PyTorch构建图像分类Web服务
  • Maven入门到实践:从安装到项目构建与IDEA集成
  • Android使用协程实现自定义Toast
  • C++大坑之——多继承(菱形继承)
  • Elasticsearch 解析:倒排索引机制/字段类型/语法/常见问题
  • 指针进阶(二)(C 语言)
  • 【1024特辑 | 机器学习-无监督学习】EM算法
  • 从文本到知识图谱:GraphRAG 各步骤的技术拆解与实现
  • django教育网站-计算机设计毕业源码89335
  • QML----Webengineview点击网页上的下载没反应,下载文件
  • 关于搜索接口被攻击,如何优化思路
  • 背包九讲——混合背包问题
  • 华为OD机试真题---We Are A Team
  • paddleocr使用FastDeploy 部署工具部署 rknn 模型
  • 智能扭矩系统Torque在新能源领域的应用_SunTorque
  • threejs中的小案例
  • autMan奥特曼机器人-出现argument list too long报错的解决方法
  • 哈希——哈希的基本概念
  • 两个开源AI应用让Claude 3.5 直接操作你的电脑;构建和部署多智能体系统课程;简化PDF文档管理并提供智能聊天功能
  • 通过运行窗口呼出Windows功能的快捷命令集合
  • Swarm集群管理常用命令与详解
  • 在 Spring 框架中,@ComponentScan` 扫描的注解类型
  • Bros!使用 focus 和 blur 事件时别忽略了这一点!
  • CentOS 6 修改 yun 源
  • 【Linux】 su 和 sudo 的区别剖析