Hi, I'm having some difficulties in determining when and how (external) interrupts remain pending. In the users manual for the XC167ci it states that hardware arbitration leaves interrupts pending if they cannot be handled at that moment (i.e. the ILVL of the PSW is too high). I use a few macros to raise or lower the ILVL temporarily. This works great, I never miss interrupts. I figure that if an interrupt occurs when the ILVL is too high, the interrupt is buffered (pending) and it is handled the moment I lower the ILVL again. But I now would like to turn of ONE specific interrupt. I do that by clearing and setting of the CC10IE bit. It seems that interrupts that occur during the time that the CC10IE bit is of are completely gone. I.e. they do not stay 'pending', they are not buffered and handled whenever I enable the CC10IE bit again. Can anyone tell me how and when the XC167 keeps interrupts pending? Did anyone else run into this same problem? Should I enable/disable one specific interrupt in another way? Thanks for your help
But my point is: if the interrupt occurs while the xxIE bit is 0. In that case the xxIR will not get set. That is not the case. Here is an extract from the manual: An interrupt request sets the associated interrupt request flag xxIR. If the requesting interrupt node is enabled by the associated interrupt enable bit xxIE arbitration starts with the next clock cycle, or after completion of an arbitration cycle that is already in progress. All interrupt requests pending at the beginning of a new arbitration cycle are considered, independently from when they were actually requested. - mike
I ran a test using the extra NOP's. It didn't make any difference. I still miss interrupts. Using a debugger I can also determine that the xxIR bit is 0 when I detect that I missed an interrupt.
It seems I have found the cause for this problem. Your remark about the NOP got me thinking about the interruptability of the disable/enable macro's themselves. Before they were: INTR_DISABLE: CC10IC = (CC10IC & ((UINT16) ~0x0040)); INTR_ENABLE: CC10IC = (CC10IC | 0x0040); But disabling it this way would mean the assembler first needs to read the CC10IC, and it with 0x40, and then write it back. This is no way near atomic! So I changed it into this: INTR_DISABLE: CC10IE = 0; _nop(); _nop(); INTR_ENABLE: CC10IE = 1; For now this seems to have resolved my problem! I will leave my board up and running for the night and see if it keeps running well. Thanks for all your support
It sounds like you solved your problem but please allow me to offer my opinion. There is usually a simple bit operation for a global enable or disable operation( EI, DI). Encasing certain short sequences of instructions( no loops or branches!) in EI/DI protects against the kind of problem you've had. The cost is a little more delay in ISR response time now and then and usually the system will tolerate the extra delay. I don't do this casually but it's a useful method that improves system reliability. Cheers!