Skip to content

Commit 89d49b5

Browse files
committed
Optimize MCP2515Class::parsePacket()
1) Use the RX STATUS command instead of READ(CANINTF) to check availability of data to read. This reduces SPI usage by 1 byte out of 3, even to just check if data is available. 2) Use the READ command to read RXB(n) registers sequentially instead of requesting them one by one. This requires 7 bytes over SPI to read SIDH, SIDL, EID8, EID0, DLC. The previous implementation used 15 bytes to read the register for standard frames, and 24 bytes for extended frames. 3) Use the READ RX BUFFER command to read the packet data, instead of requesting bytes one by one. This requires sending (1 + N) bytes over SPI instead of (3 * N) for the payload, and doesn't require sending 3 bytes to modify RXnIF. Total savings: (2 * N + 11) bytes over SPI for standard frame. For N = 8, we now send 18 bytes over SPI vs 45. That's 60% reduction! As a bonus, I was able to put all SPI operations in one SPI transaction. I don't know if it makes much of a difference, but perhaps makes things safer?
1 parent bcdd7ac commit 89d49b5

File tree

1 file changed

+53
-14
lines changed

1 file changed

+53
-14
lines changed

src/MCP2515.cpp

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -214,47 +214,86 @@ int MCP2515Class::parsePacket()
214214
{
215215
int n;
216216

217-
uint8_t intf = readRegister(REG_CANINTF);
217+
SPI.beginTransaction(_spiSettings);
218+
digitalWrite(_csPin, LOW);
219+
SPI.transfer(0xb0); // RX STATUS
220+
uint8_t rxStatus = SPI.transfer(0x00);
221+
digitalWrite(_csPin, HIGH);
218222

219-
if (intf & FLAG_RXnIF(0)) {
223+
if (rxStatus & 0x40) {
220224
n = 0;
221-
} else if (intf & FLAG_RXnIF(1)) {
225+
} else if (rxStatus & 0x80) {
222226
n = 1;
223227
} else {
228+
SPI.endTransaction();
224229
_rxId = -1;
225230
_rxExtended = false;
226231
_rxRtr = false;
232+
_rxDlc = 0;
233+
_rxIndex = 0;
227234
_rxLength = 0;
228235
return 0;
229236
}
230237

231-
_rxExtended = (readRegister(REG_RXBnSIDL(n)) & FLAG_IDE) ? true : false;
238+
digitalWrite(_csPin, LOW);
239+
SPI.transfer(0x03); // READ
240+
SPI.transfer(REG_RXBnSIDH(n));
241+
uint8_t regSIDH = SPI.transfer(0x00);
242+
uint8_t regSIDL = SPI.transfer(0x00);
243+
244+
// We could just skip the EID registers, but that would actually add more
245+
// overhead just to send a new READ command.
246+
uint8_t regEID8 = SPI.transfer(0x00);
247+
uint8_t regEID0 = SPI.transfer(0x00);
248+
uint8_t regDLC = SPI.transfer(0x00);
249+
digitalWrite(_csPin, HIGH);
250+
251+
_rxExtended = (regSIDL & FLAG_IDE) ? true : false;
232252

233-
uint32_t idA = ((readRegister(REG_RXBnSIDH(n)) << 3) & 0x07f8) | ((readRegister(REG_RXBnSIDL(n)) >> 5) & 0x07);
253+
uint32_t idA = (regSIDH << 3) | (regSIDL >> 5);
234254
if (_rxExtended) {
235-
uint32_t idB = (((uint32_t)(readRegister(REG_RXBnSIDL(n)) & 0x03) << 16) & 0x30000) | ((readRegister(REG_RXBnEID8(n)) << 8) & 0xff00) | readRegister(REG_RXBnEID0(n));
255+
uint32_t idB =
256+
((uint32_t)(regSIDL & 0x03) << 16)
257+
| ((uint32_t)regEID8 << 8)
258+
| regEID0;
236259

237260
_rxId = (idA << 18) | idB;
238-
_rxRtr = (readRegister(REG_RXBnDLC(n)) & FLAG_RTR) ? true : false;
261+
_rxRtr = (regDLC & FLAG_RTR) ? true : false;
239262
} else {
240263
_rxId = idA;
241-
_rxRtr = (readRegister(REG_RXBnSIDL(n)) & FLAG_SRR) ? true : false;
264+
_rxRtr = (regSIDL & FLAG_SRR) ? true : false;
242265
}
243-
_rxDlc = readRegister(REG_RXBnDLC(n)) & 0x0f;
266+
_rxDlc = regDLC & 0x0f;
244267
_rxIndex = 0;
245268

246269
if (_rxRtr) {
247270
_rxLength = 0;
271+
272+
// Need to manually clear the RX flag.
273+
digitalWrite(_csPin, LOW);
274+
SPI.transfer(0x05); // BIT MODIFY
275+
SPI.transfer(REG_CANINTF);
276+
SPI.transfer(FLAG_RXnIF(n));
277+
SPI.transfer(0x0);
278+
digitalWrite(_csPin, HIGH);
248279
} else {
249280
_rxLength = _rxDlc;
250281

251-
for (int i = 0; i < _rxLength; i++) {
252-
_rxData[i] = readRegister(REG_RXBnD0(n) + i);
253-
}
254-
}
282+
digitalWrite(_csPin, LOW);
283+
284+
// Send READ RX BUFFER instruction for RXBnD0(n).
285+
SPI.transfer(0b10010010 + (n * 0x04));
286+
// Get the data.
287+
for (uint8_t i = 0; i < _rxLength; i++)
288+
_rxData[i] = SPI.transfer(0x00);
255289

256-
modifyRegister(REG_CANINTF, FLAG_RXnIF(n), 0x00);
290+
digitalWrite(_csPin, HIGH);
257291

292+
// Don't need to unset the RXnIF(n) flag as this is done automatically when
293+
// setting the CS high after a READ RX BUFFER instruction.
294+
}
295+
296+
SPI.endTransaction();
258297
return _rxDlc;
259298
}
260299

0 commit comments

Comments
 (0)