This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DCAN TX after RX not working

Other Parts Discussed in Thread: HALCOGEN

 

TMS570LS1227 Interrupt driven DCAN
 
I am working on a controller board that communicates with a display.
The controller sends display messages and receives keystroke message.
The controller uses CAN3 for display RX/TX communcations.
I am using a CANUSB monitor to track the messaging.
When the controller only transmits messages, everything works fine.
When the controller only receives messages, by commenting the mainline code below, everything works fine.
If I let the controller transmit messages for a while, the touch a key on the display, the display transmits info.
The controller receives the message in MB4 properly. But the next time the controller sends a message,
The canMessageNotification never gets called to set the disp_tx_done flag and the code hangs in the mainline at the while loop.
During this time, the controller continues to properly receive messages from the display.
What am I doing wrong?
Sorry in advance for the font weirdness below.
 
===============================================================
250kHz, Identifier Extension Enabled
Message 1 Config = IntEn,HighPri,Activate,TX, id=4433, mask=0x01FFFFFF
Message 4 Config = IntEn,HighPri,Activate,RX, id=0x123456, mask=0x01FFFFFF
========================================================
MainLine Code:
Every 250ms I transmit a message
disp_tx_done=FALSE;
canTransmit(canREG3, canMESSAGE_BOX1, &displayinfo[0]);
while(disp_tx_done==FALSE);
 
 =======================================================================
Interrupt Code:
void canMessageNotification(canBASE_t *node, uint32_t messageBox){
     if(node==canREG3){
          if( canIsRxMessageArrived(canREG3, messageBox) ){
            canGetDataID(canREG3, messageBox, disp_data, &disp_Identifier);
              if( (disp_Identifier&0x1FFFFFF)==DISP1_CAN_ADDR ){
                  memcpy((uint8_t *)&cops_datain,(uint8_t *)&disp_data,8);
               UseDisplayInputs();
            }
       }else{
             if( messageBox<4 )
                disp_tx_done=TRUE;
         }
     }
}
 
void canErrorNotification(canBASE_t *node, uint32_t notification){
    if( notification ){ // don't show ZERO as notification
        if(node==canREG3 )
            sprintf((char *)outStr, "Can3ER: %d",notification);
       SerialPutString((char *)outStr);
    }
}
 
 
============================================================

  • Jeff,

    Not an expert on CAN but looking at the HalCoGen driver code, which I assume you're building on, I can see very careful management of the IF1 and IF2 register set.

    What is the code for canGetDataID?  (I generated code through HalCoGen and got 'canGetData' but not a 'canGetDataID' function...    I'd wonder if this somehow might be disturbing the careful usage of IF1/2.

    Second question would be - once the CAN transmit has stopped, what are the CAN register values?  There might be clues there to understand why it's stopped.

     

  • I wish I was a CAN expert.  Yes, I'm using the HalCoGen to generate the code.

    What's up with the text formatting when entering these responses?  I'd like to get out of the Paragraph formatting.  Each pulldown entry I use 'messes' up the text.

    It seems like I'm missing a 'big picture' item.  Like having to tell the CAN subsystem to enable TX after receiving something.

    I switched to 11 bit ID mode and got the same issue.

     

    Here is my updated mainline code:

    disp_tx_done=FALSE;

    canTransmit(canREG3, canMESSAGE_BOX1, &txstatus[0]);

    while(disp_tx_done==FALSE){

        can3GetConfigValue(&can3regs,CurrentValue);

    }

    can3GetConfigValue(&can3regs,CurrentValue);

    I checked the Registers after a good transmission and got this: 

    _CTL=0x0002140A

    _ES=0x00000008      <<< this varies between 7 and 8

    _BTR=0x000058D3

    _TEST=0x00000080

    _ABOTR=_INTMUX0=_INTMUX1=_INTMUX2=_INTMUX3=0

    _TIOC=0x0004000F

    _RIOC=0x00040009

    I checked the registers during the 'while' loop after receiving a message and got the same thing.  So there is something I'm not doing when receiving a msg.

    Is there a priority of the message boxes?  All is well when I TX message box 1,2,3 repeated.  But then stops TXing when RX on message box 4.

    What's weird is that it continues to receive properly on message box 4.

     

     

    Here is the code I used for canGetDataID:

    uint32 canGetDataID(canBASE_t *node, uint32 messageBox, uint8 * const data, uint32_t * const identifierPtr)

    {

       uint32       i;

       uint32       size;

       uint8 * pData    = data;

       uint32       success  = 0U;

       uint32       regIndex = (messageBox - 1U) >> 5U;

       uint32       bitIndex = 1U << ((messageBox - 1U) & 0x1FU);

     

       if ((!(node->NWDATx[regIndex] & bitIndex)) != 0U)    {

            success = 0U;

        }  else    {

       /** - Wait until IF2 is ready for use */

    while ((node->IF2STAT & 0x80U) ==0x80U )    {    }/* Wait */

       /** - Copy data into IF2 */

        node->IF2NO = (uint8) messageBox;   

    /** - Wait until data are copied into IF2 */

    while ((node->IF2STAT & 0x80U) ==0x80U  )    {    }

       /** - Get number of received bytes */

        size = node->IF2MCTL & 0xFU;

         for (i = 0U; i < size; i++)    {

    #ifdef__little_endian__

            *pData = node->IF2DATx[i];

            pData++;

    #else

            *pData = node->IF2DATx[s_canByteOrder[i]];

             pData++;

    #endif

        }

     

         while (node->IF1STAT & 0x80);

        node->IF1CMD  = 0x20; // read command (arbitration bits only)

        node->IF1NO   = messageBox;

        *identifierPtr = node->IF1ARB; // record the identifier that went with the data

        success = 1U;

        }

       if ((node->IF2MCTL & 0x4000U) == 0x4000U)    {

            success = 3U;

        }   

    return success;

    }

  • OK, it's fixed now.  And again, my fault.

    I updated the canGetDataID function to restore the ->IF2CMD register.  Now it works properly.

    Here is the Updated code:

    uint32 canGetDataID(canBASE_t *node, uint32 messageBox, uint8 * const data, uint32_t * const identifierPtr){

        uint32       i;

        uint32       size;

        uint8 *pData= data;

        uint32       success  = 0U;

        uint32       regIndex = (messageBox - 1U) >> 5U;

        uint32       bitIndex = 1U << ((messageBox - 1U) & 0x1FU);

        uint8 oldctlval;

        if ((!(node->NWDATx[regIndex] & bitIndex)) != 0U){

            success = 0U;  // if no new data, return 0

        }else{

        while ((node->IF2STAT & 0x80U)==0x80U ); // Wait until IF2 is ready for use

        node->IF2NO = (uint8) messageBox; // Copy data into IF2

        while ((node->IF2STAT & 0x80U)==0x80U );  //Wait until data are copied into IF2

        size = node->IF2MCTL & 0xFU;  // Get number of received bytes */

        for (i = 0U; i < size; i++){  // Copy RX data into destination buffer */

    #ifdef __little_endian__

            *pData = node->IF2DATx[i];

            pData++;

    #else

            *pData = node->IF2DATx[s_canByteOrder[i]];

            pData++;

    #endif

    }

            if ((node->IF2MCTL & 0x4000U) == 0x4000U) {

                success = 3U;  // signal data lost

            }

        while ((node->IF2STAT & 0x80U)==0x80U ); // Wait until IF2 is ready for use

        oldctlval=node->IF2CMD;

        node->IF2CMD  = 0x20; // read command (arbitration bits only)

        while ((node->IF2STAT & 0x80U)==0x80U ); // Wait until IF2 is ready for use

    *identifierPtr = node->IF2ARB; // record the identifier that went with the data

        while ((node->IF2STAT & 0x80U)==0x80U ); // Wait until IF2 is ready for use

        node->IF2CMD= oldctlval;

        while ((node->IF2STAT & 0x80U)==0x80U ); // Wait until IF2 is ready for use

    success = 1U;

        }

        return success;

    }

  • Jeff,

    Great!  My take on this is that you have to be very careful managing the IF register sets, since they're not able to be written atomically.    I'd almost even consider putting a 'critical section' around the IF register writes but it looks like it is managable with 2 IF register sets (one for writes, the other for reads) as long as you're really careful.