-2

I am working on a project based on the ESP32 processor and Arduino framework, which communicates with another board via CANBUS protocol.

The bitrate is 125k so it is presumably "fast".

I am using the Sandeep Mistry library or also known as adafruit_CAN which is compatible with a Texas Instruments SN65HVD230 CAN transceiver.

I use freeRTOS for a method that will receive frames per socket, and write them to the board.

Then the library itself provides a callback attached to the ISR to receive the responses.

This is where my problem begins, if I send it a frame per second, everything is wonderful, but when I start to send them every 200ms, I can see (with a can analyzer connected to the bus from the pc) that the frames are arriving, they are receiving on the card and it is answering, but my transceiver does not trigger the callback.

I have tried forgetting about the callback and using another RTOS method for reading, with the same result.

This method is iterating through a task, and if the vector contains a CAN_message_t object it writes it to the CAN, this works correctly.

void vTaskCANBUSWriteLoop(void *p)
{
  Serial.print("Writer Task");
 
  for (;;)
  {
    if (!my_global_vector.empty() )
    {
      response_broker_t myObject = my_global_vector.front();
      my_global_vector.pop();

      
      writePlot(myObject);
     
    }
    vTaskDelay(200 / portTICK_PERIOD_MS);
  }
}

This other method, is according to the documentation, and it works well if the program does not exceed a send per second, if it exceeds it, the program continues writing but the callback is not fired. There is a check if it matches an id, in the parser I see that this id is the one that is going in.

void canCallback(int packetSize)
{
  static uint32_t lastTime = 0;
  if (can_reader.packetId() == BOARD_ANSWER1 || can_reader.packetId() == BOARD_ANSWER2)
  {

    if (packetSize)
    {
      uint8_t buf[8];
      
      while (can_reader.available())
      {
         CAN.readBytes(buf, sizeof(buf));
      }
      uint8_tArrayToHexString2(buf, sizeof(buf), rapidResponse);
     
    }
  }
}

This is a method I use to convert to hexString it's not relevant but it may bring more clarity

void uint8_tArrayToHexString2(uint8_t *data, size_t len, char *output)
{
  static const char hexChars[] = "0123456789ABCDEF";
  for (size_t i = 0; i < len; ++i)
  {
    output[i * 3] = hexChars[(data[i] >> 4) & 0xF];
    output[i * 3 + 1] = hexChars[data[i] & 0xF];
    output[i * 3 + 2] = ' ';
  }
  output[len * 3 - 1] = '\0';
}
WikiLift
  • 11
  • 5
  • There is no telling without the actual code. CAN transceivers are "dumb", they don't trigger anything, that would be the job of the CAN _controller_. You could however check the rx pin of the transceiver with your oscilloscope to check that it is working as intended. Also please note that electronics troubleshooting is off-topic here and such questions are more suitable for https://electronics.stackexchange.com/ – Lundin Apr 26 '23 at 06:52
  • Thank you very much for answering, the response from the board is reaching the transceiver, but at the programmatic level, the callback is not firing. I am going to edit the answer trying to put the most relevant code, since it is very long and I do not want to bother. – WikiLift Apr 26 '23 at 06:55
  • "works well if the program does not exceed a send per second, if it exceeds it, the program continues writing but the callback is not fired" This sounds unrelated to the CAN communication as such, but is rather likely something caused by your RTOS setup. – Lundin Apr 26 '23 at 07:44
  • Lundin thank you very much for the active response.I'll tell you, I've even tried to do without Rtos to simplify it and isolate the problem, in both cases, when the transfer rate is high, the problems begin, as you well mention, the dog shouldn't be an impediment, so the following test I performed, It's to connect two transceivers, since I thought that perhaps the problem was that, as we well know, it cannot read and write at the same time, so I thought I am going to dedicate one to reading and the other to writing, hanging from the same bus.I get the same result,that's why I ran out of ideas. – WikiLift Apr 26 '23 at 08:08
  • CAN bus can handle reads and writes at the same time just fine, all of that is handled by the CAN controller - if you try to write while something is already sent, the controller will buffer the message and try to send as soon as the bus is free. However if there is no other node on the bus sending ACK as a message is transmitted, error counters in the transmitting node will start counting up and eventually it will disconnect itself from the bus. You can check if there are error frames present on the bus with a CAN listener or oscilloscope (both are mandatory tools to have). – Lundin Apr 26 '23 at 08:14
  • I am using a can analyzer attached to the bus, where I see the frames that come in and the ones that the board returns, the esp32 is writing the frames correctly, and the board is responding correctly with the expected id and in the expected response time, the problem It is that the moment I start to write packets with more speed, the callback stops firing, but with the analyzer I see that the board responds correctly and the esp writes correctly on it, it is the callback that does not fire. – WikiLift Apr 26 '23 at 08:21

1 Answers1

1

Although the Adafruit library is wonderful, the problem lay in its use. When you shoot many messages at the bus very quickly, it ends up becoming unstable.

I have used the IDF CAN library of the ESP32 and it has nothing to do with it, it is like night and day.

I leave a minimal implementation for the Arduino framework in case it helps someone.

#include <Arduino.h>
#include "driver/gpio.h"
#include "driver/can.h"

TaskHandle_t can_receive_task_handle;

void can_receive_task(void *arg)
{
  can_message_t rx_msg;
  for(;;)
  {
    if (can_receive(&rx_msg, pdMS_TO_TICKS(100)) == ESP_OK)
    {
      printf("Received message: ID = 0x%08X, Data: ", rx_msg.identifier);
      for (int i = 0; i < rx_msg.data_length_code; i++)
      {
        printf("%02X ", rx_msg.data[i]);
      }
      printf("\n");
    }
  }
}

void setup()
{

  Serial.begin(115200);

  //? Configure GPIO pins for CAN must be 4/5 or 16/17
  gpio_install_isr_service(0);
  gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT);
  gpio_set_direction(GPIO_NUM_16, GPIO_MODE_INPUT);

  //! Configure CAN controller
  can_general_config_t can_config = {
      .mode = CAN_MODE_NORMAL,
      .tx_io = GPIO_NUM_17,
      .rx_io = GPIO_NUM_16,
      .clkout_io = GPIO_NUM_NC,
      .bus_off_io = GPIO_NUM_NC,
      .tx_queue_len = 5,
      .rx_queue_len = 5,
      .alerts_enabled = CAN_ALERT_NONE,
      .clkout_divider = 0};
  can_timing_config_t timing_config = CAN_TIMING_CONFIG_125KBITS();
  can_filter_config_t filter_config = CAN_FILTER_CONFIG_ACCEPT_ALL();

  if (can_driver_install(&can_config, &timing_config, &filter_config) == ESP_OK &&
      can_start() == ESP_OK)
  {
    Serial.println("CAN controller initialized successfully");
  }
  else
  {
    Serial.println("Error initializing CAN controller");
    return;
  }

  //! Create RTOS task for receiving CAN messages
  xTaskCreate(can_receive_task, "can_receive_task", 2048, NULL, 5, &can_receive_task_handle);
}

void loop()
{
 
}

Special thanks to the ESP32 Arduino forum: Using the official CAN driver.

WikiLift
  • 11
  • 5