01-25-2021 01:25 AM
Hi all, i'm porting a design from Microblaze Zynq Mpsoc.
I need to disable some interrupts, modify the handler and enable again.
I use to do these operations on Intc controller, i want to figure out the best options with GIC now. This is an example for a VDMA.
XIntc_Disable(VDMA_Interrupt) XAxiVdma_IntrDisable(VDMA_Interrupt) XAxiVdma_IntrClear(VDMA_Interrupt) XIntc_Acknowledge(VDMA_Interrupt)
I haven't found an Acknowledge function for GIC. Is this not needed anymore? Should i only disable the interrupt with XScuGic_Disable?
I used to clear the interrupt because with the disable function the interrupt is still hold by the controller even if not fired.
I found people asked for something similar and they get
IntIDFull = XScuGic_CPUReadReg(&ScuGic, XSCUGIC_INT_ACK_OFFSET); XScuGic_CPUWriteReg(&ScuGic, XSCUGIC_EOI_OFFSET, IntIDFull);
But it's not clear what this code do, i think it clears the most priority pending interrupt, i want to clear only my just disabled interrupts.
01-25-2021 02:02 AM
Are you disabling interrupts after the interrupt is triggered? In your handler? What you 're trying to do is a little unclear.
A general answer is that you don't need to disable interrupts in Zynq when an interrupt is being handled. In Arm technology, when an (IRQ) interrupt is being handled, the "I" bit in the CPSR is set, meaning that further interrupts are ignored until you finish handing the current one. (Interrupts are not discarded, they will just be handled in turn.) [Also assumes that you are not using nested interrupts. I'm sure you're not here.]
Generally, in your handler you just need to clear the interrupt and handle the interrupt. When the handler function ends, your system will go back to normal.
01-25-2021 02:11 AM
@derekm_ thanks for reply,
I want to disable an interrupt (in my example the VDMA), change the handler function (the callback function to be precise) and enable the interrupt again.
I thought the required steps are:
1)disable interrupt at controller
2)disable interrupt at peripheral(VDMA)
3)clear pending interrupt at peripheral(if any)
4)clear pending interrupt at controller(if any)
5)enable interrupt at peripheral
6)enable interrupt at controller
in this way i have a clear transition and i'm not risking that an old interrupt can be fired
With GIC i don't know how to achieve this since there is no ack function for a certain interrupt source.
Hope it's more clear now
01-25-2021 03:33 AM
Okay, I see what you mean now. I don't know much about that peripheral, so I will just talk about the GIC. First of all, you can find XScuGic_Disconnect() , XScuGic_Connect() , XScuGic_Enable() and XScuGic_Disable() in xscugic.c. That file is in libsrc/scugic_XvX in the BSP. I think the _Disconnect() function will also disable the interrupt, but check through the comments in the file to be sure. If not, just use _Disable() as well.
Then, to clear any pending interrupts for your peripheral in the GIC, you should be able to write to the Clear-Pending register, using a mask for the peripheral interrupt ID. See page 1469 of the Zynq TRM, UG585. Use the XScuGic_DistWriteReg() function for this. The RegOffset is found in xscugic_hw.h, and is XSCUGIC_PENDING_CLR_OFFSET for this register (plus an offset of +4 or +8 depending on your interrupt ID).
Something like the following should work:
XScuGic_Disconnect() // May need XScuGic_Disable() as well XScuGic_DistWriteReg(*inst,XSCUGIC_PENDING_CLR_OFFSET, YOUR_ID_MASK) // Clear pending interrupts // Do peripheral specific stuff now // ... // ... XScuGic_Connect()// Connect the new handler XScuGic_Enable() // Re-enable the interrupt.
I'm speaking quite generally there, as I've never had to switch a handler dynamically in Zynq, but see how you get on with this. Also let me know your peripheral interrupt ID, if you're unsure of the location in Clear-Pending registers, and I'll tell you what it is.
01-25-2021 03:57 AM
Another thing: maybe you need to disable you VDMA interrupt(s) first before running the above sequence. In fact, you might have to experiment a little bit with the overall sequence to ensure there are no race conditions.
01-25-2021 04:31 AM
Hi @derekm_ ,
yes you understand what i'm trying to do.
I would like to point out that i'm using RPU GIC for Zynq MPSoc, not Zynq.
The procedure you pointed out makes sense but i would like a Xilinx confirmation since they are not mentioned in the Zynq Mpsoc reference manual.
01-25-2021 04:44 AM
Apologies, I missed the MPSoC part! But the RPU in MPSoC uses the same GIC as used in the Zynq-7000, so the instructions should be valid anyway (pending Xilinx confirmation, if that's what you need).
01-25-2021 05:18 AM
@derekm_ i will tryanyway your solution
the interrupt is number 142, 141 , 140
so for example if i need the interrupt 142 to be cleared i call the function with
n= 142/32= 4
bit_number= 142 mod 32 = 14
is it right?
01-25-2021 05:38 AM - edited 01-25-2021 05:41 AM
Going by the Zynq GIC (which only has 96 interrupts), I think your calculation is correct. So for ID 142 = 14, you should write 0x0000_2000 to the specific Clear-Pending register. The register is of type write-one-clear (W1C) , so you don't have to do anything else. For all three IDs I guess you can clear all three pending interrupts simultaneously i.e. write 0x0000_3800 (but I'm guessing!).
01-25-2021 06:02 AM - edited 01-25-2021 06:03 AM
sorry @derekm_ to bother you, shouldn't be 0x0000_4000 for bit 14? I think should count from 0 (for example interrupt 128 -> 128 mod 32 = 0 i would write 0x0000_0001)
and for the guessing part, since i'm using these Zynq Mpsoc i have to guess a lot