ESP32 used for CAN communication but stuck when CAN device is absent

Hello,
I am using Do-It ESP32 dev kit1 for ESP communication with CAN protocol.
The communication works properly when the communication is healthy.
But if the communication link breaks or receptive device is disconnected the ESP 32 stuck at can tx command after two or three attempt of transmission.

Please find code for reference.


#include <Arduino.h>
#include <ESP32CAN.h>
#include <CAN_config.h>

#include <WiFi.h>
#include <WiFiMulti.h>
#include <esp_task_wdt.h>
#define LED_INDICATIONS
#define WDT_TIMEOUT 1
WiFiMulti wifiMulti;

//how many clients should be able to telnet to this ESP32
#define MAX_SRV_CLIENTS 1


const char* ssid = "D-Link_DIR-615";  //
const char* password = "";  //"05424993"


IPAddress local_IP(172, 16, 5, 235);
IPAddress gateway(172, 16, 5, 1);
IPAddress subnet(255, 255, 0, 0);
IPAddress primaryDNS(8, 8, 8, 8); //optional
IPAddress secondaryDNS(8, 8, 4, 4); //optional

WiFiServer server(23);
WiFiClient serverClients[MAX_SRV_CLIENTS];

CAN_device_t CAN_cfg;               // CAN Config
const int rx_queue_size = 10;       // Receive Queue size

uint8_t i;
uint16_t reqId = 0;
uint16_t resId = 0;
uint8_t DLC = 0;
uint8_t SID = 0;
uint8_t resLen = 0;
uint8_t resLenRecv = 0;
uint8_t resp[255];

//indication leds on ESP32
#ifdef LED_INDICATIONS
#define WIFI_COMM_OK_LED              32    //green
#define CLIENT_CONN_LED               22    //blue
#define CAN_RX_LED                    23    //blue
#endif

void setup()
{
 
#ifdef LED_INDICATIONS
  pinMode(CAN_RX_LED, OUTPUT);
  pinMode(WIFI_COMM_OK_LED, OUTPUT);
  pinMode(CLIENT_CONN_LED, OUTPUT);

  digitalWrite(CAN_RX_LED, HIGH);
  digitalWrite(WIFI_COMM_OK_LED, HIGH);
  digitalWrite(CLIENT_CONN_LED, HIGH);
  delay(1000);
  digitalWrite(CAN_RX_LED,LOW);
  digitalWrite(WIFI_COMM_OK_LED,LOW);
  digitalWrite(CLIENT_CONN_LED,LOW);
  
#endif

  Serial.begin(115200);
  Serial.println("Starting...");
delay(500);
  if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
    Serial.println("STA Failed to configure");
  }

  wifiMulti.addAP(ssid, password);
  //wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2");
  //wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");

  Serial.println("Connecting Wifi ");
  for (int loops = 10; loops > 0; loops--) {
      esp_task_wdt_reset();
    if (wifiMulti.run() == WL_CONNECTED) {
      Serial.println("");
      Serial.print("WiFi connected ");
      Serial.print("IP address: ");
      Serial.println(WiFi.localIP());
      break;
    }
    else {
      Serial.println(loops);
      delay(1000);
     
    }
    
  }

  if (wifiMulti.run() != WL_CONNECTED)
  {
    Serial.println("WiFi connect failed");
    delay(1000);
    ESP.restart();
  }

  server.begin();
  server.setNoDelay(true);

  Serial.print("Ready! Use 'telnet ");
  Serial.print(WiFi.localIP());
  Serial.println(" 23' to connect");

  CAN_cfg.speed = CAN_SPEED_500KBPS;
  CAN_cfg.tx_pin_id = GPIO_NUM_5;
  CAN_cfg.rx_pin_id = GPIO_NUM_4;
  CAN_cfg.rx_queue = xQueueCreate(rx_queue_size, sizeof(CAN_frame_t));
 
 /* esp_task_wdt_init(WDT_TIMEOUT, true);
  esp_task_wdt_add(NULL);
  esp_task_wdt_reset();*/
  // Init CAN Module
  ESP32Can.CANInit();
//esp_task_wdt_disable();
  Serial.println("CAN Ready");
}

void loop() {
esp_task_wdt_reset();
  CAN_frame_t rx_frame;

  if (wifiMulti.run() == WL_CONNECTED) {

    //check if there are any new clients

#ifdef LED_INDICATIONS
    digitalWrite(WIFI_COMM_OK_LED, HIGH);     //WiFi connected so turn ON led
#endif

    if (server.hasClient()) {

      for (i = 0; i < MAX_SRV_CLIENTS; i++) {
        //find free/disconnected spot
        if (!serverClients[i] || !serverClients[i].connected()) {
          if (serverClients[i]) serverClients[i].stop();

          serverClients[i] = server.available();
          if (!serverClients[i]) Serial.println("available broken");
          Serial.print("New client: ");
          Serial.print(i);
          Serial.print(' ');
          Serial.println(serverClients[i].remoteIP());
          break;
        }
      }
      if (i >= MAX_SRV_CLIENTS) {
        //no free/disconnected spot so reject
        server.available().stop();
      }
    }

    //check clients for data
    for (i = 0; i < MAX_SRV_CLIENTS; i++) {
      if (serverClients[i] && serverClients[i].connected()) {

#ifdef LED_INDICATIONS
        digitalWrite(CLIENT_CONN_LED, HIGH);
#endif

        if (serverClients[i].available()) {

          //printf("\n");
          Serial.println("WiFi Data Received");

          size_t len = serverClients[i].available();
          Serial.print("len=");
           Serial.println(len);
          uint8_t sbuf[len];
          serverClients[i].readBytes(sbuf, len);
 Serial.println("check length");
          // Send CAN Message
          if (len == 13)
          {
            CAN_frame_t tx_frame;
            ESP32Can.CANInit();
            Serial.println("Can initialize");
            tx_frame.FIR.B.FF = CAN_frame_std;
            tx_frame.MsgID = sbuf[0] << 8 | sbuf[1]; //
            reqId = tx_frame.MsgID;
            resId = sbuf[2] << 8 | sbuf[3];
            tx_frame.FIR.B.DLC = sbuf[4];
            DLC = sbuf[4];
            SID = sbuf[6];
            tx_frame.data.u8[0] = sbuf[5]; //
            tx_frame.data.u8[1] = sbuf[6]; //
            tx_frame.data.u8[2] = sbuf[7]; //
            tx_frame.data.u8[3] = sbuf[8]; //
            tx_frame.data.u8[4] = sbuf[9]; //
            tx_frame.data.u8[5] = sbuf[10]; //
            tx_frame.data.u8[6] = sbuf[11]; //
            tx_frame.data.u8[7] = sbuf[12]; //
            Serial.println("Going to send...");
//CAN_cfg.rx_queue = xQueueCreate(rx_queue_size, sizeof(CAN_frame_t));
            resLenRecv = 0;
            resLen = 0;
           int Stat= ESP32Can.CANWriteFrame(&tx_frame);
               Serial.print("Tx Stat=");
               Serial.println(Stat);
            
uint32_t freeheap=ESP.getFreeHeap();
Serial.print("freeheap=");
Serial.println(freeheap);
            printf(" Request to 0x%08X, DLC %d, Data ", tx_frame.MsgID,  tx_frame.FIR.B.DLC);
            for (int i = 0; i < tx_frame.FIR.B.DLC; i++) {
              printf("0x%02X ", tx_frame.data.u8[i]);
            }
            printf("\n");
            Serial.println("Data Sent.");
          }
        }
      }
      else {
#ifdef LED_INDICATIONS
        digitalWrite(CLIENT_CONN_LED, LOW);
#endif

        if (serverClients[i]) {
          serverClients[i].stop();
        }
      }
    }

    // Receive next CAN frame from queue
    if (xQueueReceive(CAN_cfg.rx_queue, &rx_frame, 3 * portTICK_PERIOD_MS) == pdTRUE) {

#ifdef LED_INDICATIONS
      digitalWrite(CAN_RX_LED, HIGH);     //received some frame on CAN so blink led
#endif

      //filter out messages based on the receive ID set
      //      if (  rx_frame.MsgID == 0x0778 || rx_frame.MsgID == 0x07ED || rx_frame.MsgID == 0x0748 ||
      //            rx_frame.MsgID == 0x077F || rx_frame.MsgID == 0x07AB || rx_frame.MsgID == 0x0758 ||
      //            rx_frame.MsgID == 0x07EF || rx_frame.MsgID == 0x07BA || rx_frame.MsgID == 0x07AA  ) {
      if ( rx_frame.MsgID == resId ) {
        if (rx_frame.FIR.B.FF == CAN_frame_std) {
          printf("New standard frame");
        }
        else {
          printf("New extended frame");
        }

        if (rx_frame.FIR.B.RTR == CAN_RTR) {
          printf(" RTR from 0x%08X, DLC %d\r\n", rx_frame.MsgID,  rx_frame.FIR.B.DLC);
        }
        else {
          printf(" Response from 0x%08X, DLC %d, Data ", rx_frame.MsgID,  rx_frame.FIR.B.DLC);
          for (int i = 0; i < rx_frame.FIR.B.DLC; i++) {
            printf("0x%02X ", rx_frame.data.u8[i]);
          }
          printf("\n");

          if (rx_frame.data.u8[0] == 0x10) {
            //Serial.println("In equal to 0x10");
            //First frame of multi-part response received.
            resLen = rx_frame.data.u8[1];

            for (int i = 1; i < rx_frame.FIR.B.DLC; i++) {
              resp[resLenRecv] = rx_frame.data.u8[i];
              resLenRecv++;
            }

            //Send flow control message
            CAN_frame_t tx_frame;

            tx_frame.FIR.B.FF = CAN_frame_std;
            tx_frame.MsgID = reqId;
            tx_frame.FIR.B.DLC = DLC;
            tx_frame.data.u8[0] = 0x30;
            tx_frame.data.u8[1] = 0x00;
            tx_frame.data.u8[2] = 0x00;
            tx_frame.data.u8[3] = 0x00;
            tx_frame.data.u8[4] = 0x00;
            tx_frame.data.u8[5] = 0x00;
            tx_frame.data.u8[6] = 0x00;
            tx_frame.data.u8[7] = 0x00;
            ESP32Can.CANWriteFrame(&tx_frame);

            printf(" Request to 0x%08X, DLC %d, Data ", tx_frame.MsgID,  tx_frame.FIR.B.DLC);
            for (int i = 0; i < tx_frame.FIR.B.DLC; i++) {
              printf("0x%02X ", tx_frame.data.u8[i]);
            }
            printf("\n");
            Serial.println("Data Sent.");
          }
          else if (rx_frame.data.u8[0] < 0x10) {
            //Serial.println("In less than 0x10");
            resLen = rx_frame.data.u8[0];

            if (rx_frame.data.u8[1] == 0x7F) { 
              //NACK received
              if ((rx_frame.data.u8[2] == SID) && (rx_frame.data.u8[3] == 0x78)) {
                //Serial.println("NRC received. Waiting for positive response.");
              }
              else {
                for (int i = 1; i < rx_frame.FIR.B.DLC; i++) {
                  resp[resLenRecv] = rx_frame.data.u8[i];
                  resLenRecv++;
                }
              }
            }
            else {
              for (int i = 1; i < rx_frame.FIR.B.DLC; i++) {
                resp[resLenRecv] = rx_frame.data.u8[i];
                resLenRecv++;
              }
            }

//            for (int i = 1; i < rx_frame.FIR.B.DLC; i++) {
//              resp[resLenRecv] = rx_frame.data.u8[i];
//              resLenRecv++;
//            }
          }
          else if (rx_frame.data.u8[0] > 0x20) {
            //Serial.println("In greater than 0x20");
            for (int i = 1; i < rx_frame.FIR.B.DLC; i++) {
              resp[resLenRecv] = rx_frame.data.u8[i];
              resLenRecv++;

              if (resLenRecv > resLen) {
                break;
              }
            }
          }

          if (resLenRecv > resLen) {
            //push UART data to all connected telnet clients

            for (i = 0; i < MAX_SRV_CLIENTS; i++) {
              if (serverClients[i] && serverClients[i].connected()) {
                //              byte MsgID_DLC[3] = { highByte(rx_frame.MsgID), lowByte(rx_frame.MsgID), rx_frame.FIR.B.DLC };
                //              serverClients[i].write(MsgID_DLC, 3);
                //serverClients[i].write(rx_frame.data.u8, rx_frame.FIR.B.DLC);

                //serverClients[i].write(resp, resLenRecv);
                serverClients[i].write(resp, resLenRecv);   //SID
                delay(1);
              }
            }

            resLenRecv = 0;
            resLen = 0;
          }
        }
      }
#ifdef LED_INDICATIONS
      digitalWrite(CAN_RX_LED, LOW);     //received some frame on CAN so blink led
#endif
    }
    else{
     // Serial.println("Data not received...");
//     &rx_frame=0;
    }
  }
  else {

#ifdef LED_INDICATIONS
    digitalWrite(WIFI_COMM_OK_LED, LOW);     //WiFi not connected so turn OFF led
#endif

    Serial.println("WiFi not connected!");
    for (i = 0; i < MAX_SRV_CLIENTS; i++) {
      if (serverClients[i]) serverClients[i].stop();
    }
    delay(500);
  }
}

I have moved your topic to Programming Questions.... General Discussion is targeted for community things.

Ok thanks

If you fix the wiring break does it automatically resume sending?

If you want the rest of the program to continue running while the CAN interface is frozen, then put your CAN code in it's own task and communicate using queues,

The hardware is working perfectly! Your software is not handling errors properly. By definition CAN must have every message it sends acknowledged in frame by a remote node. Without another node that does not happen. When the transmitter does not receive an acknowledgement it tries again for a given number of times then errors out. Your code is probably not set to handle this error and stops. This is all in the CAN specifications.

Yes you are right,
But i am unable to understand mistake in my code.
Can any one could guide me how to make it correct

1 Like

Sorry I use Cory Fowler's mcp Can library and ai am not familiar with the one you're using.

can this library could work with my ESP 32 wroom?

Sorry I do not know. I had one instance working on a ESP8266 so it is possible. I used an external module MCP2515 but I believe you are using the internal CAN unit. The library may help you, with how he did things, I am not sure.

Ok thanks i have edited library where

xSemaphoreTake(sem_tx_complete,portMAX_DELAY);

this command was holding the MCU till frame tx to complete for full time.

So I replace it with

xSemaphoreTake(sem_tx_complete,1000);

Which is limiting it now to 1 second.

Thanks for support and guidance.

I also started with MCP2515 due to unresolved issue.
Can you share the code

I use Cory Fowler's mcp Can library at: GitHub - coryjfowler/MCP_CAN_lib: MCP_CAN Library

I guess my can bus supports older version / CAN 2.0A version and the newer ESp and MCP2515 supports CAN 2.0B protocol.
Is there any way we can make it support CAN2.0A protocol by either MCP2515 or ESP32

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.