平台 PYNQ-Z2
实现功能
这里用pynq实现emio 接按钮按键中断IRQ
硬件上EMIO 54接btn0,通过输入,触发中断#52,到GIC
通过SPI,操作中断寄存器指定cpu等,触发IRQ
硬件设计
一位EMIO 的GPIO_0_0_tri_io引出管教到btn0
约束
set_property -dict { PACKAGE_PIN D19 IOSTANDARD LVCMOS33 } [get_ports { GPIO_0_0_tri_io }]; #IO_L4P_T0_35 Sch=btn[0]
软件设计
#include <stdio.h>
#include "platform.h"
#include "xgpiops.h"
#include "xgpiops_hw.h"
#include "XSCUGIC.H"
#include "XSCUGIC_HW.H"
#include "sleep.h"
#define ICCPMR *(volatile unsigned int *) 0xf8f00104
//printf(" ICCPMR = %0X @ line = %d \n", ICCPMR ,__LINE__ );
//(__FILE__, __LINE__);
#define GPIO_NO 54
static void GpioHandler(void *CallBackRef, int Bank, u32 Status)
{
static int i = 0;
if (Status ==0 ) return ;
XGpioPs* pGpioPs=(XGpioPs*)CallBackRef;
XGpioPs_IntrDisablePin(pGpioPs,GPIO_NO);
printf("Gpio Handler %d...\n\r",i++);
// while (1 == XGpioPs_ReadPin( pGpioPs , GPIO_NO )) ;
usleep(100*1000);
XGpioPs_IntrClearPin(pGpioPs,GPIO_NO);
XGpioPs_IntrEnablePin(pGpioPs,GPIO_NO);
}
int main()
{
XGpioPs Gpio;
XGpioPs_Config *ConfigPtr;
printf(" ICCPMR = %0X @ line = %d \n", ICCPMR ,__LINE__ );
ConfigPtr = XGpioPs_LookupConfig(0);
XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);
//初始化GPIO的输入以及中断。
XGpioPs_SetDirectionPin(&Gpio,GPIO_NO,0x0);
XGpioPs_SetIntrTypePin(&Gpio,GPIO_NO,XGPIOPS_IRQ_TYPE_EDGE_RISING);
XGpioPs_SetCallbackHandler(&Gpio, (void *)&Gpio, GpioHandler);
XGpioPs_IntrEnablePin(&Gpio,GPIO_NO);
XScuGic ScuGic;
XScuGic_Config* pScuGicCfg;
pScuGicCfg=XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID);
XScuGic_CfgInitialize(&ScuGic,pScuGicCfg,pScuGicCfg->CpuBaseAddress);
XScuGic_Connect(&ScuGic, 52,
(Xil_ExceptionHandler)XGpioPs_IntrHandler,
(void *)&Gpio);
XScuGic_SetPriorityTriggerType(&ScuGic,52,0xa0,0x01);//优先级阈值f0
XScuGic_Enable(&ScuGic,52);
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&ScuGic);
Xil_ExceptionEnable();
printf("Intr test: \n\r");
while(1)
{
}
}
结果
按键
ICCICR (IC CPU IC REG)->
ICDDC R( UC distributor C REG)->
GPIO中断库函数分析
void XGpioPs_SetCallbackHandler(XGpioPs *InstancePtr, void *CallBackRef,
XGpioPs_Handler FuncPointer)
XGpioPs_SetCallbackHandler(&Gpio, (void *)&Gpio, GpioHandler);
XGpioPs_Handler是函数指针
中断
处理器的速度跟外围硬件设备的速度往往不在一个数量级上,因此,如果内核采取让处理器向硬件发出一个请求,然后专门等待回应的办法,显然降低内核效率。
因此,由我们来提供一种机制,让硬件在需要的时候再向内核发出信号(变内核主动为硬件主动),这就是中断机制。
不同的设备对应的中断不同,而每个中断都通过一个惟一的数字标识。
如,来自键盘的中断就有别于来自硬盘的中断,从而使得操作系统能够对中断进行区分,并知道哪个硬件设备产生了哪个中断。这样,操作系统才能给不同的中断提供不同的中断处理程序。
在它执行程序的时候,如果有另外的事件发生(比如用户又打开了一个程序)那么这时候就需要由计算机系统的中断机制来处理了。
中断机制包括硬件的中断装置和操作系统的中断处理服务程序。
让硬件在需要的时候再向内核发出信号。
早期的微机系统中将由硬件产生的中断标识码(中断源的识别标志,可用来形成相应的中断服务程序的入口地址或存放中断服务程序的首地址)称为中断向量,中断的地址的变量
中断向量表:中断类型号与相应中断源的中断处理程序入口地址之间的连接表;
_vector_table:
B _boot
B Undefined
B SVCHandler
B PrefetchAbortHandler
B DataAbortHandler
NOP /* Placeholder for address exception vector*/
B IRQHandler
B FIQHandler
中断服务程序:发送中断时所执行的中断代码
汇编
IRQHandler: /* IRQ vector handler */
stmdb sp!,{r0-r3,r12,lr} /* state save from compiled code*/
#if FPU_HARD_FLOAT_ABI_ENABLED
vpush {d0-d7}
vpush {d16-d31}
vmrs r1, FPSCR
push {r1}
vmrs r1, FPEXC
push {r1}
#endif
#ifdef PROFILING
ldr r2, =prof_pc
subs r3, lr, #0
str r3, [r2]
#endif
bl IRQInterrupt /* IRQ vector */
C
/*****************************************************************************/
/**
*
* This is the C level wrapper for the IRQ interrupt called from the vectors.s
* file.
*
* @param None.
*
* @return None.
*
* @note None.
*
******************************************************************************/
void IRQInterrupt(void)
{
XExc_VectorTable[XIL_EXCEPTION_ID_IRQ_INT].Handler(XExc_VectorTable[
XIL_EXCEPTION_ID_IRQ_INT].Data);
}
#if !defined (__aarch64__)
ref
https://blog.csdn.net/qq_18077275/article/details/89304215?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
zynq 中断
来源分成三大类SPI,PPI,SGI总共96个ID号的中断
中断运行经过了多个 interrupt hander中断处理程序,有以下步骤
-
STEP 1,首先要中断向量要转跳到IRQ的服务程序。对应一下函数
-
STEP 2, 有几十方式可以产生IRQ (ID号96个),所以我们要知道具体是哪个发生了中断号发生了IRQ中断。找到后对应调用相应的处理程序。
-
STEP 3,找到具体是哪个ID号的中断,下面步骤就是要对应再处理,可能要进行再细分
(比如要118个GPIO可以产生52号中断要判断出具体哪一位)。以及进行其他相应处理。