Menu

PIC driver use of ICODE in RX interrupt

2015-11-19
2016-01-06
  • Jens Nielsen

    Jens Nielsen - 2015-11-19

    Hi

    I'm using the driver from PIC24H_dsPIC33F and I think I have found an issue with it.

    I'm troubleshooting a problem with Rx interrupt not hitting anymore after I've halted execution with a debugger. I think it's because the CAN peripheral doesn't freeze and continues to receive messages, and therefore enters an overflow condition from which we don't recover.

    The interrupt routine in this driver checks ICODE and handles one Rx message if ICODE points to an Rx buffer, but I don't think this works if there's more than one Rx message pending. As far as I understand this is how it works:

    • A message is put in TRB1 -> RXFUL1=1, ICODE=1, RBIF=1
    • A second message is put in TRB2 -> RXFUL2=1, ICODE=2
    • Interrupt handler is called, finds ICODE==2, serves TRBUF2, sets RXFUL2=0 and RBIF=0

    Now I think TRB1 is lost forever. One could think that a new interrupt is generated and ICODE is updated to 1 since RXFUL1 is still set, since ICODE is pretty useless otherwise, but that's not the behaviour I'm seeing. The lack of examples and vagueness of documentation is disturbing, this is all I have on the subject:

    When a message is successfully received and loaded into one of the receive buffers (message
    buffers 0 to 31), the receive buffer interrupt (CiINTF<RBIF>) is activated after the module sets
    the CiRXFULm<RXFULn> bit. The ICODE bits indicates the particular buffer which generated
    interrupt.

    I.e. RBIF and ICODE is only updated upon reception of a new message, right?

    I did a quick and dirty fix like this, and it works much better

        //ICODE = CAN_REG(CANmodule->CANbaseAddress, C_VEC) & 0x1F;
    
        /* receive interrupt (New CAN messagge is available in RX FIFO buffer) */
        //if(ICODE > 0){
        if(CAN_REG(CANmodule->CANbaseAddress, C_INTF) & 0x02) //RBIF
        {
            volatile uint16_t C_RXFUL1copy;
    
            CO_DISABLE_INTERRUPTS();
            C_CTRL1old = CAN_REG(CANmodule->CANbaseAddress, C_CTRL1);
            CAN_REG(CANmodule->CANbaseAddress, C_CTRL1) = C_CTRL1old & 0xFFFE;     /* WIN = 0 - use buffer registers */
            C_RXFUL1copy = CAN_REG(CANmodule->CANbaseAddress, C_RXFUL1);
            CAN_REG(CANmodule->CANbaseAddress, C_CTRL1) = C_CTRL1old;
            CO_ENABLE_INTERRUPTS();
    
            for ( ICODE = 0; ICODE < 16; ICODE++ )
            {
                if(C_RXFUL1copy & (1 << ICODE))
                {
                    ... insert old message handling code here
                }
            }
    
            /* Clear interrupt flag */
            CAN_REG(CANmodule->CANbaseAddress, C_INTF) &= 0xFFFD;
        }
    

    What do you think?

    Best Regards
    /Jens

     
  • Janez

    Janez - 2016-01-06
     

Log in to post a comment.