[Arduino MEGA] - [CAN-BUS Shield] - [RS232-CAN cable] - [EPOS4 compact 50/5]

Hi there,

This project has been pretty fun but recently I faced a roadblock and have been stuck for a while. Would be greatly appreciative of anyone who can solve this issue.

Objective: Use the Arduino to control the EPOS4 Motor
My Method: Use CAN communication
Connection Chain:

  1. Arduino MEGA
  2. CAN-BUS Shield 13262 (SparkFun)
  3. CAN-COM cable (Maxon 520857), I call this the RS232-CAN cable
  4. CAN end goes to EPOS4 Compact X11 connector
  5. The Maxon motor is a combination of three parts
  • EC-i 40 Ø40 mm, brushless, 100 Watt, with Hall sensors | High Torque (Maxon 496661)
  • Planetary Gearhead GP 42 C Ø42 mm, 3 - 15 Nm, Ceramic Version | Ceramic Version (Maxon 203124)
  • Encoder ENC 16 EASY, 1024 pulses (Maxon 499361)

My main issue lies with the CAN-BUS Shield board. So let's start here
I understand that the CAN-BUS shield 13262 SparkFun product is built for OBDII usage by default.

However, it recommends "switching the jumpers" in order to operate using CAN Communication. I did that by swapping the wires inside the RS232-CAN cable because I could not figure out how to swap the pins on the CAN-BUS Shield board.

The image below shows the original wiring:


I rearranged the wires such that CANH on the CAN-BUS board goes to CANH on the EPOS4 X11 connection. CANL and GND on both boards are also now synced on the new pins. If you look at segment 2 of the image below, that is the final configuration. I used the multimeter to verify that the CANH and CANL lines on both boards are linked. I shorted the last two pins (Ground and Shield) together.

Now looking at segment 1 of the image above, you will see the pin connections between the CAN-BUS Shield and the Arduino MEGA. The Arduino MEGA's code will utilise the SPI.h library. And so I believe MOSI will be set automatically to pin 51, MISO will be set to pin 50, SCK will be set to pin 52, and CS will be pin 53.

The CAN-BUS Shield's schematic shows that pin 12, 11, 13, 10, and 2 are MISO, MOSI, SCK, CS, and interrupt respectively. I confirmed this by using a multimeter and checking that pins 12,11,13,10, and 2 are shorted to the MCP2515's respective MISO, MOSI, SCK, CS, and Interrupt pins.

Other Considerations
I am aware that it is good practice to have a 120ohm terminating resistor between the CANH and CANL lines at the start and end of the lines for both devices. However, only the EPOS4 compact CAN 50/5 module has this terminating resistor (in-built). And it is activated by turning on the 7th switch of the DIP switch in the middle of the EPOS4 Compact. The CAN-BUS Shield does not have this 120 ohm terminating resistor. It does have 100 ohm from both CANH and CANL lines going to ground after a decoupling resistor, but that does not count as a terminating resistor. I checked the MCP2515 and MCP2551 datasheets, and also the CAN-BUS Shield Schematic, it seems that there is no 120ohm resistor internally between the CANH and CANL lines that comes from that board. I did not do anything about this, and did not externally add a 120ohm resistor.

The Code (I believe this is the issue?)

#include <SPI.h>

const int SPI_CS_PIN = 53;
MCP_CAN CAN(SPI_CS_PIN);

void setup() {
    Serial.begin(115200);
    while (CAN_OK != CAN.begin(MCP_STDEXT, CAN_500KBPS, MCP_16MHZ)) {
        Serial.println("CAN Init Failed");
        delay(200);
    }
    Serial.println("CAN Init OK");

   // Set Operation Mode to Profile Velocity Mode (typically 3 for EPOS4)
    setOperationMode(0x03);

   // Enable Drive
    enableDrive();

   // Set motor speed to 2000 RPM
    setMotorRPM(2000);
}

void loop() {
    // Empty loop
}

void setOperationMode(byte mode) {
    byte message[] = {0x2F, 0x60, 0x60, 0x00, mode, 0x00, 0x00, 0x00};
    CAN.sendMsgBuf(0x601, 0, 8, message); // Node ID should be adjusted
}

void enableDrive() {
    // Control word for "switch on and enable operation"
    byte message[] = {0x2B, 0x40, 0x60, 0x00, 0x0F, 0x00, 0x00, 0x00};
    CAN.sendMsgBuf(0x601, 0, 8, message); // Node ID should be adjusted
}

void setMotorRPM(int rpm) {
    long velocity = rpm * 60;  // Adjust conversion factor as needed
    byte message[] = {0x23, 0xFF, 0x60, 0x00, (byte)(velocity & 0xFF), (byte)((velocity >> 8) & 0xFF), (byte)((velocity >> 16) & 0xFF), (byte)((velocity >> 24) & 0xFF)};
    CAN.sendMsgBuf(0x601, 0, 8, message);
}

What you see above is an attempt to simply drive the motor at 2000rpm. The purpose of this code is just to check that the CAN communication works. The output of the code is always:

CAN Init Failed
Init Failed
Entering Configuration Mode Failure...
CAN Init Failed
Entering Configuration Mode Failure...
CAN Init Failed

And this is where I got stuck. I have never done CAN coding in my life and this is a huge challenge to me. The connections are all good (or so it seems), yet the code does not work.

Huge thanks in to whoever is able to solve this issue.

That tells me you probably do not have the SPI connected properly or a bad CAN chip.

The 120 Ohm resistors or equal are required on the physical ends of the bus or it will not work reliably. Measure the bus resistance between CAN_H and CAN_L it should be about 60 ohms. If not you have a termination problem and it will give you lots of problems. Since you are using Cory Fowler's library build both the send and receive and get them working first, this will test the hardware. The reason I picked this is It is known good software that works with the appropriate hardware.

Another gotcha I have seen is the crystal frequency on the different modules is not always the same. You can set this in software.

CAN_500KBPS is very fast, with the library demo go slower until it works for you.

Remember the transmitter cannot successfully send a packet if the receiver(s) do not acknowledge it with a IFR (In Frame Response). Let us know how it goes.

Hey gilshultz,

I will implement the 120ohm resistor change tomorrow (unless the resistance between the CANH and CANL lines are 60 ohms already?).

I wish to clarify what the SPI pins are. From what I have read, when calling the SPI.h library, the library automatically sets certain pin functions for the Arduino. In the case of the Arduino MEGA,
Pin 50: MISO
Pin 51: MOSI
Pin 52: SCK
Pin 53: CS
Pin 2: Set by myself (Interrupt)

How do I test the build and receive to test that the CAN communication works? Do you have a code for this? I am very new to CAN communication and these are quite foreign to me :confused: ...

I will read up on the IFR and attempt to implement it into my code. I will also slow down the speed of transmission. Will let you know how it goes soon!

1 Like

You cannot do that, the Arduino is not fast enough but rest easy it is part of the CAN protocol and the MCP2515 automatically does that for you. It has one problem doing that it cannot acknowledge itself but other nodes on the bus do this automatically without any intervention. This is part of how the CAN system determines if a valid message was sent.

That is true but if you look the differences are after the transceiver, everything else is the same. To switch the CAN shield you need to cut the three jumpers on SJ4, SJ5, and SJ6. After you cut them you short the other two with a blob of solder. As the jumpers are shown center to right when finished you want center to left.

This is telling you the SPI is not correct assuming the parts are good. The MCP2515 will initialize without being connected to the bus.

Testing: I cannot recommend enough that you need to build the two modules as shown in Cory's CAN library. That gets you started from a known point and from there you can branch out. I have done several builds with this and I know first hand the library is good. I have not however used a MEGA, I have used UNO, Nano, and WeMos D1 R2 (ESP826 board) now obsolete. They were a buck and work so a good start for me.

When you have this working simply connect the motor and adjust the termination. You can then see what you send and what the motor responds with.Doing it this way saved me purchasing a CAN test tool.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.