【【FPGA中断的介绍附上 上个MicroBlaze 代码的解析】】

2023-12-02 04:12

本文主要是介绍【【FPGA中断的介绍附上 上个MicroBlaze 代码的解析】】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

FPGA中断的介绍附上 上个MicroBlaze 代码的解析

我们 先附带上上一节 Micro Blaze 的 blockdesign 结构 和 代码
本次实验参考自 正点原子达芬奇开发板 Micro Blaze 开发
在这里插入图片描述

我们 可以看出 我们圈画了一个中断控制器IP 还有一个是我们构建的软核 micro blaze 和挂载的BRAM 用来当作原本内核的 DDR 存储

我之前用的是 带硬核的 zynq 开发 ARM cpu 为设计 提供了很大的帮助

我们可以 利用 强大的FPGA端 构建出假的CPU 俗称 软核
好的 了解 这个之后 我们先了解一下 中断的基本概念和使用
1.中断 — 是 打断CPU 正常执行顺序的事件
2.中断处理函数 – CPU被动调用,当有紧急的事情发生的时候,会调用
3.中断源 – 产生中断的设备

设备要产生中断 就必须有一根中断请求线,并且将其连接到中断控制器上
中断控制器就是我们在blockdesign 中 添加的 那个 IP核
在这里插入图片描述

根据输入的中断请求 给CPU内核一个中断信号,通过CPU某某设备产生了中断。外部硬件在通过INTR发送中断请求 同时读取了这个由外部硬件提供的编号

接下来我们附上代码

#include "xparameters.h"#include "xintc.h"#include "xgpio.h"#include "sleep.h"#define KEY_DEV_ID XPAR_AXI_GPIO_0_DEVICE_ID //按键 AXI GPIO ID#define LED_DEV_ID    XPAR_AXI_GPIO_1_DEVICE_ID //LED AXI GPIO ID#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID //中断控制器 ID#define EXCEPTION_ID     XIL_EXCEPTION_ID_INT //中断异常 ID
#define AXI_GPIO_INTR_ID    XPAR_INTC_0_GPIO_0_VEC_ID //AXI GPIO 中断 IDstatic XIntc Intc; //中断控制器实例static XGpio KEY_Gpio; //GPIO 中断实例 按键static XGpio LED_Gpio; //GPIO 实例int led_value; //LED 值int key_value; //按键值int Intr_times = 0; //有效中断计数int key_intr_flag = 0; //中断标志void GpioHandler(void *CallbackRef);int main(){xil_printf("AXI GPIO INTERRUPT TEST!\r\n");//AXI_GPIO 器件初始化XGpio_Initialize(&KEY_Gpio, KEY_DEV_ID);XGpio_Initialize(&LED_Gpio, LED_DEV_ID);//为指定的 GPIO 信道设置所有独立信号的输入/输出方向XGpio_SetDataDirection(&LED_Gpio, 1, 0);//设置 LED 初始值XGpio_DiscreteWrite(&LED_Gpio, 1, 0x0f);XGpio_SetDataDirection(&KEY_Gpio, 1, 1);//初始化中断控制器XIntc_Initialize(&Intc, INTC_DEVICE_ID);//关联中断 ID 和中断服务函数XIntc_Connect(&Intc,AXI_GPIO_INTR_ID,(Xil_ExceptionHandler)GpioHandler,&KEY_Gpio );
//使能中断XGpio_InterruptEnable(&KEY_Gpio, 1);//使能全局中断XGpio_InterruptGlobalEnable(&KEY_Gpio);//在中断控制器上启用中断向量XIntc_Enable(&Intc,AXI_GPIO_INTR_ID);//启动中断控制器XIntc_Start(&Intc, XIN_REAL_MODE);//设置并打开中断异常处理Xil_ExceptionInit();Xil_ExceptionRegisterHandler(EXCEPTION_ID,(Xil_ExceptionHandler)XIntc_InterruptHandler,&Intc);Xil_ExceptionEnable();while(1){if(key_intr_flag){ //检测中断标志信号有效key_value = XGpio_DiscreteRead(&KEY_Gpio, 1); //读取按键值if(key_value == 0){ //检测按键是否按下if(Intr_times == 0) //根据有效中断数点亮 LEDled_value = 0x01;else if(Intr_times == 1)led_value = 0x02;else if(Intr_times == 2)led_value = 0x04;elseled_value = 0x08;//按键按下后点亮对应 LED 灯XGpio_DiscreteWrite(&LED_Gpio, 1, led_value);xil_printf("i = %d\r\n",Intr_times); //打印当前的 Intr_timesIntr_times = (Intr_times + 1)%4; //将计数值约束在 0 到 3 之间//延迟 1 秒消抖sleep(1);}key_intr_flag = 0; //中断标志清零}}return 0;}void GpioHandler(void *CallbackRef){XGpio *GpioPtr = (XGpio *)CallbackRef;
key_intr_flag = 1; //接收到中断,标志信号拉高XGpio_InterruptDisable(GpioPtr, 1); //关闭中断XGpio_InterruptClear(GpioPtr, 1); //清除中断XGpio_InterruptEnable(GpioPtr, 1); //使能中断
}

我们接下来 对代码进行解析

#include "xparameters.h"
#include "xintc.h"
#include "xgpio.h"
#include "sleep.h"

一开始的是文件的头文件

#define KEY_DEV_ID XPAR_AXI_GPIO_0_DEVICE_ID //按键 AXI GPIO ID
#define LED_DEV_ID    XPAR_AXI_GPIO_1_DEVICE_ID //LED AXI GPIO ID
#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID //中断控制器 ID
#define EXCEPTION_ID     XIL_EXCEPTION_ID_INT //中断异常 ID
#define AXI_GPIO_INTR_ID    XPAR_INTC_0_GPIO_0_VEC_ID //AXI GPIO 中断 ID

包括按键和 LED 对应的 AXI GPIO的 ID,中断控制器 ID,中断源 ID 以及中断异常 ID
中断源就是指连接按键的 AXI GPIO 输出到中断控制器的中断信号。中断异常 ID(XIL_EXCEPTION_ID_INT)是一个适配所有处理器的宏定义,但在不同处理器中它对应的的值也不同,我们将其宏定义为 EXCEPTION_ID

中断控制器 就是中断控制器
中断异常ID 不同的中断会有不同的ID 我们读取ID 才知道 处理的是什么中断
接下来的是 在 器件初始化、设置输入输出、设置中断系统和中断异常处理四部分。

器件初始化 :

//AXI_GPIO 器件初始化
XGpio_Initialize(&KEY_Gpio, KEY_DEV_ID);
XGpio_Initialize(&LED_Gpio, LED_DEV_ID);
//为指定的 GPIO 信道设置所有独立信号的输入/输出方向
XGpio_SetDataDirection(&LED_Gpio, 1, 0);
//设置 LED 初始值
XGpio_DiscreteWrite(&LED_Gpio, 1, 0x0f);
XGpio_SetDataDirection(&KEY_Gpio, 1, 1);

有GPIO的初始化 还有设置GPIO的 输入输出方向 还有 GPIO的LED 初始化都亮

//初始化中断控制器
XIntc_Initialize(&Intc, INTC_DEVICE_ID);
//关联中断 ID 和中断服务函数
XIntc_Connect(&Intc,AXI_GPIO_INTR_ID,(Xil_ExceptionHandler)GpioHandler,&KEY_Gpio );
//使能中断
XGpio_InterruptEnable(&KEY_Gpio, 1);
//使能全局中断
XGpio_InterruptGlobalEnable(&KEY_Gpio);
//在中断控制器上启用中断向量
XIntc_Enable(&Intc,AXI_GPIO_INTR_ID);
//启动中断控制器
XIntc_Start(&Intc, XIN_REAL_MODE);

下面是对中断系统的描述
1.//初始化中断控制器

XIntc_Initialize(&Intc, INTC_DEVICE_ID);

先初始化中断控制器 就是图上的那个 我们定义了叫 INIC_DEVICE

2.//关联中断 ID 和中断服务函数

XIntc_Connect(&Intc,AXI_GPIO_INTR_ID,(Xil_ExceptionHandler)GpioHandler,&KEY_Gpio );

我们可以在这里面看到 (Xil_ExceptionHandler)GpioHandler
这个GPIOHandler是我们自己写的中断服务函数
关联中断源与 中断服务函数 就可以帮助我们确定 何时触发中断

//使能中断
XGpio_InterruptEnable(&KEY_Gpio, 1);

//使能全局中断
XGpio_InterruptGlobalEnable(&KEY_Gpio);
使能 AXI GPIO 通道中断和 AXI GPIO全局中断,只有全局中断使能后 XGpio_InterruptEnable 启用的中断才会被传递。

 //在中断控制器上启用中断向量
XIntc_Enable(&Intc,AXI_GPIO_INTR_ID);
//启动中断控制器
XIntc_Start(&Intc, XIN_REAL_MODE);

我们在上面绑定了中断源与 需要接下来处理的中断服务函数 然后开动小脑筋想一下 还缺什么
当然缺的是 把中断源绑定到 中断控制器上 通过XIntc_Enable(&Intc,AXI_GPIO_INTR_ID); 绑定之后 再启用中断控制器

5.下面的是中断异常处理 关联中断异常处理函数和中断异常 ID

Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(EXCEPTION_ID,(Xil_ExceptionHandler)XIntc_InterruptHandler,&Intc);
Xil_ExceptionEnable();

MicroBlaze 支持多种异常情况,每种异常也都有自己的 ID标识,其中 XIL_EXCEPTION_ID_INT 用于标识中断请求(IRQ)异常,在代码第 9 行将其宏定义为EXCEPTION_ID,其对应的值为 0。代码第 49 行就是使能处理器的异常处理。

先初始化中断异常处理
然后 关联中断异常处理函数和中断ID — 还有一个是(Xil_ExceptionHandler)XIntc_InterruptHandler 关联之后就知道我们选择我们出现的是什么样子的中断
最后 Xil_ExceptionEnable(); 使能处理器异常处理

下面一部分的while 循环 是用来调配中断接受后的操作

while(1){
if(key_intr_flag){ //检测中断标志信号有效
key_value = XGpio_DiscreteRead(&KEY_Gpio, 1); //读取按键值
if(key_value == 0){ //检测按键是否按下
if(Intr_times == 0) //根据有效中断数点亮 LED
led_value = 0x01;
else if(Intr_times == 1)
led_value = 0x02;
else if(Intr_times == 2)
led_value = 0x04;
else
led_value = 0x08;
//按键按下后点亮对应 LED 灯
XGpio_DiscreteWrite(&LED_Gpio, 1, led_value);
xil_printf("i = %d\r\n",Intr_times); //打印当前的 Intr_times
Intr_times = (Intr_times + 1)%4; //将计数值约束在 0 到 3 之间
//延迟 1 秒消抖
sleep(1);
}
key_intr_flag = 0; //中断标志清零
}
}

最后一段是自己写的 中断服务函数

void GpioHandler(void *CallbackRef){
XGpio *GpioPtr = (XGpio *)CallbackRef;
key_intr_flag = 1; //接收到中断,标志信号拉高
XGpio_InterruptDisable(GpioPtr, 1); //关闭中断
XGpio_InterruptClear(GpioPtr, 1); //清除中断
XGpio_InterruptEnable(GpioPtr, 1); //使能中断
}

当系统接收到中断信号时就将中断标志信号 key_intr_flag 拉高,
然后用 XGpio_InterruptDisable 函数关闭中断,
再调用 XGpio_InterruptClear(GpioPtr, 1)函数清除 AXI GPIO通道 1 的中断状态寄存器,
最后再使能 AXI GPIO 中断以等待下一次中断触发。

这篇关于【【FPGA中断的介绍附上 上个MicroBlaze 代码的解析】】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/443906

相关文章

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

一文解析C#中的StringSplitOptions枚举

《一文解析C#中的StringSplitOptions枚举》StringSplitOptions是C#中的一个枚举类型,用于控制string.Split()方法分割字符串时的行为,核心作用是处理分割后... 目录C#的StringSplitOptions枚举1.StringSplitOptions枚举的常用

Python函数作用域与闭包举例深度解析

《Python函数作用域与闭包举例深度解析》Python函数的作用域规则和闭包是编程中的关键概念,它们决定了变量的访问和生命周期,:本文主要介绍Python函数作用域与闭包的相关资料,文中通过代码... 目录1. 基础作用域访问示例1:访问全局变量示例2:访问外层函数变量2. 闭包基础示例3:简单闭包示例4

MyBatis延迟加载与多级缓存全解析

《MyBatis延迟加载与多级缓存全解析》文章介绍MyBatis的延迟加载与多级缓存机制,延迟加载按需加载关联数据提升性能,一级缓存会话级默认开启,二级缓存工厂级支持跨会话共享,增删改操作会清空对应缓... 目录MyBATis延迟加载策略一对多示例一对多示例MyBatis框架的缓存一级缓存二级缓存MyBat

前端缓存策略的自解方案全解析

《前端缓存策略的自解方案全解析》缓存从来都是前端的一个痛点,很多前端搞不清楚缓存到底是何物,:本文主要介绍前端缓存的自解方案,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、为什么“清缓存”成了技术圈的梗二、先给缓存“把个脉”:浏览器到底缓存了谁?三、设计思路:把“发版”做成“自愈”四、代码

Java集合之Iterator迭代器实现代码解析

《Java集合之Iterator迭代器实现代码解析》迭代器Iterator是Java集合框架中的一个核心接口,位于java.util包下,它定义了一种标准的元素访问机制,为各种集合类型提供了一种统一的... 目录一、什么是Iterator二、Iterator的核心方法三、基本使用示例四、Iterator的工

Java 线程池+分布式实现代码

《Java线程池+分布式实现代码》在Java开发中,池通过预先创建并管理一定数量的资源,避免频繁创建和销毁资源带来的性能开销,从而提高系统效率,:本文主要介绍Java线程池+分布式实现代码,需要... 目录1. 线程池1.1 自定义线程池实现1.1.1 线程池核心1.1.2 代码示例1.2 总结流程2. J

5 种使用Python自动化处理PDF的实用方法介绍

《5种使用Python自动化处理PDF的实用方法介绍》自动化处理PDF文件已成为减少重复工作、提升工作效率的重要手段,本文将介绍五种实用方法,从内置工具到专业库,帮助你在Python中实现PDF任务... 目录使用内置库(os、subprocess)调用外部工具使用 PyPDF2 进行基本 PDF 操作使用