zynq中一个中断程序分析

原文:http://blog.csdn.net/husipeng86/article/details/52206439

本文通过分析一个中断例程来了解zynq中断执行过程

基础知识

ARM体系架构的处理器中通常将低地址32字节作为中断向量表,当中断产生时会执行以下操作:

  1. 保存处理器当前状态,设置中断屏蔽位和各条件标志位
  2. 设置当前程序状态寄存器CPSR中相应位
  3. 将lr_mode寄存器设置成返回地址
  4. 跳转到中断向量地址执行,从而跳转到相应的中断程序中执行
  5. 执行中断处理函数内容
  6. 恢复被屏蔽的中断屏蔽位
  7. 返回到被中断指令的下一条指令处继续执行

zynq中低32字节作为中断向量表,每个中断占据4字节,这4字节通常存储一个跳转指令,从而跳转到中断解析程序中。这低32字节中断向量表如:

地址中断类型异常中断模式优先级说明
0x00复位中断特权模式(SVC)1系统上电和系统复位或软复位时产生
0x04未定义指令中断未定义指令中止模式(Undef)6当执行的指令不是ARM处理器或协处理器的指令时产生
0x08软件中断(SWI)特权模式(SVC)6用户定义中断指令,可用于用户模式下调用特权操作指令
0x0c指令预取中止中止模式5当预取指令地址不存在或地址不允许当前指令访问时产生
0x10数据访问中止中止模式2当数据访问指令的目的地址不存在或地址不允许当前指令访问时产生
0x14保留
0x18外部中断请求(IRQ)外部中断模式4处理器外部中断请求引脚有效而且CPSR的I位被清除时产生
0x1c快速中断请求(FIQ)快速中断模式3处理器外部快速中断请求引脚有效而且CPSR的F位被清除时产生

本内容部分修改自《Xilinx Zynq SoC与嵌入式Linux设计实战指南——兼容ARM Cortex-A9的设计方法》

例程

vivado中ps部分配置如下图:

中断_vivado配置

选中Fabric Interrupts和IRQ_F2P[15:0]

连接如下图:

中断_vivado连接

其中Concat模块只是简单的将多个信号合并为一个总线连接到zynq;而Utility Vector Logic则是执行一些逻辑计算,这里选择not逻辑计算。

#include <stdio.h>
#include "platform.h"
#include "xscugic.h"
#include "xil_exception.h"

#define INT_CFG0_OFFSET 0x00000C00

// Parameter definitions
#define SW1_INT_ID              61
#define SW2_INT_ID              62
#define SW3_INT_ID              63
#define INTC_DEVICE_ID          XPAR_PS7_SCUGIC_0_DEVICE_ID
#define INT_TYPE_RISING_EDGE    0x03
#define INT_TYPE_HIGHLEVEL      0x01
#define INT_TYPE_MASK           0x03

static XScuGic INTCInst;

static void SW_intr_Handler(void *param);
static int InterruptSystemSetup(XScuGic *XScuGicInstancePtr);
static int IntcInitFunction(u16 DeviceId);

static void SW_intr_Handler(void *param)
{
    int sw_id = (int)param;
    printf("SW%d int\n\r", sw_id);
}

void IntcTypeSetup(XScuGic *InstancePtr, int intId, int intType)
{
    int mask;

    intType &= INT_TYPE_MASK;
    mask = XScuGic_DistReadReg(InstancePtr, INT_CFG0_OFFSET + (intId/16)*4);
    mask &= ~(INT_TYPE_MASK << (intId%16)*2);
    mask |= intType << ((intId%16)*2);
    XScuGic_DistWriteReg(InstancePtr, INT_CFG0_OFFSET + (intId/16)*4, mask);
}

int IntcInitFunction(u16 DeviceId)
{
    XScuGic_Config *IntcConfig;
    int status;

    // Interrupt controller initialisation
    IntcConfig = XScuGic_LookupConfig(DeviceId);
    status = XScuGic_CfgInitialize(&INTCInst, IntcConfig, IntcConfig->CpuBaseAddress);
    if(status != XST_SUCCESS) return XST_FAILURE;

    // Call to interrupt setup
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
                                 (Xil_ExceptionHandler)XScuGic_InterruptHandler,
                                 &INTCInst);
    Xil_ExceptionEnable();

    // Connect SW1~SW3 interrupt to handler
    status = XScuGic_Connect(&INTCInst,
                             SW1_INT_ID,
                             (Xil_ExceptionHandler)SW_intr_Handler,
                             (void *)1);
    if(status != XST_SUCCESS) return XST_FAILURE;

    status = XScuGic_Connect(&INTCInst,
                             SW2_INT_ID,
                             (Xil_ExceptionHandler)SW_intr_Handler,
                             (void *)2);
    if(status != XST_SUCCESS) return XST_FAILURE;

    status = XScuGic_Connect(&INTCInst,
                             SW3_INT_ID,
                             (Xil_ExceptionHandler)SW_intr_Handler,
                             (void *)3);
    if(status != XST_SUCCESS) return XST_FAILURE;

    // Set interrupt type of SW1~SW3 to rising edge
    IntcTypeSetup(&INTCInst, SW1_INT_ID, INT_TYPE_RISING_EDGE);
    IntcTypeSetup(&INTCInst, SW2_INT_ID, INT_TYPE_RISING_EDGE);
    IntcTypeSetup(&INTCInst, SW3_INT_ID, INT_TYPE_RISING_EDGE);

    // Enable SW1~SW3 interrupts in the controller
    XScuGic_Enable(&INTCInst, SW1_INT_ID);
    XScuGic_Enable(&INTCInst, SW2_INT_ID);
    XScuGic_Enable(&INTCInst, SW3_INT_ID);

    return XST_SUCCESS;
}

int main(void)
{
    init_platform();

    print("PL int test\n\r");
    IntcInitFunction(INTC_DEVICE_ID);
    while(1);
    cleanup_platform();
    return 0;
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98

例程修改自z-turn例程

过程分析

查看U585第231页,可以看到从PL部分输入的中断号为{[91:84],[68:61]}对应IRQ_F2P[15:0],这里使用IRQ_F2P[2:0],所以才有SW1_INT_ID到SW3_INT_ID定义为61到63。

分析中断执行要从中断执行开始的中断向量表开始,查找.org 0,可以在BSP目录下\ps7_cortexa9_0\libsrc\standalone_v5_2\src下asm_vectors.s文件中的第64行可以找到,其下便是中断向量表,作为IRQ中断,在中断向量表中为第5条(地址:0x18)指令,对应第77行B IRQHandler,跳转到IRQHandler标签,其后第99行再次跳转到IRQInterrupt,从BSP目录下\ps7_cortexa9_0\libsrc\standalone_v5_2\src下vectors.c文件中可以找到IRQInterrupt函数,其中调用XExc_VectorTable[XIL_EXCEPTION_ID_IRQ_INT].Handler(XExc_VectorTable[XIL_EXCEPTION_ID_IRQ_INT].Data);即IRQ中断最终调用了XExc_VectorTable数组中第XIL_EXCEPTION_ID_IRQ_INT(即5)个成员的Handler函数,并传入Data作为参数。

回到以上例程中有Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&INTCInst);从BSP目录下\ps7_cortexa9_0\libsrc\standalone_v5_2\src下xil_exception.c中可找到此函数,其将(Xil_ExceptionHandler)XScuGic_InterruptHandler和&INTCInst赋值给XExc_VectorTable第XIL_EXCEPTION_ID_INT(即5)个成员的Handler和Data成员,结合上一段中说明,则IRQ中断最终执行了:XScuGic_InterruptHandler(&INTCInst)

再看以上例程有status = XScuGic_Connect(&INTCInst,SW1_INT_ID,(Xil_ExceptionHandler)SW_intr_Handler,(void *)1);,可以从BSP目录下\ps7_cortexa9_0\libsrc\standalone_v5_2\src下xscugic.c中可找到此函数,可以看到(其中InstancePtr对应&INTCInst;Int_Id对应SW1_INT_ID;Handler对应SW_intr_Handler;CallBackRef对应1,当然其它中断分别为2,3):

InstancePtr->Config->HandlerTable[Int_Id].Handler = Handler;        //  即参数SW_intr_Handler
InstancePtr->Config->HandlerTable[Int_Id].CallBackRef = CallBackRef;//  即参数1
 
 
  • 1
  • 2

即将处理函数(SW_intr_Handler)及其参数(1)放到&INTCInst中,
再次回到IRQ中断后会执行的XScuGic_InterruptHandler函数(在BSP目录下\ps7_cortexa9_0\libsrc\standalone_v5_2\src下xscugic_intr.c)中有以下语句:

TablePtr = &(InstancePtr->Config->HandlerTable[InterruptID]);
if(TablePtr != NULL) {
    TablePtr->Handler(TablePtr->CallBackRef);
}
 
 
  • 1
  • 2
  • 3
  • 4

即当TablePtr不为空时就执行了InstancePtr->Config->HandlerTable[InterruptID]->Handler(InstancePtr->Config->HandlerTable[InterruptID]->CallBackRef);结合上一段说明即执行了SW_intr_Handler(1)或参数为2、3。

综上,IRQ中断产生后跳转到0x18执行B IRQHandler执行,在IRQHandler下执行bl IRQInterrupt;在函数IRQInterrupt中XExc_VectorTable[XIL_EXCEPTION_ID_IRQ_INT].Handler(XExc_VectorTable[XIL_EXCEPTION_ID_IRQ_INT].Data);经过Xil_ExceptionRegisterHandler函数后即XScuGic_InterruptHandler(&INTCInst)再经过XScuGic_Connect函数这也即SW_intr_Handler(1)或参数为2、3。最终IRQ中断执行了SW_intr_Handler函数。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: zynq pl 29中断一直存在的原因可能有多种。首先,中断是处理器在执行某些任务时打断正常流程的一种机制。因此,在使用zynq pl 29时,由于计算量大、硬件资源有限,可能会出现大量的中断,以确保正常的任务执行。 其次,zynq pl 29的设计可能会使用中断的方式来处理设备的输入/输出请求或者提示状态的改变。这样,当外设需要与处理器进行通信时,会通过中断请求将处理器的注意力转移到外设。这些中断请求可能会持续存在直到处理器处理完相关的任务并做出相应的响应。 此外,zynq pl 29可能还存在硬件故障或者错误,导致中断一直发生。这可能是由于设计或者制造过程的错误、电路连线不良、供电问题等引起的。当硬件出现故障时,可能会引发中断并持续存在。 最后,中断的持续存在可能还与zynq pl 29的软件设计有关。如果软件程序存在某些错误,比如无限循环、死锁等,会导致中断无法被正确处理或解除,从而导致中断一直存在。 综上所述,zynq pl 29中断一直存在可能是由于系统设计、硬件故障、软件错误等多种原因导致的。针对这个问题,我们可以根据具体的情况逐一排查并解决问题,比如检查硬件连线、供电情况,调试软件代码等。 ### 回答2: 在Zynq PL(Programmable Logic),29中断是指第29个中断中断是计算机系统的一种机制,用于处理来自外部设备或内部事件的通知。在Zynq PL中断被用于处理与可编程逻辑相关的事件。 "中断一直有" 的意思可能是指29号中断一直持续发生。这可能是由于在程序设置了某种循环或条件,导致在特定情况下29号中断一直触发。这可能是PL特定模块的设计需求,也可能是在软件/固件的代码设置的。 要解决这个问题,可以检查程序的代码,查看是否存在循环或条件语句,这些语句可能导致29号中断一直触发。此外,还可以检查与29号中断相关的外设或模块,以确定是否存在与此中断相关的问题。 在解决这个问题之前,要考虑处理这个中断是否符合系统设计的需求。如果该中断是有意设置的,并与某些特定功能或事件相关,那么不需要解决此问题。然而,如果29号中断的不断触发是不希望的,并且会干扰系统的正常运行,那么需要检查并修正代码或硬件的设计问题,以避免中断的持续触发。 总之,"Zynq PL 29中断一直有"的问题需要对相关代码、硬件设计和系统需求进行仔细检查和分析,以确定合适的解决方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值