Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP-IDF CAN controller driver not working for transmit: invalid_state error #3921

Closed
Civilduino opened this issue Apr 20, 2020 · 14 comments
Closed

Comments

@Civilduino
Copy link

Civilduino commented Apr 20, 2020

Hardware:

Board: Wemos LOLIN D32 Pro
CAN Bus Transceiver: SN65HVD230

Software

PLATFORM: Espressif 32 1.12.0 > WEMOS LOLIN D32 PRO
HARDWARE: ESP32 240MHz, 320KB RAM, 4MB Flash
PACKAGES:
-- framework-arduinoespressif32 3.10004.200129 (1.0.4)
-- tool-esptoolpy 1.20600.0 (2.6.0)
-- toolchain-xtensa32 2.50200.80 (5.2.0)
Dependency Graph
--Ticker 1.1

RAM: [ ] 4.5% (used 14796 bytes from 327680 bytes)
Flash: [== ] 20.8% (used 272229 bytes from 1310720 bytes)

IDE name: Platformio.io Core 4.3.1, Home 3.1.1 using Visual Code IDE
Flash Frequency: default
PSRAM enabled: yes
Upload Speed: 460800
Computer OS: Mac OSX

Description:

I am trying to use the ESP-IDF driver for the CAN controller in my CAN BUS application. I am getting an error when trying to transmit a CAN data frame or RTR. The error appears when trying to send the second CAN data frame. However, the first frame seems to be corrupted as well when I look at it with a digital analyser directly at the Tx pin.

Why does the CAN controller enters an "invalid_state" and then it goes "bus-off"?

How exactly I need to use this API? if I were to only receive CAN frames my approach seems to work.

or can it be a hardware issue as described here (from page 16) https://esp32.com/viewtopic.php?t=380&start=170 ?

Sketch:

#include <Arduino.h>
#include <driver/can.h>
#include <driver/gpio.h>

#include <Ticker.h>

// Global objects
Ticker canBusTimer;

// Global variables
uint8_t canBusFLAG = 0;

// Prototype functions
void CAN_begin(void);
void CAN_receive(void);
void CAN_transmit_RTR(uint32_t id);
void CAN_transmit_stdData(uint32_t id, uint8_t len, uint8_t *data);

void can_flag(void);

void setup()
{
  CAN_begin();
  delay(1000);
  canBusTimer.attach_ms(1000, can_flag);
}

void loop()
{
  if (canBusFLAG == 1)
  {
    uint8_t canData[1] = {1};
    CAN_transmit_stdData(0x003, 1, canData);
    canBusFLAG = 0;
    CAN_receive();
  }
}

// FUNCTIONS
void can_flag(void)
{
  canBusFLAG = 1;
}

void CAN_begin(void)
{
  //Initialize configuration structures using macro initializers (changed GPIO type in esp idf library)
  can_general_config_t g_config = CAN_GENERAL_CONFIG_DEFAULT(GPIO_NUM_22, GPIO_NUM_23, CAN_MODE_NO_ACK);
  can_timing_config_t t_config = CAN_TIMING_CONFIG_25KBITS();
  can_filter_config_t f_config = CAN_FILTER_CONFIG_ACCEPT_ALL();

  //Install CAN driver
  if (can_driver_install(&g_config, &t_config, &f_config) == ESP_OK)
    printf("Driver installed\n");
  else
  {
    printf("Failed to install driver\n");
    return;
  }

  //Start CAN driver
  if (can_start() == ESP_OK)
    printf("Driver started\n");
  else
  {
    printf("Failed to start driver\n");
    return;
  }
}

void CAN_receive(void)
{
  can_status_info_t can_status;
  can_message_t message;

  //Check for received messages
  can_get_status_info(&can_status);
  if (can_status.msgs_to_rx >= 1)
  {
    if (can_receive(&message, pdMS_TO_TICKS(10)) == ESP_OK)
      printf("Message received\n");
    else
    {
      printf("Failed to receive message\n");
      return;
    }

    //Process received message
    printf("ID is %d\n", message.identifier);
    for (int i = 0; i < message.data_length_code; i++)
    {
      printf("Data byte %d = %d\n", i, message.data[i]);
    }
  }
}

void CAN_transmit_stdData(uint32_t id, uint8_t len, uint8_t *data)
{
  //Configure message to transmit
  can_message_t message;
  message.flags = CAN_MSG_FLAG_SELF;
  message.identifier = id;
  message.data_length_code = len;
  message.data[0] = 1;
  // for (uint8_t i = 0; i < len; i++)
  // {
  //     message.data[i] = 1;
  // }

  can_status_info_t info;
  can_get_status_info(&info);

  if (info.state == CAN_STATE_RUNNING)
    printf("CAN running\n");
  else if (info.state == CAN_STATE_STOPPED)
    printf("CAN stopped\n");
  else if (info.state == CAN_STATE_RECOVERING)
    printf("CAN recovering\n");
  else if (info.state == CAN_STATE_BUS_OFF)
    printf("CAN bus-off\n");

  ESP_ERROR_CHECK_WITHOUT_ABORT(can_transmit(&message, pdMS_TO_TICKS(100)));

  // //Queue message for transmission
  // if (can_transmit(&message, pdMS_TO_TICKS(100)) == ESP_OK)
  //     printf("Message queued for transmission\n");
  // else
  //     printf("Failed to queue message for transmission\n");
}

void CAN_transmit_RTR(uint32_t id)
{
  //Configure message to transmit
  can_message_t message;
  message.flags = CAN_MSG_FLAG_RTR;
  message.identifier = id;
  message.data_length_code = 0;

  //Queue message for transmission
  ESP_ERROR_CHECK_WITHOUT_ABORT(can_transmit(&message, pdMS_TO_TICKS(100)));
}

Debug Messages:

ESP_ERROR_CHECK_WITHOUT_ABORT failed: esp_err_t 0x103 (ESP_ERR_INVALID_STATE) at 0x4008d8df
file: "src/main.cpp" line 122
func: void CAN_transmit_stdData(uint32_t, uint8_t, uint8_t*)
expression: can_transmit(&message, pdMS_TO_TICKS(100))

Platformio configuration

[env:lolin_d32_pro]
platform = espressif32
board = lolin_d32_pro
framework = arduino
upload_port = /dev/tty.wchusbserial1410
monitor_speed = 115200

; debug_tool = esp-prog
; debug_init_break = tbreak setup
; monitor_filters = log2file, esp32_exception_decoder
build_flags =
    -DBOARD_HAS_PSRAM
    -mfix-esp32-psram-cache-issue
    -DCORE_DEBUG_LEVEL=4
@Civilduino
Copy link
Author

So it appears that it was a hardware problem after all. Changed the IC in the CJMCU-230 module (think is fake) for an original SN65HVD230 and everything worked as it should.

See picture below. Hope it avoid headaches to others.
SN65HVD230

@notmmao
Copy link

notmmao commented Sep 17, 2020

@Civilduino I have encountered the same problem as you ( first frame return 0, the latter return 0x103).
To be additional, The can_receive works fine.
Could this be a hardware problem? Seek your help.

@CKRS2
Copy link

CKRS2 commented Jan 26, 2021

@Civilduino I have encountered the same problem as you ( first frame return 0, the latter return 0x103).
To be additional, The can_receive works fine.
Could this be a hardware problem? Seek your help.

Did you find any reason for this problem?
Currently, I'm facing the same problem.

Receiving is going fine, transmitting is not working!

@Civilduino
Copy link
Author

See my comment above, it is a hardware problem. There are counterfeit chips of SN65HVD230 out there. Order original chips from a reliable supplier and replace the one on your PCB. It worked for me. Good luck!

@gitcnd
Copy link

gitcnd commented Nov 15, 2021

It might actually be a software problem? When the QMC chips replaced the HMC ones for magnetometers, minor subtle code adjustments were needed. Chips that are MARKED DIFFERENTLY but serve as replacements for other chips, are not per-se "counterfeit". What were the markings on the chip that you had problems with, and what were the ones on the "original" that you found to work ? (Your photo is not clear enough)

@Civilduino
Copy link
Author

Sorry for late answer.
The "counterfeit" are marked VP230 82M ACNP04 and "original" VP230 87M AP48.

@Casaadi
Copy link

Casaadi commented Jun 30, 2022

I have a query with the Hardware Connection. How does ESP32 with CAN work. CAN I define any pins as CAN Rx and Tx and just change the definition here:
CAN_GENERAL_CONFIG_DEFAULT(GPIO_NUM_22, GPIO_NUM_23, CAN_MODE_NO_ACK);

Or this program only works with Pins 22 and 23?? Also which is Rx and which one is Tx??
Thanks

@lbernstone
Copy link
Contributor

I don't think there are specific pins for CAN, you can use what gpio you have open.
CAN_GENERAL_CONFIG_DEFAULT(tx_io_num, rx_io_num, op_mode)

@Samg381
Copy link

Samg381 commented Aug 11, 2022

Does anyone here have any experience with reading raw input from a transceiver board (SN65HVD230) via the GPIO pins on an ESP32? I am trying to read CAN messages very quickly bit-by-bit.

@gitcnd
Copy link

gitcnd commented Aug 12, 2022

Some CAN boards do not work on 3.3 volts, and require 5v at least.
Some CAN boards are sketchy and just do not work at all.
Keep in mind there's 2 kind of CAN board - ones with just the transceiver chip, and others with the CAN decode ship as well - you want the 2nd kind - trying to decode CAN in software is a monster can of worms.

If you're "bitbashing", use an ESP with 2 cores, so you can bitbash in one core, and process in the other.

@Samg381
Copy link

Samg381 commented Aug 12, 2022 via email

@gitcnd
Copy link

gitcnd commented Aug 12, 2022

Generic CAN-Bus code: I looked myself about 2 months ago, and could not find any, no.
Get the CAN modules that include the CAN decoder chip (not just the transceiver board), then you won't have any problems.

I'm not sure why China makes the "CAN" boards without the chip - I expect it's for people who want to do differential signalling, but do not want to use CAN protocols. I doubt that's you.

@Samg381
Copy link

Samg381 commented Aug 12, 2022 via email

@Vincent-Chan98
Copy link

Hi guys, I have a question here. Does anyone know how to reactivate the twai_transmit() function in xTaskCreatePinnedToCore(). The output only shows one-time message successfully queued for transmission while the next and so forth saying transmission failed. Any idea?
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants