From cbf46d5b53b5f22059dbc7b7d28129753e04de00 Mon Sep 17 00:00:00 2001 From: Jay Date: Sun, 23 Feb 2025 14:41:12 -0500 Subject: [PATCH 01/16] Update CAN.h Changing library to work exclusively with MCP2515 on an ESP32 --- src/CAN.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/CAN.h b/src/CAN.h index d8edc06..6fa3e61 100644 --- a/src/CAN.h +++ b/src/CAN.h @@ -4,10 +4,7 @@ #ifndef CAN_H #define CAN_H -#ifdef ARDUINO_ARCH_ESP32 -#include "ESP32SJA1000.h" -#else + #include "MCP2515.h" -#endif #endif From b9f4f8891bb6e8cd0b2124e1ea7bc0e2cf3efd7b Mon Sep 17 00:00:00 2001 From: JayFromProgramming Date: Sun, 23 Feb 2025 14:43:21 -0500 Subject: [PATCH 02/16] Attempting to adjust library to work with ESP32 and MCP2515 --- src/MCP2515.cpp | 696 +++++++++++++++++++++++------------------------- src/MCP2515.h | 4 - 2 files changed, 335 insertions(+), 365 deletions(-) diff --git a/src/MCP2515.cpp b/src/MCP2515.cpp index 36c160d..59fb835 100644 --- a/src/MCP2515.cpp +++ b/src/MCP2515.cpp @@ -1,8 +1,6 @@ // Copyright (c) Sandeep Mistry. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -#ifndef ARDUINO_ARCH_ESP32 - #include "MCP2515.h" #define REG_BFPCTRL 0x0c @@ -56,442 +54,418 @@ #define FLAG_RXM1 0x40 -MCP2515Class::MCP2515Class() : - CANControllerClass(), - _spiSettings(10E6, MSBFIRST, SPI_MODE0), - _csPin(MCP2515_DEFAULT_CS_PIN), - _intPin(MCP2515_DEFAULT_INT_PIN), - _clockFrequency(MCP2515_DEFAULT_CLOCK_FREQUENCY) -{ +MCP2515Class::MCP2515Class() : CANControllerClass(), + _spiSettings(10E6, MSBFIRST, SPI_MODE0), + _csPin(MCP2515_DEFAULT_CS_PIN), + _intPin(MCP2515_DEFAULT_INT_PIN), + _clockFrequency(MCP2515_DEFAULT_CLOCK_FREQUENCY) { } -MCP2515Class::~MCP2515Class() -{ +MCP2515Class::~MCP2515Class() { } -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)666666, { 0xC0, 0xB8, 0x01 } }, - { (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)666666, { 0xC0, 0xF8, 0x81 } }, - { (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; +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) 666666, {0xC0, 0xB8, 0x01}}, + {(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) 666666, {0xC0, 0xF8, 0x81}}, + {(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; - } + if (cnf == NULL) { + return 0; + } - writeRegister(REG_CNF1, cnf[0]); - writeRegister(REG_CNF2, cnf[1]); - writeRegister(REG_CNF3, cnf[2]); + 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_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; - } + writeRegister(REG_CANCTRL, 0x00); + if (readRegister(REG_CANCTRL) != 0x00) { + return 0; + } - return 1; + return 1; } -void MCP2515Class::end() -{ - SPI.end(); +void MCP2515Class::end() { + SPI.end(); - CANControllerClass::end(); + CANControllerClass::end(); } -int MCP2515Class::endPacket() -{ - if (!CANControllerClass::endPacket()) { - return 0; - } - - int n = 0; - - if (_txExtended) { - writeRegister(REG_TXBnSIDH(n), _txId >> 21); - writeRegister(REG_TXBnSIDL(n), (((_txId >> 18) & 0x07) << 5) | FLAG_EXIDE | ((_txId >> 16) & 0x03)); - writeRegister(REG_TXBnEID8(n), (_txId >> 8) & 0xff); - writeRegister(REG_TXBnEID0(n), _txId & 0xff); - } else { - 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); - - for (int i = 0; i < _txLength; i++) { - writeRegister(REG_TXBnD0(n) + i, _txData[i]); +int MCP2515Class::endPacket() { + if (!CANControllerClass::endPacket()) { + return 0; } - } - writeRegister(REG_TXBnCTRL(n), 0x08); - - bool aborted = false; + int n = 0; + + if (_txExtended) { + writeRegister(REG_TXBnSIDH(n), _txId >> 21); + writeRegister(REG_TXBnSIDL(n), (((_txId >> 18) & 0x07) << 5) | FLAG_EXIDE | ((_txId >> 16) & 0x03)); + writeRegister(REG_TXBnEID8(n), (_txId >> 8) & 0xff); + writeRegister(REG_TXBnEID0(n), _txId & 0xff); + } else { + writeRegister(REG_TXBnSIDH(n), _txId >> 3); + writeRegister(REG_TXBnSIDL(n), _txId << 5); + writeRegister(REG_TXBnEID8(n), 0x00); + writeRegister(REG_TXBnEID0(n), 0x00); + } - while (readRegister(REG_TXBnCTRL(n)) & 0x08) { - if (readRegister(REG_TXBnCTRL(n)) & 0x10) { - // abort - aborted = true; + if (_txRtr) { + writeRegister(REG_TXBnDLC(n), 0x40 | _txLength); + } else { + writeRegister(REG_TXBnDLC(n), _txLength); - modifyRegister(REG_CANCTRL, 0x10, 0x10); + for (int i = 0; i < _txLength; i++) { + writeRegister(REG_TXBnD0(n) + i, _txData[i]); + } } - yield(); - } + writeRegister(REG_TXBnCTRL(n), 0x08); + + bool aborted = false; + + while (readRegister(REG_TXBnCTRL(n)) & 0x08) { + if (readRegister(REG_TXBnCTRL(n)) & 0x10) { + // abort + aborted = true; + + modifyRegister(REG_CANCTRL, 0x10, 0x10); + } - if (aborted) { - // clear abort command - modifyRegister(REG_CANCTRL, 0x10, 0x00); - } + yield(); + } + + if (aborted) { + // clear abort command + modifyRegister(REG_CANCTRL, 0x10, 0x00); + } - modifyRegister(REG_CANINTF, FLAG_TXnIF(n), 0x00); + modifyRegister(REG_CANINTF, FLAG_TXnIF(n), 0x00); - return (readRegister(REG_TXBnCTRL(n)) & 0x70) ? 0 : 1; + return (readRegister(REG_TXBnCTRL(n)) & 0x70) ? 0 : 1; } -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; - _rxExtended = false; - _rxRtr = false; - _rxLength = 0; - return 0; - } - - _rxExtended = (readRegister(REG_RXBnSIDL(n)) & FLAG_IDE) ? true : false; - - uint32_t idA = ((readRegister(REG_RXBnSIDH(n)) << 3) & 0x07f8) | ((readRegister(REG_RXBnSIDL(n)) >> 5) & 0x07); - if (_rxExtended) { - uint32_t idB = (((uint32_t)(readRegister(REG_RXBnSIDL(n)) & 0x03) << 16) & 0x30000) | ((readRegister(REG_RXBnEID8(n)) << 8) & 0xff00) | readRegister(REG_RXBnEID0(n)); - - _rxId = (idA << 18) | idB; - _rxRtr = (readRegister(REG_RXBnDLC(n)) & FLAG_RTR) ? true : false; - } else { - _rxId = idA; - _rxRtr = (readRegister(REG_RXBnSIDL(n)) & FLAG_SRR) ? true : false; - } - _rxDlc = readRegister(REG_RXBnDLC(n)) & 0x0f; - _rxIndex = 0; - - if (_rxRtr) { - _rxLength = 0; - } else { - _rxLength = _rxDlc; - - for (int i = 0; i < _rxLength; i++) { - _rxData[i] = readRegister(REG_RXBnD0(n) + i); +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; + _rxExtended = false; + _rxRtr = false; + _rxLength = 0; + return 0; + } + + _rxExtended = (readRegister(REG_RXBnSIDL(n)) & FLAG_IDE) ? true : false; + + uint32_t idA = ((readRegister(REG_RXBnSIDH(n)) << 3) & 0x07f8) | ((readRegister(REG_RXBnSIDL(n)) >> 5) & 0x07); + if (_rxExtended) { + uint32_t idB = (((uint32_t) (readRegister(REG_RXBnSIDL(n)) & 0x03) << 16) & 0x30000) | ( + (readRegister(REG_RXBnEID8(n)) << 8) & 0xff00) | readRegister(REG_RXBnEID0(n)); + + _rxId = (idA << 18) | idB; + _rxRtr = (readRegister(REG_RXBnDLC(n)) & FLAG_RTR) ? true : false; + } else { + _rxId = idA; + _rxRtr = (readRegister(REG_RXBnSIDL(n)) & FLAG_SRR) ? true : false; } - } + _rxDlc = readRegister(REG_RXBnDLC(n)) & 0x0f; + _rxIndex = 0; - modifyRegister(REG_CANINTF, FLAG_RXnIF(n), 0x00); + if (_rxRtr) { + _rxLength = 0; + } else { + _rxLength = _rxDlc; - return _rxDlc; + for (int i = 0; i < _rxLength; i++) { + _rxData[i] = readRegister(REG_RXBnD0(n) + i); + } + } + + modifyRegister(REG_CANINTF, FLAG_RXnIF(n), 0x00); + + return _rxDlc; } -void MCP2515Class::onReceive(void(*callback)(int)) -{ - CANControllerClass::onReceive(callback); +void MCP2515Class::onReceive(void (*callback)(int)) { + CANControllerClass::onReceive(callback); // set callback + + pinMode(_intPin, INPUT); - pinMode(_intPin, INPUT); + if (callback) { + // SPI.usingInterrupt(digitalPinToInterrupt(_intPin)); // Possibly not needed for ESP32 with FreeRTOS - if (callback) { - SPI.usingInterrupt(digitalPinToInterrupt(_intPin)); - attachInterrupt(digitalPinToInterrupt(_intPin), MCP2515Class::onInterrupt, LOW); - } else { - detachInterrupt(digitalPinToInterrupt(_intPin)); + attachInterrupt(digitalPinToInterrupt(_intPin), MCP2515Class::onInterrupt, LOW); + } else { + detachInterrupt(digitalPinToInterrupt(_intPin)); #ifdef SPI_HAS_NOTUSINGINTERRUPT SPI.notUsingInterrupt(digitalPinToInterrupt(_intPin)); #endif - } + } } -int MCP2515Class::filter(int id, int mask) -{ - id &= 0x7ff; - mask &= 0x7ff; - - // config mode - writeRegister(REG_CANCTRL, 0x80); - if (readRegister(REG_CANCTRL) != 0x80) { - return 0; - } - - for (int n = 0; n < 2; n++) { - // standard only - writeRegister(REG_RXBnCTRL(n), FLAG_RXM0); - writeRegister(REG_RXBnCTRL(n), FLAG_RXM0); - - writeRegister(REG_RXMnSIDH(n), mask >> 3); - writeRegister(REG_RXMnSIDL(n), mask << 5); - writeRegister(REG_RXMnEID8(n), 0); - writeRegister(REG_RXMnEID0(n), 0); - } - - for (int n = 0; n < 6; n++) { - writeRegister(REG_RXFnSIDH(n), id >> 3); - writeRegister(REG_RXFnSIDL(n), id << 5); - writeRegister(REG_RXFnEID8(n), 0); - writeRegister(REG_RXFnEID0(n), 0); - } - - // normal mode - writeRegister(REG_CANCTRL, 0x00); - if (readRegister(REG_CANCTRL) != 0x00) { - return 0; - } - - return 1; -} +int MCP2515Class::filter(int id, int mask) { + id &= 0x7ff; + mask &= 0x7ff; + + // config mode + writeRegister(REG_CANCTRL, 0x80); + if (readRegister(REG_CANCTRL) != 0x80) { + return 0; + } + + for (int n = 0; n < 2; n++) { + // standard only + writeRegister(REG_RXBnCTRL(n), FLAG_RXM0); + writeRegister(REG_RXBnCTRL(n), FLAG_RXM0); + + writeRegister(REG_RXMnSIDH(n), mask >> 3); + writeRegister(REG_RXMnSIDL(n), mask << 5); + writeRegister(REG_RXMnEID8(n), 0); + writeRegister(REG_RXMnEID0(n), 0); + } + + for (int n = 0; n < 6; n++) { + writeRegister(REG_RXFnSIDH(n), id >> 3); + writeRegister(REG_RXFnSIDL(n), id << 5); + writeRegister(REG_RXFnEID8(n), 0); + writeRegister(REG_RXFnEID0(n), 0); + } + + // normal mode + writeRegister(REG_CANCTRL, 0x00); + if (readRegister(REG_CANCTRL) != 0x00) { + return 0; + } -int MCP2515Class::filterExtended(long id, long mask) -{ - id &= 0x1FFFFFFF; - mask &= 0x1FFFFFFF; - - // config mode - writeRegister(REG_CANCTRL, 0x80); - if (readRegister(REG_CANCTRL) != 0x80) { - return 0; - } - - for (int n = 0; n < 2; n++) { - // extended only - writeRegister(REG_RXBnCTRL(n), FLAG_RXM1); - writeRegister(REG_RXBnCTRL(n), FLAG_RXM1); - - writeRegister(REG_RXMnSIDH(n), mask >> 21); - writeRegister(REG_RXMnSIDL(n), (((mask >> 18) & 0x03) << 5) | FLAG_EXIDE | ((mask >> 16) & 0x03)); - writeRegister(REG_RXMnEID8(n), (mask >> 8) & 0xff); - writeRegister(REG_RXMnEID0(n), mask & 0xff); - } - - for (int n = 0; n < 6; n++) { - writeRegister(REG_RXFnSIDH(n), id >> 21); - writeRegister(REG_RXFnSIDL(n), (((id >> 18) & 0x03) << 5) | FLAG_EXIDE | ((id >> 16) & 0x03)); - writeRegister(REG_RXFnEID8(n), (id >> 8) & 0xff); - writeRegister(REG_RXFnEID0(n), id & 0xff); - } - - // normal mode - writeRegister(REG_CANCTRL, 0x00); - if (readRegister(REG_CANCTRL) != 0x00) { - return 0; - } - - return 1; + return 1; } -int MCP2515Class::observe() -{ - writeRegister(REG_CANCTRL, 0x60); - if (readRegister(REG_CANCTRL) != 0x60) { - return 0; - } +int MCP2515Class::filterExtended(long id, long mask) { + id &= 0x1FFFFFFF; + mask &= 0x1FFFFFFF; + + // config mode + writeRegister(REG_CANCTRL, 0x80); + if (readRegister(REG_CANCTRL) != 0x80) { + return 0; + } + + for (int n = 0; n < 2; n++) { + // extended only + writeRegister(REG_RXBnCTRL(n), FLAG_RXM1); + writeRegister(REG_RXBnCTRL(n), FLAG_RXM1); + + writeRegister(REG_RXMnSIDH(n), mask >> 21); + writeRegister(REG_RXMnSIDL(n), (((mask >> 18) & 0x03) << 5) | FLAG_EXIDE | ((mask >> 16) & 0x03)); + writeRegister(REG_RXMnEID8(n), (mask >> 8) & 0xff); + writeRegister(REG_RXMnEID0(n), mask & 0xff); + } + + for (int n = 0; n < 6; n++) { + writeRegister(REG_RXFnSIDH(n), id >> 21); + writeRegister(REG_RXFnSIDL(n), (((id >> 18) & 0x03) << 5) | FLAG_EXIDE | ((id >> 16) & 0x03)); + writeRegister(REG_RXFnEID8(n), (id >> 8) & 0xff); + writeRegister(REG_RXFnEID0(n), id & 0xff); + } + + // normal mode + writeRegister(REG_CANCTRL, 0x00); + if (readRegister(REG_CANCTRL) != 0x00) { + return 0; + } - return 1; + return 1; } -int MCP2515Class::loopback() -{ - writeRegister(REG_CANCTRL, 0x40); - if (readRegister(REG_CANCTRL) != 0x40) { - return 0; - } +int MCP2515Class::observe() { + writeRegister(REG_CANCTRL, 0x60); + if (readRegister(REG_CANCTRL) != 0x60) { + return 0; + } - return 1; + return 1; } -int MCP2515Class::sleep() -{ - writeRegister(REG_CANCTRL, 0x01); - if (readRegister(REG_CANCTRL) != 0x01) { - return 0; - } +int MCP2515Class::loopback() { + writeRegister(REG_CANCTRL, 0x40); + if (readRegister(REG_CANCTRL) != 0x40) { + return 0; + } - return 1; + return 1; } -int MCP2515Class::wakeup() -{ - writeRegister(REG_CANCTRL, 0x00); - if (readRegister(REG_CANCTRL) != 0x00) { - return 0; - } +int MCP2515Class::sleep() { + writeRegister(REG_CANCTRL, 0x01); + if (readRegister(REG_CANCTRL) != 0x01) { + return 0; + } - return 1; + return 1; } -void MCP2515Class::setPins(int cs, int irq) -{ - _csPin = cs; - _intPin = irq; +int MCP2515Class::wakeup() { + writeRegister(REG_CANCTRL, 0x00); + if (readRegister(REG_CANCTRL) != 0x00) { + return 0; + } + + return 1; } -void MCP2515Class::setSPIFrequency(uint32_t frequency) -{ - _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); +void MCP2515Class::setPins(int cs, int irq) { + _csPin = cs; + _intPin = irq; } -void MCP2515Class::setClockFrequency(long clockFrequency) -{ - _clockFrequency = clockFrequency; +void MCP2515Class::setSPIFrequency(uint32_t frequency) { + _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); } -void MCP2515Class::dumpRegisters(Stream& out) -{ - for (int i = 0; i < 128; i++) { - byte b = readRegister(i); +void MCP2515Class::setClockFrequency(long clockFrequency) { + _clockFrequency = clockFrequency; +} - out.print("0x"); - if (i < 16) { - out.print('0'); +void MCP2515Class::dumpRegisters(Stream &out) { + for (int i = 0; i < 128; i++) { + byte b = readRegister(i); + + out.print("0x"); + if (i < 16) { + out.print('0'); + } + out.print(i, HEX); + out.print(": 0x"); + if (b < 16) { + out.print('0'); + } + out.println(b, HEX); } - out.print(i, HEX); - out.print(": 0x"); - if (b < 16) { - out.print('0'); - } - out.println(b, HEX); - } } -void MCP2515Class::reset() -{ - SPI.beginTransaction(_spiSettings); - digitalWrite(_csPin, LOW); - SPI.transfer(0xc0); - digitalWrite(_csPin, HIGH); - SPI.endTransaction(); +void MCP2515Class::reset() { + SPI.beginTransaction(_spiSettings); + digitalWrite(_csPin, LOW); + SPI.transfer(0xc0); + digitalWrite(_csPin, HIGH); + SPI.endTransaction(); - delayMicroseconds(10); + delayMicroseconds(10); } -void MCP2515Class::handleInterrupt() -{ - if (readRegister(REG_CANINTF) == 0) { - return; - } +void IRAM_ATTR MCP2515Class::handleInterrupt() { + if (readRegister(REG_CANINTF) == 0) { + return; + } - while (parsePacket() || _rxId != -1) { - _onReceive(available()); - } + while (parsePacket() || _rxId != -1) { + _onReceive(available()); + } } -uint8_t MCP2515Class::readRegister(uint8_t address) -{ - uint8_t value; +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(); + SPI.beginTransaction(_spiSettings); + digitalWrite(_csPin, LOW); + SPI.transfer(0x03); + SPI.transfer(address); + value = SPI.transfer(0x00); + digitalWrite(_csPin, HIGH); + SPI.endTransaction(); - return value; + return value; } -void MCP2515Class::modifyRegister(uint8_t address, uint8_t mask, uint8_t value) -{ - SPI.beginTransaction(_spiSettings); - digitalWrite(_csPin, LOW); - SPI.transfer(0x05); - SPI.transfer(address); - SPI.transfer(mask); - SPI.transfer(value); - digitalWrite(_csPin, HIGH); - SPI.endTransaction(); +void MCP2515Class::modifyRegister(uint8_t address, uint8_t mask, uint8_t value) { + SPI.beginTransaction(_spiSettings); + digitalWrite(_csPin, LOW); + SPI.transfer(0x05); + SPI.transfer(address); + SPI.transfer(mask); + SPI.transfer(value); + digitalWrite(_csPin, HIGH); + SPI.endTransaction(); } -void MCP2515Class::writeRegister(uint8_t address, uint8_t value) -{ - SPI.beginTransaction(_spiSettings); - digitalWrite(_csPin, LOW); - SPI.transfer(0x02); - SPI.transfer(address); - SPI.transfer(value); - digitalWrite(_csPin, HIGH); - SPI.endTransaction(); +void MCP2515Class::writeRegister(uint8_t address, uint8_t value) { + SPI.beginTransaction(_spiSettings); + digitalWrite(_csPin, LOW); + SPI.transfer(0x02); + SPI.transfer(address); + SPI.transfer(value); + digitalWrite(_csPin, HIGH); + SPI.endTransaction(); } -void MCP2515Class::onInterrupt() -{ - CAN.handleInterrupt(); +void IRAM_ATTR MCP2515Class::onInterrupt() { + CAN.handleInterrupt(); } MCP2515Class CAN; - -#endif diff --git a/src/MCP2515.h b/src/MCP2515.h index 2f0444f..10ee319 100644 --- a/src/MCP2515.h +++ b/src/MCP2515.h @@ -1,8 +1,6 @@ // Copyright (c) Sandeep Mistry. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -#ifndef ARDUINO_ARCH_ESP32 - #ifndef MCP2515_H #define MCP2515_H @@ -73,5 +71,3 @@ class MCP2515Class : public CANControllerClass { extern MCP2515Class CAN; #endif - -#endif From 78bc3d68d63166dc7990f5bed4d4d93327281428 Mon Sep 17 00:00:00 2001 From: JayFromProgramming Date: Sun, 23 Feb 2025 14:52:47 -0500 Subject: [PATCH 03/16] Attempting to adjust library to work with ESP32 and MCP2515 --- src/ESP32SJA1000.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ESP32SJA1000.cpp b/src/ESP32SJA1000.cpp index 309e030..da09027 100644 --- a/src/ESP32SJA1000.cpp +++ b/src/ESP32SJA1000.cpp @@ -1,7 +1,7 @@ // Copyright (c) Sandeep Mistry. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -#ifdef ARDUINO_ARCH_ESP32 +#ifndef ARDUINO_ARCH_ESP32 #include "esp_intr.h" #include "soc/dport_reg.h" From 7a3f1ebc7594c5efba309d435df7bc68c9734c97 Mon Sep 17 00:00:00 2001 From: Jay Date: Sun, 23 Feb 2025 18:53:55 -0500 Subject: [PATCH 04/16] Update MCP2515.h --- src/MCP2515.h | 517 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 469 insertions(+), 48 deletions(-) diff --git a/src/MCP2515.h b/src/MCP2515.h index 10ee319..6efe779 100644 --- a/src/MCP2515.h +++ b/src/MCP2515.h @@ -1,73 +1,494 @@ // Copyright (c) Sandeep Mistry. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -#ifndef MCP2515_H -#define MCP2515_H +#include "MCP2515.h" -#include +#define REG_BFPCTRL 0x0c +#define REG_TXRTSCTRL 0x0d -#include "CANController.h" +#define REG_CANCTRL 0x0f -#define MCP2515_DEFAULT_CLOCK_FREQUENCY 16e6 +#define REG_CNF3 0x28 +#define REG_CNF2 0x29 +#define REG_CNF1 0x2a -#if defined(ARDUINO_ARCH_SAMD) && defined(PIN_SPI_MISO) && defined(PIN_SPI_MOSI) && defined(PIN_SPI_SCK) && (PIN_SPI_MISO == 10) && (PIN_SPI_MOSI == 8) && (PIN_SPI_SCK == 9) -// Arduino MKR board: MKR CAN shield CS is pin 3, INT is pin 7 -#define MCP2515_DEFAULT_CS_PIN 3 -#define MCP2515_DEFAULT_INT_PIN 7 -#else -#define MCP2515_DEFAULT_CS_PIN 10 -#define MCP2515_DEFAULT_INT_PIN 2 -#endif +#define REG_CANINTE 0x2b +#define REG_CANINTF 0x2c + +#define FLAG_RXnIE(n) (0x01 << n) +#define FLAG_RXnIF(n) (0x01 << n) +#define FLAG_TXnIF(n) (0x04 << n) + +#define REG_RXFnSIDH(n) (0x00 + (n * 4)) +#define REG_RXFnSIDL(n) (0x01 + (n * 4)) +#define REG_RXFnEID8(n) (0x02 + (n * 4)) +#define REG_RXFnEID0(n) (0x03 + (n * 4)) + +#define REG_RXMnSIDH(n) (0x20 + (n * 0x04)) +#define REG_RXMnSIDL(n) (0x21 + (n * 0x04)) +#define REG_RXMnEID8(n) (0x22 + (n * 0x04)) +#define REG_RXMnEID0(n) (0x23 + (n * 0x04)) + +#define REG_TXBnCTRL(n) (0x30 + (n * 0x10)) +#define REG_TXBnSIDH(n) (0x31 + (n * 0x10)) +#define REG_TXBnSIDL(n) (0x32 + (n * 0x10)) +#define REG_TXBnEID8(n) (0x33 + (n * 0x10)) +#define REG_TXBnEID0(n) (0x34 + (n * 0x10)) +#define REG_TXBnDLC(n) (0x35 + (n * 0x10)) +#define REG_TXBnD0(n) (0x36 + (n * 0x10)) + +#define REG_RXBnCTRL(n) (0x60 + (n * 0x10)) +#define REG_RXBnSIDH(n) (0x61 + (n * 0x10)) +#define REG_RXBnSIDL(n) (0x62 + (n * 0x10)) +#define REG_RXBnEID8(n) (0x63 + (n * 0x10)) +#define REG_RXBnEID0(n) (0x64 + (n * 0x10)) +#define REG_RXBnDLC(n) (0x65 + (n * 0x10)) +#define REG_RXBnD0(n) (0x66 + (n * 0x10)) + +#define FLAG_IDE 0x08 +#define FLAG_SRR 0x10 +#define FLAG_RTR 0x40 +#define FLAG_EXIDE 0x08 + +#define FLAG_RXM0 0x20 +#define FLAG_RXM1 0x40 + + +MCP2515Class::MCP2515Class() : CANControllerClass(), + _spiSettings(10E6, MSBFIRST, SPI_MODE0), + _csPin(MCP2515_DEFAULT_CS_PIN), + _intPin(MCP2515_DEFAULT_INT_PIN), + _clockFrequency(MCP2515_DEFAULT_CLOCK_FREQUENCY) { +} + +MCP2515Class::~MCP2515Class() { +} + +int MCP2515Class::begin(long baudRate) { + CANControllerClass::begin(baudRate); + + pinMode(_csPin, OUTPUT); + _interruptSemaphore = xSemaphoreCreateBinary(); + + // start SPI + SPI.begin(36, 37, 35, -1); + + 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) 666666, {0xC0, 0xB8, 0x01}}, + {(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) 666666, {0xC0, 0xF8, 0x81}}, + {(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; -class MCP2515Class : public CANControllerClass { + 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; + } + } -public: - MCP2515Class(); - virtual ~MCP2515Class(); + if (cnf == NULL) { + return 0; + } - virtual int begin(long baudRate); - virtual void end(); + writeRegister(REG_CNF1, cnf[0]); + writeRegister(REG_CNF2, cnf[1]); + writeRegister(REG_CNF3, cnf[2]); - virtual int endPacket(); + 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); - virtual int parsePacket(); + writeRegister(REG_CANCTRL, 0x00); + if (readRegister(REG_CANCTRL) != 0x00) { + return 0; + } - virtual void onReceive(void(*callback)(int)); + return 1; +} - using CANControllerClass::filter; - virtual int filter(int id, int mask); - using CANControllerClass::filterExtended; - virtual int filterExtended(long id, long mask); +void MCP2515Class::end() { + SPI.end(); - virtual int observe(); - virtual int loopback(); - virtual int sleep(); - virtual int wakeup(); + CANControllerClass::end(); +} - void setPins(int cs = MCP2515_DEFAULT_CS_PIN, int irq = MCP2515_DEFAULT_INT_PIN); - void setSPIFrequency(uint32_t frequency); - void setClockFrequency(long clockFrequency); +int MCP2515Class::endPacket() { + if (!CANControllerClass::endPacket()) { + return 0; + } - void dumpRegisters(Stream& out); + int n = 0; -private: - void reset(); + if (_txExtended) { + writeRegister(REG_TXBnSIDH(n), _txId >> 21); + writeRegister(REG_TXBnSIDL(n), (((_txId >> 18) & 0x07) << 5) | FLAG_EXIDE | ((_txId >> 16) & 0x03)); + writeRegister(REG_TXBnEID8(n), (_txId >> 8) & 0xff); + writeRegister(REG_TXBnEID0(n), _txId & 0xff); + } else { + writeRegister(REG_TXBnSIDH(n), _txId >> 3); + writeRegister(REG_TXBnSIDL(n), _txId << 5); + writeRegister(REG_TXBnEID8(n), 0x00); + writeRegister(REG_TXBnEID0(n), 0x00); + } - void handleInterrupt(); + if (_txRtr) { + writeRegister(REG_TXBnDLC(n), 0x40 | _txLength); + } else { + writeRegister(REG_TXBnDLC(n), _txLength); - uint8_t readRegister(uint8_t address); - void modifyRegister(uint8_t address, uint8_t mask, uint8_t value); - void writeRegister(uint8_t address, uint8_t value); + for (int i = 0; i < _txLength; i++) { + writeRegister(REG_TXBnD0(n) + i, _txData[i]); + } + } - static void onInterrupt(); + writeRegister(REG_TXBnCTRL(n), 0x08); -private: - SPISettings _spiSettings; - int _csPin; - int _intPin; - long _clockFrequency; -}; + bool aborted = false; -extern MCP2515Class CAN; + 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; +} + +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; + _rxExtended = false; + _rxRtr = false; + _rxLength = 0; + return 0; + } + + _rxExtended = (readRegister(REG_RXBnSIDL(n)) & FLAG_IDE) ? true : false; + + uint32_t idA = ((readRegister(REG_RXBnSIDH(n)) << 3) & 0x07f8) | ((readRegister(REG_RXBnSIDL(n)) >> 5) & 0x07); + if (_rxExtended) { + uint32_t idB = (((uint32_t) (readRegister(REG_RXBnSIDL(n)) & 0x03) << 16) & 0x30000) | ( + (readRegister(REG_RXBnEID8(n)) << 8) & 0xff00) | readRegister(REG_RXBnEID0(n)); + + _rxId = (idA << 18) | idB; + _rxRtr = (readRegister(REG_RXBnDLC(n)) & FLAG_RTR) ? true : false; + } else { + _rxId = idA; + _rxRtr = (readRegister(REG_RXBnSIDL(n)) & FLAG_SRR) ? true : false; + } + _rxDlc = readRegister(REG_RXBnDLC(n)) & 0x0f; + _rxIndex = 0; + + if (_rxRtr) { + _rxLength = 0; + } else { + _rxLength = _rxDlc; + + for (int i = 0; i < _rxLength; i++) { + _rxData[i] = readRegister(REG_RXBnD0(n) + i); + } + } + + modifyRegister(REG_CANINTF, FLAG_RXnIF(n), 0x00); + + return _rxDlc; +} + +void MCP2515Class::onReceive(void (*callback)(int)) { + CANControllerClass::onReceive(callback); // set callback + + pinMode(_intPin, INPUT); + + if (callback) { + // SPI.usingInterrupt(digitalPinToInterrupt(_intPin)); // Possibly not needed for ESP32 with FreeRTOS + xTaskCreatePinnedToCore( + &MCP2515Class::interruptHandler, + "MCP2515", + 2048, + this, + 1, + &_interruptTask, + 1); + attachInterrupt(digitalPinToInterrupt(_intPin), MCP2515Class::onInterrupt, FALLING); + } else { + detachInterrupt(digitalPinToInterrupt(_intPin)); +#ifdef SPI_HAS_NOTUSINGINTERRUPT + SPI.notUsingInterrupt(digitalPinToInterrupt(_intPin)); #endif + } +} + +int MCP2515Class::filter(int id, int mask) { + id &= 0x7ff; + mask &= 0x7ff; + + // config mode + writeRegister(REG_CANCTRL, 0x80); + if (readRegister(REG_CANCTRL) != 0x80) { + return 0; + } + + for (int n = 0; n < 2; n++) { + // standard only + writeRegister(REG_RXBnCTRL(n), FLAG_RXM0); + writeRegister(REG_RXBnCTRL(n), FLAG_RXM0); + + writeRegister(REG_RXMnSIDH(n), mask >> 3); + writeRegister(REG_RXMnSIDL(n), mask << 5); + writeRegister(REG_RXMnEID8(n), 0); + writeRegister(REG_RXMnEID0(n), 0); + } + + for (int n = 0; n < 6; n++) { + writeRegister(REG_RXFnSIDH(n), id >> 3); + writeRegister(REG_RXFnSIDL(n), id << 5); + writeRegister(REG_RXFnEID8(n), 0); + writeRegister(REG_RXFnEID0(n), 0); + } + + // normal mode + writeRegister(REG_CANCTRL, 0x00); + if (readRegister(REG_CANCTRL) != 0x00) { + return 0; + } + + return 1; +} + +int MCP2515Class::filterExtended(long id, long mask) { + id &= 0x1FFFFFFF; + mask &= 0x1FFFFFFF; + + // config mode + writeRegister(REG_CANCTRL, 0x80); + if (readRegister(REG_CANCTRL) != 0x80) { + return 0; + } + + for (int n = 0; n < 2; n++) { + // extended only + writeRegister(REG_RXBnCTRL(n), FLAG_RXM1); + writeRegister(REG_RXBnCTRL(n), FLAG_RXM1); + + writeRegister(REG_RXMnSIDH(n), mask >> 21); + writeRegister(REG_RXMnSIDL(n), (((mask >> 18) & 0x03) << 5) | FLAG_EXIDE | ((mask >> 16) & 0x03)); + writeRegister(REG_RXMnEID8(n), (mask >> 8) & 0xff); + writeRegister(REG_RXMnEID0(n), mask & 0xff); + } + + for (int n = 0; n < 6; n++) { + writeRegister(REG_RXFnSIDH(n), id >> 21); + writeRegister(REG_RXFnSIDL(n), (((id >> 18) & 0x03) << 5) | FLAG_EXIDE | ((id >> 16) & 0x03)); + writeRegister(REG_RXFnEID8(n), (id >> 8) & 0xff); + writeRegister(REG_RXFnEID0(n), id & 0xff); + } + + // normal mode + writeRegister(REG_CANCTRL, 0x00); + if (readRegister(REG_CANCTRL) != 0x00) { + return 0; + } + + return 1; +} + +int MCP2515Class::observe() { + writeRegister(REG_CANCTRL, 0x60); + if (readRegister(REG_CANCTRL) != 0x60) { + return 0; + } + + return 1; +} + +int MCP2515Class::loopback() { + writeRegister(REG_CANCTRL, 0x40); + if (readRegister(REG_CANCTRL) != 0x40) { + return 0; + } + + return 1; +} + +int MCP2515Class::sleep() { + writeRegister(REG_CANCTRL, 0x01); + if (readRegister(REG_CANCTRL) != 0x01) { + return 0; + } + + return 1; +} + +int MCP2515Class::wakeup() { + writeRegister(REG_CANCTRL, 0x00); + if (readRegister(REG_CANCTRL) != 0x00) { + return 0; + } + + return 1; +} + +void MCP2515Class::setPins(int cs, int irq) { + _csPin = cs; + _intPin = irq; +} + +void MCP2515Class::setSPIFrequency(uint32_t frequency) { + _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); +} + +void MCP2515Class::setClockFrequency(long clockFrequency) { + _clockFrequency = clockFrequency; +} + +void MCP2515Class::dumpRegisters(Stream &out) { + for (int i = 0; i < 128; i++) { + byte b = readRegister(i); + + out.print("0x"); + if (i < 16) { + out.print('0'); + } + out.print(i, HEX); + out.print(": 0x"); + if (b < 16) { + out.print('0'); + } + out.println(b, HEX); + } +} + +void MCP2515Class::reset() { + xSemaphoreTake(_spiSemaphore, portMAX_DELAY); + SPI.beginTransaction(_spiSettings); + digitalWrite(_csPin, LOW); + SPI.transfer(0xc0); + digitalWrite(_csPin, HIGH); + SPI.endTransaction(); + + delayMicroseconds(10); + xSemaphoreGive(_spiSemaphore); +} + +void MCP2515Class::handleInterrupt() { + if (readRegister(REG_CANINTF) == 0) { + return; + } + + while (parsePacket() || _rxId != -1) { + _onReceive(available()); + } +} + +uint8_t MCP2515Class::readRegister(uint8_t address) { + uint8_t value; + xSemaphoreTake(_spiSemaphore, portMAX_DELAY); + + SPI.beginTransaction(_spiSettings); + digitalWrite(_csPin, LOW); + SPI.transfer(0x03); + SPI.transfer(address); + value = SPI.transfer(0x00); + digitalWrite(_csPin, HIGH); + SPI.endTransaction(); + xSemaphoreGive(_spiSemaphore); + return value; +} + +void MCP2515Class::modifyRegister(uint8_t address, uint8_t mask, uint8_t value) { + xSemaphoreTake(_spiSemaphore, portMAX_DELAY); + SPI.beginTransaction(_spiSettings); + digitalWrite(_csPin, LOW); + SPI.transfer(0x05); + SPI.transfer(address); + SPI.transfer(mask); + SPI.transfer(value); + digitalWrite(_csPin, HIGH); + SPI.endTransaction(); + xSemaphoreGive(_spiSemaphore); +} + +void MCP2515Class::writeRegister(uint8_t address, uint8_t value) { + xSemaphoreTake(_spiSemaphore, portMAX_DELAY); + SPI.beginTransaction(_spiSettings); + digitalWrite(_csPin, LOW); + SPI.transfer(0x02); + SPI.transfer(address); + SPI.transfer(value); + digitalWrite(_csPin, HIGH); + SPI.endTransaction(); + xSemaphoreGive(_spiSemaphore); +} + +[[noreturn]] void MCP2515Class::interruptHandler(void* pvParameters) { + Serial.println("MCP2515Class::interruptHandler: Started interrupt handler task"); + for (;;) { // loop forever + xSemaphoreTake(CAN._interruptSemaphore, portMAX_DELAY); // wait for interrupt to be released + CAN.handleInterrupt(); + } +} + +void IRAM_ATTR MCP2515Class::onInterrupt() { + xSemaphoreGiveFromISR(CAN._interruptSemaphore, nullptr); +} + +MCP2515Class CAN; From 55edb01b75d6bc88beddb421145588c23b31d711 Mon Sep 17 00:00:00 2001 From: Jay Date: Sun, 23 Feb 2025 18:54:23 -0500 Subject: [PATCH 05/16] Update MCP2515.h --- src/MCP2515.h | 526 ++++++-------------------------------------------- 1 file changed, 57 insertions(+), 469 deletions(-) diff --git a/src/MCP2515.h b/src/MCP2515.h index 6efe779..14024f6 100644 --- a/src/MCP2515.h +++ b/src/MCP2515.h @@ -1,494 +1,82 @@ // Copyright (c) Sandeep Mistry. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -#include "MCP2515.h" - -#define REG_BFPCTRL 0x0c -#define REG_TXRTSCTRL 0x0d - -#define REG_CANCTRL 0x0f - -#define REG_CNF3 0x28 -#define REG_CNF2 0x29 -#define REG_CNF1 0x2a - -#define REG_CANINTE 0x2b -#define REG_CANINTF 0x2c - -#define FLAG_RXnIE(n) (0x01 << n) -#define FLAG_RXnIF(n) (0x01 << n) -#define FLAG_TXnIF(n) (0x04 << n) - -#define REG_RXFnSIDH(n) (0x00 + (n * 4)) -#define REG_RXFnSIDL(n) (0x01 + (n * 4)) -#define REG_RXFnEID8(n) (0x02 + (n * 4)) -#define REG_RXFnEID0(n) (0x03 + (n * 4)) - -#define REG_RXMnSIDH(n) (0x20 + (n * 0x04)) -#define REG_RXMnSIDL(n) (0x21 + (n * 0x04)) -#define REG_RXMnEID8(n) (0x22 + (n * 0x04)) -#define REG_RXMnEID0(n) (0x23 + (n * 0x04)) - -#define REG_TXBnCTRL(n) (0x30 + (n * 0x10)) -#define REG_TXBnSIDH(n) (0x31 + (n * 0x10)) -#define REG_TXBnSIDL(n) (0x32 + (n * 0x10)) -#define REG_TXBnEID8(n) (0x33 + (n * 0x10)) -#define REG_TXBnEID0(n) (0x34 + (n * 0x10)) -#define REG_TXBnDLC(n) (0x35 + (n * 0x10)) -#define REG_TXBnD0(n) (0x36 + (n * 0x10)) - -#define REG_RXBnCTRL(n) (0x60 + (n * 0x10)) -#define REG_RXBnSIDH(n) (0x61 + (n * 0x10)) -#define REG_RXBnSIDL(n) (0x62 + (n * 0x10)) -#define REG_RXBnEID8(n) (0x63 + (n * 0x10)) -#define REG_RXBnEID0(n) (0x64 + (n * 0x10)) -#define REG_RXBnDLC(n) (0x65 + (n * 0x10)) -#define REG_RXBnD0(n) (0x66 + (n * 0x10)) - -#define FLAG_IDE 0x08 -#define FLAG_SRR 0x10 -#define FLAG_RTR 0x40 -#define FLAG_EXIDE 0x08 - -#define FLAG_RXM0 0x20 -#define FLAG_RXM1 0x40 - - -MCP2515Class::MCP2515Class() : CANControllerClass(), - _spiSettings(10E6, MSBFIRST, SPI_MODE0), - _csPin(MCP2515_DEFAULT_CS_PIN), - _intPin(MCP2515_DEFAULT_INT_PIN), - _clockFrequency(MCP2515_DEFAULT_CLOCK_FREQUENCY) { -} - -MCP2515Class::~MCP2515Class() { -} - -int MCP2515Class::begin(long baudRate) { - CANControllerClass::begin(baudRate); - - pinMode(_csPin, OUTPUT); - _interruptSemaphore = xSemaphoreCreateBinary(); - - // start SPI - SPI.begin(36, 37, 35, -1); - - 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) 666666, {0xC0, 0xB8, 0x01}}, - {(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) 666666, {0xC0, 0xF8, 0x81}}, - {(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; -} - -void MCP2515Class::end() { - SPI.end(); - - CANControllerClass::end(); -} - -int MCP2515Class::endPacket() { - if (!CANControllerClass::endPacket()) { - return 0; - } - - int n = 0; - - if (_txExtended) { - writeRegister(REG_TXBnSIDH(n), _txId >> 21); - writeRegister(REG_TXBnSIDL(n), (((_txId >> 18) & 0x07) << 5) | FLAG_EXIDE | ((_txId >> 16) & 0x03)); - writeRegister(REG_TXBnEID8(n), (_txId >> 8) & 0xff); - writeRegister(REG_TXBnEID0(n), _txId & 0xff); - } else { - 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); - - for (int i = 0; i < _txLength; i++) { - writeRegister(REG_TXBnD0(n) + i, _txData[i]); - } - } - - writeRegister(REG_TXBnCTRL(n), 0x08); - - 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; -} - -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; - _rxExtended = false; - _rxRtr = false; - _rxLength = 0; - return 0; - } - - _rxExtended = (readRegister(REG_RXBnSIDL(n)) & FLAG_IDE) ? true : false; - - uint32_t idA = ((readRegister(REG_RXBnSIDH(n)) << 3) & 0x07f8) | ((readRegister(REG_RXBnSIDL(n)) >> 5) & 0x07); - if (_rxExtended) { - uint32_t idB = (((uint32_t) (readRegister(REG_RXBnSIDL(n)) & 0x03) << 16) & 0x30000) | ( - (readRegister(REG_RXBnEID8(n)) << 8) & 0xff00) | readRegister(REG_RXBnEID0(n)); - - _rxId = (idA << 18) | idB; - _rxRtr = (readRegister(REG_RXBnDLC(n)) & FLAG_RTR) ? true : false; - } else { - _rxId = idA; - _rxRtr = (readRegister(REG_RXBnSIDL(n)) & FLAG_SRR) ? true : false; - } - _rxDlc = readRegister(REG_RXBnDLC(n)) & 0x0f; - _rxIndex = 0; - - if (_rxRtr) { - _rxLength = 0; - } else { - _rxLength = _rxDlc; - - for (int i = 0; i < _rxLength; i++) { - _rxData[i] = readRegister(REG_RXBnD0(n) + i); - } - } - - modifyRegister(REG_CANINTF, FLAG_RXnIF(n), 0x00); - - return _rxDlc; -} - -void MCP2515Class::onReceive(void (*callback)(int)) { - CANControllerClass::onReceive(callback); // set callback - - pinMode(_intPin, INPUT); - - if (callback) { - // SPI.usingInterrupt(digitalPinToInterrupt(_intPin)); // Possibly not needed for ESP32 with FreeRTOS - xTaskCreatePinnedToCore( - &MCP2515Class::interruptHandler, - "MCP2515", - 2048, - this, - 1, - &_interruptTask, - 1); - attachInterrupt(digitalPinToInterrupt(_intPin), MCP2515Class::onInterrupt, FALLING); - } else { - detachInterrupt(digitalPinToInterrupt(_intPin)); -#ifdef SPI_HAS_NOTUSINGINTERRUPT - SPI.notUsingInterrupt(digitalPinToInterrupt(_intPin)); +#ifndef MCP2515_H +#define MCP2515_H + +#include +#include +#include +#include "CANController.h" + +#define MCP2515_DEFAULT_CLOCK_FREQUENCY 16e6 + +#if defined(ARDUINO_ARCH_SAMD) && defined(PIN_SPI_MISO) && defined(PIN_SPI_MOSI) && defined(PIN_SPI_SCK) && (PIN_SPI_MISO == 10) && (PIN_SPI_MOSI == 8) && (PIN_SPI_SCK == 9) +// Arduino MKR board: MKR CAN shield CS is pin 3, INT is pin 7 +#define MCP2515_DEFAULT_CS_PIN 3 +#define MCP2515_DEFAULT_INT_PIN 7 +#else +#define MCP2515_DEFAULT_CS_PIN 10 +#define MCP2515_DEFAULT_INT_PIN 2 #endif - } -} -int MCP2515Class::filter(int id, int mask) { - id &= 0x7ff; - mask &= 0x7ff; +class MCP2515Class : public CANControllerClass { - // config mode - writeRegister(REG_CANCTRL, 0x80); - if (readRegister(REG_CANCTRL) != 0x80) { - return 0; - } +public: + MCP2515Class(); + virtual ~MCP2515Class(); - for (int n = 0; n < 2; n++) { - // standard only - writeRegister(REG_RXBnCTRL(n), FLAG_RXM0); - writeRegister(REG_RXBnCTRL(n), FLAG_RXM0); + virtual int begin(long baudRate); + virtual void end(); - writeRegister(REG_RXMnSIDH(n), mask >> 3); - writeRegister(REG_RXMnSIDL(n), mask << 5); - writeRegister(REG_RXMnEID8(n), 0); - writeRegister(REG_RXMnEID0(n), 0); - } + virtual int endPacket(); - for (int n = 0; n < 6; n++) { - writeRegister(REG_RXFnSIDH(n), id >> 3); - writeRegister(REG_RXFnSIDL(n), id << 5); - writeRegister(REG_RXFnEID8(n), 0); - writeRegister(REG_RXFnEID0(n), 0); - } + virtual int parsePacket(); - // normal mode - writeRegister(REG_CANCTRL, 0x00); - if (readRegister(REG_CANCTRL) != 0x00) { - return 0; - } + virtual void onReceive(void(*callback)(int)); - return 1; -} + using CANControllerClass::filter; + virtual int filter(int id, int mask); + using CANControllerClass::filterExtended; + virtual int filterExtended(long id, long mask); -int MCP2515Class::filterExtended(long id, long mask) { - id &= 0x1FFFFFFF; - mask &= 0x1FFFFFFF; + virtual int observe(); + virtual int loopback(); + virtual int sleep(); + virtual int wakeup(); - // config mode - writeRegister(REG_CANCTRL, 0x80); - if (readRegister(REG_CANCTRL) != 0x80) { - return 0; - } + void setPins(int cs = MCP2515_DEFAULT_CS_PIN, int irq = MCP2515_DEFAULT_INT_PIN); + void setSPIFrequency(uint32_t frequency); + void setClockFrequency(long clockFrequency); - for (int n = 0; n < 2; n++) { - // extended only - writeRegister(REG_RXBnCTRL(n), FLAG_RXM1); - writeRegister(REG_RXBnCTRL(n), FLAG_RXM1); + void dumpRegisters(Stream& out); - writeRegister(REG_RXMnSIDH(n), mask >> 21); - writeRegister(REG_RXMnSIDL(n), (((mask >> 18) & 0x03) << 5) | FLAG_EXIDE | ((mask >> 16) & 0x03)); - writeRegister(REG_RXMnEID8(n), (mask >> 8) & 0xff); - writeRegister(REG_RXMnEID0(n), mask & 0xff); - } +private: + void reset(); - for (int n = 0; n < 6; n++) { - writeRegister(REG_RXFnSIDH(n), id >> 21); - writeRegister(REG_RXFnSIDL(n), (((id >> 18) & 0x03) << 5) | FLAG_EXIDE | ((id >> 16) & 0x03)); - writeRegister(REG_RXFnEID8(n), (id >> 8) & 0xff); - writeRegister(REG_RXFnEID0(n), id & 0xff); - } + void handleInterrupt(); - // normal mode - writeRegister(REG_CANCTRL, 0x00); - if (readRegister(REG_CANCTRL) != 0x00) { - return 0; - } + uint8_t readRegister(uint8_t address); + void modifyRegister(uint8_t address, uint8_t mask, uint8_t value); + void writeRegister(uint8_t address, uint8_t value); - return 1; -} + static void onInterrupt(); -int MCP2515Class::observe() { - writeRegister(REG_CANCTRL, 0x60); - if (readRegister(REG_CANCTRL) != 0x60) { - return 0; - } + static void interruptHandler(void* arg); - return 1; -} +private: -int MCP2515Class::loopback() { - writeRegister(REG_CANCTRL, 0x40); - if (readRegister(REG_CANCTRL) != 0x40) { - return 0; - } - return 1; -} -int MCP2515Class::sleep() { - writeRegister(REG_CANCTRL, 0x01); - if (readRegister(REG_CANCTRL) != 0x01) { - return 0; - } + SemaphoreHandle_t _spiSemaphore; // FreeRTOS semaphore for SPI bus sharing + SemaphoreHandle_t _interruptSemaphore; // FreeRTOS semaphore for interrupt handling + TaskHandle_t _interruptTask; // FreeRTOS task handle for interrupt handling + SPISettings _spiSettings; + int _csPin; + int _intPin; + long _clockFrequency; +}; - return 1; -} +extern MCP2515Class CAN; -int MCP2515Class::wakeup() { - writeRegister(REG_CANCTRL, 0x00); - if (readRegister(REG_CANCTRL) != 0x00) { - return 0; - } - - return 1; -} - -void MCP2515Class::setPins(int cs, int irq) { - _csPin = cs; - _intPin = irq; -} - -void MCP2515Class::setSPIFrequency(uint32_t frequency) { - _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); -} - -void MCP2515Class::setClockFrequency(long clockFrequency) { - _clockFrequency = clockFrequency; -} - -void MCP2515Class::dumpRegisters(Stream &out) { - for (int i = 0; i < 128; i++) { - byte b = readRegister(i); - - out.print("0x"); - if (i < 16) { - out.print('0'); - } - out.print(i, HEX); - out.print(": 0x"); - if (b < 16) { - out.print('0'); - } - out.println(b, HEX); - } -} - -void MCP2515Class::reset() { - xSemaphoreTake(_spiSemaphore, portMAX_DELAY); - SPI.beginTransaction(_spiSettings); - digitalWrite(_csPin, LOW); - SPI.transfer(0xc0); - digitalWrite(_csPin, HIGH); - SPI.endTransaction(); - - delayMicroseconds(10); - xSemaphoreGive(_spiSemaphore); -} - -void MCP2515Class::handleInterrupt() { - if (readRegister(REG_CANINTF) == 0) { - return; - } - - while (parsePacket() || _rxId != -1) { - _onReceive(available()); - } -} - -uint8_t MCP2515Class::readRegister(uint8_t address) { - uint8_t value; - xSemaphoreTake(_spiSemaphore, portMAX_DELAY); - - SPI.beginTransaction(_spiSettings); - digitalWrite(_csPin, LOW); - SPI.transfer(0x03); - SPI.transfer(address); - value = SPI.transfer(0x00); - digitalWrite(_csPin, HIGH); - SPI.endTransaction(); - xSemaphoreGive(_spiSemaphore); - return value; -} - -void MCP2515Class::modifyRegister(uint8_t address, uint8_t mask, uint8_t value) { - xSemaphoreTake(_spiSemaphore, portMAX_DELAY); - SPI.beginTransaction(_spiSettings); - digitalWrite(_csPin, LOW); - SPI.transfer(0x05); - SPI.transfer(address); - SPI.transfer(mask); - SPI.transfer(value); - digitalWrite(_csPin, HIGH); - SPI.endTransaction(); - xSemaphoreGive(_spiSemaphore); -} - -void MCP2515Class::writeRegister(uint8_t address, uint8_t value) { - xSemaphoreTake(_spiSemaphore, portMAX_DELAY); - SPI.beginTransaction(_spiSettings); - digitalWrite(_csPin, LOW); - SPI.transfer(0x02); - SPI.transfer(address); - SPI.transfer(value); - digitalWrite(_csPin, HIGH); - SPI.endTransaction(); - xSemaphoreGive(_spiSemaphore); -} - -[[noreturn]] void MCP2515Class::interruptHandler(void* pvParameters) { - Serial.println("MCP2515Class::interruptHandler: Started interrupt handler task"); - for (;;) { // loop forever - xSemaphoreTake(CAN._interruptSemaphore, portMAX_DELAY); // wait for interrupt to be released - CAN.handleInterrupt(); - } -} - -void IRAM_ATTR MCP2515Class::onInterrupt() { - xSemaphoreGiveFromISR(CAN._interruptSemaphore, nullptr); -} - -MCP2515Class CAN; +#endif From 137ffee34d2c1b873f8ac75026a5e01f31f8dd1d Mon Sep 17 00:00:00 2001 From: Jay Date: Sun, 23 Feb 2025 18:54:39 -0500 Subject: [PATCH 06/16] Update MCP2515.cpp --- src/MCP2515.cpp | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/MCP2515.cpp b/src/MCP2515.cpp index 59fb835..6efe779 100644 --- a/src/MCP2515.cpp +++ b/src/MCP2515.cpp @@ -68,9 +68,10 @@ int MCP2515Class::begin(long baudRate) { CANControllerClass::begin(baudRate); pinMode(_csPin, OUTPUT); + _interruptSemaphore = xSemaphoreCreateBinary(); // start SPI - SPI.begin(); + SPI.begin(36, 37, 35, -1); reset(); @@ -259,8 +260,15 @@ void MCP2515Class::onReceive(void (*callback)(int)) { if (callback) { // SPI.usingInterrupt(digitalPinToInterrupt(_intPin)); // Possibly not needed for ESP32 with FreeRTOS - - attachInterrupt(digitalPinToInterrupt(_intPin), MCP2515Class::onInterrupt, LOW); + xTaskCreatePinnedToCore( + &MCP2515Class::interruptHandler, + "MCP2515", + 2048, + this, + 1, + &_interruptTask, + 1); + attachInterrupt(digitalPinToInterrupt(_intPin), MCP2515Class::onInterrupt, FALLING); } else { detachInterrupt(digitalPinToInterrupt(_intPin)); #ifdef SPI_HAS_NOTUSINGINTERRUPT @@ -410,6 +418,7 @@ void MCP2515Class::dumpRegisters(Stream &out) { } void MCP2515Class::reset() { + xSemaphoreTake(_spiSemaphore, portMAX_DELAY); SPI.beginTransaction(_spiSettings); digitalWrite(_csPin, LOW); SPI.transfer(0xc0); @@ -417,9 +426,10 @@ void MCP2515Class::reset() { SPI.endTransaction(); delayMicroseconds(10); + xSemaphoreGive(_spiSemaphore); } -void IRAM_ATTR MCP2515Class::handleInterrupt() { +void MCP2515Class::handleInterrupt() { if (readRegister(REG_CANINTF) == 0) { return; } @@ -431,6 +441,7 @@ void IRAM_ATTR MCP2515Class::handleInterrupt() { uint8_t MCP2515Class::readRegister(uint8_t address) { uint8_t value; + xSemaphoreTake(_spiSemaphore, portMAX_DELAY); SPI.beginTransaction(_spiSettings); digitalWrite(_csPin, LOW); @@ -439,11 +450,12 @@ uint8_t MCP2515Class::readRegister(uint8_t address) { value = SPI.transfer(0x00); digitalWrite(_csPin, HIGH); SPI.endTransaction(); - + xSemaphoreGive(_spiSemaphore); return value; } void MCP2515Class::modifyRegister(uint8_t address, uint8_t mask, uint8_t value) { + xSemaphoreTake(_spiSemaphore, portMAX_DELAY); SPI.beginTransaction(_spiSettings); digitalWrite(_csPin, LOW); SPI.transfer(0x05); @@ -452,9 +464,11 @@ void MCP2515Class::modifyRegister(uint8_t address, uint8_t mask, uint8_t value) SPI.transfer(value); digitalWrite(_csPin, HIGH); SPI.endTransaction(); + xSemaphoreGive(_spiSemaphore); } void MCP2515Class::writeRegister(uint8_t address, uint8_t value) { + xSemaphoreTake(_spiSemaphore, portMAX_DELAY); SPI.beginTransaction(_spiSettings); digitalWrite(_csPin, LOW); SPI.transfer(0x02); @@ -462,10 +476,19 @@ void MCP2515Class::writeRegister(uint8_t address, uint8_t value) { SPI.transfer(value); digitalWrite(_csPin, HIGH); SPI.endTransaction(); + xSemaphoreGive(_spiSemaphore); +} + +[[noreturn]] void MCP2515Class::interruptHandler(void* pvParameters) { + Serial.println("MCP2515Class::interruptHandler: Started interrupt handler task"); + for (;;) { // loop forever + xSemaphoreTake(CAN._interruptSemaphore, portMAX_DELAY); // wait for interrupt to be released + CAN.handleInterrupt(); + } } void IRAM_ATTR MCP2515Class::onInterrupt() { - CAN.handleInterrupt(); + xSemaphoreGiveFromISR(CAN._interruptSemaphore, nullptr); } MCP2515Class CAN; From 53c697d56053f4e2e4fc5e4415e7cc006bed92e4 Mon Sep 17 00:00:00 2001 From: JayFromProgramming Date: Mon, 24 Feb 2025 08:56:06 -0500 Subject: [PATCH 07/16] Forgot to init the spi Semaphore --- src/MCP2515.cpp | 3 ++- src/MCP2515.h | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/MCP2515.cpp b/src/MCP2515.cpp index 6efe779..b10f9f7 100644 --- a/src/MCP2515.cpp +++ b/src/MCP2515.cpp @@ -69,6 +69,7 @@ int MCP2515Class::begin(long baudRate) { pinMode(_csPin, OUTPUT); _interruptSemaphore = xSemaphoreCreateBinary(); + _spiSemaphore = xSemaphoreCreateBinary(); // start SPI SPI.begin(36, 37, 35, -1); @@ -141,7 +142,7 @@ int MCP2515Class::begin(long baudRate) { if (readRegister(REG_CANCTRL) != 0x00) { return 0; } - + _hasBegun = true; return 1; } diff --git a/src/MCP2515.h b/src/MCP2515.h index 14024f6..5429e12 100644 --- a/src/MCP2515.h +++ b/src/MCP2515.h @@ -65,9 +65,7 @@ class MCP2515Class : public CANControllerClass { static void interruptHandler(void* arg); private: - - - + bool _hasBegun = false; SemaphoreHandle_t _spiSemaphore; // FreeRTOS semaphore for SPI bus sharing SemaphoreHandle_t _interruptSemaphore; // FreeRTOS semaphore for interrupt handling TaskHandle_t _interruptTask; // FreeRTOS task handle for interrupt handling From f0b463bea52a37965077104e7779528e9bf3e933 Mon Sep 17 00:00:00 2001 From: JayFromProgramming Date: Mon, 24 Feb 2025 13:27:27 -0500 Subject: [PATCH 08/16] Forgot to init the spi Semaphore --- src/MCP2515.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/MCP2515.cpp b/src/MCP2515.cpp index b10f9f7..be57bfe 100644 --- a/src/MCP2515.cpp +++ b/src/MCP2515.cpp @@ -70,6 +70,7 @@ int MCP2515Class::begin(long baudRate) { pinMode(_csPin, OUTPUT); _interruptSemaphore = xSemaphoreCreateBinary(); _spiSemaphore = xSemaphoreCreateBinary(); + xSemaphoreGive(_spiSemaphore); // give the semaphore to allow SPI access // start SPI SPI.begin(36, 37, 35, -1); @@ -260,7 +261,6 @@ void MCP2515Class::onReceive(void (*callback)(int)) { pinMode(_intPin, INPUT); if (callback) { - // SPI.usingInterrupt(digitalPinToInterrupt(_intPin)); // Possibly not needed for ESP32 with FreeRTOS xTaskCreatePinnedToCore( &MCP2515Class::interruptHandler, "MCP2515", @@ -268,8 +268,9 @@ void MCP2515Class::onReceive(void (*callback)(int)) { this, 1, &_interruptTask, - 1); - attachInterrupt(digitalPinToInterrupt(_intPin), MCP2515Class::onInterrupt, FALLING); + 0); + attachInterrupt(digitalPinToInterrupt(_intPin), MCP2515Class::onInterrupt, LOW); + xSemaphoreGive(_interruptSemaphore); } else { detachInterrupt(digitalPinToInterrupt(_intPin)); #ifdef SPI_HAS_NOTUSINGINTERRUPT @@ -484,6 +485,7 @@ void MCP2515Class::writeRegister(uint8_t address, uint8_t value) { Serial.println("MCP2515Class::interruptHandler: Started interrupt handler task"); for (;;) { // loop forever xSemaphoreTake(CAN._interruptSemaphore, portMAX_DELAY); // wait for interrupt to be released + Serial.println("MCP2515Class::interruptHandler: Interrupt received"); CAN.handleInterrupt(); } } From 0c09c66ba109d5f926cbd99aaa06255bb92dc98f Mon Sep 17 00:00:00 2001 From: JayFromProgramming Date: Mon, 24 Feb 2025 14:07:36 -0500 Subject: [PATCH 09/16] Attempting to bypass the INT pin --- src/MCP2515.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/MCP2515.cpp b/src/MCP2515.cpp index be57bfe..e7aa357 100644 --- a/src/MCP2515.cpp +++ b/src/MCP2515.cpp @@ -258,7 +258,7 @@ int MCP2515Class::parsePacket() { void MCP2515Class::onReceive(void (*callback)(int)) { CANControllerClass::onReceive(callback); // set callback - pinMode(_intPin, INPUT); + pinMode(_intPin, INPUT_PULLUP); if (callback) { xTaskCreatePinnedToCore( @@ -482,11 +482,10 @@ void MCP2515Class::writeRegister(uint8_t address, uint8_t value) { } [[noreturn]] void MCP2515Class::interruptHandler(void* pvParameters) { - Serial.println("MCP2515Class::interruptHandler: Started interrupt handler task"); + Serial.println("MCP2515Class::interruptPoller: Interrupt handler started"); for (;;) { // loop forever - xSemaphoreTake(CAN._interruptSemaphore, portMAX_DELAY); // wait for interrupt to be released - Serial.println("MCP2515Class::interruptHandler: Interrupt received"); CAN.handleInterrupt(); + vTaskDelay(5); // Delay 5 ticks to prevent completely hogging CPU0 } } From b87f62e0a4093b991342085ad7c19611e62a79e6 Mon Sep 17 00:00:00 2001 From: JayFromProgramming Date: Tue, 25 Feb 2025 08:35:43 -0500 Subject: [PATCH 10/16] Added cleaned up ESP32 interrupt support and re-added support for the ESP32s builtin CAN controller --- src/CAN.h | 11 ++++-- src/MCP2515.cpp | 89 ++++++++++++++++++++++++++++++++----------------- src/MCP2515.h | 18 +++++++--- 3 files changed, 79 insertions(+), 39 deletions(-) diff --git a/src/CAN.h b/src/CAN.h index 6fa3e61..8922e4d 100644 --- a/src/CAN.h +++ b/src/CAN.h @@ -4,7 +4,12 @@ #ifndef CAN_H #define CAN_H - -#include "MCP2515.h" - +#ifdef USE_ESP32SJA1000 + #ifndef ARDUINO_ARCH_ESP32 + #error "Arduino-Jay-CAN: ESP32SJA1000 is only supported on the ESP32 platform" + #endif + #include "ESP32SJA1000.h" +#else + #include "MCP2515.h" +#endif #endif diff --git a/src/MCP2515.cpp b/src/MCP2515.cpp index e7aa357..27cc559 100644 --- a/src/MCP2515.cpp +++ b/src/MCP2515.cpp @@ -68,10 +68,11 @@ int MCP2515Class::begin(long baudRate) { CANControllerClass::begin(baudRate); pinMode(_csPin, OUTPUT); +#ifdef ARDUINO_ARCH_ESP32 _interruptSemaphore = xSemaphoreCreateBinary(); _spiSemaphore = xSemaphoreCreateBinary(); xSemaphoreGive(_spiSemaphore); // give the semaphore to allow SPI access - +#endif // start SPI SPI.begin(36, 37, 35, -1); @@ -258,20 +259,27 @@ int MCP2515Class::parsePacket() { void MCP2515Class::onReceive(void (*callback)(int)) { CANControllerClass::onReceive(callback); // set callback - pinMode(_intPin, INPUT_PULLUP); + pinMode(_intPin, INPUT); if (callback) { - xTaskCreatePinnedToCore( - &MCP2515Class::interruptHandler, - "MCP2515", +#ifdef ARDUINO_ARCH_ESP32 + xTaskCreatePinnedToCore( // create a task to handle the interrupts in task context instead of ISR context + &MCP2515Class::interruptTask, + "MCP2515-Handler", 2048, this, 1, &_interruptTask, 0); + xSemaphoreGive(_interruptSemaphore); // Give the semaphore once to catch any preexisting interrupts +#else + SPI.usingInterrupt(digitalPinToInterrupt(_intPin)); +#endif attachInterrupt(digitalPinToInterrupt(_intPin), MCP2515Class::onInterrupt, LOW); - xSemaphoreGive(_interruptSemaphore); } else { +#ifdef ARDUINO_ARCH_ESP32 + vTaskDelete(_interruptTask); // stop the interrupt task +#endif detachInterrupt(digitalPinToInterrupt(_intPin)); #ifdef SPI_HAS_NOTUSINGINTERRUPT SPI.notUsingInterrupt(digitalPinToInterrupt(_intPin)); @@ -431,61 +439,72 @@ void MCP2515Class::reset() { xSemaphoreGive(_spiSemaphore); } -void MCP2515Class::handleInterrupt() { +bool MCP2515Class::handleInterrupt() { if (readRegister(REG_CANINTF) == 0) { - return; + return false; } while (parsePacket() || _rxId != -1) { _onReceive(available()); } + return true; } -uint8_t MCP2515Class::readRegister(uint8_t address) { +uint8_t MCP2515Class::readRegister(uint8_t address) const { uint8_t value; - xSemaphoreTake(_spiSemaphore, portMAX_DELAY); - - SPI.beginTransaction(_spiSettings); - digitalWrite(_csPin, LOW); + acquireSPIBus(); SPI.transfer(0x03); SPI.transfer(address); value = SPI.transfer(0x00); - digitalWrite(_csPin, HIGH); - SPI.endTransaction(); - xSemaphoreGive(_spiSemaphore); + releaseSPIBus(); return value; } -void MCP2515Class::modifyRegister(uint8_t address, uint8_t mask, uint8_t value) { - xSemaphoreTake(_spiSemaphore, portMAX_DELAY); - SPI.beginTransaction(_spiSettings); - digitalWrite(_csPin, LOW); +void MCP2515Class::modifyRegister(uint8_t address, uint8_t mask, uint8_t value) const { + acquireSPIBus(); SPI.transfer(0x05); SPI.transfer(address); SPI.transfer(mask); SPI.transfer(value); - digitalWrite(_csPin, HIGH); - SPI.endTransaction(); - xSemaphoreGive(_spiSemaphore); + releaseSPIBus(); } -void MCP2515Class::writeRegister(uint8_t address, uint8_t value) { - xSemaphoreTake(_spiSemaphore, portMAX_DELAY); - SPI.beginTransaction(_spiSettings); - digitalWrite(_csPin, LOW); +void MCP2515Class::writeRegister(uint8_t address, uint8_t value) const { + acquireSPIBus(); SPI.transfer(0x02); SPI.transfer(address); SPI.transfer(value); + releaseSPIBus(); +} + +void MCP2515Class::acquireSPIBus() const { +#ifdef ARDUINO_ARCH_ESP32 + xSemaphoreTake(_spiSemaphore, portMAX_DELAY); // Only needed for ESP32 with FreeRTOS +#endif + SPI.beginTransaction(_spiSettings); + digitalWrite(_csPin, LOW); +} + +void MCP2515Class::releaseSPIBus() const { digitalWrite(_csPin, HIGH); SPI.endTransaction(); +#ifdef ARDUINO_ARCH_ESP32 xSemaphoreGive(_spiSemaphore); +#endif } -[[noreturn]] void MCP2515Class::interruptHandler(void* pvParameters) { - Serial.println("MCP2515Class::interruptPoller: Interrupt handler started"); +#ifdef ARDUINO_ARCH_ESP32 +[[noreturn]] void MCP2515Class::interruptTask(void* pvParameters) { + Serial.println("MCP2515Class::interruptTask: Interrupt task started"); for (;;) { // loop forever - CAN.handleInterrupt(); - vTaskDelay(5); // Delay 5 ticks to prevent completely hogging CPU0 + if (xSemaphoreTake(CAN._interruptSemaphore, 15) == pdTRUE) { + CAN.handleInterrupt(); + } else { + Serial.println("MCP2515Class::interruptTask: Interrupt starvation detected"); + if (CAN.handleInterrupt()) { + Serial.println("MCP2515Class::interruptTask: Interrupt failure recovered"); + } + } } } @@ -493,4 +512,12 @@ void IRAM_ATTR MCP2515Class::onInterrupt() { xSemaphoreGiveFromISR(CAN._interruptSemaphore, nullptr); } +#else + +void MCP2515Class::onInterrupt() { + CAN.handleInterrupt(); +} + +#endif + MCP2515Class CAN; diff --git a/src/MCP2515.h b/src/MCP2515.h index 5429e12..0a1aa7f 100644 --- a/src/MCP2515.h +++ b/src/MCP2515.h @@ -54,15 +54,23 @@ class MCP2515Class : public CANControllerClass { private: void reset(); - void handleInterrupt(); + bool handleInterrupt(); - uint8_t readRegister(uint8_t address); - void modifyRegister(uint8_t address, uint8_t mask, uint8_t value); - void writeRegister(uint8_t address, uint8_t value); + uint8_t readRegister(uint8_t address) const; + void modifyRegister(uint8_t address, uint8_t mask, uint8_t value) const; + void writeRegister(uint8_t address, uint8_t value) const; + void acquireSPIBus() const; + void releaseSPIBus() const; + + +#ifdef ARDUINO_ARCH_ESP32 + static void interruptTask(void* arg); static void onInterrupt(); +#else + static void onInterrupt(); +#endif - static void interruptHandler(void* arg); private: bool _hasBegun = false; From 869a8272553f5c592c043d959d0ae494fdfa4bc0 Mon Sep 17 00:00:00 2001 From: JayFromProgramming Date: Tue, 25 Feb 2025 10:01:51 -0500 Subject: [PATCH 11/16] Added cleaned up ESP32 interrupt support and re-added support for the ESP32s builtin CAN controller --- src/MCP2515.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/MCP2515.cpp b/src/MCP2515.cpp index 27cc559..f988a6e 100644 --- a/src/MCP2515.cpp +++ b/src/MCP2515.cpp @@ -266,11 +266,11 @@ void MCP2515Class::onReceive(void (*callback)(int)) { xTaskCreatePinnedToCore( // create a task to handle the interrupts in task context instead of ISR context &MCP2515Class::interruptTask, "MCP2515-Handler", - 2048, + 1024, this, - 1, + 1, // Set to max priority &_interruptTask, - 0); + 0); // Pinned to core 0 as the default arduino loop() runs on core 1 xSemaphoreGive(_interruptSemaphore); // Give the semaphore once to catch any preexisting interrupts #else SPI.usingInterrupt(digitalPinToInterrupt(_intPin)); @@ -497,12 +497,11 @@ void MCP2515Class::releaseSPIBus() const { [[noreturn]] void MCP2515Class::interruptTask(void* pvParameters) { Serial.println("MCP2515Class::interruptTask: Interrupt task started"); for (;;) { // loop forever - if (xSemaphoreTake(CAN._interruptSemaphore, 15) == pdTRUE) { + if (xSemaphoreTake(CAN._interruptSemaphore, (20 * 1000 / portTICK_PERIOD_MS)) == pdTRUE) { CAN.handleInterrupt(); } else { - Serial.println("MCP2515Class::interruptTask: Interrupt starvation detected"); if (CAN.handleInterrupt()) { - Serial.println("MCP2515Class::interruptTask: Interrupt failure recovered"); + Serial.println("MCP2515Class::interruptTask: Interrupt failure detected"); } } } From dbdacbea604961e577e26d241f6d3eef0b0f6181 Mon Sep 17 00:00:00 2001 From: JayFromProgramming Date: Tue, 25 Feb 2025 10:14:28 -0500 Subject: [PATCH 12/16] Fixed interrupt timeout to be in milliseconds not seconds --- src/MCP2515.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MCP2515.cpp b/src/MCP2515.cpp index f988a6e..4c233c8 100644 --- a/src/MCP2515.cpp +++ b/src/MCP2515.cpp @@ -259,7 +259,7 @@ int MCP2515Class::parsePacket() { void MCP2515Class::onReceive(void (*callback)(int)) { CANControllerClass::onReceive(callback); // set callback - pinMode(_intPin, INPUT); + pinMode(_intPin, INPUT_PULLUP); if (callback) { #ifdef ARDUINO_ARCH_ESP32 @@ -497,7 +497,7 @@ void MCP2515Class::releaseSPIBus() const { [[noreturn]] void MCP2515Class::interruptTask(void* pvParameters) { Serial.println("MCP2515Class::interruptTask: Interrupt task started"); for (;;) { // loop forever - if (xSemaphoreTake(CAN._interruptSemaphore, (20 * 1000 / portTICK_PERIOD_MS)) == pdTRUE) { + if (xSemaphoreTake(CAN._interruptSemaphore, 250) == pdTRUE) { CAN.handleInterrupt(); } else { if (CAN.handleInterrupt()) { From be9a5f037fa5fc5a401ebe6946f538d0905664e1 Mon Sep 17 00:00:00 2001 From: JayFromProgramming Date: Tue, 25 Feb 2025 10:29:41 -0500 Subject: [PATCH 13/16] Attempting to debug interrupt issues --- src/MCP2515.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/MCP2515.cpp b/src/MCP2515.cpp index 4c233c8..c36b8a9 100644 --- a/src/MCP2515.cpp +++ b/src/MCP2515.cpp @@ -500,6 +500,9 @@ void MCP2515Class::releaseSPIBus() const { if (xSemaphoreTake(CAN._interruptSemaphore, 250) == pdTRUE) { CAN.handleInterrupt(); } else { + if (digitalRead(CAN._intPin) == LOW) { + Serial.println("MCP2515Class::interruptTask: Interrupt triggered but semaphore not taken"); + } if (CAN.handleInterrupt()) { Serial.println("MCP2515Class::interruptTask: Interrupt failure detected"); } From d04527cf51000da6a9af0fb6b0267a262d5ac49b Mon Sep 17 00:00:00 2001 From: JayFromProgramming Date: Tue, 25 Feb 2025 10:39:17 -0500 Subject: [PATCH 14/16] Attempting to debug interrupt issues --- src/MCP2515.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/MCP2515.cpp b/src/MCP2515.cpp index c36b8a9..a49e61a 100644 --- a/src/MCP2515.cpp +++ b/src/MCP2515.cpp @@ -275,7 +275,7 @@ void MCP2515Class::onReceive(void (*callback)(int)) { #else SPI.usingInterrupt(digitalPinToInterrupt(_intPin)); #endif - attachInterrupt(digitalPinToInterrupt(_intPin), MCP2515Class::onInterrupt, LOW); + attachInterrupt(digitalPinToInterrupt(_intPin), MCP2515Class::onInterrupt, FALLING); } else { #ifdef ARDUINO_ARCH_ESP32 vTaskDelete(_interruptTask); // stop the interrupt task @@ -427,15 +427,10 @@ void MCP2515Class::dumpRegisters(Stream &out) { } } -void MCP2515Class::reset() { - xSemaphoreTake(_spiSemaphore, portMAX_DELAY); - SPI.beginTransaction(_spiSettings); - digitalWrite(_csPin, LOW); +void MCP2515Class::reset() const { + acquireSPIBus(); SPI.transfer(0xc0); - digitalWrite(_csPin, HIGH); - SPI.endTransaction(); - - delayMicroseconds(10); + releaseSPIBus(); xSemaphoreGive(_spiSemaphore); } @@ -443,11 +438,13 @@ bool MCP2515Class::handleInterrupt() { if (readRegister(REG_CANINTF) == 0) { return false; } - + bool hadPacket = false; while (parsePacket() || _rxId != -1) { - _onReceive(available()); + const uint16_t avail = available(); + _onReceive(avail); + if (avail) hadPacket = true; } - return true; + return hadPacket; } uint8_t MCP2515Class::readRegister(uint8_t address) const { @@ -499,6 +496,7 @@ void MCP2515Class::releaseSPIBus() const { for (;;) { // loop forever if (xSemaphoreTake(CAN._interruptSemaphore, 250) == pdTRUE) { CAN.handleInterrupt(); + if (digitalRead(CAN._intPin) == LOW) xSemaphoreGive(CAN._interruptSemaphore); } else { if (digitalRead(CAN._intPin) == LOW) { Serial.println("MCP2515Class::interruptTask: Interrupt triggered but semaphore not taken"); From bfd548c2f68f43a2cd5cd6b22d06a2a7c4f2ee9b Mon Sep 17 00:00:00 2001 From: JayFromProgramming Date: Tue, 25 Feb 2025 10:43:42 -0500 Subject: [PATCH 15/16] Attempting to debug interrupt issues --- src/MCP2515.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MCP2515.h b/src/MCP2515.h index 0a1aa7f..0a87973 100644 --- a/src/MCP2515.h +++ b/src/MCP2515.h @@ -52,7 +52,7 @@ class MCP2515Class : public CANControllerClass { void dumpRegisters(Stream& out); private: - void reset(); + void reset() const; bool handleInterrupt(); From 8f1bc84a1aa9af7997d32a696414542d2480f2a8 Mon Sep 17 00:00:00 2001 From: JayFromProgramming Date: Tue, 25 Feb 2025 10:54:24 -0500 Subject: [PATCH 16/16] Attempting to debug interrupt issues --- src/MCP2515.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/MCP2515.cpp b/src/MCP2515.cpp index a49e61a..f438ef8 100644 --- a/src/MCP2515.cpp +++ b/src/MCP2515.cpp @@ -431,7 +431,6 @@ void MCP2515Class::reset() const { acquireSPIBus(); SPI.transfer(0xc0); releaseSPIBus(); - xSemaphoreGive(_spiSemaphore); } bool MCP2515Class::handleInterrupt() {