Forum Discussion
Altera_Forum
Honored Contributor
15 years agoNIOS + IRQ + custom component
Hi, I'm trying to interrupt a Nios Prosessor whit a Custom Component and setup a successful interrupt routine. But I can't Do it.
The problem is that i can't find a complete example of a custom component connected to a NIOS II processor who succesfuly call a ISR. Can someone help me? Jairo34 Replies
- Altera_Forum
Honored Contributor
@BadOmen would you send the example SOPC custom component with IRQ to my email ?
thanks - Altera_Forum
Honored Contributor
Hi Fightingdreamer,
The IRQ signal needs to be >> 1 clock period wide. The CPU invokes initial processing to ID the interrupt and select the correct handler. Sorry I can post links but google NIOS II Exception Handling by John Loomis and look at alterawiki for IRQ code. In my case I had to make the IRQ pulse 50 clock cyles wide. I presently don't know of any Altera guidelines on this (Is there one?). I would suggest the interrupt sender should be assigned to the MM slave (a custom CSR interface ??) were you should clear the defined IRQ bit before existing the ISR. Hope this is helpful. kohagan. - Altera_Forum
Honored Contributor
Hi Kohagan,
Thanks for your reply. I've tried to modify and provide an Avalon MM slave, it consists of a 'write' and a 'writedata' signal. This Avalaon MM slave function is to let the CPU send a command to clear the interrupt bit. Then, I assign my interrupt signal in SOPC to this Avalon MM. However, the result is very strange... my program totally doesn't work, even it has hanged in the beginning.... :( I don't know why.., I've set the interrupt priority low enough such that it didn't overlap with previous process. Do you have any suggestion why it happens? Thanks - Altera_Forum
Honored Contributor
Hi Fightingdreamer,
Not sure if you are implementing the procedure correctly. Process I implemented was: 1. IRQ signal ( interrupt sender) is generated. This signal needs to have a period of typically 50 clocks wide (wrt Nios Clock). 2. The IRQ signal is used to simultaneously set an IRQ bit in an avalon MM register, i.e. Status reg within your custom component. Process 1 alerts the NIOS to an interrupt event and points to the entry point of your ISR code. The ISR code reads and clears the IRQ bit (set in Process 2) before exiting the ISR. Hope this helps, Ken. - Altera_Forum
Honored Contributor
I would make the IRQ signal indefinite - ie stay active until the ISR clears the source.
The IRQ can then be a logical 'or' of all the bits of the MM slave register. You then need to do 'write to clear' on that location from the nios. The ISR then does: 1) Read IRQ register 2) Write the value back to clear the IRQ bits that were present at the time it was read. 3) Check each IRQ bit in turn (or fifo level (etc)) to actually service the interrupt. 4) exit from ISR There are some systems [1] where it is possible to exit the ISR before the write (2) has propogated far enough to actually cause the IRQ line to be deasserted. This can cause 'splurious' ISR messages under certain loads. [1] eg when the write gets 'posted' on some bus, and the check (3) involves looking in shared memory (typical of ethernet receive). - Altera_Forum
Honored Contributor
Oh - you also want to add a 2nd MM slave register so that the nios code can disable interrupts without regard for what the hardware is actually doing.
This could feed in either side of the 'or' of the multiple IRQ sources. - Altera_Forum
Honored Contributor
Hi dsl,
Thanks for the post. I can appreciate that your closed loop IRQ process is a better solution as it automatically maintains the required IRQ signal period. kohagan - Altera_Forum
Honored Contributor
Dear kohagan & dsl,
Wow...your posts really make my day! :D Now I understand what part that I missed. I thought before that IRQ signal were same as IRQ bit. Ok, soon I will try your suggestions Thanks! - Altera_Forum
Honored Contributor
You need to close the loop with the ISR.
The nios interrupts are level sensitive, so if the hardware removes the IRQ signal (to the cpu) and the cpu was running with interrupts disabled, then the interrupt wont be detected. - Altera_Forum
Honored Contributor
Dear all,
I have followed your instructions in the previous posts, but it still doesn't work (I think my C-code is wrong) :( I attach the snapshot of the configuration of my component in SOPC builder. As your suggestions I added an additional Avalon MM slave that is responsible to store the IRQ bit (I named it 'interrupt handler'). This Avalon MM consists of this following signals : - IRQ_bit (the register that stores the IRQ bit, the signal type is readdata) - READ_IRQ (read signal of the Avalon MM slave to read the IRQ_bit) - interrupt (the register that used to set / clear the IRQ_bit) - interrupt_en (write signal of the Avalon MM slave to clear the IRQ_bit). The interrupt sender is assigned to this Avalon MM slave (interrupt handler). I also attach the verilog code of my component and its testbench. And here is the snapshot of my C code :
When I ran my program, the program didn't recognize the interrupt. The SignalTap showed that when the IRQ signal (wrfinish) was active, the IRQ bit (IRQ_bit) was also active which meant there was no mistake in the hardware (I think..). So the problem should be in my C code... Would you check my verilog code and the above C code? Hope you can help me to find where the problem is..:( Thanks a lotvolatile int fifo_interrupt; # ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT void FIFOinterrupt_handler(void* context) # else void FIFOinterrupt_handler(void* context, alt_u32 id) # endif { INT8U error_code; volatile int* fifo_interrupt_ptr = (volatile int*) context; printf("IRQ bit 1 : %d\n",IORD(FIFIO_DUALWIDE_INTERRUPT_HANDLER_BASE,0)); *fifo_interrupt_ptr = IORD(FIFIO_DUALWIDE_INTERRUPT_HANDLER_BASE,0); // get the IRQ bit IOWR(FIFIO_DUALWIDE_INTERRUPT_HANDLER_BASE,0,0x0); // clear the IRQ bit printf("IRQ bit 2 : %d\n",IORD(FIFIO_DUALWIDE_INTERRUPT_HANDLER_BASE,0)); OSSemPost(DMAActvSem); alt_uCOSIIErrorHandler(error_code, 0); IORD(FIFIO_DUALWIDE_INTERRUPT_HANDLER_BASE,0); } void main() { ..... ..... void* fifo_interrupt_ptr = (void*) &fifo_interrupt; printf("IRQ bit 0 : %d\n",IORD(FIFIO_DUALWIDE_INTERRUPT_HANDLER_BASE,0)); IOWR(FIFIO_DUALWIDE_INTERRUPT_HANDLER_BASE,0,0x0); // reset the IRQ bit printf("IRQ bit 0 : %d\n",IORD(FIFIO_DUALWIDE_INTERRUPT_HANDLER_BASE,0)); # ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT alt_ic_isr_register(FIFIO_DUALWIDE_INTERRUPT_HANDLER_IRQ_INTERRUPT_CONTROLLER_ID, FIFIO_DUALWIDE_INTERRUPT_HANDLER_IRQ, FIFOinterrupt_handler, fifo_interrupt_ptr, 0x0); # else alt_irq_register(FIFIO_DUALWIDE_INTERRUPT_HANDLER_IRQ, fifo_interrupt_ptr, FIFOinterrupt_handler); # endif ..... ..... }