Hello there!
I have designed software for a device, consisting of 8 CAN nodes (Master, Display, 6 Motor Controller) using KEIL µVision 5, RTX and newest Middleware for LPC1768. Everything works fine, but sometimes - once or twice a day - one of the Motor-Controllers stops to communicate via CAN. The CAN-API-Driver gives no error code back and the CAN hardware seems to be blocked, no output on TX pin, no data received. Because of missing any error messages from API driver I cannot react within the code, so the node (board) must be reseted manually.
I tried the "old" CMSIS CAN driver, but there is the same behaviour. So I may assume, this is not a software problem, may I?
I tried to calculate the proper timing factors for the current CAN architecture, so I have got this:
status = DriverCAN->SetBitrate(ARM_CAN_BITRATE_NOMINAL,
LocalCANRate,
ARM_CAN_BIT_PROP_SEG(4U) |
ARM_CAN_BIT_PHASE_SEG1(2U) |
ARM_CAN_BIT_PHASE_SEG2(3U) |
ARM_CAN_BIT_SJW(2U));
For the sending I use the code
while (tries)
{
FeedExtWD();
CANSendingDone = 0;
osKernelLock();
Result = DriverCAN->MessageSend(tx_obj_idx, &tx_msg_info, data, len);
osKernelUnlock();
if (Result == len)
{
while (!(CANSendingDone || CANSendError)) WDT_Feed();
if (CANSendingDone)
{
break;
}
else if (CANSendError)
{
if (tries) tries--;
dbgprintf("CAN Driver Sending Error %d, %d tries left\r\n", CANSendError, tries);
DriverCAN->Control(ARM_CAN_ABORT_MESSAGE_SEND, tx_obj_idx);
dbgprintf("Sending aborted...\r\n");
}
else
{
dbgprintf("Sending status unknown!\r\n");
}
}
else
{
if (tries) tries--;
switch (Result)
{
case ARM_DRIVER_ERROR:
uprintf("CAN Driver not sending, Unspecified error!\r\n");
break;
case ARM_DRIVER_ERROR_BUSY:
uprintf("CAN Driver not sending, Driver is busy!\r\n");
break;
case ARM_DRIVER_ERROR_TIMEOUT:
uprintf("CAN Driver not sending, Timeout occurred\r\n");
break;
case ARM_DRIVER_ERROR_UNSUPPORTED:
uprintf("CAN Driver not sending, Operation not supported!\r\n");
break;
case ARM_DRIVER_ERROR_PARAMETER:
uprintf("CAN Driver not sending, Parameter error!\r\n");
break;
case ARM_DRIVER_ERROR_SPECIFIC:
default:
uprintf("CAN Driver not sending, Result=%d\r\n", Result);
break;
}
DriverCAN->Control(ARM_CAN_ABORT_MESSAGE_SEND, tx_obj_idx);
dbgprintf("Sending aborted...\r\n");
}
}
I try to lock the RTX Kernel during the sending for eliminate the influence of other threads.
My callback functions look this way:
void CANSignalObjectEvent (uint32_t obj_idx, uint32_t event)
{
uint8_t ix, rLen;
if (obj_idx == rx_obj_idx)
{
if (event == ARM_CAN_EVENT_RECEIVE)
{
rLen = DriverCAN->MessageRead(rx_obj_idx, &rx_msg_info, rx_data, 8U);
if ( rLen > 0U)
{
for (ix = 0; ix < rLen; ix++)
{
CANData.RxBuffer[CANData.RxInIndex].data[ix] = rx_data[ix];
}
CANData.RxBuffer[CANData.RxInIndex].len = rx_msg_info.dlc;
CANData.RxBuffer[CANData.RxInIndex].id = rx_msg_info.id;
CANData.RxInIndex = (CANData.RxInIndex+1) % CAN_MAX_BUFFERS;
osThreadFlagsSet(idThreadCAN, THREAD_FLAG_CAN_RECEIVED);
}
}
}
if (obj_idx == tx_obj_idx)
{
if (event == ARM_CAN_EVENT_SEND_COMPLETE)
{
osThreadFlagsSet(idThreadCANLiveMessage, THREAD_FLAG_CAN_SENT);
CANSendingDone = 1;
CANSendError = 0;
}
}
}
and
void CANSignalUnitEvent (uint32_t event)
{
switch (event)
{
case ARM_CAN_EVENT_UNIT_INACTIVE:
dbgprintf("\r\nCAN unit changes to inactive state\r\n");
break;
case ARM_CAN_EVENT_UNIT_ACTIVE:
dbgprintf("\r\nCAN unit changes to active state\r\n");
CANSendError = 0;
break;
case ARM_CAN_EVENT_UNIT_WARNING:
dbgprintf("\r\nCAN unit error or warning\r\nCAN will be resetted...\r\n");
CANSendError = 1;
break;
case ARM_CAN_EVENT_UNIT_PASSIVE:
dbgprintf("\r\nCAN unit changest to passive state\r\n");
CANSendError = 2;
break;
case ARM_CAN_EVENT_UNIT_BUS_OFF:
dbgprintf("\r\nCAN unit bus is off\r\n");
break;
}
}
As I said, it works fine all the day, but sometimes it stucks somehow, mostly the first or the last device on bus. And no case of error is reported by the CAN driver...
Did somebody make a similar experience? Is there something, I should try out?
My colleague, who designed the hardware (boards and wiring), says there is no problem with it. Who is right?