基于ZYNQ的嵌入式学习笔记三(独立按键中断)

本文深入探讨ZYNQ的中断机制,包括私有外设中断、看门狗、FIQ/IRQ、共享外设中断和软件中断等类型。详细介绍了通用中断控制器GIC的功能,如中断信号传递、中断编程模式、中断优先级和中断处理。同时,提供了独立按键中断的实现代码,展示了如何使用GIC和GPIO进行中断配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、ZYNQ中断概述

中断类型:私有外设中断(PPI):全局定时器、私有看门狗、私有定时器、PL部分产生的FIQ/IRQ;

看门狗:WDT,  看门狗定时器,有两个, 分别监视ARM-Cortex A9用的。  如果软件跑飞,无法清定时器,一段时间后,看门狗就复位。SWDT,系统级看门狗定时器, 这个看门狗的时钟和复位信号,都可以来自于芯片外部, 这样,即使系统有严重故障,比如时钟频率本身都有问题了, 仍然可以通过与系统无关的外部信号计数,计数满就复位。

FIQ/IRQ:ARM内核可以识别正常识别正常中断请求和快速中断请求两种类型的外部中断,中断的行为模式由中断控制器来设置。ARM内核只有2个外部中断输入信号nIRQ,nFIQ,在具体嵌入式系统中,需要用中断控制器管理多个外部中断源,选择其中一个中断,通过nIRQ或nFIQ想ARM内核发出中断请求。

共享外设中断(SPI):位于PS和PL的I/O及内存控制器产生的中断;

软件中断(SGI):对通用中断控制器读写产生的中断,通过写相关寄存器产生,中断CPU自身或其他CPU,所有CPU,每个CPU有自己的SGI寄存器组。

GIC——通用中断控制器:

允许、禁止中断和管理中断优先级;所有CPU均通过私有总线访问GIC。

中断信号传递:

三、中断编程模式:

中断优先级;

中断处理:GIC寄存器访问;分发器和CPU接口;GIC安全扩展的影响;PU接口寄存器;保存和存储控制器状态;

延迟中断和安全扩展:GIC只有IRQ会抢占;FIQ采用安全模式。

其余关于中断触发方式及寄存器等内容参考我另一篇博客,AXI INTC学习笔记。

四、独立按键中断

对应按键按下之后,FPGA 的对应管脚输入电平值应该为 0。

查看U585第231页,可以看到从PL部分输入的中断号为{[91:84],[68:61]}对应IRQ_F2P[15:0],在这里我PS部分使用的就是IRQ_F2P。

实现代码:

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

#define BTN_DEVICE_ID XPAR_GPIO_BTN_DEVICE_ID
#define LEDS_DEVICE_ID XPAR_GPIO_LEDS_DEVICE_ID
#define INTC_GPIO_INTERRUPT_ID XPAR_FABRIC_GPIO_BTN_IP2INTC_IRPT_INTR
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define INTC XScuGic
#define INTC_HANDLER XScuGic_InterruptHandler
#define BUTTON_INTERRUPT XGPIO_IR_CH1_MASK
#define LED_DELAY 1000000
static u16 GlobalIntrMask; 
static volatile u32 IntrFlag;

int GpioIntrInitialize();
void GpioHandler(void *CallBackRef);
int GpioSetupIntrSystem(INTC *IntcInstancePtr, XGpio *InstancePtr,u16 DeviceId, u16 IntrId, u16 IntrMask);
void GpioDisableIntr(INTC *IntcInstancePtr, XGpio *InstancePtr,u16 IntrId, u16 IntrMask);

XGpio Gpio_BTN,Gpio_LEDS;
INTC Intc;


#ifndef TESTAPP_GEN
int main(void)
{
    int Status;
    Status= GpioIntrInitialize();
    return XST_SUCCESS;
}
#endif

int GpioIntrInitialize(){
	int Status;
	u32 delay;
	Status = XGpio_Initialize(&Gpio_BTN, BTN_DEVICE_ID);//初始化BTN的AXI_GPIO
	if (Status != XST_SUCCESS) {
	return XST_FAILURE;
	}
	Status = XGpio_Initialize(&Gpio_LEDS, LEDS_DEVICE_ID);//初始化LED和SEG7的AXI_GPIO
	if (Status != XST_SUCCESS) {
	return XST_FAILURE;
	}
	XGpio_SetDataDirection(&Gpio_BTN, 1, 0X0F); //设置独立按键通道全为输入
	XGpio_SetDataDirection(&Gpio_LEDS, 1, 0); //设置LED通道全为输出
	XGpio_SetDataDirection(&Gpio_LEDS, 2, 0); //设置SEG7通道全为输出
	XGpio_DiscreteWrite(&Gpio_LEDS, 1, 0xFF);//先将LED灯全熄灭
	XGpio_DiscreteWrite(&Gpio_LEDS, 2, 0xFF0000);//将7段数码管全熄灭
	Status = GpioSetupIntrSystem(&Intc, &Gpio_BTN, BTN_DEVICE_ID,INTC_GPIO_INTERRUPT_ID,INTR_MASK);
	if (Status != XST_SUCCESS) {
	return XST_FAILURE;
	}
	IntrFlag = 0;
	delay = 0;
//4位中断信号依次从低位到高位为0
	while(1){
	switch(IntrFlag&0xF)
	{
	case 0xE:
	XGpio_DiscreteWrite(&Gpio_LEDS, 1, 0xFC);
	XGpio_DiscreteWrite(&Gpio_LEDS, 2, 0x000606);
	break;
	case 0xD:
	XGpio_DiscreteWrite(&Gpio_LEDS, 1, 0xF3);
	XGpio_DiscreteWrite(&Gpio_LEDS, 2, 0x005B5B);
	break;
	case 0xB:
	XGpio_DiscreteWrite(&Gpio_LEDS, 1, 0xCF);
	XGpio_DiscreteWrite(&Gpio_LEDS, 2, 0x004F4F);
	break;
	case 0x7:
	XGpio_DiscreteWrite(&Gpio_LEDS, 1, 0x3F);
	XGpio_DiscreteWrite(&Gpio_LEDS, 2, 0x006666);
	break;
	default:
	//XGpio_DiscreteWrite(&Gpio_LEDS, LEDS_CHANNEL, LEDS_ALL_OFF);
	//XGpio_DiscreteWrite(&Gpio_LEDS, SEG7_CHANNEL, SEG7_ALL_OFF);
	break;
	}
	}
	GpioDisableIntr(&Intc, &Gpio_BTN, INTC_GPIO_INTERRUPT_ID, INTR_MASK);
	return Status;
}

int GpioSetupIntrSystem(INTC *IntcInstancePtr, XGpio *InstancePtr,
u16 DeviceId, u16 IntrId, u16 IntrMask)
{
	int Result;
	GlobalIntrMask = IntrMask;//中断掩码
	XScuGic_Config *IntcConfig;
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);//找到GIC驱动的ID并初始化
	if (NULL == IntcConfig) {
	return XST_FAILURE;
	}
	Result = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress);
	if (Result != XST_SUCCESS) {
	return XST_FAILURE;
	}
	XScuGic_SetPriorityTriggerType(IntcInstancePtr, IntrId,0xA0, 0x3);//设置中断触发方式和优先级
	Result = XScuGic_Connect(IntcInstancePtr, IntrId,
	(Xil_ExceptionHandler)GpioHandler, InstancePtr);
	if (Result != XST_SUCCESS) {
	return Result;
	}
	XScuGic_Enable(IntcInstancePtr, IntrId);//允许GPIO中断
//允许GPIO通道按键输入中断信号能被检测
	XGpio_InterruptEnable(InstancePtr, IntrMask);
	XGpio_InterruptGlobalEnable(InstancePtr);
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
	(Xil_ExceptionHandler)INTC_HANDLER, IntcInstancePtr);//初始化异常中断表
	/* 允许异常 */
	Xil_ExceptionEnable();
	return XST_SUCCESS;

	}

void GpioHandler(void *CallbackRef)
{
XGpio *GpioPtr = (XGpio *)CallbackRef;
IntrFlag = XGpio_DicreteRead(&Gpio_BTN, 1);//读取按键产生的中断信号
/* 清除中断 */
XGpio_InterruptClear(GpioPtr, GlobalIntrMask);
}

void GpioDisableIntr(INTC *IntcInstancePtr, XGpio *InstancePtr,
u16 IntrId, u16 IntrMask)
{
XGpio_InterruptDisable(InstancePtr, IntrMask);
/* 断开中断连接 */
XScuGic_Disable(IntcInstancePtr, IntrId);
XScuGic_Disconnect(IntcInstancePtr, IntrId);
return;
}

 

<think>好的,用户想了解Zynq中断合成的实现方法和相关文档教程。首先我需要回忆一下Zynq中断系统结构。Zynq的PS部分有通用中断控制器(GIC),可以处理来自PL的中断请求。用户提到的中断合成可能是指将多个PL中断信号合并后再传递给PS的GIC。根据引用[4],PL到PS的中断通道包括16个IRQ和4个FIQ,所以可能需要通过Vivado配置中断控制器的连接。 接下来要考虑如何在设备树中配置中断。根据引用[2],在Xilinx SDK中添加设备树源文件地址,可能需要修改设备树源文件(dts)中的中断节点,指定中断号、触发类型等参数。同时,用户需要在内核驱动中注册中断处理函数,这部分可能需要参考Linux内核的中断子系统文档。 另外,中断合成可能涉及硬件逻辑设计,比如在PL部分使用逻辑门或IP核将多个中断信号合并为一个,再连接到PS的IRQ/FIQ引脚。需要检查Vivado工程中PL部分的连接,确保中断信号正确连接到PS的中断控制器。编译步骤方面,引用[1]提到使用petalinux-build命令进行编译,生成包含设备树和内核的镜像。 用户可能需要具体的步骤,比如如何在Vivado中配置中断控制器的连接,如何编写设备树节点,以及驱动中的中断处理函数注册。还需要确保引用的相关文档如ZYNQ Linux移植说明和VxWorks的中断配置是否适用。此外,用户可能关心中断优先级、共享中断的处理方法,以及如何调试中断问题。需要综合硬件配置、设备树设置和驱动开发个方面来回答,并提供文档和教程的参考来源。</think>### Zynq中断合成实现方法 Zynq中断合成涉及PL(可编程逻辑)与PS(处理系统)的中断交互机制,主要通过以下步骤实现: 1. **硬件配置** 在Vivado中需将PL中断信号连接到PS端的中断控制器。通过双击`processing_system7_0`组件,勾选`Interrupts`中的`IRQ_F2P[15:0]`选项,开启16个IRQ和4个FIQ通道[^4]。PL端的中断信号可通过AXI Interrupt Controller或自定义逻辑合并后连接到这些引脚。 2. **设备树配置** 在设备树(Device Tree)中需定义中断号与触发方式。例如: ```dts pl_interrupt { compatible = "generic-uio"; interrupt-parent = <&intc>; interrupts = <0 29 1>; // IRQ 29, 高电平触发 }; ``` 其中`interrupt-parent`指向PS的GIC控制器,`interrupts`参数依次为中断类型(0表示SPI)、中断号、触发方式[^2]。 3. **驱动开发** 在Linux内核驱动中需注册中断处理函数,例如: ```c irq_handler_t pl_irq_handler(int irq, void *dev_id) { // 中断处理逻辑 return IRQ_HANDLED; } request_irq(irq_num, pl_irq_handler, IRQF_TRIGGER_HIGH, "pl_irq", NULL); ``` 需注意共享中断(`IRQF_SHARED`)和中断线程化处理等优化方法[^3]。 4. **系统编译** 使用PetaLinux工具链完成配置后,执行`petalinux-build`命令编译内核、设备树及驱动模块[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值