From 4a9eb413896f12c7fa74ca4da037caf7671d41e3 Mon Sep 17 00:00:00 2001 From: wangcoolc <1387172050@163.com> Date: Tue, 8 Dec 2020 17:58:41 +0800 Subject: [PATCH] Add mcp2515 canbus code --- mcp2515_can.cpp | 1579 +++++++++++++++++++++++++++++++++++++++++++++ mcp2515_can.h | 156 +++++ mcp2515_can_dfs.h | 484 ++++++++++++++ 3 files changed, 2219 insertions(+) create mode 100644 mcp2515_can.cpp create mode 100644 mcp2515_can.h create mode 100644 mcp2515_can_dfs.h diff --git a/mcp2515_can.cpp b/mcp2515_can.cpp new file mode 100644 index 0000000..bfd5140 --- /dev/null +++ b/mcp2515_can.cpp @@ -0,0 +1,1579 @@ +/* + mcp_can.cpp + 2012 Copyright (c) Seeed Technology Inc. All right reserved. + + Author:Loovee (loovee@seeed.cc) + 2014-1-16 + + Contributor: + + Cory J. Fowler + Latonita + Woodward1 + Mehtajaghvi + BykeBlast + TheRo0T + Tsipizic + ralfEdmund + Nathancheek + BlueAndi + Adlerweb + Btetz + Hurvajs + xboxpro1 + ttlappalainen + + The MIT License (MIT) + + Copyright (c) 2013 Seeed Technology Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ +#include "mcp2515_can.h" + +#define spi_readwrite pSPI->transfer +#define spi_read() spi_readwrite(0x00) +#define spi_write(spi_val) spi_readwrite(spi_val) +#define SPI_BEGIN() pSPI->beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)) +#define SPI_END() pSPI->endTransaction() + +/********************************************************************************************************* +** Function name: txCtrlReg +** Descriptions: return tx ctrl reg according to tx buffer index. +** According to my tests this is faster and saves memory compared using vector +*********************************************************************************************************/ +byte txCtrlReg(byte i) { + switch (i) { + case 0: return MCP_TXB0CTRL; + case 1: return MCP_TXB1CTRL; + case 2: return MCP_TXB2CTRL; + } + return MCP_TXB2CTRL; +} + +/********************************************************************************************************* +** Function name: statusToBuffer +** Descriptions: converts CANINTF status to tx buffer index +*********************************************************************************************************/ +byte statusToTxBuffer(byte status) { + switch (status) { + case MCP_TX0IF : return 0; + case MCP_TX1IF : return 1; + case MCP_TX2IF : return 2; + } + + return 0xff; +} + +/********************************************************************************************************* +** Function name: statusToBuffer +** Descriptions: converts CANINTF status to tx buffer sidh +*********************************************************************************************************/ +byte statusToTxSidh(byte status) { + switch (status) { + case MCP_TX0IF : return MCP_TXB0SIDH; + case MCP_TX1IF : return MCP_TXB1SIDH; + case MCP_TX2IF : return MCP_TXB2SIDH; + } + + return 0; +} + +/********************************************************************************************************* +** Function name: txSidhToTxLoad +** Descriptions: return tx load command according to tx buffer sidh register +*********************************************************************************************************/ +byte txSidhToRTS(byte sidh) { + switch (sidh) { + case MCP_TXB0SIDH: return MCP_RTS_TX0; + case MCP_TXB1SIDH: return MCP_RTS_TX1; + case MCP_TXB2SIDH: return MCP_RTS_TX2; + } + return 0; +} + +/********************************************************************************************************* +** Function name: txSidhToTxLoad +** Descriptions: return tx load command according to tx buffer sidh register +*********************************************************************************************************/ +byte txSidhToTxLoad(byte sidh) { + switch (sidh) { + case MCP_TXB0SIDH: return MCP_LOAD_TX0; + case MCP_TXB1SIDH: return MCP_LOAD_TX1; + case MCP_TXB2SIDH: return MCP_LOAD_TX2; + } + return 0; +} + +/********************************************************************************************************* +** Function name: txIfFlag +** Descriptions: return tx interrupt flag +*********************************************************************************************************/ +byte txIfFlag(byte i) { + switch (i) { + case 0: return MCP_TX0IF; + case 1: return MCP_TX1IF; + case 2: return MCP_TX2IF; + } + return 0; +} + +/********************************************************************************************************* +** Function name: txStatusPendingFlag +** Descriptions: return buffer tx pending flag on status +*********************************************************************************************************/ +byte txStatusPendingFlag(byte i) { + switch (i) { + case 0: return MCP_STAT_TX0_PENDING; + case 1: return MCP_STAT_TX1_PENDING; + case 2: return MCP_STAT_TX2_PENDING; + } + return 0xff; +} + +/********************************************************************************************************* +** Function name: mcp2515_reset +** Descriptions: reset the device +*********************************************************************************************************/ +void mcp2515_can::mcp2515_reset(void) { + #ifdef SPI_HAS_TRANSACTION + SPI_BEGIN(); + #endif + MCP2515_SELECT(); + spi_readwrite(MCP_RESET); + MCP2515_UNSELECT(); + #ifdef SPI_HAS_TRANSACTION + SPI_END(); + #endif + delay(10); +} + +/********************************************************************************************************* +** Function name: mcp2515_readRegister +** Descriptions: read register +*********************************************************************************************************/ +byte mcp2515_can::mcp2515_readRegister(const byte address) { + byte ret; + + #ifdef SPI_HAS_TRANSACTION + SPI_BEGIN(); + #endif + MCP2515_SELECT(); + spi_readwrite(MCP_READ); + spi_readwrite(address); + ret = spi_read(); + MCP2515_UNSELECT(); + #ifdef SPI_HAS_TRANSACTION + SPI_END(); + #endif + + return ret; +} + +/********************************************************************************************************* +** Function name: mcp2515_readRegisterS +** Descriptions: read registerS +*********************************************************************************************************/ +void mcp2515_can::mcp2515_readRegisterS(const byte address, byte values[], const byte n) { + byte i; + #ifdef SPI_HAS_TRANSACTION + SPI_BEGIN(); + #endif + MCP2515_SELECT(); + spi_readwrite(MCP_READ); + spi_readwrite(address); + // mcp2515 has auto-increment of address-pointer + for (i = 0; i < n && i < CAN_MAX_CHAR_IN_MESSAGE; i++) { + values[i] = spi_read(); + } + MCP2515_UNSELECT(); + #ifdef SPI_HAS_TRANSACTION + SPI_END(); + #endif +} + +/********************************************************************************************************* +** Function name: mcp2515_setRegister +** Descriptions: set register +*********************************************************************************************************/ +void mcp2515_can::mcp2515_setRegister(const byte address, const byte value) { + #ifdef SPI_HAS_TRANSACTION + SPI_BEGIN(); + #endif + MCP2515_SELECT(); + spi_readwrite(MCP_WRITE); + spi_readwrite(address); + spi_readwrite(value); + MCP2515_UNSELECT(); + #ifdef SPI_HAS_TRANSACTION + SPI_END(); + #endif +} + +/********************************************************************************************************* +** Function name: mcp2515_setRegisterS +** Descriptions: set registerS +*********************************************************************************************************/ +void mcp2515_can::mcp2515_setRegisterS(const byte address, const byte values[], const byte n) { + byte i; + #ifdef SPI_HAS_TRANSACTION + SPI_BEGIN(); + #endif + MCP2515_SELECT(); + spi_readwrite(MCP_WRITE); + spi_readwrite(address); + + for (i = 0; i < n; i++) { + spi_readwrite(values[i]); + } + MCP2515_UNSELECT(); + #ifdef SPI_HAS_TRANSACTION + SPI_END(); + #endif +} + +/********************************************************************************************************* +** Function name: mcp2515_modifyRegister +** Descriptions: set bit of one register +*********************************************************************************************************/ +void mcp2515_can::mcp2515_modifyRegister(const byte address, const byte mask, const byte data) { + #ifdef SPI_HAS_TRANSACTION + SPI_BEGIN(); + #endif + MCP2515_SELECT(); + spi_readwrite(MCP_BITMOD); + spi_readwrite(address); + spi_readwrite(mask); + spi_readwrite(data); + MCP2515_UNSELECT(); + #ifdef SPI_HAS_TRANSACTION + SPI_END(); + #endif +} + +/********************************************************************************************************* +** Function name: mcp2515_readStatus +** Descriptions: read mcp2515's Status +*********************************************************************************************************/ +byte mcp2515_can::mcp2515_readStatus(void) { + byte i; + #ifdef SPI_HAS_TRANSACTION + SPI_BEGIN(); + #endif + MCP2515_SELECT(); + spi_readwrite(MCP_READ_STATUS); + i = spi_read(); + MCP2515_UNSELECT(); + #ifdef SPI_HAS_TRANSACTION + SPI_END(); + #endif + + return i; +} + +/********************************************************************************************************* +** Function name: setSleepWakeup +** Descriptions: Enable or disable the wake up interrupt (If disabled the MCP2515 will not be woken up by CAN bus activity) +*********************************************************************************************************/ +void mcp2515_can::setSleepWakeup(const byte enable) { + mcp2515_modifyRegister(MCP_CANINTE, MCP_WAKIF, enable ? MCP_WAKIF : 0); +} + +/********************************************************************************************************* +** Function name: sleep +** Descriptions: Put mcp2515 in sleep mode to save power +*********************************************************************************************************/ +byte mcp2515_can::sleep() { + if (getMode() != MODE_SLEEP) { + return mcp2515_setCANCTRL_Mode(MODE_SLEEP); + } else { + return CAN_OK; + } +} + +/********************************************************************************************************* +** Function name: wake +** Descriptions: wake MCP2515 manually from sleep. It will come back in the mode it was before sleeping. +*********************************************************************************************************/ +byte mcp2515_can::wake() { + byte currMode = getMode(); + if (currMode != mcpMode) { + return mcp2515_setCANCTRL_Mode(mcpMode); + } else { + return CAN_OK; + } +} + +/********************************************************************************************************* +** Function name: setMode +** Descriptions: Sets control mode +*********************************************************************************************************/ +byte mcp2515_can::setMode(const byte opMode) { + if (opMode != + MODE_SLEEP) { // if going to sleep, the value stored in opMode is not changed so that we can return to it later + mcpMode = opMode; + } + return mcp2515_setCANCTRL_Mode(opMode); +} + +/********************************************************************************************************* +** Function name: getMode +** Descriptions: Returns current control mode +*********************************************************************************************************/ +byte mcp2515_can::getMode() { + return mcp2515_readRegister(MCP_CANSTAT) & MODE_MASK; +} + +/********************************************************************************************************* +** Function name: mcp2515_setCANCTRL_Mode +** Descriptions: set control mode +*********************************************************************************************************/ +byte mcp2515_can::mcp2515_setCANCTRL_Mode(const byte newmode) { + // If the chip is asleep and we want to change mode then a manual wake needs to be done + // This is done by setting the wake up interrupt flag + // This undocumented trick was found at https://github.com/mkleemann/can/blob/master/can_sleep_mcp2515.c + if ((getMode()) == MODE_SLEEP && newmode != MODE_SLEEP) { + // Make sure wake interrupt is enabled + byte wakeIntEnabled = (mcp2515_readRegister(MCP_CANINTE) & MCP_WAKIF); + if (!wakeIntEnabled) { + mcp2515_modifyRegister(MCP_CANINTE, MCP_WAKIF, MCP_WAKIF); + } + + // Set wake flag (this does the actual waking up) + mcp2515_modifyRegister(MCP_CANINTF, MCP_WAKIF, MCP_WAKIF); + + // Wait for the chip to exit SLEEP and enter LISTENONLY mode. + + // If the chip is not connected to a CAN bus (or the bus has no other powered nodes) it will sometimes trigger the wake interrupt as soon + // as it's put to sleep, but it will stay in SLEEP mode instead of automatically switching to LISTENONLY mode. + // In this situation the mode needs to be manually set to LISTENONLY. + + if (mcp2515_requestNewMode(MODE_LISTENONLY) != MCP2515_OK) { + return MCP2515_FAIL; + } + + // Turn wake interrupt back off if it was originally off + if (!wakeIntEnabled) { + mcp2515_modifyRegister(MCP_CANINTE, MCP_WAKIF, 0); + } + } + + // Clear wake flag + mcp2515_modifyRegister(MCP_CANINTF, MCP_WAKIF, 0); + + return mcp2515_requestNewMode(newmode); +} + +/********************************************************************************************************* +** Function name: mcp2515_requestNewMode +** Descriptions: Set control mode +*********************************************************************************************************/ +byte mcp2515_can::mcp2515_requestNewMode(const byte newmode) { + unsigned long startTime = millis(); + + // Spam new mode request and wait for the operation to complete + while (1) { + // Request new mode + // This is inside the loop as sometimes requesting the new mode once doesn't work (usually when attempting to sleep) + mcp2515_modifyRegister(MCP_CANCTRL, MODE_MASK, newmode); + + byte statReg = mcp2515_readRegister(MCP_CANSTAT); + if ((statReg & MODE_MASK) == newmode) { // We're now in the new mode + return MCP2515_OK; + } else if ((millis() - startTime) > 200) { // Wait no more than 200ms for the operation to complete + return MCP2515_FAIL; + } + } +} + +/********************************************************************************************************* +** Function name: mcp2515_configRate +** Descriptions: set baudrate +*********************************************************************************************************/ +byte mcp2515_can::mcp2515_configRate(const byte canSpeed, const byte clock) { + byte set, cfg1, cfg2, cfg3; + set = 1; + switch (clock) { + case (MCP_16MHz) : + switch (canSpeed) { + case (CAN_5KBPS): + cfg1 = MCP_16MHz_5kBPS_CFG1; + cfg2 = MCP_16MHz_5kBPS_CFG2; + cfg3 = MCP_16MHz_5kBPS_CFG3; + break; + + case (CAN_10KBPS): + cfg1 = MCP_16MHz_10kBPS_CFG1; + cfg2 = MCP_16MHz_10kBPS_CFG2; + cfg3 = MCP_16MHz_10kBPS_CFG3; + break; + + case (CAN_20KBPS): + cfg1 = MCP_16MHz_20kBPS_CFG1; + cfg2 = MCP_16MHz_20kBPS_CFG2; + cfg3 = MCP_16MHz_20kBPS_CFG3; + break; + + case (CAN_25KBPS): + cfg1 = MCP_16MHz_25kBPS_CFG1; + cfg2 = MCP_16MHz_25kBPS_CFG2; + cfg3 = MCP_16MHz_25kBPS_CFG3; + break; + + case (CAN_31K25BPS): + cfg1 = MCP_16MHz_31k25BPS_CFG1; + cfg2 = MCP_16MHz_31k25BPS_CFG2; + cfg3 = MCP_16MHz_31k25BPS_CFG3; + break; + + case (CAN_33KBPS): + cfg1 = MCP_16MHz_33kBPS_CFG1; + cfg2 = MCP_16MHz_33kBPS_CFG2; + cfg3 = MCP_16MHz_33kBPS_CFG3; + break; + + case (CAN_40KBPS): + cfg1 = MCP_16MHz_40kBPS_CFG1; + cfg2 = MCP_16MHz_40kBPS_CFG2; + cfg3 = MCP_16MHz_40kBPS_CFG3; + break; + + case (CAN_50KBPS): + cfg1 = MCP_16MHz_50kBPS_CFG1; + cfg2 = MCP_16MHz_50kBPS_CFG2; + cfg3 = MCP_16MHz_50kBPS_CFG3; + break; + + case (CAN_80KBPS): + cfg1 = MCP_16MHz_80kBPS_CFG1; + cfg2 = MCP_16MHz_80kBPS_CFG2; + cfg3 = MCP_16MHz_80kBPS_CFG3; + break; + + case (CAN_83K3BPS): + cfg1 = MCP_16MHz_83k3BPS_CFG1; + cfg2 = MCP_16MHz_83k3BPS_CFG2; + cfg3 = MCP_16MHz_83k3BPS_CFG3; + break; + + case (CAN_95KBPS): + cfg1 = MCP_16MHz_95kBPS_CFG1; + cfg2 = MCP_16MHz_95kBPS_CFG2; + cfg3 = MCP_16MHz_95kBPS_CFG3; + break; + + case (CAN_100KBPS): + cfg1 = MCP_16MHz_100kBPS_CFG1; + cfg2 = MCP_16MHz_100kBPS_CFG2; + cfg3 = MCP_16MHz_100kBPS_CFG3; + break; + + case (CAN_125KBPS): + cfg1 = MCP_16MHz_125kBPS_CFG1; + cfg2 = MCP_16MHz_125kBPS_CFG2; + cfg3 = MCP_16MHz_125kBPS_CFG3; + break; + + case (CAN_200KBPS): + cfg1 = MCP_16MHz_200kBPS_CFG1; + cfg2 = MCP_16MHz_200kBPS_CFG2; + cfg3 = MCP_16MHz_200kBPS_CFG3; + break; + + case (CAN_250KBPS): + cfg1 = MCP_16MHz_250kBPS_CFG1; + cfg2 = MCP_16MHz_250kBPS_CFG2; + cfg3 = MCP_16MHz_250kBPS_CFG3; + break; + + case (CAN_500KBPS): + cfg1 = MCP_16MHz_500kBPS_CFG1; + cfg2 = MCP_16MHz_500kBPS_CFG2; + cfg3 = MCP_16MHz_500kBPS_CFG3; + break; + + case (CAN_666KBPS): + cfg1 = MCP_16MHz_666kBPS_CFG1; + cfg2 = MCP_16MHz_666kBPS_CFG2; + cfg3 = MCP_16MHz_666kBPS_CFG3; + break; + + case (CAN_1000KBPS): + cfg1 = MCP_16MHz_1000kBPS_CFG1; + cfg2 = MCP_16MHz_1000kBPS_CFG2; + cfg3 = MCP_16MHz_1000kBPS_CFG3; + break; + + default: + set = 0; + break; + } + break; + + case (MCP_8MHz) : + switch (canSpeed) { + case (CAN_5KBPS) : + cfg1 = MCP_8MHz_5kBPS_CFG1; + cfg2 = MCP_8MHz_5kBPS_CFG2; + cfg3 = MCP_8MHz_5kBPS_CFG3; + break; + + case (CAN_10KBPS) : + cfg1 = MCP_8MHz_10kBPS_CFG1; + cfg2 = MCP_8MHz_10kBPS_CFG2; + cfg3 = MCP_8MHz_10kBPS_CFG3; + break; + + case (CAN_20KBPS) : + cfg1 = MCP_8MHz_20kBPS_CFG1; + cfg2 = MCP_8MHz_20kBPS_CFG2; + cfg3 = MCP_8MHz_20kBPS_CFG3; + break; + + case (CAN_31K25BPS) : + cfg1 = MCP_8MHz_31k25BPS_CFG1; + cfg2 = MCP_8MHz_31k25BPS_CFG2; + cfg3 = MCP_8MHz_31k25BPS_CFG3; + break; + + case (CAN_40KBPS) : + cfg1 = MCP_8MHz_40kBPS_CFG1; + cfg2 = MCP_8MHz_40kBPS_CFG2; + cfg3 = MCP_8MHz_40kBPS_CFG3; + break; + + case (CAN_50KBPS) : + cfg1 = MCP_8MHz_50kBPS_CFG1; + cfg2 = MCP_8MHz_50kBPS_CFG2; + cfg3 = MCP_8MHz_50kBPS_CFG3; + break; + + case (CAN_80KBPS) : + cfg1 = MCP_8MHz_80kBPS_CFG1; + cfg2 = MCP_8MHz_80kBPS_CFG2; + cfg3 = MCP_8MHz_80kBPS_CFG3; + break; + + case (CAN_100KBPS) : + cfg1 = MCP_8MHz_100kBPS_CFG1; + cfg2 = MCP_8MHz_100kBPS_CFG2; + cfg3 = MCP_8MHz_100kBPS_CFG3; + break; + + case (CAN_125KBPS) : + cfg1 = MCP_8MHz_125kBPS_CFG1; + cfg2 = MCP_8MHz_125kBPS_CFG2; + cfg3 = MCP_8MHz_125kBPS_CFG3; + break; + + case (CAN_200KBPS) : + cfg1 = MCP_8MHz_200kBPS_CFG1; + cfg2 = MCP_8MHz_200kBPS_CFG2; + cfg3 = MCP_8MHz_200kBPS_CFG3; + break; + + case (CAN_250KBPS) : + cfg1 = MCP_8MHz_250kBPS_CFG1; + cfg2 = MCP_8MHz_250kBPS_CFG2; + cfg3 = MCP_8MHz_250kBPS_CFG3; + break; + + case (CAN_500KBPS) : + cfg1 = MCP_8MHz_500kBPS_CFG1; + cfg2 = MCP_8MHz_500kBPS_CFG2; + cfg3 = MCP_8MHz_500kBPS_CFG3; + break; + + case (CAN_1000KBPS) : + cfg1 = MCP_8MHz_1000kBPS_CFG1; + cfg2 = MCP_8MHz_1000kBPS_CFG2; + cfg3 = MCP_8MHz_1000kBPS_CFG3; + break; + + default: + set = 0; + break; + } + break; + + default: + set = 0; + break; + } + + if (set) { + mcp2515_setRegister(MCP_CNF1, cfg1); + mcp2515_setRegister(MCP_CNF2, cfg2); + mcp2515_setRegister(MCP_CNF3, cfg3); + return MCP2515_OK; + } else { + return MCP2515_FAIL; + } +} + +/********************************************************************************************************* +** Function name: mcp2515_initCANBuffers +** Descriptions: init canbuffers +*********************************************************************************************************/ +void mcp2515_can::mcp2515_initCANBuffers(void) { + byte i, a1, a2, a3; + + a1 = MCP_TXB0CTRL; + a2 = MCP_TXB1CTRL; + a3 = MCP_TXB2CTRL; + for (i = 0; i < 14; i++) { // in-buffer loop + mcp2515_setRegister(a1, 0); + mcp2515_setRegister(a2, 0); + mcp2515_setRegister(a3, 0); + a1++; + a2++; + a3++; + } + mcp2515_setRegister(MCP_RXB0CTRL, 0); + mcp2515_setRegister(MCP_RXB1CTRL, 0); +} + +/********************************************************************************************************* +** Function name: mcp2515_init +** Descriptions: init the device +*********************************************************************************************************/ +byte mcp2515_can::mcp2515_init(const byte canSpeed, const byte clock) { + + byte res; + + mcp2515_reset(); + + res = mcp2515_setCANCTRL_Mode(MODE_CONFIG); + if (res > 0) { + #if DEBUG_EN + Serial.print("Enter setting mode fail\r\n"); + #else + delay(10); + #endif + return res; + } + #if DEBUG_EN + Serial.print("Enter setting mode success \r\n"); + #else + delay(10); + #endif + + // set boadrate + if (mcp2515_configRate(canSpeed, clock)) { + #if DEBUG_EN + Serial.print("set rate fall!!\r\n"); + #else + delay(10); + #endif + return res; + } + #if DEBUG_EN + Serial.print("set rate success!!\r\n"); + #else + delay(10); + #endif + + if (res == MCP2515_OK) { + + // init canbuffers + mcp2515_initCANBuffers(); + + // interrupt mode + mcp2515_setRegister(MCP_CANINTE, MCP_RX0IF | MCP_RX1IF); + + #if (DEBUG_RXANY==1) + // enable both receive-buffers to receive any message and enable rollover + mcp2515_modifyRegister(MCP_RXB0CTRL, + MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK, + MCP_RXB_RX_ANY | MCP_RXB_BUKT_MASK); + mcp2515_modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK, + MCP_RXB_RX_ANY); + #else + // enable both receive-buffers to receive messages with std. and ext. identifiers and enable rollover + mcp2515_modifyRegister(MCP_RXB0CTRL, + MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK, + MCP_RXB_RX_STDEXT | MCP_RXB_BUKT_MASK); + mcp2515_modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK, + MCP_RXB_RX_STDEXT); + #endif + // enter normal mode + res = setMode(MODE_NORMAL); + if (res) { + #if DEBUG_EN + Serial.print("Enter Normal Mode Fail!!\r\n"); + #else + delay(10); + #endif + return res; + } + + + #if DEBUG_EN + Serial.print("Enter Normal Mode Success!!\r\n"); + #else + delay(10); + #endif + + } + return res; + +} + +/********************************************************************************************************* +** Function name: mcp2515_id_to_buf +** Descriptions: configure tbufdata[4] from id and ext +*********************************************************************************************************/ +void mcp2515_id_to_buf(const byte ext, const unsigned long id, byte* tbufdata) { + uint16_t canid; + + canid = (uint16_t)(id & 0x0FFFF); + + if (ext == 1) { + tbufdata[MCP_EID0] = (byte)(canid & 0xFF); + tbufdata[MCP_EID8] = (byte)(canid >> 8); + canid = (uint16_t)(id >> 16); + tbufdata[MCP_SIDL] = (byte)(canid & 0x03); + tbufdata[MCP_SIDL] += (byte)((canid & 0x1C) << 3); + tbufdata[MCP_SIDL] |= MCP_TXB_EXIDE_M; + tbufdata[MCP_SIDH] = (byte)(canid >> 5); + } else { + tbufdata[MCP_SIDH] = (byte)(canid >> 3); + tbufdata[MCP_SIDL] = (byte)((canid & 0x07) << 5); + tbufdata[MCP_EID0] = 0; + tbufdata[MCP_EID8] = 0; + } +} + +/********************************************************************************************************* +** Function name: mcp2515_write_id +** Descriptions: write can id +*********************************************************************************************************/ +void mcp2515_can::mcp2515_write_id(const byte mcp_addr, const byte ext, const unsigned long id) { + byte tbufdata[4]; + + mcp2515_id_to_buf(ext, id, tbufdata); + mcp2515_setRegisterS(mcp_addr, tbufdata, 4); +} + +/********************************************************************************************************* +** Function name: mcp2515_read_id +** Descriptions: read can id +*********************************************************************************************************/ +void mcp2515_can::mcp2515_read_id(const byte mcp_addr, byte* ext, unsigned long* id) { + byte tbufdata[4]; + + *ext = 0; + *id = 0; + + mcp2515_readRegisterS(mcp_addr, tbufdata, 4); + + *id = (tbufdata[MCP_SIDH] << 3) + (tbufdata[MCP_SIDL] >> 5); + + if ((tbufdata[MCP_SIDL] & MCP_TXB_EXIDE_M) == MCP_TXB_EXIDE_M) { + // extended id + *id = (*id << 2) + (tbufdata[MCP_SIDL] & 0x03); + *id = (*id << 8) + tbufdata[MCP_EID8]; + *id = (*id << 8) + tbufdata[MCP_EID0]; + *ext = 1; + } +} + +/********************************************************************************************************* +** Function name: mcp2515_write_canMsg +** Descriptions: write msg +** Note! There is no check for right address! +*********************************************************************************************************/ +void mcp2515_can::mcp2515_write_canMsg(const byte buffer_sidh_addr, unsigned long id, byte ext, byte rtrBit, byte len, + volatile const byte* buf) { + byte load_addr = txSidhToTxLoad(buffer_sidh_addr); + + byte tbufdata[4]; + byte dlc = len | (rtrBit ? MCP_RTR_MASK : 0) ; + byte i; + + mcp2515_id_to_buf(ext, id, tbufdata); + + #ifdef SPI_HAS_TRANSACTION + SPI_BEGIN(); + #endif + MCP2515_SELECT(); + spi_readwrite(load_addr); + for (i = 0; i < 4; i++) { + spi_write(tbufdata[i]); + } + spi_write(dlc); + for (i = 0; i < len && i < CAN_MAX_CHAR_IN_MESSAGE; i++) { + spi_write(buf[i]); + } + + MCP2515_UNSELECT(); + #ifdef SPI_HAS_TRANSACTION + SPI_END(); + #endif + + mcp2515_start_transmit(buffer_sidh_addr); + +} + +/********************************************************************************************************* +** Function name: mcp2515_read_canMsg +** Descriptions: read message +*********************************************************************************************************/ +void mcp2515_can::mcp2515_read_canMsg(const byte buffer_load_addr, volatile unsigned long* id, volatile byte* ext, + volatile byte* rtrBit, volatile byte* len, volatile byte* buf) { /* read can msg */ + byte tbufdata[4]; + byte i; + + MCP2515_SELECT(); + spi_readwrite(buffer_load_addr); + // mcp2515 has auto-increment of address-pointer + for (i = 0; i < 4; i++) { + tbufdata[i] = spi_read(); + } + + *id = (tbufdata[MCP_SIDH] << 3) + (tbufdata[MCP_SIDL] >> 5); + *ext = 0; + if ((tbufdata[MCP_SIDL] & MCP_TXB_EXIDE_M) == MCP_TXB_EXIDE_M) { + /* extended id */ + *id = (*id << 2) + (tbufdata[MCP_SIDL] & 0x03); + *id = (*id << 8) + tbufdata[MCP_EID8]; + *id = (*id << 8) + tbufdata[MCP_EID0]; + *ext = 1; + } + + byte pMsgSize = spi_read(); + *len = pMsgSize & MCP_DLC_MASK; + *rtrBit = (pMsgSize & MCP_RTR_MASK) ? 1 : 0; + for (i = 0; i < *len && i < CAN_MAX_CHAR_IN_MESSAGE; i++) { + buf[i] = spi_read(); + } + + MCP2515_UNSELECT(); +} + +/********************************************************************************************************* +** Function name: mcp2515_start_transmit +** Descriptions: Start message transmit on mcp2515 +*********************************************************************************************************/ +void mcp2515_can::mcp2515_start_transmit(const byte mcp_addr) { // start transmit + #ifdef SPI_HAS_TRANSACTION + SPI_BEGIN(); + #endif + MCP2515_SELECT(); + spi_readwrite(txSidhToRTS(mcp_addr)); + MCP2515_UNSELECT(); + #ifdef SPI_HAS_TRANSACTION + SPI_END(); + #endif +} + +/********************************************************************************************************* +** Function name: mcp2515_isTXBufFree +** Descriptions: Test is tx buffer free for transmitting +*********************************************************************************************************/ +byte mcp2515_can::mcp2515_isTXBufFree(byte* txbuf_n, byte iBuf) { /* get Next free txbuf */ + *txbuf_n = 0x00; + + if (iBuf >= MCP_N_TXBUFFERS || + (mcp2515_readStatus() & txStatusPendingFlag(iBuf)) != 0) { + return MCP_ALLTXBUSY; + } + + *txbuf_n = txCtrlReg(iBuf) + 1; /* return SIDH-address of Buffer */ + mcp2515_modifyRegister(MCP_CANINTF, txIfFlag(iBuf), 0); + + return MCP2515_OK; +} + +/********************************************************************************************************* +** Function name: mcp2515_getNextFreeTXBuf +** Descriptions: finds next free tx buffer for sending. Return MCP_ALLTXBUSY, if there is none. +*********************************************************************************************************/ +byte mcp2515_can::mcp2515_getNextFreeTXBuf(byte* txbuf_n) { // get Next free txbuf + byte status = mcp2515_readStatus() & MCP_STAT_TX_PENDING_MASK; + byte i; + + *txbuf_n = 0x00; + + if (status == MCP_STAT_TX_PENDING_MASK) { + return MCP_ALLTXBUSY; // All buffers are pending + } + + // check all 3 TX-Buffers except reserved + for (i = 0; i < MCP_N_TXBUFFERS - nReservedTx; i++) { + if ((status & txStatusPendingFlag(i)) == 0) { + *txbuf_n = txCtrlReg(i) + 1; // return SIDH-address of Buffer + mcp2515_modifyRegister(MCP_CANINTF, txIfFlag(i), 0); + return MCP2515_OK; // ! function exit + } + } + + return MCP_ALLTXBUSY; +} +/********************************************************************************************************* +** Function name: begin +** Descriptions: init can and set speed +*********************************************************************************************************/ +byte mcp2515_can::begin(byte speedset, const byte clockset) { + pSPI->begin(); + byte res = mcp2515_init(speedset, clockset); + + return ((res == MCP2515_OK) ? CAN_OK : CAN_FAILINIT); +} + +/********************************************************************************************************* +** Function name: enableTxInterrupt +** Descriptions: enable interrupt for all tx buffers +*********************************************************************************************************/ +void mcp2515_can::enableTxInterrupt(bool enable) { + byte interruptStatus = mcp2515_readRegister(MCP_CANINTE); + + if (enable) { + interruptStatus |= MCP_TX_INT; + } else { + interruptStatus &= ~MCP_TX_INT; + } + + mcp2515_setRegister(MCP_CANINTE, interruptStatus); +} + +/********************************************************************************************************* +** Function name: init_Mask +** Descriptions: init canid Masks +*********************************************************************************************************/ +byte mcp2515_can::init_Mask(byte num, byte ext, unsigned long ulData) { + byte res = MCP2515_OK; + #if DEBUG_EN + Serial.print("Begin to set Mask!!\r\n"); + #else + delay(10); + #endif + res = mcp2515_setCANCTRL_Mode(MODE_CONFIG); + if (res > 0) { + #if DEBUG_EN + Serial.print("Enter setting mode fall\r\n"); + #else + delay(10); + #endif + return res; + } + + if (num == 0) { + mcp2515_write_id(MCP_RXM0SIDH, ext, ulData); + + } else if (num == 1) { + mcp2515_write_id(MCP_RXM1SIDH, ext, ulData); + } else { + res = MCP2515_FAIL; + } + + res = mcp2515_setCANCTRL_Mode(mcpMode); + if (res > 0) { + #if DEBUG_EN + Serial.print("Enter normal mode fall\r\n"); + #else + delay(10); + #endif + return res; + } + #if DEBUG_EN + Serial.print("set Mask success!!\r\n"); + #else + delay(10); + #endif + return res; +} + +/********************************************************************************************************* +** Function name: init_Filt +** Descriptions: init canid filters +*********************************************************************************************************/ +byte mcp2515_can::init_Filt(byte num, byte ext, unsigned long ulData) { + byte res = MCP2515_OK; + #if DEBUG_EN + Serial.print("Begin to set Filter!!\r\n"); + #else + delay(10); + #endif + res = mcp2515_setCANCTRL_Mode(MODE_CONFIG); + if (res > 0) { + #if DEBUG_EN + Serial.print("Enter setting mode fall\r\n"); + #else + delay(10); + #endif + return res; + } + + switch (num) { + case 0: + mcp2515_write_id(MCP_RXF0SIDH, ext, ulData); + break; + + case 1: + mcp2515_write_id(MCP_RXF1SIDH, ext, ulData); + break; + + case 2: + mcp2515_write_id(MCP_RXF2SIDH, ext, ulData); + break; + + case 3: + mcp2515_write_id(MCP_RXF3SIDH, ext, ulData); + break; + + case 4: + mcp2515_write_id(MCP_RXF4SIDH, ext, ulData); + break; + + case 5: + mcp2515_write_id(MCP_RXF5SIDH, ext, ulData); + break; + + default: + res = MCP2515_FAIL; + } + + res = mcp2515_setCANCTRL_Mode(mcpMode); + if (res > 0) { + #if DEBUG_EN + Serial.print("Enter normal mode fall\r\nSet filter fail!!\r\n"); + #else + delay(10); + #endif + return res; + } + #if DEBUG_EN + Serial.print("set Filter success!!\r\n"); + #else + delay(10); + #endif + + return res; +} + +/********************************************************************************************************* +** Function name: sendMsgBuf +** Descriptions: Send message by using buffer read as free from CANINTF status +** Status has to be read with readRxTxStatus and filtered with checkClearTxStatus +*********************************************************************************************************/ +byte mcp2515_can::sendMsgBuf(byte status, unsigned long id, byte ext, byte rtrBit, byte len, volatile const byte* buf) { + byte txbuf_n = statusToTxSidh(status); + + if (txbuf_n == 0) { + return CAN_FAILTX; // Invalid status + } + + mcp2515_modifyRegister(MCP_CANINTF, status, 0); // Clear interrupt flag + mcp2515_write_canMsg(txbuf_n, id, ext, rtrBit, len, buf); + + return CAN_OK; +} + +/********************************************************************************************************* +** Function name: trySendMsgBuf +** Descriptions: Try to send message. There is no delays for waiting free buffer. +*********************************************************************************************************/ +byte mcp2515_can::trySendMsgBuf(unsigned long id, byte ext, byte rtrBit, byte len, const byte* buf, byte iTxBuf) { + byte txbuf_n; + + if (iTxBuf < MCP_N_TXBUFFERS) { // Use specified buffer + if (mcp2515_isTXBufFree(&txbuf_n, iTxBuf) != MCP2515_OK) { + return CAN_FAILTX; + } + } else { + if (mcp2515_getNextFreeTXBuf(&txbuf_n) != MCP2515_OK) { + return CAN_FAILTX; + } + } + + mcp2515_write_canMsg(txbuf_n, id, ext, rtrBit, len, buf); + + return CAN_OK; +} + +/********************************************************************************************************* +** Function name: sendMsg +** Descriptions: send message +*********************************************************************************************************/ +byte mcp2515_can::sendMsg(unsigned long id, byte ext, byte rtrBit, byte len, const byte* buf, bool wait_sent) { + byte res, res1, txbuf_n; + uint16_t uiTimeOut = 0; + + can_id = id; + ext_flg = ext; + rtr = rtrBit; + + do { + if (uiTimeOut > 0) { + delayMicroseconds(10); + } + res = mcp2515_getNextFreeTXBuf(&txbuf_n); // info = addr. + uiTimeOut++; + } while (res == MCP_ALLTXBUSY && (uiTimeOut < TIMEOUTVALUE)); + + if (uiTimeOut == TIMEOUTVALUE) { + return CAN_GETTXBFTIMEOUT; // get tx buff time out + } + mcp2515_write_canMsg(txbuf_n, id, ext, rtrBit, len, buf); + + if (wait_sent) { + uiTimeOut = 0; + do { + if (uiTimeOut > 0) { + delayMicroseconds(10); + } + uiTimeOut++; + res1 = mcp2515_readRegister(txbuf_n - 1); // read send buff ctrl reg + res1 = res1 & 0x08; + } while (res1 && (uiTimeOut < TIMEOUTVALUE)); + + if (uiTimeOut == TIMEOUTVALUE) { // send msg timeout + return CAN_SENDMSGTIMEOUT; + } + } + + return CAN_OK; + +} + +/********************************************************************************************************* +** Function name: sendMsgBuf +** Descriptions: send buf +*********************************************************************************************************/ +byte mcp2515_can::sendMsgBuf(unsigned long id, byte ext, byte rtrBit, byte len, const byte* buf, bool wait_sent) { + return sendMsg(id, ext, rtrBit, len, buf, wait_sent); +} + +/********************************************************************************************************* +** Function name: sendMsgBuf +** Descriptions: send buf +*********************************************************************************************************/ +byte mcp2515_can::sendMsgBuf(unsigned long id, byte ext, byte len, const byte* buf, bool wait_sent) { + return sendMsg(id, ext, 0, len, buf, wait_sent); +} + + +/********************************************************************************************************* +** Function name: readMsgBuf +** Descriptions: read message buf +*********************************************************************************************************/ +byte mcp2515_can::readMsgBuf(byte* len, byte buf[]) { + return readMsgBufID(readRxTxStatus(), &can_id, &ext_flg, &rtr, len, buf); +} + +/********************************************************************************************************* +** Function name: readMsgBufID +** Descriptions: read message buf and can bus source ID +*********************************************************************************************************/ +byte mcp2515_can::readMsgBufID(unsigned long* ID, byte* len, byte buf[]) { + return readMsgBufID(readRxTxStatus(), ID, &ext_flg, &rtr, len, buf); +} + +/********************************************************************************************************* +** Function name: readMsgBufID +** Descriptions: Read message buf and can bus source ID according to status. +** Status has to be read with readRxTxStatus. +*********************************************************************************************************/ +byte mcp2515_can::readMsgBufID(byte status, volatile unsigned long* id, volatile byte* ext, volatile byte* rtrBit, + volatile byte* len, volatile byte* buf) { + byte rc = CAN_NOMSG; + + if (status & MCP_RX0IF) { // Msg in Buffer 0 + mcp2515_read_canMsg(MCP_READ_RX0, id, ext, rtrBit, len, buf); + rc = CAN_OK; + } else if (status & MCP_RX1IF) { // Msg in Buffer 1 + mcp2515_read_canMsg(MCP_READ_RX1, id, ext, rtrBit, len, buf); + rc = CAN_OK; + } + + if (rc == CAN_OK) { + rtr = *rtrBit; + // dta_len=*len; // not used on any interface function + ext_flg = *ext; + can_id = *id; + } else { + *len = 0; + } + + return rc; +} + +/********************************************************************************************************* +** Function name: readRxTxStatus +** Descriptions: Read RX and TX interrupt bits. Function uses status reading, but translates. +** result to MCP_CANINTF. With this you can check status e.g. on interrupt sr +** with one single call to save SPI calls. Then use checkClearRxStatus and +** checkClearTxStatus for testing. +*********************************************************************************************************/ +byte mcp2515_can::readRxTxStatus(void) { + byte ret = (mcp2515_readStatus() & (MCP_STAT_TXIF_MASK | MCP_STAT_RXIF_MASK)); + ret = (ret & MCP_STAT_TX0IF ? MCP_TX0IF : 0) | + (ret & MCP_STAT_TX1IF ? MCP_TX1IF : 0) | + (ret & MCP_STAT_TX2IF ? MCP_TX2IF : 0) | + (ret & MCP_STAT_RXIF_MASK); // Rx bits happend to be same on status and MCP_CANINTF + return ret; +} + +/********************************************************************************************************* +** Function name: checkClearRxStatus +** Descriptions: Return first found rx CANINTF status and clears it from parameter. +** Note that this does not affect to chip CANINTF at all. You can use this +** with one single readRxTxStatus call. +*********************************************************************************************************/ +byte mcp2515_can::checkClearRxStatus(byte* status) { + byte ret; + + ret = *status & MCP_RX0IF; *status &= ~MCP_RX0IF; + + if (ret == 0) { + ret = *status & MCP_RX1IF; + *status &= ~MCP_RX1IF; + } + + return ret; +} + +/********************************************************************************************************* +** Function name: checkClearTxStatus +** Descriptions: Return specified buffer of first found tx CANINTF status and clears it from parameter. +** Note that this does not affect to chip CANINTF at all. You can use this +** with one single readRxTxStatus call. +*********************************************************************************************************/ +byte mcp2515_can::checkClearTxStatus(byte* status, byte iTxBuf) { + byte ret; + + if (iTxBuf < MCP_N_TXBUFFERS) { // Clear specific buffer flag + ret = *status & txIfFlag(iTxBuf); *status &= ~txIfFlag(iTxBuf); + } else { + ret = 0; + for (byte i = 0; i < MCP_N_TXBUFFERS - nReservedTx; i++) { + ret = *status & txIfFlag(i); + if (ret != 0) { + *status &= ~txIfFlag(i); + return ret; + } + }; + } + + return ret; +} + +/********************************************************************************************************* +** Function name: clearBufferTransmitIfFlags +** Descriptions: Clear transmit interrupt flags for specific buffer or for all unreserved buffers. +** If interrupt will be used, it is important to clear all flags, when there is no +** more data to be sent. Otherwise IRQ will newer change state. +*********************************************************************************************************/ +void mcp2515_can::clearBufferTransmitIfFlags(byte flags) { + flags &= MCP_TX_INT; + if (flags == 0) { + return; + } + mcp2515_modifyRegister(MCP_CANINTF, flags, 0); +} + +/********************************************************************************************************* +** Function name: checkReceive +** Descriptions: check if got something +*********************************************************************************************************/ +byte mcp2515_can::checkReceive(void) { + byte res; + res = mcp2515_readStatus(); // RXnIF in Bit 1 and 0 + return ((res & MCP_STAT_RXIF_MASK) ? CAN_MSGAVAIL : CAN_NOMSG); +} + +/********************************************************************************************************* +** Function name: checkError +** Descriptions: if something error +*********************************************************************************************************/ +byte mcp2515_can::checkError(void) { + byte eflg = mcp2515_readRegister(MCP_EFLG); + return ((eflg & MCP_EFLG_ERRORMASK) ? CAN_CTRLERROR : CAN_OK); +} + +/********************************************************************************************************* +** Function name: getCanId +** Descriptions: when receive something, you can get the can id!! +*********************************************************************************************************/ +unsigned long mcp2515_can::getCanId(void) { + return can_id; +} + +/********************************************************************************************************* +** Function name: isRemoteRequest +** Descriptions: when receive something, you can check if it was a request +*********************************************************************************************************/ +byte mcp2515_can::isRemoteRequest(void) { + return rtr; +} + +/********************************************************************************************************* +** Function name: isExtendedFrame +** Descriptions: did we just receive standard 11bit frame or extended 29bit? 0 = std, 1 = ext +*********************************************************************************************************/ +byte mcp2515_can::isExtendedFrame(void) { + return ext_flg; +} + +/********************************************************************************************************* +** Function name: mcpPinMode +** Descriptions: switch supported pins between HiZ, interrupt, output or input +*********************************************************************************************************/ +bool mcp2515_can::mcpPinMode(const byte pin, const byte mode) { + byte res; + bool ret = true; + + switch (pin) { + case MCP_RX0BF: + switch (mode) { + case MCP_PIN_HIZ: + mcp2515_modifyRegister(MCP_BFPCTRL, B0BFE, 0); + break; + case MCP_PIN_INT: + mcp2515_modifyRegister(MCP_BFPCTRL, B0BFM | B0BFE, B0BFM | B0BFE); + break; + case MCP_PIN_OUT: + mcp2515_modifyRegister(MCP_BFPCTRL, B0BFM | B0BFE, B0BFE); + break; + default: + #if DEBUG_EN + Serial.print("Invalid pin mode request\r\n"); + #endif + return false; + } + return true; + break; + case MCP_RX1BF: + switch (mode) { + case MCP_PIN_HIZ: + mcp2515_modifyRegister(MCP_BFPCTRL, B1BFE, 0); + break; + case MCP_PIN_INT: + mcp2515_modifyRegister(MCP_BFPCTRL, B1BFM | B1BFE, B1BFM | B1BFE); + break; + case MCP_PIN_OUT: + mcp2515_modifyRegister(MCP_BFPCTRL, B1BFM | B1BFE, B1BFE); + break; + default: + #if DEBUG_EN + Serial.print("Invalid pin mode request\r\n"); + #endif + return false; + } + return true; + break; + case MCP_TX0RTS: + res = mcp2515_setCANCTRL_Mode(MODE_CONFIG); + if (res > 0) { + #if DEBUG_EN + Serial.print("Entering Configuration Mode Failure...\r\n"); + #else + delay(10); + #endif + return false; + } + switch (mode) { + case MCP_PIN_INT: + mcp2515_modifyRegister(MCP_TXRTSCTRL, B0RTSM, B0RTSM); + break; + case MCP_PIN_IN: + mcp2515_modifyRegister(MCP_TXRTSCTRL, B0RTSM, 0); + break; + default: + #if DEBUG_EN + Serial.print("Invalid pin mode request\r\n"); + #endif + ret = false; + } + res = mcp2515_setCANCTRL_Mode(mcpMode); + if (res) { + #if DEBUG_EN + Serial.print("`Setting ID Mode Failure...\r\n"); + #else + delay(10); + #endif + return false; + } + return ret; + break; + case MCP_TX1RTS: + res = mcp2515_setCANCTRL_Mode(MODE_CONFIG); + if (res > 0) { + #if DEBUG_EN + Serial.print("Entering Configuration Mode Failure...\r\n"); + #else + delay(10); + #endif + return false; + } + switch (mode) { + case MCP_PIN_INT: + mcp2515_modifyRegister(MCP_TXRTSCTRL, B1RTSM, B1RTSM); + break; + case MCP_PIN_IN: + mcp2515_modifyRegister(MCP_TXRTSCTRL, B1RTSM, 0); + break; + default: + #if DEBUG_EN + Serial.print("Invalid pin mode request\r\n"); + #endif + ret = false; + } + res = mcp2515_setCANCTRL_Mode(mcpMode); + if (res) { + #if DEBUG_EN + Serial.print("`Setting ID Mode Failure...\r\n"); + #else + delay(10); + #endif + return false; + } + return ret; + break; + case MCP_TX2RTS: + res = mcp2515_setCANCTRL_Mode(MODE_CONFIG); + if (res > 0) { + #if DEBUG_EN + Serial.print("Entering Configuration Mode Failure...\r\n"); + #else + delay(10); + #endif + return false; + } + switch (mode) { + case MCP_PIN_INT: + mcp2515_modifyRegister(MCP_TXRTSCTRL, B2RTSM, B2RTSM); + break; + case MCP_PIN_IN: + mcp2515_modifyRegister(MCP_TXRTSCTRL, B2RTSM, 0); + break; + default: + #if DEBUG_EN + Serial.print("Invalid pin mode request\r\n"); + #endif + ret = false; + } + res = mcp2515_setCANCTRL_Mode(mcpMode); + if (res) { + #if DEBUG_EN + Serial.print("`Setting ID Mode Failure...\r\n"); + #else + delay(10); + #endif + return false; + } + return ret; + break; + default: + #if DEBUG_EN + Serial.print("Invalid pin for mode request\r\n"); + #endif + return false; + } +} + +/********************************************************************************************************* +** Function name: mcpDigitalWrite +** Descriptions: write HIGH or LOW to RX0BF/RX1BF +*********************************************************************************************************/ +bool mcp2515_can::mcpDigitalWrite(const byte pin, const byte mode) { + switch (pin) { + case MCP_RX0BF: + switch (mode) { + case HIGH: + mcp2515_modifyRegister(MCP_BFPCTRL, B0BFS, B0BFS); + return true; + break; + default: + mcp2515_modifyRegister(MCP_BFPCTRL, B0BFS, 0); + return true; + } + break; + case MCP_RX1BF: + switch (mode) { + case HIGH: + mcp2515_modifyRegister(MCP_BFPCTRL, B1BFS, B1BFS); + return true; + break; + default: + mcp2515_modifyRegister(MCP_BFPCTRL, B1BFS, 0); + return true; + } + break; + default: + #if DEBUG_EN + Serial.print("Invalid pin for mcpDigitalWrite\r\n"); + #endif + return false; + } +} + +/********************************************************************************************************* +** Function name: mcpDigitalRead +** Descriptions: read HIGH or LOW from supported pins +*********************************************************************************************************/ +byte mcp2515_can::mcpDigitalRead(const byte pin) { + switch (pin) { + case MCP_RX0BF: + if ((mcp2515_readRegister(MCP_BFPCTRL) & B0BFS) > 0) { + return HIGH; + } else { + return LOW; + } + break; + case MCP_RX1BF: + if ((mcp2515_readRegister(MCP_BFPCTRL) & B1BFS) > 0) { + return HIGH; + } else { + return LOW; + } + break; + case MCP_TX0RTS: + if ((mcp2515_readRegister(MCP_TXRTSCTRL) & B0RTS) > 0) { + return HIGH; + } else { + return LOW; + } + break; + case MCP_TX1RTS: + if ((mcp2515_readRegister(MCP_TXRTSCTRL) & B1RTS) > 0) { + return HIGH; + } else { + return LOW; + } + break; + case MCP_TX2RTS: + if ((mcp2515_readRegister(MCP_TXRTSCTRL) & B2RTS) > 0) { + return HIGH; + } else { + return LOW; + } + break; + default: + #if DEBUG_EN + Serial.print("Invalid pin for mcpDigitalRead\r\n"); + #endif + return LOW; + } +} + +/********************************************************************************************************* + END FILE +*********************************************************************************************************/ diff --git a/mcp2515_can.h b/mcp2515_can.h new file mode 100644 index 0000000..a954ca2 --- /dev/null +++ b/mcp2515_can.h @@ -0,0 +1,156 @@ +/* + mcp_can.h + 2012 Copyright (c) Seeed Technology Inc. All right reserved. + + Author:Loovee (loovee@seeed.cc) + 2014-1-16 + + Contributor: + + Cory J. Fowler + Latonita + Woodward1 + Mehtajaghvi + BykeBlast + TheRo0T + Tsipizic + ralfEdmund + Nathancheek + BlueAndi + Adlerweb + Btetz + Hurvajs + ttlappalainen + + The MIT License (MIT) + + Copyright (c) 2013 Seeed Technology Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ +#ifndef _MCP2515_H_ +#define _MCP2515_H_ + +#include "mcp_can.h" +#include "mcp2515_can_dfs.h" + +#define MAX_CHAR_IN_MESSAGE 8 + +class mcp2515_can : public MCP_CAN +{ +public: + mcp2515_can(byte _CS) : MCP_CAN(_CS), nReservedTx(0){}; + /* + mcp2515 driver function + */ +public: + virtual void enableTxInterrupt(bool enable = true); // enable transmit interrupt + virtual void reserveTxBuffers(byte nTxBuf = 0) + { + nReservedTx = (nTxBuf < MCP_N_TXBUFFERS ? nTxBuf : MCP_N_TXBUFFERS - 1); + } + virtual byte getLastTxBuffer() + { + return MCP_N_TXBUFFERS - 1; // read index of last tx buffer + } + virtual byte begin(byte speedset, const byte clockset = MCP_16MHz); // init can + virtual byte init_Mask(byte num, byte ext, unsigned long ulData); // init Masks + virtual byte init_Filt(byte num, byte ext, unsigned long ulData); // init filters + virtual void setSleepWakeup(byte enable); // Enable or disable the wake up interrupt (If disabled the MCP2515 will not be woken up by CAN bus activity, making it send only) + virtual byte sleep(); // Put the MCP2515 in sleep mode + virtual byte wake(); // Wake MCP2515 manually from sleep + virtual byte setMode(byte opMode); // Set operational mode + virtual byte getMode(); // Get operational mode + virtual byte sendMsgBuf(unsigned long id, byte ext, byte rtrBit, byte len, const byte *buf, bool wait_sent = true); // send buf + virtual byte sendMsgBuf(unsigned long id, byte ext, byte len, const byte *buf, bool wait_sent = true); // send buf + virtual byte readMsgBuf(byte *len, byte *buf); // read buf + virtual byte readMsgBufID(unsigned long *ID, byte *len, byte *buf); // read buf with object ID + virtual byte checkReceive(void); // if something received + virtual byte checkError(void); // if something error + virtual unsigned long getCanId(void); // get can id when receive + virtual byte isRemoteRequest(void); // get RR flag when receive + virtual byte isExtendedFrame(void); // did we recieve 29bit frame? + virtual byte readMsgBufID(byte status, volatile unsigned long *id, volatile byte *ext, volatile byte *rtr, volatile byte *len, volatile byte *buf); // read buf with object ID + virtual byte trySendMsgBuf(unsigned long id, byte ext, byte rtrBit, byte len, const byte *buf, byte iTxBuf = 0xff); // as sendMsgBuf, but does not have any wait for free buffer + virtual byte sendMsgBuf(byte status, unsigned long id, byte ext, byte rtrBit, byte len, volatile const byte *buf); // send message buf by using parsed buffer status + virtual void clearBufferTransmitIfFlags(byte flags = 0); // Clear transmit flags according to status + virtual byte readRxTxStatus(void); // read has something send or received + virtual byte checkClearRxStatus(byte *status); // read and clear and return first found rx status bit + virtual byte checkClearTxStatus(byte *status, byte iTxBuf = 0xff); // read and clear and return first found or buffer specified tx status bit + virtual bool mcpPinMode(const byte pin, const byte mode); // switch supported pins between HiZ, interrupt, output or input + virtual bool mcpDigitalWrite(const byte pin, const byte mode); // write HIGH or LOW to RX0BF/RX1BF + virtual byte mcpDigitalRead(const byte pin); + +private: + void mcp2515_reset(void); // reset mcp2515 + + byte mcp2515_readRegister(const byte address); // read mcp2515's register + + void mcp2515_readRegisterS(const byte address, + byte values[], + const byte n); + void mcp2515_setRegister(const byte address, // set mcp2515's register + const byte value); + + void mcp2515_setRegisterS(const byte address, // set mcp2515's registers + const byte values[], + const byte n); + + void mcp2515_initCANBuffers(void); + + void mcp2515_modifyRegister(const byte address, // set bit of one register + const byte mask, + const byte data); + + byte mcp2515_readStatus(void); // read mcp2515's Status + byte mcp2515_setCANCTRL_Mode(const byte newmode); // set mode + byte mcp2515_requestNewMode(const byte newmode); // Set mode + byte mcp2515_configRate(const byte canSpeed, const byte clock); // set baudrate + byte mcp2515_init(const byte canSpeed, const byte clock); // mcp2515init + + void mcp2515_write_id(const byte mcp_addr, // write can id + const byte ext, + const unsigned long id); + + void mcp2515_read_id(const byte mcp_addr, // read can id + byte *ext, + unsigned long *id); + + void mcp2515_write_canMsg(const byte buffer_sidh_addr, unsigned long id, byte ext, byte rtr, byte len, + volatile const byte *buf); // read can msg + void mcp2515_read_canMsg(const byte buffer_load_addr, volatile unsigned long *id, volatile byte *ext, + volatile byte *rtr, volatile byte *len, volatile byte *buf); // write can msg + void mcp2515_start_transmit(const byte mcp_addr); // start transmit + byte mcp2515_getNextFreeTXBuf(byte *txbuf_n); // get Next free txbuf + byte mcp2515_isTXBufFree(byte *txbuf_n, byte iBuf); // is buffer by index free + + /* + can operator function + */ + + byte sendMsg(unsigned long id, byte ext, byte rtrBit, byte len, const byte *buf, bool wait_sent = true); // send message +private: + byte rtr; // rtr + byte nReservedTx; // Count of tx buffers for reserved send +}; + +#endif +/********************************************************************************************************* + END FILE +*********************************************************************************************************/ diff --git a/mcp2515_can_dfs.h b/mcp2515_can_dfs.h new file mode 100644 index 0000000..83c4078 --- /dev/null +++ b/mcp2515_can_dfs.h @@ -0,0 +1,484 @@ +/* + mcp_can_dfs.h + 2012 Copyright (c) Seeed Technology Inc. All right reserved. + + Author:Loovee (loovee@seeed.cc) + 2014-1-16 + + Contributor: + + Cory J. Fowler + Latonita + Woodward1 + Mehtajaghvi + BykeBlast + TheRo0T + Tsipizic + ralfEdmund + Nathancheek + BlueAndi + Adlerweb + Btetz + Hurvajs + xboxpro1 + ttlappalainen + + The MIT License (MIT) + + Copyright (c) 2013 Seeed Technology Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ +#ifndef _MCP2515DFS_H_ +#define _MCP2515DFS_H_ + +#include +#include +#include + + +// if print debug information +#ifndef DEBUG_EN + #define DEBUG_EN 1 +#endif + +// Begin mt + +#define TIMEOUTVALUE 50 +#define MCP_SIDH 0 +#define MCP_SIDL 1 +#define MCP_EID8 2 +#define MCP_EID0 3 + +#define MCP_TXB_EXIDE_M 0x08 // In TXBnSIDL +#define MCP_DLC_MASK 0x0F // 4 LSBits +#define MCP_RTR_MASK 0x40 // (1<<6) Bit 6 + +#define MCP_RXB_RX_ANY 0x60 +#define MCP_RXB_RX_EXT 0x40 +#define MCP_RXB_RX_STD 0x20 +#define MCP_RXB_RX_STDEXT 0x00 +#define MCP_RXB_RX_MASK 0x60 +#define MCP_RXB_BUKT_MASK (1<<2) + + +// Bits in the TXBnCTRL registers. + +#define MCP_TXB_TXBUFE_M 0x80 +#define MCP_TXB_ABTF_M 0x40 +#define MCP_TXB_MLOA_M 0x20 +#define MCP_TXB_TXERR_M 0x10 +#define MCP_TXB_TXREQ_M 0x08 +#define MCP_TXB_TXIE_M 0x04 +#define MCP_TXB_TXP10_M 0x03 + +#define MCP_TXB_RTR_M 0x40 // In TXBnDLC +#define MCP_RXB_IDE_M 0x08 // In RXBnSIDL +#define MCP_RXB_RTR_M 0x40 // In RXBnDLC + +#define MCP_STAT_TX_PENDING_MASK (0x54) +#define MCP_STAT_TX0_PENDING (0x04) +#define MCP_STAT_TX1_PENDING (0x10) +#define MCP_STAT_TX2_PENDING (0x40) +#define MCP_STAT_TXIF_MASK (0xA8) +#define MCP_STAT_TX0IF (0x08) +#define MCP_STAT_TX1IF (0x20) +#define MCP_STAT_TX2IF (0x80) +#define MCP_STAT_RXIF_MASK (0x03) +#define MCP_STAT_RX0IF (1<<0) +#define MCP_STAT_RX1IF (1<<1) + +#define MCP_EFLG_RX1OVR (1<<7) +#define MCP_EFLG_RX0OVR (1<<6) +#define MCP_EFLG_TXBO (1<<5) +#define MCP_EFLG_TXEP (1<<4) +#define MCP_EFLG_RXEP (1<<3) +#define MCP_EFLG_TXWAR (1<<2) +#define MCP_EFLG_RXWAR (1<<1) +#define MCP_EFLG_EWARN (1<<0) +#define MCP_EFLG_ERRORMASK (0xF8) // 5 MS-Bits + +// Define MCP2515 register addresses + +#define MCP_RXF0SIDH 0x00 +#define MCP_RXF0SIDL 0x01 +#define MCP_RXF0EID8 0x02 +#define MCP_RXF0EID0 0x03 +#define MCP_RXF1SIDH 0x04 +#define MCP_RXF1SIDL 0x05 +#define MCP_RXF1EID8 0x06 +#define MCP_RXF1EID0 0x07 +#define MCP_RXF2SIDH 0x08 +#define MCP_RXF2SIDL 0x09 +#define MCP_RXF2EID8 0x0A +#define MCP_RXF2EID0 0x0B +#define MCP_BFPCTRL 0x0C +#define MCP_TXRTSCTRL 0x0D +#define MCP_CANSTAT 0x0E +#define MCP_CANCTRL 0x0F +#define MCP_RXF3SIDH 0x10 +#define MCP_RXF3SIDL 0x11 +#define MCP_RXF3EID8 0x12 +#define MCP_RXF3EID0 0x13 +#define MCP_RXF4SIDH 0x14 +#define MCP_RXF4SIDL 0x15 +#define MCP_RXF4EID8 0x16 +#define MCP_RXF4EID0 0x17 +#define MCP_RXF5SIDH 0x18 +#define MCP_RXF5SIDL 0x19 +#define MCP_RXF5EID8 0x1A +#define MCP_RXF5EID0 0x1B +#define MCP_TEC 0x1C +#define MCP_REC 0x1D +#define MCP_RXM0SIDH 0x20 +#define MCP_RXM0SIDL 0x21 +#define MCP_RXM0EID8 0x22 +#define MCP_RXM0EID0 0x23 +#define MCP_RXM1SIDH 0x24 +#define MCP_RXM1SIDL 0x25 +#define MCP_RXM1EID8 0x26 +#define MCP_RXM1EID0 0x27 +#define MCP_CNF3 0x28 +#define MCP_CNF2 0x29 +#define MCP_CNF1 0x2A +#define MCP_CANINTE 0x2B +#define MCP_CANINTF 0x2C +#define MCP_EFLG 0x2D +#define MCP_TXB0CTRL 0x30 +#define MCP_TXB0SIDH 0x31 +#define MCP_TXB1CTRL 0x40 +#define MCP_TXB1SIDH 0x41 +#define MCP_TXB2CTRL 0x50 +#define MCP_TXB2SIDH 0x51 +#define MCP_RXB0CTRL 0x60 +#define MCP_RXB0SIDH 0x61 +#define MCP_RXB1CTRL 0x70 +#define MCP_RXB1SIDH 0x71 + +#define MCP_TX_INT 0x1C // Enable all transmit interrup ts +#define MCP_TX01_INT 0x0C // Enable TXB0 and TXB1 interru pts +#define MCP_RX_INT 0x03 // Enable receive interrupts +#define MCP_NO_INT 0x00 // Disable all interrupts + +#define MCP_TX01_MASK 0x14 +#define MCP_TX_MASK 0x54 + + +// Define SPI Instruction Set + +#define MCP_WRITE 0x02 +#define MCP_READ 0x03 +#define MCP_BITMOD 0x05 +#define MCP_LOAD_TX0 0x40 +#define MCP_LOAD_TX1 0x42 +#define MCP_LOAD_TX2 0x44 + +#define MCP_RTS_TX0 0x81 +#define MCP_RTS_TX1 0x82 +#define MCP_RTS_TX2 0x84 +#define MCP_RTS_ALL 0x87 +#define MCP_READ_RX0 0x90 +#define MCP_READ_RX1 0x94 +#define MCP_READ_STATUS 0xA0 +#define MCP_RX_STATUS 0xB0 +#define MCP_RESET 0xC0 + + +// CANCTRL Register Values + +#define MODE_NORMAL 0x00 +#define MODE_SLEEP 0x20 +#define MODE_LOOPBACK 0x40 +#define MODE_LISTENONLY 0x60 +#define MODE_CONFIG 0x80 +#define MODE_POWERUP 0xE0 +#define MODE_MASK 0xE0 +#define ABORT_TX 0x10 +#define MODE_ONESHOT 0x08 +#define CLKOUT_ENABLE 0x04 +#define CLKOUT_DISABLE 0x00 +#define CLKOUT_PS1 0x00 +#define CLKOUT_PS2 0x01 +#define CLKOUT_PS4 0x02 +#define CLKOUT_PS8 0x03 + + +// CNF1 Register Values + +#define SJW1 0x00 +#define SJW2 0x40 +#define SJW3 0x80 +#define SJW4 0xC0 + + +// CNF2 Register Values + +#define BTLMODE 0x80 +#define SAMPLE_1X 0x00 +#define SAMPLE_3X 0x40 + + +// CNF3 Register Values + +#define SOF_ENABLE 0x80 +#define SOF_DISABLE 0x00 +#define WAKFIL_ENABLE 0x40 +#define WAKFIL_DISABLE 0x00 + + +// CANINTF Register Bits + +#define MCP_RX0IF 0x01 +#define MCP_RX1IF 0x02 +#define MCP_TX0IF 0x04 +#define MCP_TX1IF 0x08 +#define MCP_TX2IF 0x10 +#define MCP_ERRIF 0x20 +#define MCP_WAKIF 0x40 +#define MCP_MERRF 0x80 + +// BFPCTRL Register Bits + +#define B1BFS 0x20 +#define B0BFS 0x10 +#define B1BFE 0x08 +#define B0BFE 0x04 +#define B1BFM 0x02 +#define B0BFM 0x01 + +// TXRTCTRL Register Bits + +#define B2RTS 0x20 +#define B1RTS 0x10 +#define B0RTS 0x08 +#define B2RTSM 0x04 +#define B1RTSM 0x02 +#define B0RTSM 0x01 + +// clock + +#define MCP_16MHz 1 +#define MCP_8MHz 2 + +// speed 16M + +#define MCP_16MHz_1000kBPS_CFG1 (0x00) +#define MCP_16MHz_1000kBPS_CFG2 (0xD0) +#define MCP_16MHz_1000kBPS_CFG3 (0x82) + +#define MCP_16MHz_500kBPS_CFG1 (0x00) +#define MCP_16MHz_500kBPS_CFG2 (0xF0) +#define MCP_16MHz_500kBPS_CFG3 (0x86) + +#define MCP_16MHz_250kBPS_CFG1 (0x41) +#define MCP_16MHz_250kBPS_CFG2 (0xF1) +#define MCP_16MHz_250kBPS_CFG3 (0x85) + +#define MCP_16MHz_200kBPS_CFG1 (0x01) +#define MCP_16MHz_200kBPS_CFG2 (0xFA) +#define MCP_16MHz_200kBPS_CFG3 (0x87) + +#define MCP_16MHz_125kBPS_CFG1 (0x03) +#define MCP_16MHz_125kBPS_CFG2 (0xF0) +#define MCP_16MHz_125kBPS_CFG3 (0x86) + +#define MCP_16MHz_100kBPS_CFG1 (0x03) +#define MCP_16MHz_100kBPS_CFG2 (0xFA) +#define MCP_16MHz_100kBPS_CFG3 (0x87) + +#define MCP_16MHz_95kBPS_CFG1 (0x03) +#define MCP_16MHz_95kBPS_CFG2 (0xAD) +#define MCP_16MHz_95kBPS_CFG3 (0x07) + +#define MCP_16MHz_83k3BPS_CFG1 (0x03) +#define MCP_16MHz_83k3BPS_CFG2 (0xBE) +#define MCP_16MHz_83k3BPS_CFG3 (0x07) + +#define MCP_16MHz_80kBPS_CFG1 (0x03) +#define MCP_16MHz_80kBPS_CFG2 (0xFF) +#define MCP_16MHz_80kBPS_CFG3 (0x87) + +#define MCP_16MHz_50kBPS_CFG1 (0x07) +#define MCP_16MHz_50kBPS_CFG2 (0xFA) +#define MCP_16MHz_50kBPS_CFG3 (0x87) + +#define MCP_16MHz_40kBPS_CFG1 (0x07) +#define MCP_16MHz_40kBPS_CFG2 (0xFF) +#define MCP_16MHz_40kBPS_CFG3 (0x87) + +#define MCP_16MHz_33kBPS_CFG1 (0x09) +#define MCP_16MHz_33kBPS_CFG2 (0xBE) +#define MCP_16MHz_33kBPS_CFG3 (0x07) + +#define MCP_16MHz_31k25BPS_CFG1 (0x0F) +#define MCP_16MHz_31k25BPS_CFG2 (0xF1) +#define MCP_16MHz_31k25BPS_CFG3 (0x85) + +#define MCP_16MHz_25kBPS_CFG1 (0X0F) +#define MCP_16MHz_25kBPS_CFG2 (0XBA) +#define MCP_16MHz_25kBPS_CFG3 (0X07) + +#define MCP_16MHz_20kBPS_CFG1 (0x0F) +#define MCP_16MHz_20kBPS_CFG2 (0xFF) +#define MCP_16MHz_20kBPS_CFG3 (0x87) + +#define MCP_16MHz_10kBPS_CFG1 (0x1F) +#define MCP_16MHz_10kBPS_CFG2 (0xFF) +#define MCP_16MHz_10kBPS_CFG3 (0x87) + +#define MCP_16MHz_5kBPS_CFG1 (0x3F) +#define MCP_16MHz_5kBPS_CFG2 (0xFF) +#define MCP_16MHz_5kBPS_CFG3 (0x87) + +#define MCP_16MHz_666kBPS_CFG1 (0x00) +#define MCP_16MHz_666kBPS_CFG2 (0xA0) +#define MCP_16MHz_666kBPS_CFG3 (0x04) + + +// speed 8M + +#define MCP_8MHz_1000kBPS_CFG1 (0x00) +#define MCP_8MHz_1000kBPS_CFG2 (0x80) +#define MCP_8MHz_1000kBPS_CFG3 (0x00) + +#define MCP_8MHz_500kBPS_CFG1 (0x00) +#define MCP_8MHz_500kBPS_CFG2 (0x90) +#define MCP_8MHz_500kBPS_CFG3 (0x02) + +#define MCP_8MHz_250kBPS_CFG1 (0x00) +#define MCP_8MHz_250kBPS_CFG2 (0xb1) +#define MCP_8MHz_250kBPS_CFG3 (0x05) + +#define MCP_8MHz_200kBPS_CFG1 (0x00) +#define MCP_8MHz_200kBPS_CFG2 (0xb4) +#define MCP_8MHz_200kBPS_CFG3 (0x06) + +#define MCP_8MHz_125kBPS_CFG1 (0x01) +#define MCP_8MHz_125kBPS_CFG2 (0xb1) +#define MCP_8MHz_125kBPS_CFG3 (0x05) + +#define MCP_8MHz_100kBPS_CFG1 (0x01) +#define MCP_8MHz_100kBPS_CFG2 (0xb4) +#define MCP_8MHz_100kBPS_CFG3 (0x06) + +#define MCP_8MHz_80kBPS_CFG1 (0x01) +#define MCP_8MHz_80kBPS_CFG2 (0xbf) +#define MCP_8MHz_80kBPS_CFG3 (0x07) + +#define MCP_8MHz_50kBPS_CFG1 (0x03) +#define MCP_8MHz_50kBPS_CFG2 (0xb4) +#define MCP_8MHz_50kBPS_CFG3 (0x06) + +#define MCP_8MHz_40kBPS_CFG1 (0x03) +#define MCP_8MHz_40kBPS_CFG2 (0xbf) +#define MCP_8MHz_40kBPS_CFG3 (0x07) + +#define MCP_8MHz_31k25BPS_CFG1 (0x07) +#define MCP_8MHz_31k25BPS_CFG2 (0xa4) +#define MCP_8MHz_31k25BPS_CFG3 (0x04) + +#define MCP_8MHz_20kBPS_CFG1 (0x07) +#define MCP_8MHz_20kBPS_CFG2 (0xbf) +#define MCP_8MHz_20kBPS_CFG3 (0x07) + +#define MCP_8MHz_10kBPS_CFG1 (0x0f) +#define MCP_8MHz_10kBPS_CFG2 (0xbf) +#define MCP_8MHz_10kBPS_CFG3 (0x07) + +#define MCP_8MHz_5kBPS_CFG1 (0x1f) +#define MCP_8MHz_5kBPS_CFG2 (0xbf) +#define MCP_8MHz_5kBPS_CFG3 (0x07) + +#define MCPDEBUG (0) +#define MCPDEBUG_TXBUF (0) +#define MCP_N_TXBUFFERS (3) + +#define MCP_RXBUF_0 (MCP_RXB0SIDH) +#define MCP_RXBUF_1 (MCP_RXB1SIDH) + +#define MCP2515_SELECT() digitalWrite(SPICS, LOW) +#define MCP2515_UNSELECT() digitalWrite(SPICS, HIGH) + +#define MCP2515_OK (0) +#define MCP2515_FAIL (1) +#define MCP_ALLTXBUSY (2) + +#define CANDEBUG 1 + +#define CANUSELOOP 0 + +#define CANSENDTIMEOUT (200) // milliseconds + +#define MCP_PIN_HIZ (0) +#define MCP_PIN_INT (1) +#define MCP_PIN_OUT (2) +#define MCP_PIN_IN (3) + +#define MCP_RX0BF (0) +#define MCP_RX1BF (1) +#define MCP_TX0RTS (2) +#define MCP_TX1RTS (3) +#define MCP_TX2RTS (4) + + +// initial value of gCANAutoProcess + +#define CANAUTOPROCESS (1) +#define CANAUTOON (1) +#define CANAUTOOFF (0) +#define CAN_STDID (0) +#define CAN_EXTID (1) +#define CANDEFAULTIDENT (0x55CC) +#define CANDEFAULTIDENTEXT (CAN_EXTID) + +#define CAN_5KBPS 1 +#define CAN_10KBPS 2 +#define CAN_20KBPS 3 +#define CAN_25KBPS 4 +#define CAN_31K25BPS 5 +#define CAN_33KBPS 6 +#define CAN_40KBPS 7 +#define CAN_50KBPS 8 +#define CAN_80KBPS 9 +#define CAN_83K3BPS 10 +#define CAN_95KBPS 11 +#define CAN_100KBPS 12 +#define CAN_125KBPS 13 +#define CAN_200KBPS 14 +#define CAN_250KBPS 15 +#define CAN_500KBPS 16 +#define CAN_666KBPS 17 +#define CAN_1000KBPS 18 + +#define CAN_OK (0) +#define CAN_FAILINIT (1) +#define CAN_FAILTX (2) +#define CAN_MSGAVAIL (3) +#define CAN_NOMSG (4) +#define CAN_CTRLERROR (5) +#define CAN_GETTXBFTIMEOUT (6) +#define CAN_SENDMSGTIMEOUT (7) +#define CAN_FAIL (0xff) + +#define CAN_MAX_CHAR_IN_MESSAGE (8) + +#endif +/********************************************************************************************************* + END FILE +*********************************************************************************************************/