zynq的spi中断设置——以GPIO中断为例

zynq的spi中断设置——以GPIO中断为例

前言

1.采用器件

XC7Z010CLG400

2.参考的手册

  1. 《Zynq-7000 All Programmable SoC Technical Reference Manual UG585 (v1.10) February 23, 2015》
  2. 《Xilinx Zynq -7000嵌人式系统设计与实现 基于ARMCortex-A9双核处理器和Vivado的设计方法》

3.前置知识

3.1 ARM的中断处理机制
3.1.1 参考资料

ARM的中断处理机制,处理硬件请求,终于有人讲明白了……——https://www.bilibili.com/video/BV14e4y1h7Ms/?spm_id_from=333.337.search-card.all.click&vd_source=4a58493d16f50229c3283d2be2c272ba

3.1.2 概念梳理

什么是异常和arm的异常处理机制
什么是异常和arm的异常处理机制
2. 异常源有哪些?
异常源的分类
3. arm的异常模式(它和异常源不一样)
arm的异常模式
4. arm的异常响应
arm的异常响应
5. 异常向量表
异常向量表
6. IRQ异常举例
IRQ异常举例

3.2 指针加1和C语言指针强制类型转换
3.2.1 参考资料
  1. 指针+1的问题 https://blog.csdn.net/wade23/article/details/4546119?spm=1001.2014.3001.5506
  2. C语言指针强制类型转换
    2.1 C语言指针强制类型转换 https://blog.csdn.net/mhjcumt/article/details/7355127
    2.2 浅谈c语言指针的强制转换 https://blog.csdn.net/qq_46284844/article/details/124274127?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-124274127-blog-7355127.235%5Ev39%5Epc_relevant_default_base&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-124274127-blog-7355127.235%5Ev39%5Epc_relevant_default_base&utm_relevant_index=5
    2.3 函数指针的强制类型转换与void指针 https://blog.csdn.net/mickey35/article/details/80756348?spm=1001.2101.3001.6650.17&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-17-80756348-blog-124274127.235%5Ev39%5Epc_relevant_default_base&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-17-80756348-blog-124274127.235%5Ev39%5Epc_relevant_default_base&utm_relevant_index=25
3.2.2 概念梳理
  1. cpu中一个地址存储一个byte
    在这里插入图片描述

char类型,一个值a[x]是占8bit一个byte cpu中一个地址深度为一个byte,能存储8bit数,所以
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 如3.2.1 参考资料中2.1所说点击跳转强制类型转换就是按照某个变量的类型取出该变量的值,再按照xxx to xxx的规则进行强制转转换。

  2. 指针 + 1 并不是指针代表的地址值 + 1。指针变量加1,即向后移动1 个位置表示指针变量指向下一个数据元素的首地址。而不是在原地址基础上加1。至于真实的地址加了多少,要看原来指针指向的数据类型是什么。点击跳转
    例如:

char a[4] = {1, 2, 3 ,4};
	int *p = (int*) a;
	int y1;
	int y2;
	int y3;
	int y4;
	y1 = p;
	y2 = p+1;
	y3 = p+2;
    y4 = p+3;

a为数组的首地址&a[0],为char型的指针,(int*) 强制类型转换为int型指针赋值给p,p的值仍然是数组的首地址&a[0],但是其为int型指针,指向的是int数据类型,所以p+1的值较于p的值来说多了4,是因为1个int变量其占4个字节,cpu中一个地址存储1个byte,所以多了4.
在这里插入图片描述

3.3 函数指针和指针函数
3.3.1 参考资料
  1. 函数指针和指针函数用法和区别 https://blog.csdn.net/luoyayun361/article/details/80428882?spm=1001.2014.3001.5506
3.3.2 概念梳理

指针函数本质是一个函数,其返回值为指针。
函数指针本质是一个指针,其指向一个函数。

3.4 注册函数、回调函数、handle和handler
3.4.1 参考资料
  1. C语言——深入浅出回调函数 https://blog.csdn.net/u011486738/article/details/115005173
  2. 3分钟理解回调函数(小白扫盲篇) https://zhuanlan.zhihu.com/p/631248309
  3. 闲话handle和handler https://www.cnblogs.com/idorax/p/6414007.html
  4. C 语言句柄handle https://blog.csdn.net/Godsight/article/details/52738175?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3-52738175-blog-80600593.235%5Ev39%5Epc_relevant_default_base&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3-52738175-blog-80600593.235%5Ev39%5Epc_relevant_default_base&utm_relevant_index=6
3.4.2 概念梳理

我的个人理解:
首先如3.4.1 参考资料中1.所说点击跳转,回调函数就是一个通过函数指针进行调用的函数(其实回调函数只是一个功能函数而已)。当你把函数名(即函数的地址)作为参数传递给另外一个函数(即注册函数),向注册函数进行回调函数的注册时,注册函数通过函数指针来调用该函数指针所指向的函数时,我们就说这是在回调函数,被函数指针指向的函数即称为回调函数(回调函数其实只是一个名字而已,不需深究,叫被调函数也可以)。

handler(A handler is an asynchronous callback subroutine)就是注册函数中指向回调函数的函数指针

handle(A handle is an abstract reference to a resource)是对某个资源的抽象引用。handle也叫句柄,指针可以当句柄,句柄不一定都是指针,如同3.4.1 参考资料里面的4.所说点击跳转

3.5 ZYNQ-7000 GPIO的MIO和EMIO
3.5.1 参考资料
  1. ZYNQ-7000 GPIO使用 https://blog.csdn.net/asd1147170607/article/details/108105770
3.5.2 概念梳理

GPIO(Generous Purpose Input Output)是指CPU引出的,可以配置为输入或输出的端口,用于CPU与外界进行数据的传输。ZYNQ-7000 架构由 PL+PS 组成,所以它的 GPIO 与一般的 ARM 不同。ZYNQ 的 GPIO,分为两种,MIO(multiuse I/O)和 EMIO(extendable multiuse I/O)。MIO 有54个,分配在 GPIO 的 Bank0 和 Bank1 隶属于 PS 部分,这些 IO 与 PS 直接相连。不需要添加引脚约束,MIO 信号对 PL 部分是透明的,不可见。EMIO有64个,EMIO连接PS到PL,作为ZYNQ的拓展MIO,当 MIO 不够用时,PS 可以通过驱动 EMIO 控制 PL 部分的引脚。因此使用PS的EMIO时,需要添加PL引脚约束。
GPIO

本博客后面中断设置用到EMIO

3.6 ZYNQ 中断子系统
3.6.1 参考资料
  1. ZYNQ 中断子系统 https://blog.csdn.net/zhoutaopower/article/details/106103266
  2. Zynq-PS-SDK(4) 之 GIC 配置 https://blog.csdn.net/zhoutaopower/article/details/115113160
  3. Linux 中断 —— ARM GIC 中断控制器 https://blog.csdn.net/zhoutaopower/article/details/90454258
3.6.2 概念梳理

如3.6.1 参考资料的2.描述——Zynq 的中断控制,由 GIC 来控制,UG585 中已经描述,GIC 的配置不用 ps_init 中来进行配置,而是在 SDK 使用到的时候,调用SDK的GIC相关的API来进行配置;GIC的中断类型分为:SGI、PPI 和 SPI;

3.6.1 参考资料1. 中描述——ZYNQ-7000 带双核 Cortex-A9 处理器的 7020 芯片,PS 端集成的是 GIC 中断控制器;GIC 是通用中断控制器(Generic Interrupt Controller)的简称。GIC 的版本是 pl390,也就是 GIC 的 v1 版本

GPIO中断的中断设置

1. 参考资料

Zynq-PS-SDK(4) 之 GIC 配置 https://blog.csdn.net/zhoutaopower/article/details/115113160

2. 总体概览和重点函数


在这里插入图片描述
可以看到比较核心的就是3个桥梁函数

Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&Gic);

Status = XScuGic_Connect(&Gic, GPIOINTR_ID,(Xil_InterruptHandler)XGpioPs_IntrHandler,(void *)&Gpio);

XGpioPs_SetCallbackHandler(&Gpio, (void* )&Gpio, (XGpioPs_Handler)UserDefKeyInterupt);

为什么要这么填,现在进行一个解释

2.1 Xil_ExceptionRegisterHandler()

arm利用Xil_ExceptionRegisterHandler()函数根据具体的异常id u32 Exception_id(异常源有很多个,中断只是其中一种,具体看前置知识点击跳转
),来执行对应的异常处理程序,
在vitis里面打开他的定义如下:

/*****************************************************************************/
/**
* @brief	Register a handler for a specific exception. This handler is being
*			called when the processor encounters the specified exception.
*
* @param	Exception_id contains the ID of the exception source and shouldbe in the range of 0 to XIL_EXCEPTION_ID_LAST.See xil_exception.h for further information.
* @param	Handler to the Handler for that exception.
* @param	Data is a reference to Data that will be passed to the
*			Handler when it gets called.
*
* @return	None.
*
****************************************************************************/
void Xil_ExceptionRegisterHandler(u32 Exception_id,
				    Xil_ExceptionHandler Handler,
				    void *Data)
{
#if defined (versal) && !defined(ARMR5) && EL3
	if ( XIL_EXCEPTION_ID_IRQ_INT == Exception_id )
	{
	/*
	 * Cortexa72 processor in versal is coupled with GIC-500, and
	 * GIC-500 supports only FIQ at EL3. Hence, tweaking this API
	 * to act on IRQ, if Exception_id is pointing to IRQ
	 */
		Exception_id = XIL_EXCEPTION_ID_FIQ_INT;
	}
#endif
	XExc_VectorTable[Exception_id].Handler = Handler;
	XExc_VectorTable[Exception_id].Data = Data;
}
2.1.1怎么填u32 Exception_id

Exception_id contains the ID of the exception source and shouldbe in the range of 0 to XIL_EXCEPTION_ID_LAST.See xil_exception.h for further information.
在Cortex-A 系列中异常源id如下:

#define XIL_EXCEPTION_ID_RESET			    0U
#define XIL_EXCEPTION_ID_UNDEFINED_INT		1U
#define XIL_EXCEPTION_ID_SWI_INT		    2U
#define XIL_EXCEPTION_ID_PREFETCH_ABORT_INT	3U
#define XIL_EXCEPTION_ID_DATA_ABORT_INT		4U
#define XIL_EXCEPTION_ID_IRQ_INT		    5U
#define XIL_EXCEPTION_ID_FIQ_INT		    6U

我们的异常源gpio中断是irq的中断所以填 XIL_EXCEPTION_ID_IRQ_INT

2.1.2怎么填Xil_ExceptionHandler Handler

Handler to the Handler for that exception.
Xil_ExceptionHandler是个函数指针的类型

typedef void (*Xil_ExceptionHandler)(void *data);

Gic向CPU注册异常处理回调函数,“Handler”填XScuGic_InterruptHandler,它是由arm的scu提供的指向Gic的异常处理回调函数的函数指针。

2.1.3怎么填void *Data

Data is a reference to Data that will be passed to the Handler when it gets called.

当回调的时候,void *Data会传递给XScuGic_InterruptHandler,这个void *Data要填Gic实体的指针&Gic,以连接gic层和arm,如图点击跳转

2.2 XScuGic_Connect()

Gic利用XScuGic_Connect()函数根据具体的中断号u32 Int_Id(中断的类型有多种,gpio是其中一种),连接GPIO中断信号,来执行对应的 ISR(中断服务程序)如图点击跳转
在vitis里面打开他的定义如下:

/*****************************************************************************/
/**
*
* Makes the connection between the Int_Id of the interrupt source and the
* associated handler that is to run when the interrupt is recognized. The
* argument provided in this call as the Callbackref is used as the argument
* for the handler when it is called.
*
* @param	InstancePtr is a pointer to the XScuGic instance.
* @param	Int_Id contains the ID of the interrupt source and should be
*		in the range of 0 to XSCUGIC_MAX_NUM_INTR_INPUTS - 1
* @param	Handler to the handler for that interrupt.
* @param	CallBackRef is the callback reference, usually the instance
*		pointer of the connecting driver.
*
* @return
*
*		- XST_SUCCESS if the handler was connected correctly.
*
* @note
*
* WARNING: The handler provided as an argument will overwrite any handler
* that was previously connected.
*
****************************************************************************/
s32  XScuGic_Connect(XScuGic *InstancePtr, u32 Int_Id,
				Xil_InterruptHandler Handler, void *CallBackRef)
{
	/*
	 * Assert the arguments
	 */
	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
	Xil_AssertNonvoid(Handler != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	/*
	 * The Int_Id is used as an index into the table to select the proper
	 * handler
	 */
	InstancePtr->Config->HandlerTable[Int_Id].Handler = (Xil_InterruptHandler)Handler;
	InstancePtr->Config->HandlerTable[Int_Id].CallBackRef = CallBackRef;

	return XST_SUCCESS;
}
2.2.1怎么填XScuGic *InstancePtr

InstancePtr is a pointer to the XScuGic instance.
XScuGic_Connect()函数要连接Gic层和Gpio层,所以需要Gic实体的指针,所以填&Gic

2.2.2怎么填u32 Int_Id

这里要填写中断类型,中断类型由中断号决定,我们设置的中断是spi共享中断下的iop类别中的gpio中断如下图,中断号为52,zynq的中断子系统看这里点击跳转
在这里插入图片描述

2.2.3怎么填Xil_InterruptHandler Handler

Handler to the handler for that interrupt.
Xil_InterruptHandler为函数指针的类型

typedef void (*Xil_InterruptHandler)(void *data);

GPIO向Gic注册中断处理回调函数,“Handler”填XGpioPs_IntrHandler,它是由Gic提供的指向Gpio中的中断处理回调函数的指针。

2.2.4怎么填void *CallBackRef

CallBackRef is the callback reference, usually the instance pointer of the connecting driver.

XScuGic_Connect()函数要连接Gic层和Gpio层,现在有了Gic实体的指针,需要Gpio实体的指针,所以填&Gpio,该指针要传递给XGpioPs_IntrHandler

2.3 XGpioPs_SetCallbackHandler()

Gpio 层 利用 XGpioPs_SetCallbackHandler()通过FuncPointer连接用户自定义的gpio中断函数
在vitis里面打开他的定义如下:

/*****************************************************************************/
/**
* This function sets the status callback function. The callback function is
* called by the  XGpioPs_IntrHandler when an interrupt occurs.
*
* @param	InstancePtr is a pointer to the XGpioPs instance.
* @param	CallBackRef is the upper layer callback reference passed back when the callback function is invoked.
* @param	FuncPointer is the pointer to the callback function.
* @return	None.
* @note		The handler is called within interrupt context, so it should do its work quickly and queue potentially time-consuming work to a task-level thread.
*
******************************************************************************/
void XGpioPs_SetCallbackHandler(XGpioPs *InstancePtr, void *CallBackRef,XGpioPs_Handler FuncPointer)
{
	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(FuncPointer != NULL);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

	InstancePtr->Handler = FuncPointer;
	InstancePtr->CallBackRef = CallBackRef;
}
2.3.1怎么填XGpioPs *InstancePtr

InstancePtr is a pointer to the XGpioPs instance.
XGpioPs_SetCallbackHandler()函数要连接Gpio层和用户自定义函数层,所以需要Gpio实体的指针,所以填&Gpio

2.3.2怎么填void *CallBackRef

CallBackRef is the upper layer callback reference passed back when the callback function is invoked.

gpio的上层为gic层,gic层的CallBackRef为Gpio实体的指针,所以填写(void* )&Gpio,该CallBackRef会传给FuncPointer,因为用户自定义的函数需要对这个Gpio实体进行操作

2.3.3怎么填XGpioPs_Handler FuncPointer

FuncPointer is the pointer to the callback function.
XGpioPs_Handler是一个函数指针类型

typedef void (*XGpioPs_Handler) (void *CallBackRef, u32 Bank, u32 Status);

用户层向Gpio层注册用户自定义gpio中断处理回调函数,“FuncPointer”填用户自定义gpio中断处理回调函数的指针,它指向用户自定义gpio中断处理回调函数。

3. 具体流程

具体流程如下图所示
在这里插入图片描述
讲一下第2步gic实体的初始化,这篇文章说的很清楚《Zynq-PS-SDK(4) 之 GIC 配置》点击跳转
在这里插入图片描述

第5步中断设置,注意我们bank是emio的bank2,其他的配置结合具体的中断来编写
在这里插入图片描述

4. 注意的点

4.1 几个id

在这里插入图片描述

4.2 CallBackRef

因为都是对同一个Gpio实体进行操作
在这里插入图片描述

  • 23
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Zynq芯片中,GPIO引脚的中断是通过AXI_GPIO模块和PS相连的中断信号线的电平变换引发的。可以通过配置中断触发方式来设置GPIO引脚的中断。具体来说,可以使用XScuGic_SetPriorityTriggerType函数来设置中断触发优先级和触发类型。例如,可以通过设置中断触发类型为上升沿触发来使得当GPIO引脚的电平变为上升沿时触发中断。 需要注意的是,GPIO引脚的中断方式已经由硬件决定好了,无法在此处进行配置。参考函数的注释中提到,只有两种方式可以设置中断,即高电平和上升沿,这里的高电平和上升沿指的是AXI_GPIO模块和PS相连的中断信号线的电平变换引发PS中断,而不是GPIO引脚的中断方式。 因此,在配置中断触发方式时,需要确定好AXI_GPIO模块和PS相连的中断信号线的电平变换方式并设置相应的中断触发类型。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [zynq-7000.rar_linux 中断 zynq_zynq DMA_zynq DMA Linux_zynq gpio_i2](https://download.csdn.net/download/weixin_42651887/86201535)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [ZYNQ_GPIO_中断](https://blog.csdn.net/Master_0_/article/details/125125000)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅癌晚期的彦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值