I'm running a CAN bus at 20k instead of the the usual 125k or 500k found in cars.
At this slow data rate I get transmit timeout errors due to the presence of a hard coded value in a retry loop where it checks the chip 50 times to see if the data has been sent or else returns CAN_SENDMSGTIMEOUT. The data does actually get sent from the chip, it's just that the Arduino code returns too early and indicates an error when there isn't one.
At high bus speeds this isn't a problem as by the time it has gone through the loop 50 times the data frame has left the chip.
At 20k I found by trial and error that I have to change this hard coded value to 300 in order to give the chip enough time to push out a data frame.
In the code the retry count is is labelled TIMEOUTVALUE, which is a bit confusing as it isn't a time value, it's just a retry count, which by virtue of the SPI and chip speed indirectly results in a time delay.
A couple of questions:
-
Is it really necessary to block waiting for the chip to push the data frame out. Why not return immediately?
Wouldn't a Tx failure be evident when it fails to return a Tx buffer the next time you try to send a message. Alternatively you could periodically check the Tx status in the Arduino main loop rather than having it block. -
If blocking is necessary, how would you modify the code to dynamically choose a sensible timeout value depending on the data rate, bearing in mind that congestion on the CAN bus will also influence how long it takes to send a frame?
The "#define TIMEOUTVALUE 50" is defined in
The sendMsg() function is defined in
INT8U MCP_CAN::sendMsg()
{
INT8U res, res1, txbuf_n;
uint16_t uiTimeOut = 0;
do {
res = mcp2515_getNextFreeTXBuf(&txbuf_n); /* info = addr. */
uiTimeOut++;
} while (res == MCP_ALLTXBUSY && (uiTimeOut < TIMEOUTVALUE));
if(uiTimeOut == TIMEOUTVALUE)
{
return CAN_GETTXBFTIMEOUT; /* get tx buff time out */
}
uiTimeOut = 0;
mcp2515_write_canMsg( txbuf_n);
mcp2515_modifyRegister( txbuf_n-1 , MCP_TXB_TXREQ_M, MCP_TXB_TXREQ_M );
do
{
uiTimeOut++;
res1 = mcp2515_readRegister(txbuf_n-1); /* read send buff ctrl reg */
res1 = res1 & 0x08;
} while (res1 && (uiTimeOut < TIMEOUTVALUE));
if(uiTimeOut == TIMEOUTVALUE) /* send msg timeout */
return CAN_SENDMSGTIMEOUT;
return CAN_OK;
}