2
\$\begingroup\$

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.

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 200 ms, I can see (with a CAN analyzer connected to the bus from the PC) that the frames are arriving, they are received 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.

Any ideas?

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. It works well if the program does not exceed one send per second. If it exceeds that 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';
}

\$\endgroup\$
2
  • 2
    \$\begingroup\$ The SO question was closed for not providing enough details to answer, not because it was off-topic (I've voted to re-open your question there after changes). What I said in a comment was that in case your question is related to hardware, it's off-topic on SO and on-topic here. Questions about microcontroller programming and RTOS are on-topic on both sites. \$\endgroup\$
    – Lundin
    Commented Apr 26, 2023 at 7:51
  • 2
    \$\begingroup\$ And as I mentioned on SO I suspect this problem is related to your RTOS setup or maybe you have a different process disabling all interrupts etc. \$\endgroup\$
    – Lundin
    Commented Apr 26, 2023 at 7:52

1 Answer 1

2
\$\begingroup\$

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.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ You may want to 'accept' your answer in order to mark your question as solved. \$\endgroup\$
    – Velvet
    Commented Apr 26, 2023 at 13:16
  • 1
    \$\begingroup\$ Thanks for the info but forum says "you may accept in 2 days". Thank you mate. \$\endgroup\$
    – WikiLift
    Commented Apr 26, 2023 at 13:25
  • \$\begingroup\$ Thanks, I didn't know about that requirement. \$\endgroup\$
    – Velvet
    Commented Apr 26, 2023 at 13:36

Not the answer you're looking for? Browse other questions tagged or ask your own question.