Add sleep and gpio support + examples

Added sleep support for MCP2515 + MCP2551. This way, you can reduce the power consumption of a complete node down to around 240uA!
Changes:
- Reintroduced gpio support from commits 43521de/bac66d1 (adlerweb, 15/01/2018) and corrected the errors
- Introduced advanced sleep support based on https://github.com/coryjfowler/MCP_CAN_lib/pull/10/files
- added example code (receive_sleep and send_sleep)
- tested everything
This commit is contained in:
kaixxx
2019-01-07 15:37:30 +01:00
parent 962660f3e8
commit 19203a365d
8 changed files with 731 additions and 23 deletions
+9
View File
@@ -142,6 +142,15 @@ When frame is received you may check whether it was remote request and whether i
**return value** is '0' for a negative response and '1' for a positive
### 8. Sleep Mode
By setting the MCU, the CAN controller (MCP2515) and the transceiver (MCP2551) into sleep mode, you can reduce the power consumption of the whole setup from around 50mA down to 240uA (Arduino directly connected to 5V, regulator and power LED removed). The node will wake up when a new message arrives, process the message and go back to sleep afterwards.
Look at the examples "receive_sleep" and "send_sleep" for more info.
In order to set the MCP2551 CAN transceiver on the shield into sleep/standby mode, a small hardware modification is necessary. The Rs pin of the transceiver must either be connected to pin RX0BF of the MCP2515 or to a free output of the Arduino, both via the resistor R1 (17k). Cut the connection to ground after R1 and solder in a wire to one of the pins. Note however that from now on, you have to pull this pin low in software before using the transceiver. Pulling the pin high will set the transceiver into standby mode.
Without this modification, the transceiver will stay awake and the power consumption in sleep mode will be around 8mA - still a significant improvement!
<br>
+2 -2
View File
@@ -19,7 +19,7 @@ void setup()
}
Serial.println("CAN init ok");
if(CAN.pinMode(MCP_TX2RTS, MCP_PIN_IN))
if(CAN.mcpPinMode(MCP_TX2RTS, MCP_PIN_IN))
{
Serial.println("TX2RTS is now an input");
}
@@ -32,7 +32,7 @@ void setup()
void loop()
{
Serial.print("TX2RTS is currently ");
Serial.println(CAN.digitalRead(MCP_TX2RTS));
Serial.println(CAN.mcpDigitalRead(MCP_TX2RTS));
delay(500);
}
+6 -6
View File
@@ -19,7 +19,7 @@ void setup()
}
Serial.println("CAN init ok");
if(CAN.pinMode(MCP_RX0BF, MCP_PIN_OUT))
if(CAN.mcpPinMode(MCP_RX0BF, MCP_PIN_OUT))
{
Serial.println("RX0BF is now an output");
}
@@ -28,7 +28,7 @@ void setup()
Serial.println("Could not switch RX0BF");
}
if(CAN.pinMode(MCP_RX1BF, MCP_PIN_OUT))
if(CAN.mcpPinMode(MCP_RX1BF, MCP_PIN_OUT))
{
Serial.println("RX1BF is now an output");
}
@@ -41,12 +41,12 @@ void setup()
void loop()
{
Serial.println("10");
CAN.digitalWrite(MCP_RX0BF, HIGH);
CAN.digitalWrite(MCP_RX1BF, LOW);
CAN.mcpDigitalWrite(MCP_RX0BF, HIGH);
CAN.mcpDigitalWrite(MCP_RX1BF, LOW);
delay(500);
Serial.println("01");
CAN.digitalWrite(MCP_RX0BF, LOW);
CAN.digitalWrite(MCP_RX1BF, HIGH);
CAN.mcpDigitalWrite(MCP_RX0BF, LOW);
CAN.mcpDigitalWrite(MCP_RX1BF, HIGH);
delay(500);
}
+158
View File
@@ -0,0 +1,158 @@
// demo: CAN Sleep Example - receive
// by Kai, based on the receive_interrupt example by loovee and the additions from Zak Kemble (https://github.com/coryjfowler/MCP_CAN_lib/pull/10/files)
//
// By setting the MCU, the CAN controller (MCP2515) and the transceiver (MCP2551) into sleep mode, you can reduce
// the power consumption of the whole setup from around 50mA down to 240uA (Arduino directly connected to 5V, regulator and
// power LED removed). The node will wake up when a new message arrives, process the message and go back to sleep
// afterwards.
//
// Known issues:
// - Because it takes some time for the controller to wake up, the first message is usually lost. Look at the
// send_sleep example on how to avoid this by sending a special wakeup message before the normal message.
// - If you only have 2 devices on the CAN bus (the device running this sketch and some other device sending
// messages), you may find that duplicate messages are received when waking up. This is because when
// the MCP2515 wakes up it enters LISTENONLY mode where it does not send ACKs to messages, so the transmitter
// will retransmit the same message a few times. See below for a simple solution to filter duplicate messages out.
#include <SPI.h>
#include "mcp_can.h"
#include <avr/sleep.h>
// the cs pin of the version after v1.1 is default to D9
// v0.9b and v1.0 is default D10
const int SPI_CS_PIN = 9;
#define CAN_INT 2 // Set INT to pin 2
// To use the sleep mode of the transceiver (MCP2551), it's Rs pin must be connected to either the MCP2515 or
// any free Arduino output.
#define RS_TO_MCP2515 true // Set this to false if Rs is connected to your Arduino
#define RS_OUTPUT MCP_RX0BF // RX0BF is a pin of the MCP2515. You can also define an Arduino pin here
MCP_CAN CAN(SPI_CS_PIN); // Set CS pin
#define KEEP_AWAKE_TIME 200 // time the controller will stay awake after the last activity on the bus (in ms)
unsigned long lastBusActivity = millis();
unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[8];
int lastLen = -1;
unsigned char lastBuf[8]; // used for duplicate message check below
unsigned long lastMsgTime = 0;
#define DUPLICATE_TIMEOUT 20
char str[20];
void setup()
{
Serial.begin(115200);
while (CAN_OK != CAN.begin(CAN_500KBPS, MCP_16MHz)) // init can bus : baudrate = 500k
{
Serial.println("CAN BUS Shield init fail");
Serial.println(" Init CAN BUS Shield again");
delay(100);
}
Serial.println("CAN BUS Shield init ok!");
// attach interrupt
pinMode(CAN_INT, INPUT);
attachInterrupt(digitalPinToInterrupt(CAN_INT), MCP2515_ISR, FALLING);
CAN.setSleepWakeup(1); // this tells the MCP2515 to wake up on incoming messages
// Pull the Rs pin of the MCP2551 transceiver low to enable it:
if(RS_TO_MCP2515)
{
CAN.mcpPinMode(MCP_RX0BF, MCP_PIN_OUT);
CAN.mcpDigitalWrite(RS_OUTPUT, LOW);
} else {
pinMode(RS_OUTPUT, OUTPUT);
digitalWrite(RS_OUTPUT, LOW);
}
}
void MCP2515_ISR()
{
flagRecv = 1;
}
void loop()
{
if(flagRecv)
{ // check if get data
flagRecv = 0; // clear flag
lastBusActivity = millis();
// iterate over all pending messages
// If either the bus is saturated or the MCU is busy,
// both RX buffers may be in use and reading a single
// message does not clear the IRQ conditon.
while (CAN_MSGAVAIL == CAN.checkReceive())
{
// read data, len: data length, buf: data buf
CAN.readMsgBuf(&len, buf);
// check if this is a duplicate message (including a timeout, so that the same message is accepted again after a while)
if((len != lastLen) || (millis() > lastMsgTime + DUPLICATE_TIMEOUT) || (memcmp((const void *)lastBuf, (const void *)buf, sizeof(buf)) != 0))
{
lastLen = len;
memcpy(lastBuf, buf, sizeof(buf));
lastMsgTime = millis();
// print the data
for(int i = 0; i<len; i++)
{
Serial.print(buf[i]);Serial.print("\t");
}
Serial.println();
}
}
} else if(millis() > lastBusActivity + KEEP_AWAKE_TIME)
{
// Put MCP2515 into sleep mode
Serial.println(F("CAN sleep"));
CAN.sleep();
// Put the transceiver into standby (by pulling Rs high):
if(RS_TO_MCP2515)
CAN.mcpDigitalWrite(RS_OUTPUT, HIGH);
else
digitalWrite(RS_OUTPUT, HIGH);
// Put the MCU to sleep
Serial.println(F("MCU sleep"));
// Clear serial buffers before sleeping
Serial.flush();
cli(); // Disable interrupts
if(!flagRecv) // Make sure we havn't missed an interrupt between the check above and now. If an interrupt happens between now and sei()/sleep_cpu() then sleep_cpu() will immediately wake up again
{
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_bod_disable();
sei();
sleep_cpu();
// Now the Arduino sleeps until the next message arrives...
sleep_disable();
}
sei();
CAN.wake(); // When the MCP2515 wakes up it will be in LISTENONLY mode, here we put it into the mode it was before sleeping
// Wake up the transceiver:
if(RS_TO_MCP2515)
CAN.mcpDigitalWrite(RS_OUTPUT, LOW);
else
digitalWrite(RS_OUTPUT, LOW);
Serial.println(F("Woke up"));
}
}
/*********************************************************************************************************
END FILE
*********************************************************************************************************/
+136
View File
@@ -0,0 +1,136 @@
// demo: CAN Sleep Example - send
// by Kai, based on the send example by loovee and the additions from Zak Kemble (https://github.com/coryjfowler/MCP_CAN_lib/pull/10/files)
//
// See receive_sleep example for additional notes.
#include <mcp_can.h>
#include <SPI.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
// the cs pin of the version after v1.1 is default to D9
// v0.9b and v1.0 is default D10
const int SPI_CS_PIN = 9;
// To use the sleep mode of the transceiver (MCP2551), it's Rs pin must be connected to either the MCP2515 or
// any free Arduino output.
#define RS_TO_MCP2515 true // Set this to false if Rs is connected to your Arduino
#define RS_OUTPUT MCP_RX0BF // RX0BF is a pin of the MCP2515. You can also define an Arduino pin here
MCP_CAN CAN(SPI_CS_PIN); // Set CS pin
// Watchdog interrupt, used to wake the MCU periodically.
ISR (WDT_vect)
{
wdt_disable(); // disable watchdog
}
void sleepMCU()
// Sleep the MCU for one second.
// See http://www.gammon.com.au/power for details.
// (You can make your life a lot easyer by using one of the numeral low power libraries for Arduino.)
{
// disable ADC
ADCSRA = 0;
// clear various "reset" flags
MCUSR = 0;
// allow changes, disable reset
WDTCSR = bit (WDCE) | bit (WDE);
// set interrupt mode and an interval
WDTCSR = bit (WDIE) | bit (WDP2) | bit (WDP1); // set WDIE, and 1 second delay
wdt_reset(); // pat the dog
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
noInterrupts (); // timed sequence follows
sleep_enable();
// turn off brown-out enable in software
MCUCR = bit (BODS) | bit (BODSE);
MCUCR = bit (BODS);
interrupts (); // guarantees next instruction executed
sleep_cpu ();
// cancel sleep as a precaution
sleep_disable();
}
void setup()
{
Serial.begin(115200);
while (CAN_OK != CAN.begin(CAN_500KBPS, MCP_16MHz)) // init can bus : baudrate = 500k
{
Serial.println("CAN BUS Shield init fail");
Serial.println(" Init CAN BUS Shield again");
delay(100);
}
Serial.println("CAN BUS Shield init ok!");
CAN.setSleepWakeup(0); // the MCP2515 will NOT wake up on incoming messages,
// making it a 'send only' node
// Pull the Rs pin of the MCP2551 transceiver low to enable it:
if(RS_TO_MCP2515)
{
CAN.mcpPinMode(MCP_RX0BF, MCP_PIN_OUT);
CAN.mcpDigitalWrite(RS_OUTPUT, LOW);
} else {
pinMode(RS_OUTPUT, OUTPUT);
digitalWrite(RS_OUTPUT, LOW);
}
}
unsigned char stmp[8] = {0, 0, 0, 0, 0, 0, 0, 0};
void loop()
{
Serial.println("Sending message");
CAN.sendMsgBuf(0x00, 0, 0, NULL); // Send empty wakeup message
delay(100); // give the receiving node some time to wake up
// send data: id = 0x00, standard frame, data len = 8, stmp: data buf
stmp[7] = stmp[7]+1;
if(stmp[7] == 100)
{
stmp[7] = 0;
stmp[6] = stmp[6] + 1;
if(stmp[6] == 100)
{
stmp[6] = 0;
stmp[5] = stmp[6] + 1;
}
}
CAN.sendMsgBuf(0x00, 0, 8, stmp);
// sleep
Serial.println("Sleep");
Serial.flush();
// Put MCP2515 into sleep mode
CAN.sleep();
// Put the transceiver into standby (by pulling Rs high):
if(RS_TO_MCP2515)
CAN.mcpDigitalWrite(RS_OUTPUT, HIGH);
else
digitalWrite(RS_OUTPUT, HIGH);
// Put the MCU to sleep for one second
sleepMCU();
// wake MCP2515 and transceiver
CAN.wake();
if(RS_TO_MCP2515)
CAN.mcpDigitalWrite(RS_OUTPUT, LOW);
else
digitalWrite(RS_OUTPUT, LOW);
}
// END FILE
+377 -14
View File
@@ -298,25 +298,120 @@ byte MCP_CAN::mcp2515_readStatus(void)
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 MCP_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 MCP_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 MCP_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 MCP_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 MCP_CAN::getMode()
{
return mcp2515_readRegister(MCP_CANSTAT) & MODE_MASK;
}
/*********************************************************************************************************
** Function name: mcp2515_setCANCTRL_Mode
** Descriptions: set control mode
*********************************************************************************************************/
byte MCP_CAN::mcp2515_setCANCTRL_Mode(const byte newmode)
{
byte i;
// 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);
mcp2515_modifyRegister(MCP_CANCTRL, MODE_MASK, newmode);
// Set wake flag (this does the actual waking up)
mcp2515_modifyRegister(MCP_CANINTF, MCP_WAKIF, MCP_WAKIF);
i = mcp2515_readRegister(MCP_CANCTRL);
i &= MODE_MASK;
// Wait for the chip to exit SLEEP and enter LISTENONLY mode.
if ( i == newmode )
{
return MCP2515_OK;
}
// 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.
return MCP2515_FAIL;
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 MCP_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;
}
}
/*********************************************************************************************************
@@ -640,7 +735,7 @@ byte MCP_CAN::mcp2515_init(const byte canSpeed, const byte clock)
MCP_RXB_RX_STDEXT);
#endif
// enter normal mode
res = mcp2515_setCANCTRL_Mode(MODE_NORMAL);
res = setMode(MODE_NORMAL);
if (res)
{
#if DEBUG_EN
@@ -867,7 +962,7 @@ MCP_CAN::MCP_CAN(byte _CS) : nReservedTx(0)
}
/*********************************************************************************************************
** Function name: set CS
** Function name: init_CS
** Descriptions: init CS pin and set UNSELECTED
*********************************************************************************************************/
void MCP_CAN::init_CS(byte _CS)
@@ -886,7 +981,8 @@ byte MCP_CAN::begin(byte speedset, const byte clockset)
{
pSPI->begin();
byte res = mcp2515_init(speedset, clockset);
return ((res == MCP2515_OK) ? CAN_OK : CAN_FAILINIT);
return ((res == MCP2515_OK) ? CAN_OK : CAN_FAILINIT);
}
/*********************************************************************************************************
@@ -937,7 +1033,7 @@ byte MCP_CAN::init_Mask(byte num, byte ext, unsigned long ulData)
}
else res = MCP2515_FAIL;
res = mcp2515_setCANCTRL_Mode(MODE_NORMAL);
res = mcp2515_setCANCTRL_Mode(mcpMode);
if (res > 0) {
#if DEBUG_EN
Serial.print("Enter normal mode fall\r\n");
@@ -1007,7 +1103,7 @@ byte MCP_CAN::init_Filt(byte num, byte ext, unsigned long ulData)
res = MCP2515_FAIL;
}
res = mcp2515_setCANCTRL_Mode(MODE_NORMAL);
res = mcp2515_setCANCTRL_Mode(mcpMode);
if (res > 0)
{
#if DEBUG_EN
@@ -1297,6 +1393,273 @@ byte MCP_CAN::isExtendedFrame(void)
return ext_flg;
}
/*********************************************************************************************************
** Function name: mcpPinMode
** Descriptions: switch supported pins between HiZ, interrupt, output or input
*********************************************************************************************************/
bool MCP_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 MCP_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 MCP_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
*********************************************************************************************************/
+12 -1
View File
@@ -62,6 +62,7 @@ class MCP_CAN
byte SPICS;
SPIClass *pSPI;
byte nReservedTx; // Count of tx buffers for reserved send
byte mcpMode; // Current controller mode
/*
* mcp2515 driver function
@@ -91,6 +92,7 @@ private:
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
@@ -125,7 +127,12 @@ public:
byte begin(byte speedset, const byte clockset = MCP_16MHz); // init can
byte init_Mask(byte num, byte ext, unsigned long ulData); // init Masks
byte init_Filt(byte num, byte ext, unsigned long ulData); // init filters
byte sendMsgBuf(unsigned long id, byte ext, byte rtrBit, byte len, const byte *buf, bool wait_sent=true); // send buf
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)
byte sleep(); // Put the MCP2515 in sleep mode
byte wake(); // Wake MCP2515 manually from sleep
byte setMode(byte opMode); // Set operational mode
byte getMode(); // Get operational mode
byte sendMsgBuf(unsigned long id, byte ext, byte rtrBit, byte len, const byte *buf, bool wait_sent=true); // send buf
byte sendMsgBuf(unsigned long id, byte ext, byte len, const byte *buf, bool wait_sent=true); // send buf
byte readMsgBuf(byte *len, byte *buf); // read buf
byte readMsgBufID(unsigned long *ID, byte *len, byte *buf); // read buf with object ID
@@ -148,6 +155,10 @@ public:
byte readRxTxStatus(void); // read has something send or received
byte checkClearRxStatus(byte *status); // read and clear and return first found rx status bit
byte checkClearTxStatus(byte *status, byte iTxBuf=0xff); // read and clear and return first found or buffer specified tx status bit
bool mcpPinMode(const byte pin, const byte mode); // switch supported pins between HiZ, interrupt, output or input
bool mcpDigitalWrite(const byte pin, const byte mode); // write HIGH or LOW to RX0BF/RX1BF
byte mcpDigitalRead(const byte pin); // read HIGH or LOW from supported pins
};
+31
View File
@@ -126,6 +126,8 @@
#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
@@ -249,6 +251,24 @@
#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
@@ -403,6 +423,17 @@
#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