Using the official CAN driver
Using the official CAN driver
Has anyone successfully used the ESP-IDF CAN driver in Arduino?
Ive tried a bunch of different things, but cant get it to compile...
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.
-
- Posts: 829
- Joined: Mon Jul 22, 2019 3:20 pm
Re: Using the official CAN driver with Arduino
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};
Re: Using the official CAN driver with Arduino
Could explain what steps you have taken to port the driver over to Arduino, and also the compilation error log you are seeing.dmaxben wrote: Ive tried a bunch of different things, but cant get it to compile
-
- Posts: 14
- Joined: Mon Oct 07, 2019 4:55 pm
Re: Using the official CAN driver with Arduino
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.
https://github.com/miwagner/ESP32-Arduino-CAN
It is a port from the official CAN driver, it work as expected.
Re: Using the official CAN driver with Arduino
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.MStackoverflow wrote: ↑Tue Oct 08, 2019 3:26 pmHave 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 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.
Re: Using the official CAN driver
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.
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.
Re: Using the official CAN driver with Arduino
@ 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).
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.
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}
};
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.
Re: Using the official CAN driver with Arduino
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.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).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.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} };
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.
Good advice on splitting things into separate tasks, thanks!
Ben
Re: Using the official CAN driver with Arduino
dmaxben wrote: ↑Wed Oct 09, 2019 3:41 pmAlso, 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?
Re: Using the official CAN driver with Arduino
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.
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: No registered users and 64 guests