I have two ESP32S, each connected to a CAN driver (MCP2515 + TJA1050). One is constantly sending data, the other is constantly only receiving it. I want whoever receives the data to work in Listen-only mode. The problem is that in Listen-only mode, I receive an interrupt only once and read two buffers RXB0 and RXB1 once - after the interrupt from the INT output (MCP2515), then the interrupts do not arrive (I looked in the logic analyzer). When I set Normal operation mode, everything works fine: interrupts come and I easily receive data from buffers. I've looked through all the documentation on the MCP2515 and haven't found anything that could help me. This is my first time using the MCP2515. Here is the receiver code:
#include
#include
#include
#include "can.h"
#include "esp_timer.h"
#include "hal/gpio_types.h"
#include "lwip/err.h"
#include "mcp2515.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#define MCP2515_CS_PIN 5
#define MCP2515_MISO_PIN 19
#define MCP2515_MOSI_PIN 23
#define MCP2515_CLK_PIN 18
#define MCP2515_INT_PIN 4
#define MCP2515_MAX_TRANSFER_SZ 3
#define MCP2515_CLOCK_SPEED_HZ 8000000
#define MCP2515_QUEUE_SIZE 1024
#define MCP2515_SPI_HOST_ID SPI2_HOST
#define MCP2515_CAN_SPEED CAN_500KBPS
#define MCP2515_CAN_CLOCK MCP_8MHZ
#define USE_CAN_FILTERS 0
volatile bool is_frame_ready = false;
void can_bus_spi_init(void)
{
spi_bus_config_t bus_cfg={
.miso_io_num = MCP2515_MISO_PIN,
.mosi_io_num = MCP2515_MOSI_PIN,
.sclk_io_num = MCP2515_CLK_PIN,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = MCP2515_MAX_TRANSFER_SZ
};
esp_err_t ret = spi_bus_initialize(MCP2515_SPI_HOST_ID, &bus_cfg, SPI_DMA_CH_AUTO);
ESP_ERROR_CHECK(ret);
spi_device_interface_config_t dev_cfg = {
.mode = 0,
.clock_speed_hz = MCP2515_CLOCK_SPEED_HZ,
.spics_io_num = MCP2515_CS_PIN,
.queue_size = MCP2515_QUEUE_SIZE
};
ret = spi_bus_add_device(MCP2515_SPI_HOST_ID, &dev_cfg, &MCP2515_Object->spi);
ESP_ERROR_CHECK(ret);
}
void IRAM_ATTR mcp2515_isr_handler(void* arg)
{
is_frame_ready = true;
}
void mcp2515_int_init(void)
{
gpio_config_t io_conf = {
.intr_type = GPIO_INTR_NEGEDGE,
.mode = GPIO_MODE_INPUT,
.pin_bit_mask = (1ULL << MCP2515_INT_PIN),
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE
};
gpio_config(&io_conf);
gpio_install_isr_service(0);
gpio_isr_handler_add(MCP2515_INT_PIN, mcp2515_isr_handler, NULL);
}
void can_bus_init(void)
{
MCP2515_init();
can_bus_spi_init();
MCP2515_reset();
MCP2515_setConfigMode();
MCP2515_setBitrate(MCP2515_CAN_SPEED, MCP2515_CAN_CLOCK);
mcp2515_int_init();
#if USE_CAN_FILTERS
ERROR_t ret = MCP2515_setFilterMask(MASK0, false, 0xff8);
if (ret != ERROR_OK)
{
printf("Error to set mask");
esp_restart();
return;
}
ret = MCP2515_setFilter(RXF0, false, 0x7e8);
if (ret != ERROR_OK)
{
printf("Error to set filter");
esp_restart();
return;
}
ret = MCP2515_setFilterMask(MASK1, false, 0xff8);
if (ret != ERROR_OK)
{
printf("Error to set mask");
esp_restart();
return;
}
ret = MCP2515_setFilter(RXF2, false, 0x7e8);
if (ret != ERROR_OK)
{
printf("Error to set filter");
esp_restart();
return;
}
#endif
//MCP2515_setListenOnlyMode();
MCP2515_setNormalMode();
}
void print_can_frame(CAN_FRAME frame, RXBn_t RXBn) {
if (!frame) return;
const char* RXBn_name; // указатель на строку
if (RXBn == RXB0) {
RXBn_name = "RXB0";
} else if (RXBn == RXB1) {
RXBn_name = "RXB1";
} else {
RXBn_name = "UNKNOWN";
}
int64_t timestamp_us = esp_timer_get_time();
printf("[%s][Time: %lld.%03lld ms] ", RXBn_name, timestamp_us / 1000, timestamp_us % 1000);
printf("CAN ID: 0x%08lX, DLC: %u, Data: ", frame->can_id, frame->can_dlc);
for (int i = 0; i < frame->can_dlc; i++) {
printf("%02X ", frame->data[i]);
}
printf("\n");
}
void app_main(void)
{
can_bus_init();
while (true) {
if (is_frame_ready)
{
is_frame_ready = false;
uint8_t irq = MCP2515_getInterrupts();
CAN_FRAME_t can_frame;
if (irq & CANINTF_RX0IF) {
if (MCP2515_readMessage(RXB0, &can_frame) == ERROR_OK) {
print_can_frame(can_frame, RXB0);
}
else
{
printf("Error to read");
}
}
if (irq & CANINTF_RX1IF) {
if (MCP2515_readMessage(RXB1, &can_frame) == ERROR_OK) {
print_can_frame(can_frame, RXB1);
}
else
{
printf("Error to read");
}
}
}
vTaskDelay(pdMS_TO_TICKS(200));
}
}
I also want to ask car enthusiasts if it will be safe to read telemetry data from the car's OBD2 connector based on PID requests. I'm afraid to disrupt the operation of any ECU. In the future, I want to use this idea, but for now I just want to analyze the traffic in the car's CAN bus in Listen-only mode. I can use Listen-only mode for this idea (not for PID requests), but I'm afraid I won't see telemetry data with a normal frequency. If anything, I'm new to this business. Thank you in advance!