#967 PIC16: Signal dispatcher doesn't check **IE bits

closed-accepted
5
2013-05-25
2005-08-07
Peter Onion
No

I've found a problem with the scheme used poll the
device interrupt flags .

My C code has these definitions for the signal handlers.

/* Set up the interrupt handlers */

DEF_INTHIGH(high_int)
DEF_HANDLER(SIG_RC, _RC_handler)
DEF_HANDLER(SIG_TX, _TX_handler)
DEF_HANDLER(SIG_TMR2, _TMR2_handler)
DEF_HANDLER(SIG_TMR0, _tmr0_handler)

END_DEF

The order of the lines above is CRITICAL as it
determines the order the interrupt flags are checked.
Here is the corresponding code in the .asm file

; ; Starting pCode block
S_picklenet0__high_int code
_high_int:

btfsc _PIR1, 0x5
goto __RC_handler
btfsc _PIR1, 0x4
goto __TX_handler
btfsc _PIR1, 0x1
goto __TMR2_handler
btfsc _INTCON, 0x2
goto __tmr0_handler
retfie

The problem concerns the fact that only the TXIE bit
(_PIR1:4) is checked before jumping to the handler.
The Microchip application note
Asynchronous Communications with the PICmicroŽ USART
AN774 contains example code for using the transmit
interrupt which contains this section

btfss PIR1,TXIF ;test for TXIF
transmit interrupt flag
bra LowInt1 ;if TXIF is not set,
done with test
btfsc PIE1,TXIE ;else test if Tx
interrupt is enabled
bra PutData ;if so, go transmit data

;can do special error handling here - an unexpected
interrupt occurred

LowInt1:

[SNIP]

PutData: btfss Flags,TxBufEmpty ;check if transmit
buffer is empty
bra PutDat1 ;if not then go transmit
bcf PIE1,TXIE ;else disable Tx
interrupt
bra EndLowInt

PutDat1: rcall GetTxBuffer ;get data from
transmit buffer
movwf TXREG ;and transmit

When there is nothing more to send, TXIE is cleared to
prevent the transmitter triggering any more interrupts
but TXIF is not reset because no character is written
to TXREG. When the next character is available all
that is required is to set TXIE and because TXIF is
still set an interrupt will occur.

The sdcc signal handler code does NOT allow for the
possibility that TXIF may be set even though it was not
the USART that triggered the interrupt. If TXIF is set
it always jumps to the handler. If the correct handler
is further down the list an interrupt dead lock occures.

My solution is an extended version of the DEF_HANDLER
macro which allows both **IE and **IF bits to be
checked before jumping to a handler. (Note I've used
the SIG_ prefixes to avoid clashes as I detailed in an
earlier post)

#define SIG_TXIF 0x4

#define SIG1_TX _PIR1, SIG_TXIF
#define SIG2_TX _PIE1, SIG_TXIF

#define DEF_HANDLER2(sig1,sig2, handler) \ btfss sig1 \n\ bra $+8 \n\ btfsc sig2 \n\ goto _ ## handler

It is used like this...

DEF_HANDLER2(SIG1_TX, SIG2_TX,_TX_handler)

Peter

Discussion

  • Peter Onion
    Peter Onion
    2005-08-07

    Logged In: YES
    user_id=1316390

    Typo in the above... It shoud read
    "The problem concerns the fact that only the TXIF bit
    (_PIR1:4) is checked before jumping to the handler."
    Peter

     
  • Raphael Neider
    Raphael Neider
    2005-08-07

    • milestone: --> fixed
    • assigned_to: nobody --> tecodev
    • status: open --> closed-accepted
     
  • Raphael Neider
    Raphael Neider
    2005-08-07

    Logged In: YES
    user_id=1115835

    "Fixed" in SDCC 2.5.2 #1083 (provided means to achieve the
    desired effect; users have to modify their code).

    I added SIG_<src>IE definitions for all signals and added
    the proposed DEF_HANDLER2() macro so that one can use
    DEF_HANDLER2(SIG_TX, SIG_TXIE, _TX_handler)
    to achieve the desired effect.
    (Note that for signals outside of PIR/PIE the enable bit
    definition cannot be deduced from the flag definition --
    this makes the definitions rather ugly...)