arduino-CAN icon indicating copy to clipboard operation
arduino-CAN copied to clipboard

MCP2515 bandwidth issues at 500K and 1Mbps -> SPI command optimizations

Open BiggRanger opened this issue 5 years ago • 3 comments

I made a few optimizations to improve the performance of the interface for the MCP2515. There are a couple of commands to reduce the overhead of the SPI to increase the data throughput to and from the MCP2515; LOAD RX BUFFER, RTS, and READ RX BUFFER. I added it endPacket() even though it doesn't matter as much since it waits for the packet to complete sending before returning (there is still an improvement), the improvement in parsePacket() is nice.

int MCP2515Class::parsePacket()
{
  int n;

  uint8_t intf = readRegister(REG_CANINTF);

  if (intf & FLAG_RXnIF(0)) 
  {
    n = 0;
  } 
  else if (intf & FLAG_RXnIF(1)) 
  {
    n = 1;
  }
  else
  {
    _rxId = -1;
    _rxRtr = false;
    _rxLength = 0;
    return 0;
  }
  uint8_t SIDH = readRegister(REG_RXBnSIDH(n));
  uint8_t SIDL = readRegister(REG_RXBnSIDL(n));
  uint32_t idA = ((SIDH << 3) & 0x07f8) | ((SIDL >> 5) & 0x07);
  _rxId = idA;
  _rxRtr = (SIDL & FLAG_SRR) ? true : false;

  _rxDlc = readRegister(REG_RXBnDLC(n)) & 0x0f;
  _rxIndex = 0;

  if (_rxRtr) 
  {
    _rxLength = 0;
  } 
  else 
  {
    _rxLength = _rxDlc;

    SPI.beginTransaction(_spiSettings);
    digitalWrite(_csPin, LOW);
    SPI.transfer(0b10010010 | (n << 2));        //Set to stream RX data from Buffer n
    for (uint8_t x = 0; x < _rxLength; x++)
      _rxData[x] = SPI.transfer(0x00);          //Stream data form RX buffer
    digitalWrite(_csPin, HIGH);                 //unsetting CS pin will reset IRQ flag
    SPI.endTransaction();
  }

  return _rxRtr ? true : _rxDlc;
}

int MCP2515Class::endPacket()
{
  if (!CANControllerClass::endPacket()) 
  {
    return 0;
  }

  int n = 0;

  writeRegister(REG_TXBnSIDH(n), _txId >> 3);
  writeRegister(REG_TXBnSIDL(n), _txId << 5);
  writeRegister(REG_TXBnEID8(n), 0x00);
  writeRegister(REG_TXBnEID0(n), 0x00);

  if (_txRtr)
  {
    writeRegister(REG_TXBnDLC(n), 0x40 | _txLength);
  }
  else 
  {
    writeRegister(REG_TXBnDLC(n), _txLength);    //set packet length

    SPI.beginTransaction(_spiSettings);
    digitalWrite(_csPin, LOW);
    SPI.transfer(0b01000000 | (n * 2 + 1));      //set TX buffer for stream
    for (uint8_t x = 0; x < _txLength; x++)
      SPI.transfer(_txData[x]);                  //stream data to buffer
    digitalWrite(_csPin, HIGH);
    SPI.endTransaction();
  }

  SPI.beginTransaction(_spiSettings);
  digitalWrite(_csPin, LOW);
  SPI.transfer(0b10000000 | (1 << n));          //set RTS for TX Buffer n
  digitalWrite(_csPin, HIGH);
  SPI.endTransaction();  

  bool aborted = false;

  while (readRegister(REG_TXBnCTRL(n)) & 0x08) 
  {
    if (readRegister(REG_TXBnCTRL(n)) & 0x10) 
    {
      // abort
      aborted = true;

      modifyRegister(REG_CANCTRL, 0x10, 0x10);
    }

    yield();
  }

  if (aborted) {
    // clear abort command
    modifyRegister(REG_CANCTRL, 0x10, 0x00);
  }

  modifyRegister(REG_CANINTF, FLAG_TXnIF(n), 0x00);

  return (readRegister(REG_TXBnCTRL(n)) & 0x70) ? 0 : 1;
}

BiggRanger avatar Jan 12 '20 02:01 BiggRanger

Thanks for filing this! Once I realized there is room for improvement, I've decided to take a closer look at the datasheet and this is what I came up with for parsePacket(). I'm sure something similar can be done for endPacket().

timurrrr avatar Jul 31 '20 17:07 timurrrr

Links to PRs: parsePacket(): https://github.com/sandeepmistry/arduino-CAN/pull/46 endPacket(): https://github.com/sandeepmistry/arduino-CAN/pull/49

timurrrr avatar Aug 05 '20 01:08 timurrrr

Thank you @timurrrr ! With your fix I got 0% packets loss from over 30% when I tried multiple messages with the same time cycle. I wonder why it's still not merged though...

gorghino avatar Jun 10 '21 12:06 gorghino