This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi - I'm using Micrium uCos III with a TMS570LC4357 and am trying to debug a phantom interrupt issue. I've read spna063.pdf and still don't quite understand the core/VIM dependencies regarding the prevention of phantom interrupts. Is there a document that more clearly describes how the index register (IRQINDEX, offset 0 in the VIM) is updated/cleared based on interrupts occurring and masking activity? And also how the core is triggered during this process? A timing diagram would be GREAT. Even a logic diagram would help if it illustrates the race condition that is described in scenario 2 of spna063.
In my current configuration there are 2 interrupts enabled, RTI (index = 4, IRQ channel = 3) and DCAN3 (index = 46, IRQ channel = 45). FIQ is not used. All interrupts are funneled through the IRQ vector and the OS 'manages' the interrupts by masking all lower priority interrupts when servicing a particular request. I'm seeing two situations -
1. RTI occurs, and when interrupts are re-enabled, a nested CAN interrupt occurs which when serviced, winds up having a "0" in the index register. Note, the way I can tell which IRQ I'm dealing with is I added some assembly code early on in the service to read the index and toggle a GPIO bit based on whether it's either RTI or CAN. I also toggle a GPIO bit in the Micrium 'nested irq detection' section. It seems every time a nested interrupt is detected, a phantom interrupt is generated. Although rare, I don't understand either how to prevent, or, whether it's actually a problem or not - I haven't looked at whether the frame is dropped or whether the frame is serviced at a later time.
2. A CAN interrupt occurs and another CAN interrupt nests which causes a phantom interrupt. This I REALLY don't understand because I don't re-enable interrupts during the CAN service. It's my understanding that CPSR bit 7 is set when an IRQ is serviced, thus disabling interrupts for the duration of the service. So in this case, unless interrupts are explicitly re-enabled by clearing CPSR bit 7 (which I'm not), I don't see how the CAN interrupt could possibly nest. But I'm definitely seeing it.
One of the things that doesn't seem quite right is that in the standard Micrium configuration, the IRQ index register is not read very early on in the ISR. There seems to be some housekeeping that needs to occur prior. This is just something I noticed that may or may not be an issue. But I would think fishing the index out as soon as possible might mitigate the race condition. But then again reading the index earlier might just move the same issue to an earlier time.
Any thoughts or info would be appreciated. I'll include the priority/masking routine - I added the line " if( ch_ix == 0U ) ... " to abort the service of the phantom interrupt. Without this line the code would lock up - the phantom interrupt would persist when re-enabling interrupts before the call to the specific ISR.
void BSP_IntHandlerSrc (CPU_INT16U src_id) { CPU_FNCT_PTR isr_fnct; CPU_REG32 *p_vim_tbl; CPU_INT32U ch_ix; CPU_INT32U pend_reg_0; CPU_INT32U pend_reg_1; CPU_INT32U pend_reg_2; CPU_INT32U pend_reg_3; CPU_INT32U pend_mask; switch (src_id) { case OS_CPU_ARM_EXCEPT_IRQ: ch_ix = (CPU_INT32U )BSP_INT_REG_IRQ_INDEX; if( ch_ix == 0U ) { phantomIRQcnt++; break; /*phantomInterrupt();*/ } p_vim_tbl = (CPU_REG32 *)BSP_INT_ADDR_INT_TBL; isr_fnct = (CPU_FNCT_PTR )p_vim_tbl[ch_ix]; ch_ix--; if( (ch_ix == 16u) || (ch_ix == 35u) || (ch_ix == 45u) || (ch_ix == 113u) ) { // execute ISR without enabling interrupts (*isr_fnct)((void *)ch_ix); /* Invoke ISR, and pass it the channel as the arg. */ break; } if (isr_fnct != (CPU_FNCT_PTR)0) { pend_reg_0 = BSP_INT_REG_REQENACLR0; /* Store interrupt state */ pend_reg_1 = BSP_INT_REG_REQENACLR1; pend_reg_2 = BSP_INT_REG_REQENACLR2; pend_reg_3 = BSP_INT_REG_REQENACLR3; if (ch_ix <= 31) { /* Dis. all interrupts of lower priority than current */ pend_mask = 0xFFFFFFFF << ch_ix; BSP_INT_REG_REQENACLR0 = pend_mask; BSP_INT_REG_REQENACLR1 = 0xFFFFFFFF; BSP_INT_REG_REQENACLR2 = 0xFFFFFFFF; BSP_INT_REG_REQENACLR3 = 0xFFFFFFFF; } else if (ch_ix <= 63) { pend_mask = 0xFFFFFFFF << (ch_ix - 32); BSP_INT_REG_REQENACLR1 = pend_mask; BSP_INT_REG_REQENACLR2 = 0xFFFFFFFF; BSP_INT_REG_REQENACLR3 = 0xFFFFFFFF; } else if (ch_ix <= 95) { pend_mask = 0xFFFFFFFF << (ch_ix - 64); BSP_INT_REG_REQENACLR2 = pend_mask; BSP_INT_REG_REQENACLR3 = 0xFFFFFFFF; } else { pend_mask = 0xFFFFFFFF << (ch_ix - 96); BSP_INT_REG_REQENACLR3 = pend_mask; } // execute all other ISRs with interrupts enabled CPU_IntEn(); /* Enable high-priority interrupts */ (*isr_fnct)((void *)ch_ix); /* Invoke ISR, and pass it the channel as the arg. */ CPU_IntDis(); /* Disable interrupts */ BSP_INT_REG_REQENASET0 = pend_reg_0; /* Restore original interrupt state */ BSP_INT_REG_REQENASET1 = pend_reg_1; BSP_INT_REG_REQENASET2 = pend_reg_2; BSP_INT_REG_REQENASET3 = pend_reg_3; } else { nullIRQcnt++; } break; case OS_CPU_ARM_EXCEPT_FIQ: /* See Note #1. */ default: break; } }