AnsweredAssumed Answered

LPC1768 has no output on CAN TX while sending

Question asked by Hans-Georg Kujawa on Mar 7, 2019
Latest reply on Mar 7, 2019 by jeremyzhou

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,                    /* Set nominal bitrate */
                                                   LocalCANRate,                         /* Set bitrate to 500 kbit/s */
                                                   ARM_CAN_BIT_PROP_SEG(4U)   |          /* Set propagation segment to 4 time quanta */
                                                   ARM_CAN_BIT_PHASE_SEG1(2U) |          /* Set phase segment 2 to 2 time quantum (sample point at 87.5% of bit time) */
                                                   ARM_CAN_BIT_PHASE_SEG2(3U) |          /* Set phase segment 2 to 3 time quantum (total bit is 8 time quanta long) */
                                                   ARM_CAN_BIT_SJW(2U));                             /* Resynchronization jump width 2 is same as phase segment 2 */

 

 

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 receive object event */
     {                 
   if (event == ARM_CAN_EVENT_RECEIVE)                     /* If message was received successfully */
          {
               
          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;         /* Point to the next free position */
               osThreadFlagsSet(idThreadCAN, THREAD_FLAG_CAN_RECEIVED);     
               }
          }
     }
     
if (obj_idx == tx_obj_idx)                                         /* If transmit object event */
     {                 
     if (event == ARM_CAN_EVENT_SEND_COMPLETE)           /* If message was sent successfully */
          {
          osThreadFlagsSet(idThreadCANLiveMessage, THREAD_FLAG_CAN_SENT);     
          CANSendingDone = 1;
          CANSendError = 0;     
          // KU dbgprintf("!");     
          }
     }
}

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?   

Outcomes