I am trying to get a CAN system operating between two separate TWR-K60D100M / TWR-SER bds elevator systems, using CW 10.4 and the can_loopback_node bare-metal example.
I have split the can_loopback_node program, with one set to only receive CAN messages, and the other to only transmit to try and understand the operation.
I only have about 0.5m of CAN bus, with the J5[9-10] linked on the TWR-SER module to give the 120ohms termination resistor at both ends of the CAN bus on both systems.
I am operating at a 50kbps CAN bus speed.
I can transmit one CAN message from one node which is then received by the other node. The oscilloscope trace indicates only one CAN message is transmitted.
If I transmit two or more CAN messages, the transmission is not occurring until both CAN messages have been loaded in to the Message Buffer – what can cause that when transmitting more than one CAN message ?.
It appears as though with multiple CAN messages, the first one ends up not being acknowledged for an undetermined delay, and then the second one is transmitted – though again multiple messages are being transmitted – presumably due to an ACK not being initially received, but after the ‘repeat’ CAN messages, the node set to receive receives both CAN messages correctly, ID and data.
I had expected interrupts to be generated, but adding breakpoints on the associated ISR’s are not being executed. As far as I can see polling is not used so what is happening when a CAN message is being successfully received?.
Looking at the bits after the CRC when one CAN message has been transmitted gives 0,1,0 on the CAH_H – CAN_L trace, but this ie 011 when more than CAN message is transmitted.
I am looking for guidance on what to check – my knowledge on CAN being still rather basic.
After further investigation it appears that only after a 'delay' after the last CAN message is loaded in the Message Buffer I get the transmission of the 1st CAN message, which results in the FlexCAN_MB_ISR being called for a transmission. After another delay - the 2nd CAN message is transmitted and the FlexCAN_MB_ISR is again called. What I don't understand is why I am not getting a CAN transmission after loading the CAN message in the Message buffer with FLEX_CAN_MB_CODE_TX_ONCE. It makes no difference if I have a break-point on FlexCAN_Write, I won't get a transmission until a 'delay' after the last CAN message has been loaded. As far as I am aware after the Message Buffer has been loaded, then any 'delay' should only be due to arbitration logic.
The data transmitted is successfully received on the second CAN node - just don't understand why it waits until my last CAN message is loaded - via a call to FlexCAN_Write - whether 2 or 7 CAN messages, before I get an actual transmission.
I would appreciate help on the above.
Hi
We met the similar question about FlexCAN delay between transmitted messages.
I did a test with TWR-K70F120M board with repeated transfer standard CAN frame (FlexCAN configured 1Mbps baud rate) with CodeWarrior MCU V10.6 with processor expert [CAN_LDD] driver.
Below is the test code abstracted:
MyCANPtr = CAN1_Init(NULL); /* Initialization of CAN2 component */
Frame.MessageID = 0x123U; /* Set Tx ID value - standard */
Frame.FrameType = LDD_CAN_DATA_FRAME; /* Specyfying type of Tx frame - Data frame */
Frame.Length = sizeof(CAN_OutData); /* Set number of bytes in data frame - 4B */
Frame.Data = CAN_OutData; /* Set pointer to OutData buffer */
DataFrameTxFlg = FALSE; /* Initialization of DataFrameTxFlg */
while(1)
{
//PITCounter_pre = PIT_CVAL0; /*get CAN1_SendFrame() function execute time*/
Error = CAN1_SendFrame(MyCANPtr, 5U, &Frame); /* Sends the data frame over buffer 0 */
//PITCounter_aft = PIT_CVAL0;
while (!DataFrameTxFlg) { /* Wait until data frame is transmitted */
}
}
Below is the test result:
There with 25us interval from the first CAN frame [after ACK field] to the next CAN frame [before Start of Frame].
I using the PIT timer to counter the CAN1_SendFrame() function execute time is about 9us.
From the CAN spec (CAN baud rate 1Mbps), there with below time interval between the two CAN frames interval:
[ACK Delimiter] 1us
[End of Frame] 7us
[CAN1_SendFrame() function execute time] 9us
[INTERFRAME SPACE]'s [Intermission] 3us
[INTERFRAME SPACE]'s [Bus IDLE] 1us
Total interval value added is 21us.
The actual interval between two CAN frame is 25ms, not 21us as expected.
I checked this issue with Kinetis product team with below feedback.
The TASD field will affect start of arbitration delay among TX message buffers (internal arbitration). The next message to be transmitted must be configured before CRC field to participate of arbitration process. Otherwise, the arbitration will start again in BusIdle.
So to optimize the transmit delay, new Tx MB must be configured before CRC field in the current transmission/reception. If the Tx Message is configured after IFLAG set from current transmission/reception, the next internal arbitration to select a Tx winner will happen in BusIdle.
The PE generated code is not optimized this way.
You can see in the main loop, it will wait for DataFrameTxFlg set then to configure TX buffer for next transmission. The DataFrameFlag is set in event code which in turn is executed in CAN ISR.
while(1)
{
Error = CAN1_SendFrame(MyCANPtr, 5U, &Frame); /* Sends the data frame over buffer 0 */
while (!DataFrameTxFlg) { /* Wait until data frame is transmitted */
}
}
Looking at the CAN ISR code, you can find it will scan through configured MBs for both TX and RX, with lowest number MB first, this will cause more delays if you configured more MBs or you configured the TX MB to higher number before it actually set the DataFrameTxFlg flag, so this means the internal arbitration could happen in BusIdle state, so this will increase time delay.
TxBufferMask = (LDD_CAN_TBufferMask)(DeviceDataPrv->TxBufferMask & StatusReg);
if (TxBufferMask != 0x00U) { /* Is Tx Buffer? */
BufferMask = 0x01U;
for (MBIndex=0x00U; MBIndex<MBIndexMax; MBIndex++) {
if ((TxBufferMask & BufferMask) != 0x00U) {
CAN1_OnFreeTxBuffer(DeviceDataPrv->UserData, MBIndex); /* Invoke user event */
}
BufferMask = (LDD_CAN_TBufferMask)(BufferMask << 0x01U);
}
}
RxBufferMask = (LDD_CAN_TBufferMask)(DeviceDataPrv->RxBufferMask & StatusReg);
if (RxBufferMask != 0x00U) { /* Is Rx Buffer? */
BufferMask = 0x01U;
for (MBIndex=0x00U; MBIndex<MBIndexMax; MBIndex++) {
if ((RxBufferMask & BufferMask) != 0x00U) {
CAN1_OnFullRxBuffer(DeviceDataPrv->UserData, MBIndex); /* Invoke user event */
}
BufferMask = (LDD_CAN_TBufferMask)(BufferMask << 0x01U);
}
}
Wish it helps.
Have a great day,
Ma Hui
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Thank you for the detailed response to my query. It is surprising that more detail on optimising arbitration delays is not mentioned in the reference manual. It seems strange you are effectively having to ‘pre-load’ the next message to get the performance.
Setting up a system where specific CAN messages are generated at timed intervals (10,50,100,250,500,1000msec), rather than just a stream of CAN messages appears to work more predictably. CAN messages are received at the required timed intervals at the Rx Node and thus working satisfactorily for my required application.
Hi Robert,
The above test is to measure continue transmit CAN frame interval time.
The requirement from one customer , who want to reduce the interval time between consecutive CAN messages.
Thanks.
Have a great day,
Ma Hui
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------