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

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

Open
BiggRanger opened this issue Jan 12, 2020 · 3 comments

Comments

@BiggRanger
Copy link

BiggRanger commented Jan 12, 2020

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;
}

@timurrrr
Copy link

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
Copy link

timurrrr commented Aug 5, 2020

Links to PRs:
parsePacket(): #46
endPacket(): #49

@gorghino
Copy link

gorghino commented Jun 10, 2021

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...

fterretf added a commit to fterretf/arduino-CAN that referenced this issue May 23, 2023
fterretf added a commit to fterretf/arduino-CAN that referenced this issue May 23, 2023
fterretf added a commit to fterretf/arduino-CAN that referenced this issue Jun 1, 2023
-remove eCan3
fterretf added a commit to fterretf/arduino-CAN that referenced this issue Jun 7, 2023
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

3 participants