Can bus issue , stuck messages

Brendant182
Posts: 2
Joined: Mon Oct 07, 2019 1:42 pm

Can bus issue , stuck messages

Postby Brendant182 » Mon Oct 07, 2019 2:17 pm

I have hit the limitation of what I could feel I could do with my Arduino Uno and I have moved to a shiny new ESP32. Almost everything worked immediately with very minor changes but I have encountered one issues that has me stumped.

Currently I have an ESP32 and an Arduino Uno connected to each other using two TJA1050 can bus transceivers.

The Uno is generating an sending messages using the following loop

Code: Select all

void loop()
{

  bar2 = bar2 +1;
  if(bar2 == 10){
    bar2 = 0; 
    bar1 = bar1 + 1;
  }
  if(bar1 == 10){
    bar1 = 0;
  }
 

    unsigned char stmp[8] = {bar2, bar2, bar1, bar1, bar2, bar1, bar1, bar2};
    CAN.sendMsgBuf(0x372, 0, 8, stmp); 
    delay(1000);   
    CAN.sendMsgBuf(0x368, 0, 8, stmp);
    delay(1000);
    CAN.sendMsgBuf(0x3E2, 0, 8, stmp);
    delay(1000);
    CAN.sendMsgBuf(0x3E0, 0, 8, stmp);
    delay(1000);                       // send data per 500ms
}
On the receiving end the ESP32 uses the following code

Code: Select all

#include <Arduino.h>
#include <SPI.h>
#include <Wire.h>
#include <mcp_can.h>


#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
  #define SERIAL SerialUSB
#else
  #define SERIAL Serial
#endif

const int SPI_CS_PIN = 2;    // Defines the CS pin for the CAN interface 
MCP_CAN CAN(SPI_CS_PIN);      // Set CS pin

 void setup(void) {
  
  SERIAL.begin(115200);   // Allows for the SERIAL data to be monitored over USB
    while (CAN_OK != CAN.begin(CAN_1000KBPS))              
    {
        SERIAL.println("CAN BUS Shield init fail");
        SERIAL.println(" Init CAN BUS Shield again");
        delay(100);
    }
    SERIAL.println("CAN BUS Shield init ok!");
}


  void loop(void) {

    unsigned char len = 0;
    unsigned char buf[8];

    if(CAN_MSGAVAIL == CAN.checkReceive())            // check if data coming
    {
        CAN.readMsgBuf(&len, buf);    // read data,  len: data length, buf: data buf
        unsigned long canId = CAN.getCanId();
        SERIAL.println("-----------------------------");
        SERIAL.print("CAN ID: 0x");
        SERIAL.println(canId, HEX);
        for(int i = 0; i<len; i++)    // print the data
        {
            SERIAL.print(buf[i], HEX);
            SERIAL.print("\t");
        }
      
}
}


This was previously working on the Arduino with out any issues.
But since moving to the ESP32 when I watch the logs the can bus transceivers connect, a message with each tag is received
but then it only ever spams the following log. The one can message that no longer adds up

Code: Select all

01:02:45.458 -> CAN ID: 0x3E2
01:02:45.458 -> 1	1	0	0	1	0	0	1		-----------------------------
01:02:45.458 -> CAN ID: 0x3E2
01:02:45.458 -> 1	1	0	0	1	0	0	1		-----------------------------
01:02:45.458 -> CAN ID: 0x3E2
01:02:45.458 -> 1	1	0	0	1	0	0	1		-----------------------------
01:02:45.458 -> CAN ID: 0x3E2
01:02:45.458 -> 1	1	0	0	1	0	0	1		-----------------------------
01:02:45.458 -> CAN ID: 0x3E2
01:02:45.458 -> 1	1	0	0	1	0	0	1		-----------------------------
01:02:45.458 -> CAN ID: 0x3E2
01:02:45.492 -> 1	1	0	0	1	0	0	1		-----------------------------
01:02:45.492 -> CAN ID: 0x3E2
01:02:45.492 -> 1	1	0	0	1	0	0	1		-----------------------------
01:02:45.492 -> CAN ID: 0x3E2
01:02:45.492 -> 1	1	0	0	1	0	0	1		-----------------------------
01:02:45.492 -> CAN ID: 0x3E2
01:02:45.492 -> 1	1	0	0	1	0	0	1		-----------------------------
01:02:45.492 -> CAN ID: 0x3E2

If anyone has any suggestion as to what could cause this fault your help would be greatly appreciated.

Thank you for your time.

ESP_Dazz
Posts: 308
Joined: Fri Jun 02, 2017 6:50 am

Re: Can bus issue , stuck messages

Postby ESP_Dazz » Tue Oct 08, 2019 7:30 am

I'm not too familiar with the MCP CAN controllers, but generally speaking, a CAN node that is transmitting a message will continuously repeat a message if it detects some form of error in the message it is trying to transmit (e.g. Bit, Form, CRC, and ACK errors). Depending on the error type, this can continue on indefinitely (in the case of ACK errors), or stop when the transmitter's Transmit Error Counter exceeds 255 and enters the BUS OFF state (in the case of Bit and Form errors).

If the transmitter is constantly spamming the same message, use a logical analyzer to check if the transmitter is actually able to receive the acknowledgement bit from the receiver. You can also check the Transmit and Receive Error counters on both the Transmitter and Receiver sides to get a better idea what types of errors (if any) are occurring.

MStackoverflow
Posts: 14
Joined: Mon Oct 07, 2019 4:55 pm

Re: Can bus issue , stuck messages

Postby MStackoverflow » Tue Oct 08, 2019 3:22 pm

Hi,

The ESP32 has a built-in CANbus controller. With the library you are using, it's taking the SPI bus to use the CAN.

Have you tried connecting the TJA1050 directly to the CANbus RX/TX pins (GPIO4/GPIO5)? You have to make sure the RX pins is 3.3v on the TJA1050, or you'll burn the pin.

Look at this library, it is an adapted library from the official ESP-IDF CAN driver :

https://github.com/miwagner/ESP32-Arduino-CAN


Like @ESP_Dazz said, if the message that the UNO sent was not seen by any nodes, the ACK bit of the message will not trigger and the MCP2515 (CAN controller for UNO) have a built-in function to resend the message if it was not ACKnowledge. You can also disable this function by sending the right SPI message to the MCP2515 (see " One-Shot mode" in the MCP2515 datasheet).

dmaxben
Posts: 108
Joined: Thu Nov 16, 2017 6:04 pm

Re: Can bus issue , stuck messages

Postby dmaxben » Wed Oct 09, 2019 3:55 pm

Just use the ESP32's internal CAN controller! No need to use an MCP2515 with the ESP32 unless you specifically need more than one CAN bus.

Once you've switched to using the ESP32's internal CAN controller, just use the correct ESP-IDF native CAN drivers.

The Thomas Barth/Miwagner Arduino ESP32 CAN libraries do work, but in my opinion, they have some significant shortcomings and glitches when your project starts to become larger and more complex...

See my thread here about using the official ESP-IDF CAN library in Arduino:

https://esp32.com/viewtopic.php?f=19&t=12607

Brendant182
Posts: 2
Joined: Mon Oct 07, 2019 1:42 pm

Re: Can bus issue , stuck messages

Postby Brendant182 » Thu Oct 10, 2019 9:51 am

Okay,thank you so much everyone for replying, unfortunately I am currently limited with the hardware I have on hand at this second, and the TJA1050 and MCP2515 are all soldered on to the one board. So I have ordered a TJA1051 and a SN65HVD230 that I can use as an alternative to test with.

I was not aware that the ESP32 did not require the MCP2515 CAN controller and no question about it I will removing that component from the ESP32 side entirely.

Everything in my current setup when I checked using an old DSO201, was found to be 3.3v.

I have also order a logic analyzer which I will have to learn how to use, but if the transmitter was waiting for a response or the acknowledgement bit from the receiver. Would I be right in assuming that it wouldn't have gotten to the 4th message correctly before spamming the same message, and should have just spammed 0x372 rather than 0x3E0? I apologise that I may not have made that clear.

While I am waiting for parts to arrive, I will do some reading and try to enable One-Shot mode. If One-Shot mode works I will still need to change everything on the ESP32's side, but I the Arduino would function one step closer to what I will eventually connecting too. When I asked Haltech support, they advised there ECU's only ask for acknowledgement bits sent to other Haltech devices such as the wide-band controller.

I will let you know how I go.

ESP_Dazz
Posts: 308
Joined: Fri Jun 02, 2017 6:50 am

Re: Can bus issue , stuck messages

Postby ESP_Dazz » Thu Oct 10, 2019 10:45 am

@Brendant182 A few things you can do whilst you're waiting for your hardware

On the transmitter side (UNO), you check the return value of each call to sendMsgBuf() to make sure the send was actually successful. Likewise on the receiver side (ESP32), check the return value of readMsgBuf() as well.

The Arduino MCP driver also provides the functions errorCountRX()and errorCountTX(). Call those after each send or receive to see if the error counter values change. If they do, it's indicative of some CAN bus errors occurring.

MStackoverflow
Posts: 14
Joined: Mon Oct 07, 2019 4:55 pm

Re: Can bus issue , stuck messages

Postby MStackoverflow » Tue Oct 15, 2019 5:26 pm

Depending on how critical is your application, I would recommend to enable One-Shot mode ONLY if it is necessary.

idahowalker
Posts: 166
Joined: Wed Aug 01, 2018 12:06 pm

Re: Can bus issue , stuck messages

Postby idahowalker » Mon Oct 21, 2019 11:20 pm

Declare:

Code: Select all

#include <CAN_config.h>
#include <ESP32CAN.h>
CAN_device_t CAN_cfg;
In setup():

Code: Select all

/* set CAN pins and baudrate */
  //// CAN_cfg.speed = CAN_SPEED_100KBPS;
  ////  CAN_cfg.speed = CAN_SPEED_250KBPS;
  //// CAN_cfg.speed = CAN_SPEED_500KBPS;
  ////CAN_cfg.speed = CAN_SPEED_800KBPS;
  CAN_cfg.speed = CAN_SPEED_1000KBPS;
  CAN_cfg.tx_pin_id = GPIO_NUM_12; // green wire
  CAN_cfg.rx_pin_id =  GPIO_NUM_13; // white wire
  CAN_cfg.rx_queue = xQueueCreate(3, sizeof(CAN_frame_t));
  //start CAN Module
  ESP32Can.CANInit();
Used to send and receive CAN

Code: Select all

void fSendCAN_Buss( void *pvParameters )
{
  stuSERVO_Message pxServo_Message;
  for ( ;; )
  {
    xEventGroupWaitBits (eg, evtSendCAN_Buss, pdTRUE, pdTRUE, portMAX_DELAY);
    if ( xSemaphoreTake( sema__Send_CAN_Bus, xTicksToWait0 ) == pdTRUE ) // grab semaphore no wait
    {
      CAN_frame_t rx_frame;
      // Serial.println ( " fSendCAN_Buss 2 "  );
      if ( (CAN_cfg.rx_queue != NULL) && (uxQueueMessagesWaiting(CAN_cfg.rx_queue)) ) // if queue not null and something is waiting in queue
      {
        // Serial.println ( uxQueueMessagesWaiting(CAN_cfg.rx_queue) );
        if (xQueueReceive( CAN_cfg.rx_queue, &rx_frame , xTicksToWait0) == pdTRUE )
        {
          if ( rx_frame.MsgID == 2 )
          {
            // Serial.println ( rx_frame.data.u8[0] );
            if ( rx_frame.data.u8[0] == '6' )
            {
              EOT = false;
              // Serial.print ( " frame ID " );
              // Serial.print ( rx_frame.MsgID );
              // Serial.println ( "ACK" );
              //              rx_frame.FIR.B.FF = CAN_frame_std;
              //              rx_frame.MsgID = xServo_EOT.MsgID;
              //              rx_frame.FIR.B.DLC = xServo_EOT.DLC;
              //              rx_frame.data.u8[0] = xServo_EOT.Servo_EOT;
              //              rx_frame.data.u8[1] = xServo_EOT.p4; // send all '0'
              //              rx_frame.data.u8[2] = xServo_EOT.p4;
              //              rx_frame.data.u8[3] = xServo_EOT.p4;
              //              rx_frame.data.u8[4] = xServo_EOT.p4;
              //              rx_frame.data.u8[5] = xServo_EOT.p4;
              //              rx_frame.data.u8[6] = xServo_EOT.p4;
              //              rx_frame.data.u8[7] = xServo_EOT.p4;
              //              ESP32Can.CANWriteFrame(&rx_frame);
              // Serial.println ( " sent Servo controller ack " );
              //              vTaskDelay( pdMS_TO_TICKS( 6 ) );
            }
            //            if (rx_frame.data.u8[0] = '3')
            //              {
            //                EOT = false;
            //              }
            if ( rx_frame.data.u8[0] == '4' )
            {
              //                          rx_frame.FIR.B.FF = CAN_frame_std;
              //                          rx_frame.MsgID = xServo_EOT.MsgID;
              //                          rx_frame.FIR.B.DLC = xServo_EOT.DLC;
              //                          rx_frame.data.u8[0] = '4';
              //                          rx_frame.data.u8[1] = xServo_EOT.p4;
              //                          rx_frame.data.u8[2] = xServo_EOT.p4;
              //                          rx_frame.data.u8[3] = xServo_EOT.p4;
              //                          rx_frame.data.u8[4] = xServo_EOT.p4;
              //                          rx_frame.data.u8[5] = xServo_EOT.p4;
              //                          rx_frame.data.u8[6] = xServo_EOT.p4;
              //                          rx_frame.data.u8[7] = xServo_EOT.p4;
              //                          ESP32Can.CANWriteFrame(&rx_frame);
              // Serial.println ( "InitComplete ack " );
              EOT = false;
              xSemaphoreGive ( sema_HexaPodAdjustment ); // begin walking forward task
            }
          } // if ( rx_frame.MsgID == 2 )
        } // if (xQueueReceive( CAN_cfg.rx_queue, &rx_frame , xTicksToWait5) == pdTRUE )
      } // if ( (CAN_cfg.rx_queue != NULL) && (uxQueueMessagesWaiting(CAN_cfg.rx_queue)) )
      //      // ack the initialization
      if ( xQueueReceive ( xQ_SERVO_Message, &pxServo_Message, QueueReceiveDelayTime ) == pdTRUE )
      {
        rx_frame.FIR.B.FF = CAN_frame_std;
        rx_frame.MsgID = pxServo_Message.MsgID;
        rx_frame.FIR.B.DLC = pxServo_Message.DLC;
        rx_frame.data.u8[0] = pxServo_Message.Instruction;
        rx_frame.data.u8[1] = pxServo_Message.p1;
        rx_frame.data.u8[2] = pxServo_Message.p2;
        rx_frame.data.u8[3] = pxServo_Message.p3;
        rx_frame.data.u8[4] = pxServo_Message.p4; // end of torque to position
        rx_frame.data.u8[5] = pxServo_Message.p5;
        rx_frame.data.u8[6] = pxServo_Message.p6;
        rx_frame.data.u8[7] = pxServo_Message.p7;
        //                Serial.print ( " message in sendCanBus " );
        //                Serial.print ( ", " );
        //                Serial.print ( rx_frame.data.u8[0] );
        //                Serial.print ( ", " );
        //                Serial.print ( rx_frame.data.u8[1] );
        //                Serial.print ( ", " );
        //                Serial.print (rx_frame.data.u8[2] );
        //                Serial.print ( ", " );
        //                Serial.print ( rx_frame.data.u8[3] );
        //                Serial.print ( ", " );
        //                Serial.print ( rx_frame.data.u8[4] );
        //                Serial.println ( " message end." );
        ESP32Can.CANWriteFrame(&rx_frame);
      }
      //
      xSemaphoreGive ( sema__Send_CAN_Bus );
      ////
      // Serial.print( "fSendCAN_Buss " );
      // Serial.print(uxTaskGetStackHighWaterMark( NULL ));
      // Serial.println();
      // Serial.flush();
    }  // if ( xSemaphoreTake( sema__Send_CAN_Bus, xTicksToWait0 ) == pdTRUE ) // grab semaphore no wait
  } // the for loop
  vTaskDelete( NULL );
} // void fSendCAN_Buss( void *pvParameters )
I left in my troubleshooting code.
If you are familiar with the ESP2 OS, freeRTOS, use it.

In reference to this line of code CAN_cfg.rx_queue = xQueueCreate(3, sizeof(CAN_frame_t));, A queue size of over 7 and the esp can library tries to keep the queues full over sending/receiving messages. I found a setting of 3 to 5 to be the most efficient.

obdevel
Posts: 2
Joined: Tue Sep 24, 2019 10:20 pm

Re: Can bus issue , stuck messages

Postby obdevel » Tue Oct 22, 2019 3:58 pm

I use the Arduino wrapper but I prefer to use the IDF CAN driver directly as it provides more control, instrumentation and alerts than the ESP32CAN library. You can take code straight from the IDF examples, although the default Arduino compiler settings are stricter and may require some explicit casts (e.g. for gpio_num_t). I use the MCP2562 transceiver chip.

e.g.

Code: Select all

// CAN config
static const can_timing_config_t t_config = CAN_TIMING_CONFIG_125KBITS();
static const can_filter_config_t f_config = CAN_FILTER_CONFIG_ACCEPT_ALL();
can_general_config_t g_config;
Then in setup:

Code: Select all

  // configure CAN bus driver
  g_config.mode = CAN_MODE_NORMAL;
  g_config.tx_io = (gpio_num_t)CAN_TX_PIN;
  g_config.rx_io = (gpio_num_t)CAN_RX_PIN;
  g_config.clkout_io = (gpio_num_t)CAN_IO_UNUSED;
  g_config.bus_off_io = (gpio_num_t)CAN_IO_UNUSED;
  g_config.tx_queue_len = 5;
  g_config.rx_queue_len = 5;
  g_config.alerts_enabled = CAN_ALERT_ALL;
  g_config.clkout_divider = 0;

  // install CAN driver
  iret = can_driver_install(&g_config, &t_config, &f_config);

  if (iret == ESP_OK) {
    VLOG("setup: CAN driver installed ok");
  } else {
    VLOG("setup: error installing CAN driver");
    log_esp_now_err(iret);
  }

  // start CAN driver
  iret = can_start();

  if (iret == ESP_OK) {
    VLOG("setup: CAN driver started ok");
  } else {
    VLOG("setup: error starting CAN driver");
    log_esp_now_err(iret);
  }
Receiving:

Code: Select all

cret = can_receive(&rx_frame, QUEUE_OP_TIMEOUT_SHORT);
    switch (cret) {
      case ESP_OK:
Sending:

Code: Select all

      // forward frame to local CAN bus
      cret = can_transmit(&tx_frame, QUEUE_OP_TIMEOUT);
      if (cret == ESP_OK) {
Getting driver stats:

Code: Select all

      can_status_info_t can_stats;
      can_get_status_info(&can_stats);

      VLOG("CAN_task: stats: state = %d, txq = %d, rxq = %d, tec = %d, rec = %d, tx fail = %d, rx drop = %d, lost arb = %d, bus error = %d", \
           can_stats.state, can_stats.msgs_to_tx, can_stats.msgs_to_rx, can_stats.tx_error_counter, can_stats.rx_error_counter, can_stats.tx_failed_count, \
           can_stats.rx_missed_count, can_stats.arb_lost_count, can_stats.bus_error_count);
    }
Getting alerts:

Code: Select all

    uint32_t can_status = can_read_alerts(&can_status, 0);

    if (can_status & CAN_ALERT_ERR_ACTIVE) {
      VLOG("CAN_task: controller is error active");
    }

    ...

idahowalker
Posts: 166
Joined: Wed Aug 01, 2018 12:06 pm

Re: Can bus issue , stuck messages

Postby idahowalker » Wed Oct 23, 2019 4:02 pm

obdevel wrote:
Tue Oct 22, 2019 3:58 pm
I use the Arduino wrapper but I prefer to use the IDF CAN driver directly as it provides more control, instrumentation and alerts than the ESP32CAN library.
Thanks for your info, I am eager to test it out.

Who is online

Users browsing this forum: No registered users and 75 guests