1.编写RTL文件,设置中断的触发条件和频率,将其封装成IP;
2.配置BD,为上述IP提供CLK和RST,注意敏感列表;
3.在zynq processor中配置中断号,分配中断号:
PL终端号可选:#61 至 #68 和 #84 至 #91


4.启动Vitis,在C文件中绑定CPUID,并使能硬中断的中断号,连接,配置优先级和灵敏度类型。
使用的几个函数:
XScuGic_SetPriTrigTypeByDistAddr
XScuGic_InterruptMaptoCpu
- int GIC_init(){
- int Status;
-
- Xil_ExceptionInit();
- GIC_SGI_ConFig = XScuGic_LookupConfig(GIC_DECIVE_ID_INT);
- if (NULL == GIC_SGI_ConFig) {
- return XST_FAILURE;
- }
-
- Status = XScuGic_CfgInitialize(&GIC_SGI_instance_point,
- GIC_SGI_ConFig,
- GIC_SGI_ConFig->CpuBaseAddress);
- if (Status != XST_SUCCESS) {
- return XST_FAILURE;
- }
- Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
- (Xil_ExceptionHandler) XScuGic_InterruptHandler,
- &GIC_SGI_instance_point);
- //SGI
- Status = XScuGic_Connect(&GIC_SGI_instance_point,
- Interrupt_ID_SGI_14,
- (Xil_InterruptHandler )SGI_IntrHandler,
- (void *)&GIC_SGI_instance_point
- );
- if (Status != XST_SUCCESS) {
- return XST_FAILURE;
- }
- XScuGic_Enable(&GIC_SGI_instance_point,
- Interrupt_ID_SGI_14);
- //HGI
- Status = XScuGic_Connect(&GIC_SGI_instance_point,
- Interrupt_ID_Hardware_0,
- (Xil_InterruptHandler )Hardware_IntrHandler,
- (void *)&GIC_SGI_instance_point
- );
- if (Status != XST_SUCCESS) {
- return XST_FAILURE;
- }
- // XScuGic_SetPriorityTriggerType();
- XScuGic_SetPriTrigTypeByDistAddr(DistBaseAddress,
- Interrupt_ID_Hardware_0,
- 0x20,
- 0x03);
- XScuGic_InterruptMaptoCpu(&GIC_SGI_instance_point,
- CPU_id_0,
- Interrupt_ID_Hardware_0);
- XScuGic_Enable(&GIC_SGI_instance_point,
- Interrupt_ID_Hardware_0);
- Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
- return XST_SUCCESS;
- }
来自各个模块的一组大约 60 个中断可以路由到一个或两个 CPU 或 PL。中断控制器管理 CPU 的这些中断的优先级和接收。
除了 IRQ #61 至 #68 和 #84 至 #91 之外,所有中断敏感度类型均由请求源固定且无法更改。 GIC 必须进行编程以适应这种情况。引导 ROM 不会对这些寄存器进行编程;因此,SDK 设备驱动程序必须对 GIC 进行编程以适应这些敏感度类型。
比较SGI:ICDICFR0可以不用太关心,因为不可配。
所有 SGI 都是边沿触发的。 SGI 的灵敏度类型是固定的且无法更改; ICDICFR0 寄存器是只读的,因为它指定了所有 16 个 SGI 的灵敏度类型。
需要注意的问题:
ZYNQ AMP模式下CPU1响应外部中断_zynq core 1 中断-CSDN博客
对于电平敏感类型的中断,请求源必须提供一种机制,以便中断处理程序在中断被应答后清除中断。此要求适用于任何具有高级别灵敏度类型的 IRQF2P[n](来自 PL)。
对于上升沿敏感的中断,请求源必须提供足够宽的脉冲供 GIC 捕获。这通常至少是 2 个 CPU_2x3x 周期。此要求适用于任何具有上升沿敏感类型的 IRQF2P[n](来自 PL)。
ICDICFR2 至 ICDICFR5 寄存器配置所有 SPI 的中断类型。每个中断都有一个 2 位字段,指定敏感类型和处理模型。
ICD ICFR 0 寄存器控制 16 个软件生成中断 (SGI)、IRQ ID #0 至 ID #15 的中断灵敏度。该只读寄存器每个中断有两位,始终指示每个 SGI 中断是边沿敏感的,并且必须由 ICD IPTR [3:0] 寄存器中指示的所有目标 CPU 进行处理。
ICDICFR 2寄存器控制共享外设中断 (SPI)、IRQ ID #32 至 ID #47(IRQ 36 被保留)的中断灵敏度。该寄存器每个中断有两位。该两位字段要么等于 01(高电平有效),要么等于 11(上升沿敏感)。 LSB 始终为 1,因为无论目标 CPU 数量如何,只有一个 CPU 会处理 SPI 中断。
请参阅 UG585 TRM 第 7.2.3 节共享外设中断 (SPI),了解 SPI 中断所需的灵敏度类型。 SPI 中断必须符合预期的灵敏度。
来自 PL 的中断可能是高电平或上升沿敏感的;这必须与 PL 硬件和软件相协调。
本次使用的PL端只用了两个中断输入,只看61和62吧。
ICDICFR 3 寄存器控制共享外设中断 (SPI)、IRQ ID #48 至 ID #63 的中断灵敏度。该寄存器每个中断有两位。该两位字段要么等于 01(高电平有效),要么等于 11(上升沿敏感)。 LSB 始终为 1,因为无论目标 CPU 数量如何,只有一个 CPU 会处理 SPI 中断。
请参阅 UG585 TRM 第 7.2.3 节共享外设中断 (SPI),了解 SPI 中断所需的灵敏度类型。 SPI 中断必须符合预期的灵敏度。来自 PL 的中断可能是高电平或上升沿敏感的;这必须与 PL 硬件和软件相协调。
中断 ID#61 配置 01:高电平有效 11:上升沿 低位只读,始终为 1
中断 ID#62 配置 01:高电平有效 11:上升沿 低位只读,始终为 1。
ZYNQ的中断设置都有一个基地址,对各个中断号的中断的响应,可以通过中断号来进行偏移。
Name ICDDCR
Software Name GIC_DIST_EN
Relative Address 0x00001000
Absolute Address 0xF8F01000
Width 32 bits
Access Type rw
Reset Value 0x00000000
Description Distributor Control Register
DistBaseAddress根据UG585需要填入
DistBaseAddress = XPAR_PS7_SCUGIC_0_DIST_BASEADDR=0xF8F01000
Int_Id填入中断号
Priority填入优先级
Trigger根据ICDICFR中的需求填入
- /****************************************************************************/
- /**
- * Sets the interrupt priority and trigger type for the specificd IRQ source.
- *
- * @param DistBaseAddress is the distributor base address
- * @param Int_Id is the IRQ source number to modify
- * @param Priority is the new priority for the IRQ source. 0 is highest
- * priority, 0xF8(248) is lowest. There are 32 priority
- * levels supported with a step of 8. Hence the supported
- * priorities are 0, 8, 16, 32, 40 ..., 248.
- * @param Trigger is the new trigger type for the IRQ source.
- * Each bit pair describes the configuration for an INT_ID.
- * SFI Read Only b10 always
- * PPI Read Only depending on how the PPIs are configured.
- * b01 Active HIGH level sensitive
- * b11 Rising edge sensitive
- * SPI LSB is read only.
- * b01 Active HIGH level sensitive
- * b11 Rising edge sensitive/
- *
- * @return None.
- *
- * @note This API has the similar functionality of XScuGic_SetPriority
- * TriggerType() and should be used when there is no InstancePtr.
- *
- *****************************************************************************/
- void XScuGic_SetPriTrigTypeByDistAddr(u32 DistBaseAddress, u32 Int_Id,
- u8 Priority, u8 Trigger)
- {
- u32 RegValue;
- #if defined (GICv3)
- u32 Temp;
- u32 Index;
- #endif
- u8 LocalPriority = Priority;
-
- Xil_AssertVoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
- Xil_AssertVoid(Trigger <= XSCUGIC_INT_CFG_MASK);
- Xil_AssertVoid(LocalPriority <= XSCUGIC_MAX_INTR_PRIO_VAL);
- #if defined (GICv3)
- if (Int_Id < XSCUGIC_SPI_INT_ID_START )
- {
- XScuGic_WriteReg(DistBaseAddress + XSCUGIC_RDIST_SGI_PPI_OFFSET,
- XSCUGIC_RDIST_INT_PRIORITY_OFFSET_CALC(Int_Id),Priority);
- Temp = XScuGic_ReadReg(DistBaseAddress + XSCUGIC_RDIST_SGI_PPI_OFFSET,
- XSCUGIC_RDIST_INT_CONFIG_OFFSET_CALC(Int_Id));
- Index = XScuGic_Get_Rdist_Int_Trigger_Index(Int_Id);
- Temp |= (Trigger << Index);
- XScuGic_WriteReg(DistBaseAddress + XSCUGIC_RDIST_SGI_PPI_OFFSET,
- XSCUGIC_RDIST_INT_CONFIG_OFFSET_CALC(Int_Id),Temp);
- return;
- }
- #endif
-
- /*
- * Call spinlock to protect multiple applications running at separate
- * CPUs to write to the same register. This macro also ensures that
- * the spinlock mechanism is used only if spinlock is enabled by
- * user.
- */
- XIL_SPINLOCK();
-
- /*
- * Determine the register to write to using the Int_Id.
- */
- RegValue = XScuGic_ReadReg(DistBaseAddress,
- XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id));
-
- /*
- * The priority bits are Bits 7 to 3 in GIC Priority Register. This
- * means the number of priority levels supported are 32 and they are
- * in steps of 8. The priorities can be 0, 8, 16, 32, 48, ... etc.
- * The lower order 3 bits are masked before putting it in the register.
- */
- LocalPriority = LocalPriority & XSCUGIC_INTR_PRIO_MASK;
- /*
- * Shift and Mask the correct bits for the priority and trigger in the
- * register
- */
- RegValue &= ~((u32)XSCUGIC_PRIORITY_MASK << ((Int_Id%4U)*8U));
- RegValue |= (u32)LocalPriority << ((Int_Id%4U)*8U);
-
- /*
- * Write the value back to the register.
- */
- XScuGic_WriteReg(DistBaseAddress, XSCUGIC_PRIORITY_OFFSET_CALC(Int_Id),
- RegValue);
- /*
- * Determine the register to write to using the Int_Id.
- */
- RegValue = XScuGic_ReadReg(DistBaseAddress,
- XSCUGIC_INT_CFG_OFFSET_CALC(Int_Id));
-
- /*
- * Shift and Mask the correct bits for the priority and trigger in the
- * register
- */
- RegValue &= ~((u32)XSCUGIC_INT_CFG_MASK << ((Int_Id%16U)*2U));
- RegValue |= (u32)Trigger << ((Int_Id%16U)*2U);
-
- /*
- * Write the value back to the register.
- */
- XScuGic_WriteReg(DistBaseAddress, XSCUGIC_INT_CFG_OFFSET_CALC(Int_Id),
- RegValue);
-
- /*
- * Release the lock previously taken. This macro ensures that the lock
- * is given only if spinlock mechanism is enabled by the user.
- */
- XIL_SPINUNLOCK();
- }
- /****************************************************************************/
- /**
- * Sets the target CPU for the interrupt of a peripheral
- *
- * @param InstancePtr is a pointer to the instance to be worked on.
- * @param Cpu_Identifier is a CPU number for which the interrupt has to be targeted
- * @param Int_Id is the IRQ source number to modify
- *
- * @return None.
- *
- * @note None
- *
- *****************************************************************************/
- void XScuGic_InterruptMaptoCpu(XScuGic *InstancePtr, u8 Cpu_Identifier, u32 Int_Id)
- {
- u32 RegValue;
-
- if (Int_Id >= XSCUGIC_SPI_INT_ID_START) {
- #if defined (GICv3)
- Xil_AssertVoid(InstancePtr != NULL);
- RegValue = XScuGic_DistReadReg(InstancePtr,
- XSCUGIC_IROUTER_OFFSET_CALC(Int_Id));
- RegValue |= Cpu_Identifier;
- XScuGic_DistWriteReg(InstancePtr, XSCUGIC_IROUTER_OFFSET_CALC(Int_Id),
- RegValue);
- #else
- u8 Cpu_CoreId;
- u32 Offset;
- Xil_AssertVoid(InstancePtr != NULL);
-
- /*
- * Call spinlock to protect multiple applications running at separate
- * CPUs to write to the same register. This macro also ensures that
- * the spinlock mechanism is used only if spinlock is enabled by
- * user.
- */
- XIL_SPINLOCK();
-
- RegValue = XScuGic_DistReadReg(InstancePtr,
- XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id));
-
- Offset = (Int_Id & 0x3U);
- Cpu_CoreId = (0x1U << Cpu_Identifier);
-
- RegValue |= (u32)(Cpu_CoreId) << (Offset*8U);
- XScuGic_DistWriteReg(InstancePtr,
- XSCUGIC_SPI_TARGET_OFFSET_CALC(Int_Id),
- RegValue);
- /*
- * Release the lock previously taken. This macro ensures that the lock
- * is given only if spinlock mechanism is enabled by the user.
- */
- XIL_SPINUNLOCK();
- #endif
- }
- }