This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Missing interrupts and their 'pending' status

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

Parents
  • 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;
    }
    
    When I used the commented version transmitting of bytes stops after a while. With the atomic instruction it works.

    Does anybody know why disabling a specific interrupt enable bit doesnt work?

    Best regards

    Bert Weber

Reply
  • 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;
    }
    
    When I used the commented version transmitting of bytes stops after a while. With the atomic instruction it works.

    Does anybody know why disabling a specific interrupt enable bit doesnt work?

    Best regards

    Bert Weber

Children
  • 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_();
    
    I would also suggest using the _atomic(0); ...; _endatomic_(); construct rather than specifiyng the number of atomic instructions explicitly. Compiler output can change between versions and compiler settings, so there is no guarantee that the fixed _atomic_(n) instruction will cover all the needed instructions.

    - mike

  • @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.