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.

TM4C123G CAN TX update data bytes only

Hello, I am going a bit crazy here. I am initializing the CAN module on a TM4C123 eval board with the following statements:

// can data
	can.txdata = 0xAAAAAAAA;
	can.ptxdata = (uint8_t *) (&can.txdata);

msgobject.pui8MsgData = can.ptxdata; msgobject.ui32MsgID = 1365; msgobject.ui32MsgIDMask= 0; msgobject.ui32Flags = 0; msgobject.ui32MsgLen = 4; CANMessageSet(CAN0_BASE, 1, &msgobject, MSG_OBJ_TYPE_TX);
msgobject.pui8MsgData = can.ptxdata; msgobject.ui32MsgID = 10; msgobject.ui32MsgIDMask= 0; msgobject.ui32Flags = 0; msgobject.ui32MsgLen = 4; CANMessageSet(CAN0_BASE, 2, &msgobject, MSG_OBJ_TYPE_TX);

After initialized, I would like to update the data bytes of each message object and send as needed, for which I have created the following function, as explained on datasheet 17.3.5:

// -----------------------------------------------------------------------------
// can send
// -----------------------------------------------------------------------------
void can_send(uint32_t ui32ObjID, uint32_t data){

	can.txdata = data;

    // update DA and DB registers
    HWREG(CAN0_BASE + CAN_O_IF1CMSK) |= (CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_DATAA | CAN_IF1CMSK_DATAB);

    // write to data bytes (same as _CANDataRegRead without arguments)
    can_write_data_reg();

    // set a transmit request
    HWREG(CAN0_BASE + CAN_O_IF1MCTL) |= CAN_IF1MCTL_TXRQST;

    // initiate the transfer
    HWREG(CAN0_BASE + CAN_O_IF1CRQ) = ui32ObjID & CAN_IF1CRQ_MNUM_M;

}

When I call this function, a packet is sent out but the ID does not correspond to the ID I configured in the message object. It is like it is ignoring the CAN_IF1CRQ_MNUM_M line.

Anybody have any idea what I am doing wrong here? Thanks!

  • Hello Mariano,

    What is the ID being sent out on the CAN Bus?

    Regards
    Amit
  • The last one I configured: 10.
    can_send(1,0xAA) will send ID of 10 and data of 0xAA
    can_send(2,0x55) will send ID of 10 and data of 0x55.
    So it is taking the data update but seems it is not going through the different message object.
  • Hello Mariano,

    The use of CANMessageSet API will cause the message to be transmitted, Please read the description of the API in the API User Guide.

    Regards
    Amit
  • Yes, I know CANMessageSet will send a message. It also configures the message object completely and it is a blocking function (while not busy loop inside).

    I do not need the overhead of setting the complete message. I want to configure the message object once and have a short quick function to update the data bytes when needed and transmit the message with its current settings, as described in datasheet "17.3.5 Updating a Transmit Message Object".

    Mariano

  • Hello Mariano,

    The whole point of the Busy is to ensure that message is transferred between the CAN Interface Register and the Message RAM. Avoiding the Blocking statement will run you into more issues.

    If the intent is just to update the data bytes w/o configuring the whole , then modify can_write_data_reg() to first optimize the CANMessageSet function and do the data copy there, with the Initialization being done before the can_send_data is called.

    Regards
    Amit
  • Amit, thanks for the replies.

    Yes, I understand that the Busy flag is needed. I am implementing it without using a blocking loop. I am using a separate function to check if can is ready to accept a TX transaction before calling can_send_data(), otherwise I release CPU to other processes until can tx is ready.

    I'll give this one more try with a stripped down version of CANMessageSet to see if it works.

    Thanks,
    Mariano
  • One of the problems I found:

    I send two messages back to back using TIVA's CANMessageSet with AutoRetry set to off:

    tCANMsgObject msgobject;

    CANRetrySet(CAN0_BASE, false);

    can.txdata = data;
    can.ptxdata = (uint8_t *) (&can.txdata);
    msgobject.pui8MsgData = can.ptxdata;
    msgobject.ui32MsgIDMask= 0;
    msgobject.ui32Flags = 0;
    msgobject.ui32MsgLen = 4;
    msgobject.ui32MsgID = 1365;
    CANMessageSet(CAN0_BASE, 1, &msgobject, MSG_OBJ_TYPE_TX);
    msgobject.ui32MsgID = 10;
    CANMessageSet(CAN0_BASE, 2, &msgobject, MSG_OBJ_TYPE_TX);

    Half of the time only one message goes through, the rest of the time both go out. When only ONE goes out, I get no error flag, no error count and no TX pending bit (checking CAN_STS_CONTROL, CAN_STS_TXREQUEST and CANErrCntrGet). So why is the micro not sending the second object? and why is it not flagging an error? Am I missing something here?

    Mariano

  • Hello Mariano,

    If you add a delay between the two CANMessageSet (preferably a large delay of few 10's ms) then does it send both the messages. Also is the sending of messages using a CAN Bus or is it using an internal loopback?

    Regards
    Amit
  • If I add a delay down to 1ms the problem goes away. Any thoughts on the reason of this behavior? The library checks for the BUSY bit in CANIF1CRQ, delays should not be required having busy flags and pending bits.

    I am using two eval boards with both CAN0 peripherals enabled and connected together, one board transmits and the other does nothing but ACK each message.

    Mariano
  • Hello Mariano,

    The BUSY bit is to indicate that the transfer is over between registers and RAM, but the physical transmission would still be going on. To check for physical transmission the CANSTS and CANINT registers would be used. This is given in the example code as well in TivaWare.

    Regards
    Amit
  • The example in Tivaware uses interrupts, I am not using interrupts. I have tested both BUSY flag and TXOK flag through CANStatusGet to send two messages back to back, still lose a message and get no error back. I have tested CANTXRQ1 and still lose messages. What other flag am I missing?

    	tCANMsgObject msgobject;
    
    	CANRetrySet(CAN0_BASE, false);
    	can.txdata = data;
    	can.ptxdata = (uint8_t *) (&can.txdata);
    	msgobject.pui8MsgData = can.ptxdata;
    	msgobject.ui32MsgIDMask= 0;
    	msgobject.ui32Flags = 0;
    	msgobject.ui32MsgLen = 4;
    
    	while ((CANStatusGet(CAN0_BASE, CAN_STS_CONTROL)&CAN_STS_TXOK)!=0);
    	msgobject.ui32MsgID = 1365;
    	CANMessageSet(CAN0_BASE, 1, &msgobject, MSG_OBJ_TYPE_TX);
    
    	while ((CANStatusGet(CAN0_BASE, CAN_STS_CONTROL)&CAN_STS_TXOK)!=0);
    	msgobject.ui32MsgID = 10;
    	CANMessageSet(CAN0_BASE, 2, &msgobject, MSG_OBJ_TYPE_TX);

  • Hello Mariano,

    What you are doing is correct, except that it must wait for the TXOK to be set . Waiting for the CAN_STS_TXOK before sending the next message is the correct approach.

    I will however make a change in the code

    msgobject.ui32MsgID = 1365;
    CANMessageSet(CAN0_BASE, 1, &msgobject, MSG_OBJ_TYPE_TX);
    while ((CANStatusGet(CAN0_BASE, CAN_STS_CONTROL)&CAN_STS_TXOK)!=CAN_STS_TXOK);

    msgobject.ui32MsgID = 10;
    CANMessageSet(CAN0_BASE, 2, &msgobject, MSG_OBJ_TYPE_TX);
    while ((CANStatusGet(CAN0_BASE, CAN_STS_CONTROL)&CAN_STS_TXOK)!=CAN_STS_TXOK);

    Regards
    Amit
  • Yes, you are correct, there was a mistake in my code, should read

    while ((CANStatusGet(CAN0_BASE, CAN_STS_CONTROL)&CAN_STS_TXOK)==0);

    Still doesn't work, now every time I lose a message I get stuck in a while loop. And still losing messages. Neither my code or your code is working. What's next to try?
  • Hello Mariano,

    I would suggest just reading the register w/o clearing till the while statement is not exited. It could be that the action of polling in it and clearing it may be having a contention.

    Regards
    Amit
  • Amit, your response seems to have fixed the problem. In TIVA's library can.c CANStatusGet() function, the following is executed:

            case CAN_STS_CONTROL:
            {
                ui32Status = HWREG(ui32Base + CAN_O_STS);
                HWREG(ui32Base + CAN_O_STS) = ~(CAN_STS_RXOK | CAN_STS_TXOK |
                                                CAN_STS_LEC_M);
                break;
            }

    The register is read and cleared after it is read, regardless whether the flags where set or not when first read. I believe this created a race condition where it is possible that the TXOK bit is set between the read process and the clear process. As soon as I modified this function to avoid the race condition, I was unable to replicate the problem.

    I am going to rewrite my software to use register access directly and void using the TIVA library, hopefully I will get everything to work. You can close this thread. Thanks for your help!

  • Hello Mariano

    Normally, this would have worked in the interrupt driven mechanism where the flaghs would have been set at the same time as the interrupt generation. Hence the correct status would get returned.

    Regards
    Amit
  • Yes, and a simple rewrite could have made it work for any case, interrupt or not, at least for TX/RX flags.

    HWREG(ui32Base + CAN_O_STS) = ~(ui32Status&(CAN_STS_RXOK | CAN_STS_TXOK));

    Still don't know if in the case of interrupt driven this race condition is guaranteed never to happen, e.g. can you be servicing a CAN interrupt where you call CANStatusGet() while a frame is going out/being received at the same time? I would rather write my own functions that do not have this possibility.

    Thanks,
    Mariano
  • Hello Mariano,

    The bits are Write 0 to clear. Hence breaking it down to TX and RX alone should be done. However when we are receiving a frame and since we do not know when the CAN controller on the bus may send one, it brings us back to the interrupt based service which allows the uC to remain unblocked.

    Regards
    Amit