Using the official CAN driver

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

Using the official CAN driver

Postby dmaxben » Mon Oct 07, 2019 2:38 pm

Has anyone successfully used the ESP-IDF CAN driver in Arduino?

Ive tried a bunch of different things, but cant get it to compile... :?
Last edited by dmaxben on Thu May 21, 2020 8:08 pm, edited 2 times in total.

lbernstone
Posts: 828
Joined: Mon Jul 22, 2019 3:20 pm

Re: Using the official CAN driver with Arduino

Postby lbernstone » Mon Oct 07, 2019 7:10 pm

Just the un-C++ bits:

Code: Select all

static const can_timing_config_t t_config = CAN_TIMING_CONFIG_25KBITS();
//Filter all other IDs except MSG_ID
static const can_filter_config_t f_config = {.acceptance_code = (uint32_t)(MSG_ID << 21),
                                             .acceptance_mask = (uint32_t)~(CAN_STD_ID_MASK << 21),
                                             .single_filter = true};
//Set to NO_ACK mode due to self testing with single module
static const can_general_config_t g_config = {.mode = CAN_MODE_NO_ACK,
                                              .tx_io = (gpio_num_t)TX_GPIO_NUM,
                                              .rx_io = (gpio_num_t)RX_GPIO_NUM,
                                              .clkout_io = (gpio_num_t)CAN_IO_UNUSED,
                                              .bus_off_io = (gpio_num_t)CAN_IO_UNUSED,
                                              .tx_queue_len = 5,
                                              .rx_queue_len = 5,
                                              .alerts_enabled = CAN_ALERT_NONE,
                                              .clkout_divider = 0
                                              };

static SemaphoreHandle_t tx_sem;
static SemaphoreHandle_t rx_sem;
static SemaphoreHandle_t ctrl_sem;
static SemaphoreHandle_t done_sem;

/* --------------------------- Tasks and Functions -------------------------- */

static void can_transmit_task(void *arg)
{
    can_message_t tx_msg = {.flags = CAN_MSG_FLAG_SELF, .identifier = MSG_ID, .data_length_code = 1};

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

Re: Using the official CAN driver with Arduino

Postby ESP_Dazz » Tue Oct 08, 2019 6:34 am

dmaxben wrote: Ive tried a bunch of different things, but cant get it to compile
Could explain what steps you have taken to port the driver over to Arduino, and also the compilation error log you are seeing.

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

Re: Using the official CAN driver with Arduino

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

Have you seen this library from miwagner?

https://github.com/miwagner/ESP32-Arduino-CAN
It is a port from the official CAN driver, it work as expected.

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

Re: Using the official CAN driver with Arduino

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

MStackoverflow wrote:
Tue Oct 08, 2019 3:26 pm
Have you seen this library from miwagner?

https://github.com/miwagner/ESP32-Arduino-CAN
It is a port from the official CAN driver, it work as expected.
The miwagner arduino driver and Thomas Barthe's arduino ESP-32 CAN driver are significantly different than the current ESP-IDF CAN driver. They are *NOT* direct ports.

The miwagner and Thomas Barth Arduino ESP32 CAN drivers have some big issues with queues, and it doesnt have any protection/safety with large multi-threaded/tasked programs. If you are trying to send CAN messages from several different areas of your multi-tasked code, it usually gets choked sooner or later....

And the biggest issue of all is that it doesnt have the IRAM_ATTR directive, which would allow it to try to access random parts of flash/code at ANY time....this includes during an OTA update (which disables flash-cache). If you leave the miwagner/Thomas Barth Arduino ESP32 CAN driver running during an OTA update, it was guaranteed to crash the whole ESP32.

The official ESP-IDF CAN driver doesnt have any of these issues, and is completely safe to use with any program, and have running at all times, including during an OTA update.

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

Re: Using the official CAN driver

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

Also, as a update, I was able to get the official ESP-IDF CAN driver working perfectly with help from a friend who knows MUCH more about programming and the ESP32 than I do.

I highly recommend doing all ESP32 CAN stuff ONLY using the official ESP-IDF CAN driver. Its task/thread-safe, remains functional while OTA is running, doesnt seem to disturb the bus when starting/rebooting the ESP32...it just works perfectly! I wish I had just started out with the ESP-IDF CAN driver from the start; it would have saved me a lot of frustration and bug-tracking.

Here is some basic starter code for anyone else who wants to use the official ESP-IDF CAN driver.

Be sure to adjust your GPIO settings, CAN bus bitrate, queue sizes, and Rx/Tx blocking (ticks) to suit your own needs/application. You can also add additional code to confirm to your program that the message was sent successfully, error checking, etc. This is just basic stuff to get anyone started.

Code: Select all

#include <driver/can.h>
#include driver/gpio.h>
#include <esp_system.h>
#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"


// define your CAN messages here, OR you can define them locally...
// standard 11-bit frame ID = 0
// extended 29-bit frame ID = 1
// format:   can_message_t (name of your message) = {std/ext frame, message ID, message DLC, {data bytes here}};

can_message_t myMessageToSend = {0, 0x123, 8, {0x01, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x99}};

uint32_t previousMillis;
const uint32_t interval = 1000;

//=================================================

void setup()
{
// anything else you might need to do....
setup_can_driver();
}

void setup_can_driver()
{
 can_general_config_t general_config = {
        .mode = CAN_MODE_NORMAL,
        .tx_io = (gpio_num_t)GPIO_NUM_5,
        .rx_io = (gpio_num_t)GPIO_NUM_4,
        .clkout_io = (gpio_num_t)CAN_IO_UNUSED,
        .bus_off_io = (gpio_num_t)CAN_IO_UNUSED,
        .tx_queue_len = 100,
        .rx_queue_len = 65,
        .alerts_enabled = CAN_ALERT_NONE,
        .clkout_divider = 0};
    can_timing_config_t timing_config = CAN_TIMING_CONFIG_500KBITS();
    can_filter_config_t filter_config = CAN_FILTER_CONFIG_ACCEPT_ALL();
    esp_err_t error;

    error = can_driver_install(&general_config, &timing_config, &filter_config);
    if (error == ESP_OK)
    {
        Serial.println("CAN Driver installation success...");
    }
    else
    {
        Serial.println("CAN Driver installation fail...");
        return;
    }

    // start CAN driver
    error = can_start();
    if (error == ESP_OK)
    {
        Serial.println("CAN Driver start success...");
    }
    else
    {
        Serial.println("CAN Driver start FAILED...");
        return;
    }
}

//=======================================================================

void loop()
{
     can_message_t rx_frame;
    if (can_receive(&rx_frame, pdMS_TO_TICKS(1000)) == ESP_OK)
    {
    //do whatever you need with your received CAN messages here
    // follow the can_message_t struct to learn how to decode/process the received frame.
    }
    
     if (millis() - previousMillis > interval)  // send out your CAN frame once every second
        { 
            previousMillis = millis();
            can_transmit(&myMessageToSend, pdMS_TO_TICKS(1000));
      }
}
Last edited by dmaxben on Thu May 21, 2020 10:43 pm, edited 3 times in total.

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

Re: Using the official CAN driver with Arduino

Postby ESP_Dazz » Wed Oct 09, 2019 4:44 pm

@ dmaxben Just a few pointers regarding IDF CAN driver usage

It's probably a good idea to use the member names when initializing a CAN message structure in case the order of the members change in the future versions of the driver. There are also a bunch of message flags documented here to set/check to a certain type (e.g., extended ID, RTR etc).

Code: Select all

can_message_t my_message = {
	.identifier = 0xABCD,
	.data_length_code = 8,
	.flags = CAN_MSG_FLAG_EXTD | CAN_MSG_FLAG_SS,
	.data = {1, 2 , 3 , 4 ,5 ,6 ,7 ,8}
};
The CAN driver was designed to be used in a multi-threaded manner, so general practice is to split receiving and transmitting into separate tasks (threads). This way, the RX queue can be emptied and the TX queue filled simultaneously by the two threads, and you won't need such a large TX and RX queue. Default queue length setting by the driver is 5, a length of 100 seems abnormally long.

You should still be able to directly call FreeRTOS functions and types to create tasks in Arduino. I suggest you take a look at the Self-Test example for a start. You should be able to easily adapt that to Arduino. In theory, it should work by just copying the code, renaming app_main() to setup(), and leaving loop() empty.

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

Re: Using the official CAN driver with Arduino

Postby dmaxben » Thu Oct 10, 2019 5:52 pm

ESP_Dazz wrote:
Wed Oct 09, 2019 4:44 pm
@ dmaxben Just a few pointers regarding IDF CAN driver usage

It's probably a good idea to use the member names when initializing a CAN message structure in case the order of the members change in the future versions of the driver. There are also a bunch of message flags documented here to set/check to a certain type (e.g., extended ID, RTR etc).

Code: Select all

can_message_t my_message = {
	.identifier = 0xABCD,
	.data_length_code = 8,
	.flags = CAN_MSG_FLAG_EXTD | CAN_MSG_FLAG_SS,
	.data = {1, 2 , 3 , 4 ,5 ,6 ,7 ,8}
};
The CAN driver was designed to be used in a multi-threaded manner, so general practice is to split receiving and transmitting into separate tasks (threads). This way, the RX queue can be emptied and the TX queue filled simultaneously by the two threads, and you won't need such a large TX and RX queue. Default queue length setting by the driver is 5, a length of 100 seems abnormally long.

You should still be able to directly call FreeRTOS functions and types to create tasks in Arduino. I suggest you take a look at the Self-Test example for a start. You should be able to easily adapt that to Arduino. In theory, it should work by just copying the code, renaming app_main() to setup(), and leaving loop() empty.
I agree on using the actual member names when defining the messsages...however my project has hundreds of CAN messages, and I didnt want to type everything out by hand, making my program hundreds of lines longer haha. :lol:

Good advice on splitting things into separate tasks, thanks!

Ben

kissinno
Posts: 10
Joined: Tue Apr 14, 2020 11:31 am

Re: Using the official CAN driver with Arduino

Postby kissinno » Tue Apr 14, 2020 11:50 am

dmaxben wrote:
Wed Oct 09, 2019 3:41 pm
Also, as a update, I was able to get the official ESP-IDF CAN driver working perfectly in Arduino

This is just basic stuff to get anyone started.

Code: Select all

#include <driver/can.h>
#include driver/gpio.h>
#include <esp_system.h>
....
[/quote]

As you, I need to keep Arduino with my ESP32 project with CAN bus.
I tried your basic exemple (Serial.begin(115200); must be added in Setup()), but it does not work. My CAN sniffer does not received anything, nor the ESP32.

What CAN interface did you used? SN65hvd2xx? See bellow, it seems having issue with SN65hvd230 while 232 works perfectly.
https://esp32.com/viewtopic.php?t=380&start=170

Bad luck for me, I do have a VP230. This may be the problem :-(

Don't you a full running exdemple please?

kissinno
Posts: 10
Joined: Tue Apr 14, 2020 11:31 am

Re: Using the official CAN driver with Arduino

Postby kissinno » Tue Apr 14, 2020 2:43 pm

As you, I need to keep Arduino with my ESP32 project with CAN bus.

I tried your basic exemple (CAN standard 11bit, 500kb) but it does not work.

Don't forget to add Serial.begin(115200) is in Setup() if you want to get the messages.

"CAN Driver installation success" & CAN Driver start success" are now shown but nothing else happens. My CAN sniffer does not received anything from ESP32, nor the ESP32 receiving what is sent by the CAN sniffer.

I also tried Michael Wagner lib & exempels without success:
https://github.com/miwagner/ESP32-Arduino-CAN

BTW, my test setup (with PEAK CAN sniffer) has been sucessfully running many time with an Arduino Mega & MCP2515 CAN interface.

dmaxben please, what CAN interface did you used please? SN65hvd2xx?
See bellow, it seems having issue with SN65hvd230 while 232 works perfectly.
https://esp32.com/viewtopic.php?t=380&start=170

Bad luck for me, I do have a VP230. This may be the problem :-(

Don't you a full running example to share please?

Thanks for any support how to use the official CAN driver with Arduino.

Who is online

Users browsing this forum: Bing [Bot] and 152 guests