From 78bf1e0620ee3a3d6566fd241cfcbbdffd79cc19 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 2 May 2023 07:53:33 +0200 Subject: [PATCH 01/13] Allow registration of callbacks in case of bus errors and bus warnings. --- src/ArduinoMCP2515.cpp | 31 ++++++++++++++++++++++++++++++- src/ArduinoMCP2515.h | 17 ++++++++++++++++- src/MCP2515/MCP2515_Const.h | 15 +++++++++++++++ src/MCP2515/MCP2515_Control.cpp | 4 ++++ src/MCP2515/MCP2515_Control.h | 6 ++++-- 5 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/ArduinoMCP2515.cpp b/src/ArduinoMCP2515.cpp index cf54efb..7a4abfd 100644 --- a/src/ArduinoMCP2515.cpp +++ b/src/ArduinoMCP2515.cpp @@ -87,13 +87,17 @@ ArduinoMCP2515::ArduinoMCP2515(SpiSelectFunc select, SpiTransferFunc transfer, MicroSecondFunc micros, OnReceiveBufferFullFunc on_rx_buf_full, - OnTransmitBufferEmptyFunc on_tx_buf_empty) + OnTransmitBufferEmptyFunc on_tx_buf_empty, + OnCanErrorFunc on_error, + OnCanWarningFunc on_warning) : _io{select, deselect, transfer} , _cfg{_io} , _ctrl{_io} , _micros{micros} , _on_rx_buf_full{on_rx_buf_full} , _on_tx_buf_empty{on_tx_buf_empty} +, _on_error{on_error} +, _on_warning{on_warning} { } @@ -164,6 +168,9 @@ bool ArduinoMCP2515::transmit(uint32_t const id, uint8_t const * data, uint8_t c void ArduinoMCP2515::onExternalEventHandler() { + /* Obtain current status and call the appropriate callback + * handlers to facilitate the necessary actions. + */ uint8_t const status = _ctrl.status(); if(isBitSet(status, bp(STATUS::RX0IF))) onReceiveBuffer_0_Full(); @@ -171,6 +178,28 @@ void ArduinoMCP2515::onExternalEventHandler() if(isBitSet(status, bp(STATUS::TX0IF))) onTransmitBuffer_0_Empty(); if(isBitSet(status, bp(STATUS::TX1IF))) onTransmitBuffer_1_Empty(); if(isBitSet(status, bp(STATUS::TX2IF))) onTransmitBuffer_2_Empty(); + + + /* Only perform error checks if a callback has been + * registered. Otherwise, it's an unnecessary SPI + * transaction which consumes valuable processing + * time. + */ + if (!_on_error || !_on_warning) + return; + + /* Check if an error flag is set and - should an error flag + * be set - deal with it. + */ + uint8_t const error_flag = _ctrl.error(); + + bool const is_error = (error_flag > EFLG_ERR_MASK) > 0; + if (is_error && _on_error) + _on_error(error_flag); + + bool const is_warning = (error_flag > EFLG_WAR_MASK) > 0; + if (is_warning && _on_warning) + _on_warning(error_flag); } /************************************************************************************** diff --git a/src/ArduinoMCP2515.h b/src/ArduinoMCP2515.h index f8925d3..13e52c6 100644 --- a/src/ArduinoMCP2515.h +++ b/src/ArduinoMCP2515.h @@ -90,6 +90,8 @@ typedef std::function OnTransmitBufferEmptyFunc; +typedef std::function OnCanErrorFunc; +typedef std::function OnCanWarningFunc; /************************************************************************************** * CLASS DECLARATION @@ -105,7 +107,18 @@ class ArduinoMCP2515 MCP2515::SpiTransferFunc transfer, MicroSecondFunc micros, OnReceiveBufferFullFunc on_rx_buf_full, - OnTransmitBufferEmptyFunc on_tx_buf_empty); + OnTransmitBufferEmptyFunc on_tx_buf_empty, + OnCanErrorFunc on_error, + OnCanWarningFunc on_warning); + + ArduinoMCP2515(MCP2515::SpiSelectFunc select, + MCP2515::SpiDeselectFunc deselect, + MCP2515::SpiTransferFunc transfer, + MicroSecondFunc micros, + OnReceiveBufferFullFunc on_rx_buf_full, + OnTransmitBufferEmptyFunc on_tx_buf_empty) + : ArduinoMCP2515{select, deselect, transfer, micros, on_rx_buf_full, on_tx_buf_empty, nullptr, nullptr} + { } void begin(); @@ -137,6 +150,8 @@ class ArduinoMCP2515 MicroSecondFunc _micros; OnReceiveBufferFullFunc _on_rx_buf_full; OnTransmitBufferEmptyFunc _on_tx_buf_empty; + OnCanErrorFunc _on_error; + OnCanWarningFunc _on_warning; bool transmitCANFrame (uint32_t const id, uint8_t const * data, uint8_t const len); void onReceiveBuffer_0_Full (); diff --git a/src/MCP2515/MCP2515_Const.h b/src/MCP2515/MCP2515_Const.h index 874d174..bdeef7a 100644 --- a/src/MCP2515/MCP2515_Const.h +++ b/src/MCP2515/MCP2515_Const.h @@ -222,6 +222,18 @@ enum class TXBnCTRL : uint8_t TXREQ = 3, }; +enum class EFLG : uint8_t +{ + RX1OVR = 7, + RX0OVR = 6, + TXBO = 5, + TXEP = 4, + RXEP = 3, + TXWAR = 2, + RXWAR = 1, + EWARN = 0, +}; + /************************************************************************************** * CONVERSION FUNCTIONS **************************************************************************************/ @@ -247,6 +259,9 @@ static uint8_t constexpr CANSTAT_OP_MASK = bm(CANSTAT::OPMOD2) | bm(CANSTAT:: static uint8_t constexpr RXB0CTRL_RXM_MASK = bm(RXB0CTRL::RXM1) | bm(RXB0CTRL::RXM0); static uint8_t constexpr RXB1CTRL_RXM_MASK = bm(RXB1CTRL::RXM1) | bm(RXB1CTRL::RXM0); +static uint8_t constexpr EFLG_ERR_MASK = bm(EFLG::RX1OVR) | bm(EFLG::RX0OVR) | bm(EFLG::TXBO) | bm(EFLG::TXEP) | bm(EFLG::RXEP); +static uint8_t constexpr EFLG_WAR_MASK = bm(EFLG::TXWAR) | bm(EFLG::RXWAR) | bm(EFLG::EWARN); + static uint32_t constexpr CAN_EFF_BITMASK = 0x80000000; static uint32_t constexpr CAN_RTR_BITMASK = 0x40000000; static uint32_t constexpr CAN_ERR_BITMASK = 0x20000000; diff --git a/src/MCP2515/MCP2515_Control.cpp b/src/MCP2515/MCP2515_Control.cpp index 987d8ec..c2944e3 100644 --- a/src/MCP2515/MCP2515_Control.cpp +++ b/src/MCP2515/MCP2515_Control.cpp @@ -107,6 +107,10 @@ void MCP2515_Control::receive(RxB const rxb, uint32_t & id, uint8_t * data, uint memcpy(data, rx_buffer.reg.data, std::min(len, 8)); } +uint8_t MCP2515_Control::error() +{ + return _io.readRegister(Register::EFLG); +} /************************************************************************************** * NAMESPACE diff --git a/src/MCP2515/MCP2515_Control.h b/src/MCP2515/MCP2515_Control.h index 852ba6b..10e64f4 100644 --- a/src/MCP2515/MCP2515_Control.h +++ b/src/MCP2515/MCP2515_Control.h @@ -33,8 +33,10 @@ class MCP2515_Control MCP2515_Control(MCP2515_Io & io); - void transmit (TxB const txb, uint32_t const id, uint8_t const * data, uint8_t const len); - void receive (RxB const rxb, uint32_t & id, uint8_t * data, uint8_t & len); + void transmit(TxB const txb, uint32_t const id, uint8_t const * data, uint8_t const len); + void receive (RxB const rxb, uint32_t & id, uint8_t * data, uint8_t & len); + + uint8_t error(); inline void reset () { _io.reset(); } inline uint8_t status () { return _io.status(); } From a6ca4c40e029662b99438b75f9740503f1664e45 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 2 May 2023 07:59:10 +0200 Subject: [PATCH 02/13] Automatically clear RX0OVR and RX1OVR errors. --- src/ArduinoMCP2515.cpp | 14 ++++++++++++++ src/MCP2515/MCP2515_Control.h | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/ArduinoMCP2515.cpp b/src/ArduinoMCP2515.cpp index 7a4abfd..3aabd72 100644 --- a/src/ArduinoMCP2515.cpp +++ b/src/ArduinoMCP2515.cpp @@ -195,8 +195,22 @@ void ArduinoMCP2515::onExternalEventHandler() bool const is_error = (error_flag > EFLG_ERR_MASK) > 0; if (is_error && _on_error) + { _on_error(error_flag); + /* RX0OVR and RX1OVR need to be cleared manually, + * otherwise the error will persist and we will + * not be able to ever again obtain received + * CAN frames. + */ + if (isBitSet(error_flag, bp(EFLG::RX0OVR))) + _ctrl.clearErrFlag(EFLG::RX0OVR); + + if (isBitSet(error_flag, bp(EFLG::RX1OVR))) + _ctrl.clearErrFlag(EFLG::RX1OVR); + } + + bool const is_warning = (error_flag > EFLG_WAR_MASK) > 0; if (is_warning && _on_warning) _on_warning(error_flag); diff --git a/src/MCP2515/MCP2515_Control.h b/src/MCP2515/MCP2515_Control.h index 10e64f4..c1e1f17 100644 --- a/src/MCP2515/MCP2515_Control.h +++ b/src/MCP2515/MCP2515_Control.h @@ -41,7 +41,7 @@ class MCP2515_Control inline void reset () { _io.reset(); } inline uint8_t status () { return _io.status(); } inline void clearIntFlag(CANINTF const int_flag) { _io.clrBit(Register::CANINTF, bp(int_flag)); } - + inline void clearErrFlag(EFLG const err_flag) { _io.clrBit(Register::EFLG, bp(err_flag)); } private: From fceca198ef1dac19700fe3b9e0a60f876eeba988 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 2 May 2023 08:07:07 +0200 Subject: [PATCH 03/13] Add function to convert from an error flag to a human-readable string. --- src/MCP2515/MCP2515_Const.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/MCP2515/MCP2515_Const.h b/src/MCP2515/MCP2515_Const.h index bdeef7a..d076d1d 100644 --- a/src/MCP2515/MCP2515_Const.h +++ b/src/MCP2515/MCP2515_Const.h @@ -250,6 +250,22 @@ constexpr auto bm(Enumeration const value) -> typename std::underlying_type Date: Tue, 2 May 2023 08:13:01 +0200 Subject: [PATCH 04/13] Enable error interrupt, but only if callbacks have been registered. --- src/ArduinoMCP2515.cpp | 13 ++++++++++++- src/MCP2515/MCP2515_Const.h | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/ArduinoMCP2515.cpp b/src/ArduinoMCP2515.cpp index 3aabd72..2c35b1a 100644 --- a/src/ArduinoMCP2515.cpp +++ b/src/ArduinoMCP2515.cpp @@ -125,6 +125,13 @@ void ArduinoMCP2515::begin() _cfg.enableIntFlag(CANINTE::RX0IE); _cfg.enableIntFlag(CANINTE::RX1IE); } + + /* Conditionally enable error interrupt + * only if we have error callbacks + * registered. + */ + if (_on_error || _on_warning) + _cfg.enableIntFlag(CANINTE::ERRIE); } void ArduinoMCP2515::setBitRate(CanBitRate const bit_rate) @@ -210,10 +217,14 @@ void ArduinoMCP2515::onExternalEventHandler() _ctrl.clearErrFlag(EFLG::RX1OVR); } - bool const is_warning = (error_flag > EFLG_WAR_MASK) > 0; if (is_warning && _on_warning) _on_warning(error_flag); + + /* Finally clear the error interrupt flag so that we are not + * continuously caught in the ERROR handling loop. + */ + _ctrl.clearIntFlag(CANINTF::ERRIF); } /************************************************************************************** diff --git a/src/MCP2515/MCP2515_Const.h b/src/MCP2515/MCP2515_Const.h index d076d1d..e0438b6 100644 --- a/src/MCP2515/MCP2515_Const.h +++ b/src/MCP2515/MCP2515_Const.h @@ -154,6 +154,7 @@ enum class STATUS : uint8_t enum class CANINTE : uint8_t { + ERRIE = 5, TX2IE = 4, TX1IE = 3, TX0IE = 2, From b8f2f551ffa68e78f858871e9a85603e1c4d3174 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 2 May 2023 08:21:07 +0200 Subject: [PATCH 05/13] Fix: error unreachable. --- src/MCP2515/MCP2515_Const.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MCP2515/MCP2515_Const.h b/src/MCP2515/MCP2515_Const.h index e0438b6..2c7aa36 100644 --- a/src/MCP2515/MCP2515_Const.h +++ b/src/MCP2515/MCP2515_Const.h @@ -263,7 +263,7 @@ constexpr const char * toStr(EFLG const err_flag) case EFLG::TXWAR : return "TXWAR"; break; case EFLG::RXWAR : return "RXWAR"; break; case EFLG::EWARN : return "EWARN"; break; - default: __builtin_unreachable; break; + default: __builtin_unreachable; return ""; break; } } From 37112e878726ac5420928a9a158cf28b06a2acb5 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 2 May 2023 08:21:44 +0200 Subject: [PATCH 06/13] Fix: return MCP2515::EFLG instead of uint8_t. This is necessary to find the correct 'toStr' function. --- src/ArduinoMCP2515.cpp | 4 ++-- src/ArduinoMCP2515.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ArduinoMCP2515.cpp b/src/ArduinoMCP2515.cpp index 2c35b1a..fba28e3 100644 --- a/src/ArduinoMCP2515.cpp +++ b/src/ArduinoMCP2515.cpp @@ -203,7 +203,7 @@ void ArduinoMCP2515::onExternalEventHandler() bool const is_error = (error_flag > EFLG_ERR_MASK) > 0; if (is_error && _on_error) { - _on_error(error_flag); + _on_error(static_cast(error_flag & EFLG_ERR_MASK)); /* RX0OVR and RX1OVR need to be cleared manually, * otherwise the error will persist and we will @@ -219,7 +219,7 @@ void ArduinoMCP2515::onExternalEventHandler() bool const is_warning = (error_flag > EFLG_WAR_MASK) > 0; if (is_warning && _on_warning) - _on_warning(error_flag); + _on_warning(static_cast(error_flag & EFLG_WAR_MASK)); /* Finally clear the error interrupt flag so that we are not * continuously caught in the ERROR handling loop. diff --git a/src/ArduinoMCP2515.h b/src/ArduinoMCP2515.h index 13e52c6..5f7cac3 100644 --- a/src/ArduinoMCP2515.h +++ b/src/ArduinoMCP2515.h @@ -90,8 +90,8 @@ typedef std::function OnTransmitBufferEmptyFunc; -typedef std::function OnCanErrorFunc; -typedef std::function OnCanWarningFunc; +typedef std::function OnCanErrorFunc; +typedef std::function OnCanWarningFunc; /************************************************************************************** * CLASS DECLARATION From d1709f30dc777b4bd0ec1b18a36a0d95758665d6 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 2 May 2023 09:08:43 +0200 Subject: [PATCH 07/13] Fix: logic error. proceed with error handling if at least one callback has been registered. --- src/ArduinoMCP2515.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ArduinoMCP2515.cpp b/src/ArduinoMCP2515.cpp index fba28e3..2a058b3 100644 --- a/src/ArduinoMCP2515.cpp +++ b/src/ArduinoMCP2515.cpp @@ -192,7 +192,7 @@ void ArduinoMCP2515::onExternalEventHandler() * transaction which consumes valuable processing * time. */ - if (!_on_error || !_on_warning) + if (!_on_error && !_on_warning) return; /* Check if an error flag is set and - should an error flag From 4c59972f5f854000ea69c85f89c5d7c159c2a7c2 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 2 May 2023 09:23:28 +0200 Subject: [PATCH 08/13] Add warning/error callbacks to example CAN-Sniffer. --- examples/MCP2515-CAN-Sniffer/MCP2515-CAN-Sniffer.ino | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/MCP2515-CAN-Sniffer/MCP2515-CAN-Sniffer.ino b/examples/MCP2515-CAN-Sniffer/MCP2515-CAN-Sniffer.ino index f735a2d..e69614f 100644 --- a/examples/MCP2515-CAN-Sniffer/MCP2515-CAN-Sniffer.ino +++ b/examples/MCP2515-CAN-Sniffer/MCP2515-CAN-Sniffer.ino @@ -38,7 +38,9 @@ ArduinoMCP2515 mcp2515([]() { digitalWrite(MKRCAN_MCP2515_CS_PIN, LOW); }, [](uint8_t const d) { return SPI.transfer(d); }, micros, onReceiveBufferFull, - nullptr); + nullptr, + [](MCP2515::EFLG const err_flag) { Serial.print("MCP2515::OnError, error code = "); Serial.println(MCP2515::toStr(err_flag)); }, + [](MCP2515::EFLG const err_flag) { Serial.print("MCP2515::OnError, error code = "); Serial.println(MCP2515::toStr(err_flag)); }); /************************************************************************************** * SETUP/LOOP From dc45d4e105308bd00ae7246560c08de92d0359f9 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 2 May 2023 09:24:15 +0200 Subject: [PATCH 09/13] Add newly available functions/namespaces to keywords.txt. --- keywords.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/keywords.txt b/keywords.txt index dd25dcc..a002674 100644 --- a/keywords.txt +++ b/keywords.txt @@ -9,6 +9,7 @@ ArduinoMCP2515 KEYWORD1 CanBitRate KEYWORD1 MCP2515 KEYWORD1 +EFLG KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -24,6 +25,7 @@ setConfigMode KEYWORD2 enableFilter KEYWORD2 transmit KEYWORD2 onExternalEventHandler KEYWORD2 +toStr KEYWORD2 ####################################### # Constants (LITERAL1) From 506dd9b8b45e7a043c4dc7e4907a2c42a929689e Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 2 May 2023 09:27:44 +0200 Subject: [PATCH 10/13] Fix: __builtin_unreachable() needs parenthesis. --- src/MCP2515/MCP2515_Const.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MCP2515/MCP2515_Const.h b/src/MCP2515/MCP2515_Const.h index 2c7aa36..cf82dff 100644 --- a/src/MCP2515/MCP2515_Const.h +++ b/src/MCP2515/MCP2515_Const.h @@ -263,7 +263,7 @@ constexpr const char * toStr(EFLG const err_flag) case EFLG::TXWAR : return "TXWAR"; break; case EFLG::RXWAR : return "RXWAR"; break; case EFLG::EWARN : return "EWARN"; break; - default: __builtin_unreachable; return ""; break; + default: __builtin_unreachable(); break; } } From 2ed5408c4578b1a77324b9064ef528c5b5ba727b Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 2 May 2023 09:31:50 +0200 Subject: [PATCH 11/13] Fix: not a return-statement. --- src/MCP2515/MCP2515_Const.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/MCP2515/MCP2515_Const.h b/src/MCP2515/MCP2515_Const.h index cf82dff..86307d1 100644 --- a/src/MCP2515/MCP2515_Const.h +++ b/src/MCP2515/MCP2515_Const.h @@ -251,7 +251,7 @@ constexpr auto bm(Enumeration const value) -> typename std::underlying_type Date: Tue, 2 May 2023 09:39:10 +0200 Subject: [PATCH 12/13] Move toStr() within MCP2515_Const, as ESP32 and SAMD cores do not handle constexpr well. --- src/MCP2515/MCP2515_Const.cpp | 45 +++++++++++++++++++++++++++++++++++ src/MCP2515/MCP2515_Const.h | 21 ++++------------ 2 files changed, 50 insertions(+), 16 deletions(-) create mode 100644 src/MCP2515/MCP2515_Const.cpp diff --git a/src/MCP2515/MCP2515_Const.cpp b/src/MCP2515/MCP2515_Const.cpp new file mode 100644 index 0000000..f16c96b --- /dev/null +++ b/src/MCP2515/MCP2515_Const.cpp @@ -0,0 +1,45 @@ +/** + * This software is distributed under the terms of the MIT License. + * Copyright (c) 2020 LXRobotics. + * Author: Alexander Entinger + * Contributors: https://github.com/107-systems/107-Arduino-MCP2515/graphs/contributors. + */ + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include "MCP2515_Const.h" + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +namespace MCP2515 +{ + +/************************************************************************************** + * FUNCTION DEFINITION + **************************************************************************************/ + +const char * toStr(EFLG const err_flag) +{ + switch(err_flag) + { + case EFLG::RX1OVR: return "RX1OVR"; break; + case EFLG::RX0OVR: return "RX0OVR"; break; + case EFLG::TXBO : return "TXBO"; break; + case EFLG::TXEP : return "TXEP"; break; + case EFLG::RXEP : return "RXEP"; break; + case EFLG::TXWAR : return "TXWAR"; break; + case EFLG::RXWAR : return "RXWAR"; break; + case EFLG::EWARN : return "EWARN"; break; + default: __builtin_unreachable(); return ""; break; + } +} + +/************************************************************************************** + * NAMESPACE + **************************************************************************************/ + +} /* MCP2515 */ diff --git a/src/MCP2515/MCP2515_Const.h b/src/MCP2515/MCP2515_Const.h index 86307d1..f76020f 100644 --- a/src/MCP2515/MCP2515_Const.h +++ b/src/MCP2515/MCP2515_Const.h @@ -251,22 +251,11 @@ constexpr auto bm(Enumeration const value) -> typename std::underlying_type Date: Tue, 2 May 2023 09:45:10 +0200 Subject: [PATCH 13/13] Remove superfluous space. --- src/MCP2515/MCP2515_Control.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MCP2515/MCP2515_Control.h b/src/MCP2515/MCP2515_Control.h index c1e1f17..3cadbcb 100644 --- a/src/MCP2515/MCP2515_Control.h +++ b/src/MCP2515/MCP2515_Control.h @@ -40,7 +40,7 @@ class MCP2515_Control inline void reset () { _io.reset(); } inline uint8_t status () { return _io.status(); } - inline void clearIntFlag(CANINTF const int_flag) { _io.clrBit(Register::CANINTF, bp(int_flag)); } + inline void clearIntFlag(CANINTF const int_flag) { _io.clrBit(Register::CANINTF, bp(int_flag)); } inline void clearErrFlag(EFLG const err_flag) { _io.clrBit(Register::EFLG, bp(err_flag)); } private: