Zynq7000 Soc的中断系统实验(一)

Zynq7000 Soc的中断系统实验(一)

  • Zynq7000的中断概述
  • 软中断使用
  • Vitis软中断示例代码解读
  • 参考文档

Zynq7000的中断概述

  1. zynq7000的三类中断类型如下图所示:
    Zynq7000 Soc的中断系统实验(一)_第1张图片
  2. 显而易见,zynq这块soc支持软件生成中断(SGI)、私有外设中断(PPI)以及共享外设中断(SPI)。注意到此处的SPI并非常见的低速通信协议,注意区分。
  3. 注意到zynq的这个Generic Interrupt Controller(通用中断控制器),以下简称GIC,可以看到GIC可以对SGI、PPI以及SPI进行反应,并且GIC拥有对中断寄存器的私有读写总线,避免了一些互联逻辑的冲突或者反应降速等问题。
  4. 大致对zynq的中断系统的一个大局理解就是这样,后续需要细节性探究时再进行文档细究即可。

软中断使用

  1. 简单来讲对软中断的使用就是两个寄存器的读写问题,ICDSGIR寄存器存放中断的ID号,软中断支持最大16个中断。中断清除可以通过读寄存器ICCIAR或者写1到寄存器ICDICPR的对应清楚位两种方式完成。
  2. 软中断的软也就意味着需要在PS端对中断进行操作和使用。具体使用须参考Vitis给出的example代码,在此基础上我们才可以掌握对软中断的灵活使用。

Vitis软中断示例代码解读

  1. 主要示例代码如下:
int main(void)
{
	int Status;


	/*
	 * Setup an assert call back to get some info if we assert.
	 */
	Xil_AssertSetCallback(AssertPrint);

	xil_printf("GIC Example Test\r\n");

	/*
	 *  Run the Gic example , specify the Device ID generated in xparameters.h
	 */
	Status = ScuGicExample(INTC_DEVICE_ID);
	if (Status != XST_SUCCESS) {
		xil_printf("GIC Example Test Failed\r\n");
		return XST_FAILURE;
	}

	xil_printf("Successfully ran GIC Example Test\r\n");
	return XST_SUCCESS;
}
  1. 示例代码的主体在于ScuGicExample的函数体。其具体实现如下:
/*****************************************************************************/
/**
*
* This function is an example of how to use the interrupt controller driver
* (XScuGic) and the hardware device.  This function is designed to
* work without any hardware devices to cause interrupts. It may not return
* if the interrupt controller is not properly connected to the processor in
* either software or hardware.
*
* This function relies on the fact that the interrupt controller hardware
* has come out of the reset state such that it will allow interrupts to be
* simulated by the software.
*
* @param	DeviceId is Device ID of the Interrupt Controller Device,
*		typically XPAR__DEVICE_ID value from
*		xparameters.h
*
* @return	XST_SUCCESS to indicate success, otherwise XST_FAILURE
*
* @note		None.
*
******************************************************************************/
int ScuGicExample(u16 DeviceId)
{
	int Status;
	#if defined (VERSAL_NET)
	u32 CoreId, ClusterId;
	#endif

	/*
	 * Initialize the interrupt controller driver so that it is ready to
	 * use.
	 */
	GicConfig = XScuGic_LookupConfig(DeviceId);
	if (NULL == GicConfig) {
		return XST_FAILURE;
	}

	Status = XScuGic_CfgInitialize(&InterruptController, GicConfig,
					GicConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}


	/*
	 * Perform a self-test to ensure that the hardware was built
	 * correctly
	 */
	Status = XScuGic_SelfTest(&InterruptController);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}


	/*
	 * Setup the Interrupt System
	 */
	Status = SetUpInterruptSystem(&InterruptController);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Connect a device driver handler that will be called when an
	 * interrupt for the device occurs, the device driver handler performs
	 * the specific interrupt processing for the device
	 */
	Status = XScuGic_Connect(&InterruptController, INTC_DEVICE_INT_ID,
			   (Xil_ExceptionHandler)DeviceDriverHandler,
			   (void *)&InterruptController);

	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Enable the interrupt for the device and then cause (simulate) an
	 * interrupt so the handlers will be called
	 */
	XScuGic_Enable(&InterruptController, INTC_DEVICE_INT_ID);

	/*
	 *  Simulate the Interrupt
	 */
#if defined (VERSAL_NET)

	CoreId = XGetCoreId();
	ClusterId = XGetClusterId();

	#if defined (ARMR52)
	CoreId = (1 << CoreId);
	#endif

	Status = XScuGic_SoftwareIntr(&InterruptController,
                                        INTC_DEVICE_INT_ID,
                                        ((ClusterId << XSCUGIC_CLUSTERID_SHIFT ) | CoreId));
#else
	Status = XScuGic_SoftwareIntr(&InterruptController,
					INTC_DEVICE_INT_ID,
					XSCUGIC_SPI_CPU_MASK);
#endif
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Wait for the interrupt to be processed, if the interrupt does not
	 * occur return failure after timeout.
	 */
	Status = Xil_WaitForEventSet(XSCUGIC_SW_TIMEOUT_VAL, 1,
				     &InterruptProcessed);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	return XST_SUCCESS;
}

  1. 结合上述两段主要代码,我们就可以基本梳理出SGI的基本使用流程与方法。

// DeviceId定义(映射)
#define INTC_DEVICE_ID		XPAR_SCUGIC_0_DEVICE_ID
// GIC对象创建
XScuGic InterruptController; 	
// GIC配置对象创建
static XScuGic_Config *GicConfig;    
// 绑定Device
GicConfig = XScuGic_LookupConfig(DeviceId);
// 初始化SGI
Status = XScuGic_CfgInitialize(&InterruptController, 
				GicConfig,GicConfig->CpuBaseAddress);
// 寄存器句柄创建并使能
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
				(Xil_ExceptionHandler) XScuGic_InterruptHandler,
				InterruptController);
Xil_ExceptionEnable();	
// 连接SGI到设备
Status = XScuGic_Connect(&InterruptController, INTC_DEVICE_INT_ID,
			   (Xil_ExceptionHandler)DeviceDriverHandler,
			   (void *)&InterruptController);
// 使能SGI
XScuGic_Enable(&InterruptController, INTC_DEVICE_INT_ID);
// 等待中断返回结果,若超时返回ERROR
Status = Xil_WaitForEventSet(XSCUGIC_SW_TIMEOUT_VAL, 1,
				     &InterruptProcessed);		
  1. 到此对SGI的示例代码基本解读完成,接下来会更新上板对SGI进行调试等系列文章,欢迎关注同ID公众号。

参考文档

  1. ug585-Zynq-7000-TRM.pdf
  2. The_Zynq_Book_ebook.pdf

你可能感兴趣的:(Zynq,单片机,嵌入式硬件,Zynq,Soc)