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

CAN RX FIFO on XE164

Hi,

I'm using CAN communication on an XE164 (MultiCAN). Currently, I'm trying to use an RX FIFO and not having much luck with it. The FIFO is set up using DAVE, but when I watch in the debugger I can see that only the first slave object (BOT) is ever filled. The pointer CUR is not advanced after reception, it remains set on the BOT object. The PNEXT of the BOT object does point to the next slave object, and all other BOT/TOP pointers appear to be correct.

Can anyone figure how this might happen?

Regards,
Alto Speckhardt

  • I probably shouldn't post in this thread, since I don't know anything at all (!) about your chip.

    But a FIFO normally has a single read address/register and a single write address/register and is controlled by flags: transmit empty, transmit not empty, transmit not full, transmit full, receive empty, receive not empty, receive not full, receive full (or a subset of the flags). So when you get a receive interrupt, the code may do: while (!receive_empty) get_entry();

    Your symbols BOT, CUR, PNEXT etc sounds more like a linked list.

    Might you have two different concepts in your project? One hardware-controlled FIFO in the CAN controller, and then a software-based external queue in the form of a linked list? A hw FIFO is normally of a very limited size, while a sw queue/list may allow a large number of entries to be buffered.

    In that case, you may have a situation where you never fill more than one object in your software-based queue/list because you are always fast enough to process this entry before a new entry gets picked up from the hw FIFO.

  • Hi,

    thanks for your answer.

    What you're referring to, the different kinds of hardware/software FIFO, is exactly what I'm concerned with now. I'm just in the process of changing architectures, the new one being the XE. On the old one (a 8051 based design) I did have to use the pure software approach. The XE, however, promises to do the same thing in hardware: You can chain a number of CAN message objects, link them together and use them for one message ID only. There is a single "base" object, which maintains the reference to all involved "slave" objects. Each slave object has a PNEXT pointer to the next slave object, the base object has a CUR pointer to the slave object that is currently in use. Again, this is all in hardware.

    Now, in a RX FIFO, the way it is supposed to work is that after each single received CAN message the CUR pointer in the base object should advance to the next object in the chain as referred to by the first object's PNEXT pointer. This advancement of CUR in my understanding should happen on every receive, regardless of the degree to which the FIFO is filled already.

    And here, it simply doesn't do that. ;-)

    Regards,
    Alto Speckhardt

  • "This advancement of CUR in my understanding should happen on every receive, regardless of the degree to which the FIFO is filled already."

    What you are saying is that the hardware does not use a hardware FIFO, but a hardware ring buffer.

    A FIFO only exports a push function on one side (normally hidden inside the hardware for the receive FIFO) and a pop function on the other side. It does not show - or allow access to - anything in the middle. Many FIFO don't even export the number of entries currently stored in the FIFO - just the special cases "empty" and "full" and possibly "non-empty" and/or "non-full".

  • One might say the logic of a buffer depends on the methods accessing it, not in the ways the information is stored internally. The suggested handling by software is according to FIFO, and that's how the reference methods generated by DAVE are implemented. The designation "FIFO", which is used throughout the datasheet, is in my opinion therefore justified.

  • I have some code that used the RX/TX FIFO's for the TC1797 basically the same CAN module as the XE164.

    I am not sure of all of your initialization but in my case the CUR pointer does advance as you receive messages.

    Perhaps, my snippet of code could be of use.

      /* configure MO16 as the base object for the receive FIFO */
      CAN_MOCTR16.U = 0x00800000u;
    
      CAN_MOFCR16.U = RX_FIFO_BASE_OBJECT | RX_IE;
    
      /* configure the FIFO setup using MO16 thru MO31 for receive FIFO */
      CAN_MOFGPR16.U = (16u  )      | /* bottom pointer         : MO16 */
                       (31u <<  8u) | /* top pointer            : MO31 */
                       (16u << 16u) | /* current select pointer : MO16 */
                       (31u << 24u);  /* object select pointer  : MO31 */
    
      /* accept reception of standard and extended frames */
      /* acceptance mask 29-bit: 0x1FFFFFFF, acceptance mask 11-bit: 0x7FF */
      CAN_MOAMR16.U = 0u; /* Accept any message 29/11 bit identifiers */
    
      CAN_MODATAL16.U = 0u;
      CAN_MODATAH16.U = 0u;
    
      /* receive acceptance filtering is based on the CAN identifier */
      CAN_MOAR16.U = 0x80000000u;
    
      /* configure message object interrupt pointer */
      CAN_MOIPR16.U = ( 3u       ) | /* RXINP receive interrupt pointer, SRN3 */
                      ( 15u << 4u) | /* TXINP transmit interrupt pointer, SRN15 */
                      ( 16u << 8u);  /* MPN, msg pending number is 0 */
    
      /* set message object valid */
      CAN_MOCTR16.U = MSGVAL;
    
      /* configure slave objects for receive FIFO */
      for (i = 1, dst = (U32 *) &CAN_MOFCR17.U; i < 16; i++) {
        *dst++       = RX_IE; /* enable receive interrupt */
        *dst++       = 0u;
        *dst++       = 0x10F3u; /* set all interrupts to the same pointer */
        *dst++       = 0u;
        *dst++       = 0u;
        *dst++       = 0u;
        *dst++       = 0x80000000u;
        *dst++       = MSGVAL;
      }
    
    

    From the interrupt handler...

    void __interrupt(RTOS_CAN0_RX_IRQ_LVL) CAN_Rx_SRN3(void) {
      U32 id;
      U32 rxHeadCurIdx;
    
      CAN_MSIMASK.U = 0x00010000u; /* set message index mask register MO16 */
    
      while (CAN_MSID0.U != NO_MSG_WAITING) {
    
        if (CAN_HWOBJ[16].MOCTR & SET_NEWDAT) { /* if NEWDAT is set */
    
          rxHeadCurIdx = CAN_HWOBJ_RX_BASE_CUR;
    
          id = CAN_HWOBJ[rxHeadCurIdx].MOAR;
    
          /* is this a standard or extended message */
          if (id & 0x20000000u) {
            canRx[rxHeadIdx].id = id & 0x1FFFFFFFu;      /* EXT*/
          }
          else {
            canRx[rxHeadIdx].id = (id >> 18u) & 0x07FFu; /* STD */
          }
    
          /* unload the data and also the dlc value */
          canRx[rxHeadIdx].data.w.h = CAN_HWOBJ[rxHeadCurIdx].data.w.h;
          canRx[rxHeadIdx].data.w.l = CAN_HWOBJ[rxHeadCurIdx].data.w.l;
          canRx[rxHeadIdx].dlc      = (U8)(CAN_HWOBJ[rxHeadCurIdx].MOFCR >> 24u);
    
          rxHeadIdx++;
    
          /* reset the CAN software FIFO pointer (circular buffer) */
          if (rxHeadIdx > (FIFO_RX_TOP_ARRAY)) {
            rxHeadIdx = FIFO_RX_BOT_ARRAY;
          }
    
          /* reset RXPND, NEWDAT, MSGLST */
          CAN_HWOBJ[16].MOCTR = RES_RXPND | RES_NEWDAT | RES_MSGLST;
    
          /* diagnostic to indicate number of received messages */
          rxCanCnt++;
        }
    
        CAN_MSPND0.U = ~0x00010000u;    /* reset PND bit */
      }
    }
    

  • Thank you very much for your message. I took your code apart bit by bit, yet couldn't discover much of a difference to mine. I'm not even using an interrupt, just polling for now, so it should be even less complicated in my example.

    I'm including my initialization, just in case I've become completely blind and overlooked something important. MO64 is my base object, MO65 the first slave object. The highest slave object is MO69 (not included, all following slave objects are initialized just like MO65.)

    When I run the program, all reception takes place in MO69 (the last - or first, whatever - slave object). The pointer CUR in the base object points to MO69 initially, but stays there, no matter how many messages are received (all stored in MO69).

    This is all DAVE-code, so I don't expect any great revelations: ;-)

    
      ///  -----------------------------------------------------------------------
      ///  Configuration of Message Object 64:
      ///  -----------------------------------------------------------------------
    
      ///  General Configuration of the Message Object 64 :
      ///  - message object 64 is valid
      ///  - message object is used as receive object
      ///  - this message object is assigned to list 3 (node 2)
    
        CAN_MOCTR64H = 0x00A0;       // load MO64 control register high
        CAN_MOCTR64L = 0x0000;       // load MO64 control register low
    
      ///  Configuration of Message Object 64 Arbitration:
      ///  - priority class 1; transmit acceptance filtering is based on the list
      ///    order
      ///  - standard 11-bit identifier
      ///  - identifier 11-bit:      0x050
    
        CAN_MOAR64H = 0x4140;        // load MO64 arbitration register high
        CAN_MOAR64L = 0x0000;        // load MO64 arbitration register low
    
      ///  Configuration of Message Object 64 acceptance mask:
      ///  - only accept receive frames with matching IDE bit
      ///  - acceptance mask 11-bit: 0x7FF
    
        CAN_MOAMR64H = 0x3FFF;       // load MO64 acceptance mask register high
        CAN_MOAMR64L = 0xFFFF;       // load MO64 acceptance mask register low
    
      ///  Configuration of Message Object 64 interrupt pointer:
      ///  - use message pending register 2 bit position 0
    
        CAN_MOIPR64H = 0x0000;       // load MO64 interrupt pointer register high
        CAN_MOIPR64L = 0x4000;       // load MO64 interrupt pointer register low
    
      ///  Configuration of Message Object 64 FIFO/Gateway pointer:
      ///  - current select pointer : MO69
      ///  - object select pointer : MO65
    
        CAN_MOFGPR64H = 0x4145;      // load MO64 FIFO/gateway pointer register
                                     // high
      ///  - bottom pointer : MO69
      ///  - top pointer : MO65
        CAN_MOFGPR64L = 0x4145;      // load MO64 FIFO/gateway pointer register
                                     // low
    
    
      ///  Configuration of Message Object 64 Function control:
      ///  - this object is a RECEIVE FIFO BASE OBJECT
      ///  - 8 valid data bytes
    
        CAN_MOFCR64H = 0x0800;       // load MO64 function control register high
        CAN_MOFCR64L = 0x0001;       // load MO64 function control register low
    
      ///  -----------------------------------------------------------------------
      ///  Configuration of Message Object 65:
      ///  -----------------------------------------------------------------------
    
      ///  General Configuration of the Message Object 65 :
      ///  - message object 65 is valid
      ///  - message object is used as receive object
      ///  - this message object is assigned to list 3 (node 2)
    
        CAN_MOCTR65H = 0x00A0;       // load MO65 control register high
        CAN_MOCTR65L = 0x0000;       // load MO65 control register low
    
      ///  Configuration of Message Object 65 Arbitration:
      ///  - priority class 1; transmit acceptance filtering is based on the list
      ///    order
      ///  - standard 11-bit identifier
      ///  - identifier 11-bit:      0x050
    
        CAN_MOAR65H = 0x4140;        // load MO65 arbitration register high
        CAN_MOAR65L = 0x0000;        // load MO65 arbitration register low
    
      ///  Configuration of Message Object 65 acceptance mask:
      ///  - only accept receive frames with matching IDE bit
      ///  - acceptance mask 11-bit: 0x7FF
    
        CAN_MOAMR65H = 0x3FFF;       // load MO65 acceptance mask register high
        CAN_MOAMR65L = 0xFFFF;       // load MO65 acceptance mask register low
    
      ///  Configuration of Message Object 65 interrupt pointer:
      ///  - use message pending register 2 bit position 1
    
        CAN_MOIPR65H = 0x0000;       // load MO65 interrupt pointer register high
        CAN_MOIPR65L = 0x4100;       // load MO65 interrupt pointer register low
    
      ///  Configuration of Message Object 65 FIFO/Gateway pointer:
    
        CAN_MOFGPR65H = 0x0000;      // load MO65 FIFO/gateway pointer register
                                     // high
        CAN_MOFGPR65L = 0x0000;      // load MO65 FIFO/gateway pointer register
                                     // low
    
    
      ///  Configuration of Message Object 65 Function control:
      ///  - this object is a RECEIVE FIFO SLAVE OBJECT connected to the base
      ///    object 64
      ///  - 0 valid data bytes
    
        CAN_MOFCR65H = 0x0000;       // load MO65 function control register high
        CAN_MOFCR65L = 0x0000;       // load MO65 function control register low
    
    
    
    

  • One more note: When I manually change the pointer CUR from MO69 to, say, MO66, the reception still occurs in MO69.

    Did I miss something in activating the FIFO in the first place, so that no FIFO handling takes place at all and the message is simply received by the highest priority object that has the identifier configured - which happens to be MO69?

  • Hum... My experience is DAVE is not always right :(

    Anyway, I could try to use DAVE for a setup but don't have time until next week at the earliest to test it.

    I do see a problem that you (DAVE) is setting the RXEN bit in a slave object.

      ///  General Configuration of the Message Object 65 :
      ///  - message object 65 is valid
      ///  - message object is used as receive object
      ///  - this message object is assigned to list 3 (node 2)
    
        CAN_MOCTR65H = 0x00A0;       // load MO65 control register high
        CAN_MOCTR65L = 0x0000;       // load MO65 control register low
    

    My code...

     *dst++ = MSGVAL; /* MOCTR */
    

    From the manual...

    In order to avoid direct reception of a message by a slave message object, as if it was an independent message object and not a part of a FIFO, the bit RXEN of each slave object must be cleared. The setting of the bit RXEN is "don't care" only if the slave object is located in a list not assigned to a CAN node.

    Maybe you could change this and see if you get a different behavior?

    Regards, Chris

  • Hum... My experience is DAVE is not always right :(

    Well... ;-)

    I do see a problem that you (DAVE) is setting the RXEN bit in a slave object.

    Yes, you're absolutly right! When I began to manually (after the DAVE initialization) reset the RXEN bits in the slave objects the FIFO started to work as expected.

    Thank you very much indeed!

    Regards,
    Alto Speckhardt