0
votes

I have a weird problem while setting up Arduino CAN Bus Communication.

Description follows below, this video shows the result: https://www.youtube.com/watch?v=NnMyC23Fe9s&feature=youtu.be

(Remark: This effect happens with every board I tried)

Hardware:

Used software: https://github.com/Seeed-Studio/CAN_BUS_Shield/blob/master/examples/send/send.ino

I started with the full setup with 2 of my Arduinos (not the Mega, it's not compatible) and 2 CAN Bus shields and was wondering, that the initialisation failed and than suddendly succeeded. I guessed it was about soldering the pins so I reworked that but it didn't get better.

After a lot of tests, I came up with the result you see in the video: I don't even need a CAN Bus Shield to initialize a CAN Bus Shield O_o. If I touch the SPI interface, it recognizes me as a CAN Bus Shield.

Going through the CAN BUS Library I checked the function CAN.begin. It uses the ISP pins (those 6 pins in 2 rows) to:

  • Write values to an address via SPI
  • Read two values from another address via SPI

Code to read via SPI (all from the Library no own code!)

uint8_t MCP2515Class::readRegister(uint8_t address)
{
  uint8_t value;

  SPI.beginTransaction(_spiSettings);
  digitalWrite(_csPin, LOW);
  SPI.transfer(0x03);
  SPI.transfer(address);
  value = SPI.transfer(0x00);
  digitalWrite(_csPin, HIGH);
  SPI.endTransaction();

  return value;
}

And the CAN.begin function

int MCP2515Class::begin(long baudRate)
{
  CANControllerClass::begin(baudRate);

  pinMode(_csPin, OUTPUT);

  // start SPI
  SPI.begin();

  reset();

  writeRegister(REG_CANCTRL, 0x80);
  if (readRegister(REG_CANCTRL) != 0x80) {
    return 0;
  }

  const struct {
    long clockFrequency;
    long baudRate;
    uint8_t cnf[3];
  } CNF_MAPPER[] = {
    {  (long)8E6, (long)1000E3, { 0x00, 0x80, 0x00 } },
    {  (long)8E6,  (long)500E3, { 0x00, 0x90, 0x02 } },
    {  (long)8E6,  (long)250E3, { 0x00, 0xb1, 0x05 } },
    {  (long)8E6,  (long)200E3, { 0x00, 0xb4, 0x06 } },
    {  (long)8E6,  (long)125E3, { 0x01, 0xb1, 0x05 } },
    {  (long)8E6,  (long)100E3, { 0x01, 0xb4, 0x06 } },
    {  (long)8E6,   (long)80E3, { 0x01, 0xbf, 0x07 } },
    {  (long)8E6,   (long)50E3, { 0x03, 0xb4, 0x06 } },
    {  (long)8E6,   (long)40E3, { 0x03, 0xbf, 0x07 } },
    {  (long)8E6,   (long)20E3, { 0x07, 0xbf, 0x07 } },
    {  (long)8E6,   (long)10E3, { 0x0f, 0xbf, 0x07 } },
    {  (long)8E6,    (long)5E3, { 0x1f, 0xbf, 0x07 } },

    { (long)16E6, (long)1000E3, { 0x00, 0xd0, 0x82 } },
    { (long)16E6,  (long)500E3, { 0x00, 0xf0, 0x86 } },
    { (long)16E6,  (long)250E3, { 0x41, 0xf1, 0x85 } },
    { (long)16E6,  (long)200E3, { 0x01, 0xfa, 0x87 } },
    { (long)16E6,  (long)125E3, { 0x03, 0xf0, 0x86 } },
    { (long)16E6,  (long)100E3, { 0x03, 0xfa, 0x87 } },
    { (long)16E6,   (long)80E3, { 0x03, 0xff, 0x87 } },
    { (long)16E6,   (long)50E3, { 0x07, 0xfa, 0x87 } },
    { (long)16E6,   (long)40E3, { 0x07, 0xff, 0x87 } },
    { (long)16E6,   (long)20E3, { 0x0f, 0xff, 0x87 } },
    { (long)16E6,   (long)10E3, { 0x1f, 0xff, 0x87 } },
    { (long)16E6,    (long)5E3, { 0x3f, 0xff, 0x87 } },
  };

  const uint8_t* cnf = NULL;

  for (unsigned int i = 0; i < (sizeof(CNF_MAPPER) / sizeof(CNF_MAPPER[0])); i++) {
    if (CNF_MAPPER[i].clockFrequency == _clockFrequency && CNF_MAPPER[i].baudRate == baudRate) {
      cnf = CNF_MAPPER[i].cnf;
      break;
    }
  }

  if (cnf == NULL) {
    return 0;
  }

  writeRegister(REG_CNF1, cnf[0]);
  writeRegister(REG_CNF2, cnf[1]);
  writeRegister(REG_CNF3, cnf[2]);

  writeRegister(REG_CANINTE, FLAG_RXnIE(1) | FLAG_RXnIE(0));
  writeRegister(REG_BFPCTRL, 0x00);
  writeRegister(REG_TXRTSCTRL, 0x00);
  writeRegister(REG_RXBnCTRL(0), FLAG_RXM1 | FLAG_RXM0);
  writeRegister(REG_RXBnCTRL(1), FLAG_RXM1 | FLAG_RXM0);

  writeRegister(REG_CANCTRL, 0x00);
  if (readRegister(REG_CANCTRL) != 0x00) {
    return 0;
  }

  return 1;
}

2 questions:

  1. How is this even possible, the system should differentiate between propper reading and a simple error, shouldn't it?
  2. What can I do to get this thing running?
1
My likely unpopular opinion would be to take your Arduino + these adapter boards and donate them to electronics recycling. This is all so needlessly complicated because of the outdated technology. Instead get a modern Cortex M with a CAN controller on chip. Then you don't need to worry about SPI, bloatware libraries and multiple boards.Lundin

1 Answers

0
votes

I suspect the shield demo program isn't working because you have not plugged the shield into an automobile's bus.

Looking at the schematic of the shield, under the Documents tab of the Seeedstudio page on the shield (https://www.seeedstudio.com/CAN-BUS-Shield-V2.html), it looks like the shield is an adapter, with no hardware to say much to an arduino. I believe it needs to be plugged into a car to work.

As you demonstrate, the software detection of the can bus isn't a reliable test for the shield being plugged into a car.

Under the Learn tab for the shield, there is a link to a demonstration. Although the demo video is not in English, you can see at about https://youtu.be/Y-1AFyOP-tk?t=565 that the board is plugged into an automobile.

Best of luck with your project!