TMS320F28035: Transmitted Canbus message copies some bytes from previously sent message when spurious message is observed

Part Number: TMS320F28035

Tool/software:

Hello,

I have inherited a legacy TMS320F28035 project I'm trying to debug. There is some kind of problem in Canbus functionality. The application is a custom design OS-style program, with prioritized tasks. One task is the Canbus message handler. When Canbus interrupt is received, it sets a flag and requests scheduling the Canbus message handler.

Lets say, we have normally this message cycle (happening during only a couple of milliseconds):

MSG_ROUND_TO_ME XX YY

MSG_STATE    AA BB CC DD EE FF GG HH

MSG_MEAS     II JJ KK LL MM NN OO PP

MSG_ROUND_TO_NEXT XX YY

So, upon receiving MSG_ROUND_TO_ME , the unit sends its state information and measurements via Canbus and finally sends the MSG_ROUND token to next unit.

All good. But sometimes, there is a spurious message to the mix like in the following (can be valid, invalid, or out-of-turn). Observe:

MSG_ROUND_TO_ME XX YY

???                   QQ RR SS TT

MSG_STATE    AA BB CC DD EE FF GG HH

MSG_STATE    AA BB KK LL MM NN OO PP

MSG_ROUND_TO_NEXT XX YY

So, what happens is that

  1. MSG_STATE is send succesfully as earlier
  2. Next message (should be MSG_MEAS) contains actually MSG_STATE bytes AA BB as first 2 bytes, but then contains the proper MSG_MEAS data bytes KK LL MM NN OO PP

So in other words, when trying to send MSG_MEAS, we get remnant bytes from the message we previously send.

What might be going wrong here?

The interrupt handler:

interrupt void isrCAN0(void)
{
  u8TaskStatus |= CAN_TASK;
  bCanInt=TRUE;
  vOS_Scheduler();
  return;
}

Here is part of the Canbus handler task:

if(!bCanInt)
{
  vOS_Wait(Timeout);
}

if(bCanInt)
{
  bCanInt = FALSE;

  while(ECanaRegs.CANRMP.all != 0)
  {
    // another frame received
    vProcessMBOX(ECanaRegs.CANGIF0.bit.MIV0));
  }
  PieCtrlRegs.PIEACK.bit.ACK9 = 1;
}


Paraphrased vProcessMBOX(X):

void vProcessMBOX(X)
{
  vSendCan(MSG_STATE);
  vOS_Wait(1 TICK);
  vSendCan(MSG_MEAS);
  vOS_Wait(1 TICK);
  vSendCan(MSG_ROUND_TO_NEXT);
  vOS_Wait(1 TICK);

  // Clear message flag of the corresponding MBOX, X=6,7 or 8
  ECanaRegs.CANRMP.bit.RMPX = 1;
}

Paraphrased vSendCan(MSG):

void vSendCan(MSG):
{
  bool bRet = FALSE;

  ECanaShadow.CANTA.all = ECanaRegs.CANTA.all;
  ECanaShadow.CANTA.bit.TA0 = TRUE;// transmission acknowledge
  ECanaRegs.CANTA.all = ECanaShadow.CANTA.all;

  ECanaShadow.CANME.all = ECanaRegs.CANME.all;
  ECanaShadow.CANME.bit.ME0 = FALSE;
  ECanaRegs.CANME.all = ECanaShadow.CANME.all;

  // disable mailbox
  ECanaShadow.CANME.all = ECanaRegs.CANME.all;
  ECanaShadow.CANME.bit.ME0 = FALSE;
  ECanaRegs.CANME.all = ECanaShadow.CANME.all;

  ECanaMboxes.MBOX0.MSGID.bit.STDMSGID = MSG->Id;// id

  // enable mailbox
  ECanaShadow.CANME.all = ECanaRegs.CANME.all;
  ECanaShadow.CANME.bit.ME0 = TRUE;
  ECanaRegs.CANME.all = ECanaShadow.CANME.all;

  ECanaMboxes.MBOX0.MDL.byte.BYTE0 = MSG->Data.Byte.Byte0;// data bytes
  ECanaMboxes.MBOX0.MDL.byte.BYTE1 = MSG->Data.Byte.Byte1;
  ECanaMboxes.MBOX0.MDL.byte.BYTE2 = MSG->Data.Byte.Byte2;
  ECanaMboxes.MBOX0.MDL.byte.BYTE3 = MSG->Data.Byte.Byte3;
  ECanaMboxes.MBOX0.MDH.byte.BYTE4 = MSG->Data.Byte.Byte4;
  ECanaMboxes.MBOX0.MDH.byte.BYTE5 = MSG->Data.Byte.Byte5;
  ECanaMboxes.MBOX0.MDH.byte.BYTE6 = MSG->Data.Byte.Byte6;
  ECanaMboxes.MBOX0.MDH.byte.BYTE7 = MSG->Data.Byte.Byte7;

  ECanaMboxes.MBOX0.MSGCTRL.bit.DLC = msg->Length;// length

  ECanaShadow.CANTRS.all = ECanaRegs.CANTRS.all;
  ECanaShadow.CANTRS.bit.TRS0 = TRUE;     // send message
  ECanaRegs.CANTRS.all = ECanaShadow.CANTRS.all;

  vRefreshWatchdog();
  vOS_Delay(2000);

  if (!ECanaRegs.CANTA.bit.TA0 && ECanaRegs.CANTRS.bit.TRS0)
  {
    // transmit failed
    bRet = TRUE;
  }

  return bRet;
}

I see some things are sub-optimal and different from example codes, but are there obvious critical flaws which would make the message sending copy bytes from ealier sent message?

  • Hmm, found this from reference manual

    "For send mailboxes, an access is usually denied if the TRS (TRS.31-0) or the TRR (TRR.31-0) flag is set. In these cases, an interrupt can be asserted. A way to access those mailboxes is to set CDR (CANMC.8) before accessing the mailbox data."

    Hmm, maybe..

    Maybe it happens so that while MSG_STATE is being sent, there is the spurious Canbus message in, causing just enough delay that message is not sent in time (remember, we just send the message, wait some time with NOPs, then determine result and do nothing with the result). Then we start sending the MSG_MEAS, but access to mailbox data is initially denied, so message ID / first data bytes are unchangeable. But exactly after 2nd byte the message is marked sent for real, and access to mailbox data is allowed. Need to test this theory.

  • Hi Janne,

    Yes, please give that a try.  Instead of waiting with NOPs after transmission, probably good to poll CANTA register to confirm that the mailbox used by MSG_STATE has sent successfully before sending another one

    Best regards,

    Joseph

  • I changed the canbus handling code so that it goes on trying the send even if there is new inwards message delay. I made a loop waiter (and not a busy-loop register poller) because I was not 100% sure that all timings in this monstrosity play out well otherwise. In our initial tests it seems this might have fixed the "copied bytes" problem.

    I will keep the thread posted, but probably the problem was what I speculated in a comment that sporadic inwards message makes the regular sender function stall the send so much that the mailbox data is locked some time during the next send and this next send is only able to fill in the tail of the canbus message, essentially creating a corrupted message with header from message A and data from message B.

    Edit: Still going strong. Zero problems, marking as fix.