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
Hi, I got a similar problem. Protecting code by setting the IE bit of a specific interrupt did work properly. It was the serial transmit interrupt. Only after changing to disable the global interrupts or using atomic instructions it was working. Here my code:
void Tx_irq(void) interrupt S0TINT = 42 { if (s_iTxWrite != s_iTxRead) // buffer not empty? { S0TBUF = TxBuffer[s_iTxRead++]; // transmit the next character if (s_iTxRead >= BUFFER_SIZE) // handle buffer wrap around s_iTxRead = 0; } else { s_bTxRestart = 1; // transmit must be restarted } } BYTE far SerWriteByte(BYTE byte) { int iNextWriteIndex = s_iTxWrite + 1; // handle buffer wrap around if (iNextWriteIndex >= BUFFER_SIZE) iNextWriteIndex = 0; while (iNextWriteIndex == s_iTxRead); // wait until free buffer space is available _atomic_(4); // CLEAR_FLAG(S0TIC, IC_IE(1)); // disable send interrupt TxBuffer[s_iTxWrite] = byte; _atomic_(2); s_iTxWrite++; _atomic_(4); if (s_iTxWrite >= BUFFER_SIZE) // handle buffer wrap around s_iTxWrite = 0; // SET_FLAG(S0TIC, IC_IE(1)); // enable send interrupt if (_testclear_(s_bTxRestart)) { S0TIR = 1; // start transmiting } return byte; }
If I remember correctly, in the C16x family of MCUs the CPU will execute one or more instructions following the flag clear instruction before it takes effect. Again, I might be wrong, but that is not the case with the XC16x family. To make sure that the interrupts are disabled when they need to be, append extra NOPs:
SOTIE = 0; _nop_(); _nop_(); _nop_();
@Mike Yes you are right, there must one instruction after clearing the interrupt enable bit. I checked this in the disassembler that the next instruction doesent need protection. But my tests got also the same problem with a nop after clearing the enable bit and I dont know why? Reagarding the usage of the atomic instructions, _atomic(0); ...; _endatomic_(); supports only 4 instructions and the compiler will not stack them. Ok, if I need more than one atomic instruction, than I can also disable the global interrupt flag. Still strange why it was not working disabling the SOTIE interrupt enable flag. Bert
Still strange why it was not working disabling the SOTIE interrupt enable flag. After a long look at the code you posted the only thing I can come up with is that maybe s_iTxRead or s_iTxWrite are not declared as volatile?
Only s_iTxRead and the restartflag are declared as volatile, because only this two are change inside the interrupt function.