Using CAN with Minima R4

I have tried to exactly reproduce the R4 CANBus example at https://docs.arduino.cc/tutorials/uno-r4-minima/can to no avail.

I purchased three of the SN65HVD230 CAN Board Accessory Network Transceiver modules recommended in the article. https://www.amazon.com/dp/B0B2W9PGKQ?psc=1&ref=ppx_yo2ov_dt_b_product_details. Wiring is simple: 3.3v, gnd, TX on D4, RX on D5. I have two R4 Minimas and connected CANH and CANL to two rails on a protoboard with 120 ohm resistors between the two rails on each end.

As an aside, I am familiar w/ CANBus and well versed in using can-utils such as candump, cansend, and cangen on a RaspPi.

I have copied the exact code from the send and receive portions of the article and sent each to the two R4s. Both appear to initialize (begin) the CAN OK but the send gets a -60003 rc "CAN.write(...) failed with error code -60003" and the receive doesn't do anything, even if I connect a pi w/ a PICAN2 shield to the rail's CANH and CANL and cangen can0 -v a bunch of traffic.

Interestingly, the successful begin could be a lie because I can remove all 4 jumper wires to the SN65HVD230 and begin still "appears" to succeed (i.e., CAN.begin(CanBitRate::BR_250k returns true). Also, I normally run my CANBus at 500k but left the sample untouched at 250k just to eliminate any confusion. I've tried both speeds to same result.

I do not own an oscilloscope but am happy to perform any other suggested diagnostics.

Does anyone have any insight?

Send from article:

/**************************************************************************************
 * INCLUDE
 **************************************************************************************/

#include <Arduino_CAN.h>

/**************************************************************************************
 * CONSTANTS
 **************************************************************************************/

static uint32_t const CAN_ID = 0x20;

/**************************************************************************************
 * SETUP/LOOP
 **************************************************************************************/

void setup()
{
  Serial.begin(115200);
  while (!Serial) { }

  if (!CAN.begin(CanBitRate::BR_250k))
  {
    Serial.println("CAN.begin(...) failed.");
    for (;;) {}
  }
}

static uint32_t msg_cnt = 0;

void loop()
{
  /* Assemble a CAN message with the format of
   * 0xCA 0xFE 0x00 0x00 [4 byte message counter]
   */
  uint8_t const msg_data[] = {0xCA,0xFE,0,0,0,0,0,0};
  memcpy((void *)(msg_data + 4), &msg_cnt, sizeof(msg_cnt));
  CanMsg msg(CAN_ID, sizeof(msg_data), msg_data);

  /* Transmit the CAN message, capture and display an
   * error core in case of failure.
   */
  if (int const rc = CAN.write(msg); rc < 0)
  {
    Serial.print  ("CAN.write(...) failed with error code ");
    Serial.println(rc);
    for (;;) { }
  }

  /* Increase the message counter. */
  msg_cnt++;

  /* Only send one message per second. */
  delay(1000);
}

Receive from article:

/**************************************************************************************
 * INCLUDE
 **************************************************************************************/

#include <Arduino_CAN.h>

/**************************************************************************************
 * SETUP/LOOP
 **************************************************************************************/

void setup()
{
  Serial.begin(115200);
  while (!Serial) { }

  if (!CAN.begin(CanBitRate::BR_250k))
  {
    Serial.println("CAN.begin(...) failed.");
    for (;;) {}
  }
}

void loop()
{
  if (CAN.available())
  {
    CanMsg const msg = CAN.read();
    Serial.println(msg);
  }
}

There are so many CAN libraries out there. The example uses Arduino_CAN. There is also CAN from the samples but it fails in begin()...

CAN.h send example (result:
16:56:30.203 -> CAN Sender
16:56:30.203 -> Starting CAN failed!)

// Copyright (c) Sandeep Mistry. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include <CAN.h>

void setup() {
  Serial.begin(9600);
  while (!Serial);

  Serial.println("CAN Sender");

  // start the CAN bus at 500 kbps
  if (!CAN.begin(500E3)) {
    Serial.println("Starting CAN failed!");
    while (1);
  }
}

void loop() {
  // send packet: id is 11 bits, packet can contain up to 8 bytes of data
  Serial.print("Sending packet ... ");

  CAN.beginPacket(0x12);
  CAN.write('h');
  CAN.write('e');
  CAN.write('l');
  CAN.write('l');
  CAN.write('o');
  CAN.endPacket();

  Serial.println("done");

  delay(1000);

  // send extended packet: id is 29 bits, packet can contain up to 8 bytes of data
  Serial.print("Sending extended packet ... ");

  CAN.beginExtendedPacket(0xabcdef);
  CAN.write('w');
  CAN.write('o');
  CAN.write('r');
  CAN.write('l');
  CAN.write('d');
  CAN.endPacket();

  Serial.println("done");

  delay(1000);
}

I've used mcp_can in the past (with a MKR 1010 and CAN shield) and would be happy to use it again with the R4 but haven't been able to get it to work either. Probably because I'm not really sure what the CS and INT pin values should be for that library. I think CS is pin 10 so this is what I tried (with result
17:01:03.363 -> Error Initializing MCP2515...
17:01:03.505 -> Error Sending Message...6)...

// CAN Send Example
//

#include <mcp_can.h>
#include <SPI.h>

MCP_CAN CAN0(10);     // Set CS to pin 10

void setup()
{
  Serial.begin(9600);
  while(!Serial);

  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  if(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK) Serial.println("MCP2515 Initialized Successfully!");
  else Serial.println("Error Initializing MCP2515...");

  CAN0.setMode(MCP_NORMAL);   // Change to normal mode to allow messages to be transmitted
}

byte data[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};

void loop()
{
  // send data:  ID = 0x100, Standard CAN Frame, Data length = 8 bytes, 'data' = array of data bytes to send
  byte sndStat = CAN0.sendMsgBuf(0x100, 0, 8, data);
  if(sndStat == CAN_OK){
    Serial.println("Message Sent Successfully!");
  } else {
    Serial.print("Error Sending Message...");
    Serial.println(sndStat);
  }
  delay(1000);   // send data per 1000ms
}

/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

You don’t have the 2515 chip on that board , I think it is just the driver ( level shifter )
For that code you need a different board that has the 2515 and the driver chip ( or different code for your board , that does all the CAN stuff in software )

Here

Hi jefflit

I am having the same problem. Im using the R4 with the MCP2551 transceiver module. I have compared yours to mine and they do the same job. My wiring is also the same as yours. I can trying to read the data from the CAN port on my lithium battery. I have connected my oscilloscope to the CAN bus and the RX port of the R4. In the picture the top waveform is the RX on D5 and bottom waveform is the CAN data from my battery. So my transceiver is working and the data is getting to the Arduino.

I have tried the transmit code too, I also get the error "CAN.write(...) failed with error code -60003" but when monitoring the CAN bus with the oscilloscope I do get the CAN bus waveforms. This suggests that the CAN transmit is working.

So either there is a problem with the arduino_can.h library or maybe the framing of the CAN data is not what the arduino is expecting? There is almost no extra info for this arduino_can library.

Hi jefflit I'm quite in your same situation: Arduino R4 wifi + SN65HVD230 CAN Board Accessory Network Transceiver module.

Having 2 R4 arduinos wifi + 2 SN65HVD230 CAN Board Accessory I was indeed able to reproduce the example in the documentation but...

...but when I tried to plug 1 Arduino R4 wifi + 1 SN65HVD230 into a woking can bus where 1 arduino MKRWifi1010 equipped with CAN Shield + 2 Arduino Nano Every equipped with 2 MCP2515 can shields are perfectly working, nothing happens.
Already done the usual homework suggested everywhere: canbus rate, pinout but still no message reading.

Could someone provide some real code examples, not the tutorial please, where an Arduino R4 Wifi is successfully reading messages from a working canbus?

Has someone developed some real documentation of the <Arduino_CAN.h> library? I know by heart what is published on the Arduino official repository and I need something really actionable.

For instance, below the code I crafted to read single bytes from the message:

/**************************************************************************************
 * INCLUDE
 **************************************************************************************/

#include <Arduino_CAN.h>

/**************************************************************************************
 * SETUP/LOOP
 **************************************************************************************/

void setup()
{
  Serial.begin(115200);
  while (!Serial) { }

  if (!CAN.begin(CanBitRate::BR_250k))
  {
    Serial.println("CAN.begin(...) failed.");
    for (;;) {}
  }
  uint8_t dataPayload[8];
}

void loop()
{
  if (CAN.available())
  {
    CanMsg const msg = CAN.read();
    for (int i = 0; i < 8; i++) {
      Serial.print(msg.data[i]);
    }
    Serial.println("");
    //Serial.println(sizeof(msg));
  }
}

guess what? The

msg.data[i]

statement is a pure "invention" suggested by ChatGPT [yes, I went even there out of frustration], not documented anywhere, that works!!?! Wouldn't be better to have some expert providing real documentation and examples?

Hope someone will really make canbus for Arduino R4 real and thanks in advance for every kind of specific, practical and documented help here!

I feel your pain. I'm more interested in sending than receiving CAN msgs at this time but it would be great if someone with understanding of the Arduino_CAN library could chime in.

If you need CAN use an external MPC2515 module complete with driver. That is a proven good module. I do not know if Cory Fowlers library will work with it. Hopefully others can confirm that.

When it comes to a working MCP2515 library I may shamelessly plug the one written by myself: 107-Arduino-MCP2515. It's battle tested in real-world :tm: custom built embedded systems :wink: .

Regarding your CAN problems, can you describe the network topology in more detail? With CAN you have to be careful with the wiring. You have to connect all modules in sequence AND there must be termination (120 Ohm) at each end of the bus, i.e. see here.

1 Like

The library looks good for what you wrote it for. For general use I would recommend you put simple send and receive sketches in it as well and one that would send and receive.

From my original post, my fake bus is:

I'm using the + and - rails of a small proto board as the "bus" with termination on each end. While no twisted pairs involved, all the connections are jumper wires less than 6" long. I have two Raspberry Pis w/ PICAN2 shields plugged into this and sending/receiving no problem.

I have no issue with shameless plugs or changing libraries but I'm not really clear on the separation of CAN functionality between the R4 Renesas RA4M1 (Arm® Cortex®-M4) processor's CANbus support and that of the SN65HVD230 transceiver. Basically, I'm not sure how to use the 107 library without knowing the INT and CS pins. The R4 gives us CAN RX and TX directly.

Perhaps you are suggesting not using the ARM CAN support and instead using a external mcp2515 module such as these little buggers: https://www.amazon.com/XLX-MCP2515-TJA1050-Receiver-Converter/dp/B081W7BPB2/ref=sr_1_6 I have a bunch of them I can try if that's what you're thinking but it seems a shame not to use the onboard capability of the R4. If you have a sample of using your library w/ the R4 and the transceivers that would be awesome.

That sounds allright to me. Twister-Pair is not a must at those distances.

The MCP2515 library is for usage with a MCP2515 chip, for the Renesas based boards you should be good with just the line driver (i.e. SN65HVD230), as the CAN IO module is inside the microcontroller (RA4M1). What the line-driver does is that you feed a CAN RX and a CAN TX signal in to them and they generate the differential CAN signal that is transported on CAN HIGH and CAN LOW.

Btw. even the MCP2515 needs a line driver, see MKR CAN schematic.

I'm still not sure on your bus topology, can you simplify it, i.e. just have one Uno R4 WiFi + SN65HVD230 in combination with a MKR CAN shield (and termination)? Are you using the same bitrate on both sides? Do you have acess to a logic analyser?

Yes, I run everything at 500k.

I ran a couple more tests. First, I kept the same proto board rail "bus", with a variety of devices (Raspberry Pi 3 w/ PICAN2, Raspberry Pi4 w/ PICAN2, Arduino Uno with a Seed Studios CAN shield, and two Arduino R4 Minimas with SN65HVD230 transceivers) plugged into the rail.

I started candump on the Pi4 and then ran the following code on the Uno to send messages to the bus. This worked fine -- the messages appear in the Pi candump as expected.

#include <mcp_can.h>
#include <SPI.h>

MCP_CAN CAN0(9); // Set CS to pin

void setup()
{
  Serial.begin(9600);
  while(!Serial);

  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  if(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK) Serial.println("MCP2515 Initialized Successfully!");
  else Serial.println("Error Initializing MCP2515...");

  CAN0.setMode(MCP_NORMAL);   // Change to normal mode to allow messages to be transmitted
}

byte data[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};

void loop()
{
  // send data:  ID = 0x100, Standard CAN Frame, Data length = 8 bytes, 'data' = array of data bytes to send
  byte sndStat = CAN0.sendMsgBuf(0x100, 0, 8, data);
  if(sndStat == CAN_OK){
    Serial.println("Message Sent Successfully!");
  } else {
    Serial.print("Error Sending Message...");
    Serial.println(sndStat);
  }
  delay(1000);
}

I then unplugged the USB cable for the Uno from my Mac and plugged in one of the R4s, which is running the following code. Amazingly and unexplainably, it works. I see the messages on the Pi. I swear this wasn't working previously.

#include <Arduino_CAN.h>

static uint32_t const CAN_ID = 0x320;
static uint32_t msg_cnt = 0;

void setup()
{
  Serial.begin(9600);
  while (!Serial) { }

  if (!CAN.begin(CanBitRate::BR_500k))
  {
    Serial.println("CAN.begin(...) failed.");
    for (;;) {}
  }
}

void loop()
{
  uint8_t const msg_data[] = {0xCA,0xFE,0,0,0,0,0,0};
  memcpy((void *)(msg_data + 4), &msg_cnt, sizeof(msg_cnt));
  CanMsg msg(CAN_ID, sizeof(msg_data), msg_data);

  if (int const rc = CAN.write(msg); rc < 0)
  {
    Serial.print  ("CAN.write(...) failed with error code ");
    Serial.println(rc);
    for (;;) { }
  }
  else {
    Serial.println("CAN Message Sent");
  }

  msg_cnt++;
  delay(1000);
}

I really can't explain what changed and I fear this isn't reliable but we'll see....

Well, you've got something working which you can now expand, that's the most important thing.

The Renesas/Arduino_CAN library has certainly room to grow and I'm happy to hear if you find a real bug.

Note: I've written the Renesas/Arduino_CAN library.

Dear @jefflit and @lxrobotics,
i'm having the same problem.

By using the last posted code, running on original barebone Arduino R4 Minima i get:
CAN Message Sent
CAN.write(...) failed with error code -60003

I noticed that the only change you made with respect the original example code are:
CAN_ID, baudrate, and the "CAN Message Sent" print.

What happens is that the sending succeeds only the first time and this is very weird.

Searching in the library i found that the function CAN.write is coded as below:

int R7FA4M1_CAN::write(CanMsg const & msg)
{
  bool const is_standard_id = msg.isStandardId();

  can_frame_t can_msg = {
    /* id               = */ is_standard_id ? msg.getStandardId()  : msg.getExtendedId(),
    /* id_mode          = */ is_standard_id ? CAN_ID_MODE_STANDARD : CAN_ID_MODE_EXTENDED,
    /* type             = */ CAN_FRAME_TYPE_DATA,
    /* data_length_code = */ min(msg.data_length, CAN_DATA_BUFFER_LENGTH),
    /* options          = */ 0
  };

  memcpy(can_msg.data, msg.data, can_msg.data_length_code);

  if(fsp_err_t const rc = R_CAN_Write(&_can_ctrl,
                                      is_standard_id ? CAN_MAILBOX_ID_0 : CAN_MAILBOX_ID_16,
                                      &can_msg); rc != FSP_SUCCESS)
    return -rc;

  return 1;
}

What I can understand is that the function of the Renesas API R_CAN_Write() returns the failure code 60003.
Digging deeper i found the documentation of that function here. The returnable codes are:
Return values
FSP_SUCCESS____________________________Operation succeeded.
FSP_ERR_NOT_OPEN_____________________Control block not open.
FSP_ERR_CAN_TRANSMIT_NOT_READY__Transmit in progress, cannot write data at this time.
FSP_ERR_CAN_TRANSMIT_FIFO_FULL___Transmit FIFO is full.
FSP_ERR_CAN_RECEIVE_MAILBOX_______Mailbox is setup for receive and cannot send.
FSP_ERR_INVALID_ARGUMENT___________Data length or frame type invalid.
FSP_ERR_ASSERTION_____________________Null pointer presented

Digging more deeper i found the solution here, in the fsp_common_api.h file. The 60003 means:
FSP_ERR_CAN_TRANSMIT_NOT_READY = 60003, ///< Transmit in progress.

The next step would be: how to manage that fault? How to clear the not acknowledged message in order to send another new one?

Any further consideration from you is appreciated.
Thank you.

Estoy utilizando un Arduino Every y consigo comunicarme con un OBD de un vehĂ­culo las pruebas de cĂłdigo las hago con la conexiĂłn al ordenador mediante el programa Canhacker. Pero cuando lo cargo a un Arduino R4 minima, la placa se bloquea desaparece el voltaje de 3.3V y no localiza el Com, Me ha sucedido ya en tres Arduino minima han quedado inutilizados. Con arranque DFU aparecen de nuevo los 3.3V pero no consigo que el IDE localice el puerto. Aparece cĂłmo Puerto "2-1.1" y no consigo avanzar. Sabe alguien cĂłmo solucionarlo ? Tampoco se cĂłmo hacer funcionar las CAN especificas del Minima, por culpa del bloqueo al cargar el cĂłdigo, me quiero conectar utilizando SN65HVD30 CAN BUS.
Mi aplicaciĂłn es Ă©sta.

GitHub - Lorevalles/Proyecto_Prius: Pruebas de laboratorio, diferentes formas de transformaciĂłn de un vehiculĂł Toyota Prius en hibrido enchufable

Muchas gracias por vuestra ayuda.

This means that the CAN transmit buffer is still full. You've either not connected a PHY driver (i.e. SN65HVD230) or your PHY driver has no termination (no 120 Ohm resistor). If you had a logic analyser you'd be seeing that the CAN module tries retransmitting your message forever, hence the buffer never goes empty.

Yes, I confirm. I want to add two words to clarify for others.

1- If arduino R4 without CAN tranceiver is used you see anything going out from pin 4 and 5.
2- If you use R4 with a CAN transceiver you see stuff at pins 4 and 5 going out infinitely as you said.
3- If you have a complete configuration (sender-transceiver-tranceiver-receiver) you see all the things working properly.

The behaviour relative to the first (and second) point is due to the CAN peripherial needs to read back the bus in order to understand if the transmitted message is dominant or recessive.

Regards.

1 Like

Same issue here...
I've had it working for a moment, when planets had proper alignment.
Then a few weeks later, using the exact same codebase (git commit-wise), it is no longer working.
Something is not very stable in Arduino's R4 library, it seems...

I found this topic while having the same issue which is now solved, so lets share some tips :

  • the CAN pins on the R4 Minima and Wifi are different (D4/D5 on Minima, D10/D13 on Wifi) and there are some mistyping in the documentation (https://docs.arduino.cc/resources/datasheets/ABX00087-datasheet.pdf page 2 of Wifi datasheet states pins D4/D5 for CAN...)

  • the library used in the code from the example/tutorial require that the CAN message is read back from the bus to confirm it's successfully sent.

When no transciever is connected (eg. for code testing/debbuging purpose) there is the possibility to enable internal loopback with the following code in the setup() function of the sketch:

int x  = CAN.enableInternalLoopback();

Then just connect CANRX and CANTX pins together and VOILA ! (confirmed with a logic analyzer and software CAN protocol decoder)

Cheers

I am new to arduino, but I have some experience with CANbus devices.

I have 2 x R4 Minimas and the waveshare SN65HVD230 transceiver breakout boards.

I have 1 each programmed with “Write” and “Read” examples. My setup is similar, using a breadboard, I created a bus with 120ohm resistors at each end.

I also have some actuators that broadcast a status message as soon as they are powered up, the program CANking, and a Kvaser based gateway.

The “Read” R4 Minima has no issue seeing CAN traffic, as soon as it’s connected to a bus. I use the kvaser to verify the traffic.

What I noticed with the “Write” R4 minima, was that it won’t start transmitting until I open the arduino serial monitor. It is repeatable, as soon as I open the monitor, it starts transmitting.

I think if you start the “Read” R4 first, then start the “Write” R4, then open the monitor for the “Write” which won’t display anything, and then open the “Read” and you will see the counter ticking away.

I don’t know exactly why this is happening, but I wanted to share what I observed.

Hi gilshultz, you are right MCP2515 is a proven good module. I'm using 3 of them connected with Arduino Nano Every since years and they work. My purpose was to use the "new CAN capabilities" of Arduino R4 which are supposed to save 2 wires, using 4 insead of 6. But I'm still in the process of really working it out. Attached a picture just to make my words more visual :grinning: