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));
}
}