Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow setting MCP2515 mask and filter registers directly, as well as control rollover #47

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,18 @@ if ((packetId & mask) == id) {

Returns `1` on success, `0` on failure.

The MCP2515 implementation also supports setting mask/filter registers directly
for more advanced usage:

```
CAN.setFilterRegisters(
mask0, filter0, filter1,
mask1, filter2, filter3, filter4, filter5,
allowRollover);
```

Please see the MCP2515 data sheet for more details on how these work.

## Other modes

### Loopback mode
Expand Down
67 changes: 63 additions & 4 deletions src/MCP2515.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@
#define FLAG_RXnIF(n) (0x01 << n)
#define FLAG_TXnIF(n) (0x04 << n)

#define REG_RXFnSIDH(n) (0x00 + (n * 4))
#define REG_RXFnSIDL(n) (0x01 + (n * 4))
#define REG_RXFnEID8(n) (0x02 + (n * 4))
#define REG_RXFnEID0(n) (0x03 + (n * 4))
// There is a 4-register gap between RXF2EID0 and RXF3SIDH.
#define REG_RXFnSIDH(n) (0x00 + ((n + (n >= 3)) * 4))
#define REG_RXFnSIDL(n) (0x01 + ((n + (n >= 3)) * 4))
#define REG_RXFnEID8(n) (0x02 + ((n + (n >= 3)) * 4))
#define REG_RXFnEID0(n) (0x03 + ((n + (n >= 3)) * 4))

#define REG_RXMnSIDH(n) (0x20 + (n * 0x04))
#define REG_RXMnSIDL(n) (0x21 + (n * 0x04))
Expand All @@ -51,6 +52,7 @@
#define FLAG_SRR 0x10
#define FLAG_RTR 0x40
#define FLAG_EXIDE 0x08
#define FLAG_RXB0CTRL_BUKT 0x04

#define FLAG_RXM0 0x20
#define FLAG_RXM1 0x40
Expand Down Expand Up @@ -288,6 +290,10 @@ int MCP2515Class::filter(int id, int mask)

for (int n = 0; n < 2; n++) {
// standard only
// TODO: This doesn't look correct. According to the datasheet, the RXM0 and
// RMX1 should either both be unset (in which case filters are active), or
// both be unset (in which case all filters are ignored).
Comment on lines +293 to +295

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to be a hangover from the MCP2510 which is no longer (officially) supported by the MCP2515. See https://i.imgur.com/QmthNtj.png vs https://i.imgur.com/sGE2jpq.png

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for finding this!
I suspect it's just a typo and the intention was to use FLAG_RXM1 on L292 (old).
But at the same time I don't want to change code that I don't fully understand, and didn't spend enough time testing. The PR as-is is already an improvement, and hopefully with the TODO someone else (or future me) will be curious to figure out how to fix it.

// Either way, it's unclear why we write to the same register twice here.
writeRegister(REG_RXBnCTRL(n), FLAG_RXM0);
writeRegister(REG_RXBnCTRL(n), FLAG_RXM0);

Expand All @@ -313,6 +319,55 @@ int MCP2515Class::filter(int id, int mask)
return 1;
}

boolean MCP2515Class::setFilterRegisters(
uint16_t mask0, uint16_t filter0, uint16_t filter1,
uint16_t mask1, uint16_t filter2, uint16_t filter3, uint16_t filter4, uint16_t filter5,
bool allowRollover)
{
mask0 &= 0x7ff;
filter0 &= 0x7ff;
filter1 &= 0x7ff;
mask1 &= 0x7ff;
filter2 &= 0x7ff;
filter3 &= 0x7ff;
filter4 &= 0x7ff;
filter5 &= 0x7ff;

// config mode
writeRegister(REG_CANCTRL, 0x80);
if (readRegister(REG_CANCTRL) != 0x80) {
return false;
}

writeRegister(REG_RXBnCTRL(0), allowRollover ? FLAG_RXB0CTRL_BUKT : 0);
writeRegister(REG_RXBnCTRL(1), 0);
for (int n = 0; n < 2; n++) {
uint8_t mask = (n == 0) ? mask0 : mask1;
writeRegister(REG_RXMnSIDH(n), mask >> 3);
writeRegister(REG_RXMnSIDL(n), mask << 5);
writeRegister(REG_RXMnEID8(n), 0);
writeRegister(REG_RXMnEID0(n), 0);
}

uint8_t filter_array[6] =
{filter0, filter1, filter2, filter3, filter4, filter5};
for (int n = 0; n < 6; n++) {
uint8_t id = filter_array[n];
writeRegister(REG_RXFnSIDH(n), id >> 3);
writeRegister(REG_RXFnSIDL(n), id << 5);
writeRegister(REG_RXFnEID8(n), 0);
writeRegister(REG_RXFnEID0(n), 0);
}

// normal mode
writeRegister(REG_CANCTRL, 0x00);
if (readRegister(REG_CANCTRL) != 0x00) {
return false;
}

return true;
}

int MCP2515Class::filterExtended(long id, long mask)
{
id &= 0x1FFFFFFF;
Expand All @@ -326,6 +381,10 @@ int MCP2515Class::filterExtended(long id, long mask)

for (int n = 0; n < 2; n++) {
// extended only
// TODO: This doesn't look correct. According to the datasheet, the RXM0 and
// RMX1 should either both be unset (in which case filters are active), or
// both be unset (in which case all filters are ignored).
// Either way, it's unclear why we write to the same register twice here.
writeRegister(REG_RXBnCTRL(n), FLAG_RXM1);
writeRegister(REG_RXBnCTRL(n), FLAG_RXM1);

Expand Down
13 changes: 13 additions & 0 deletions src/MCP2515.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,21 @@ class MCP2515Class : public CANControllerClass {

using CANControllerClass::filter;
virtual int filter(int id, int mask);

// mask0 is applied to filter0 and filter1 for RXB0.
// mask1 is applied to filter2, filter3, filter4, filter5 for RXB1.
// allowRollover controls whether messages that would otherwise overflow RXB0
// should be put in RXB1 instead.
//
// See the MCP2515 datasheet for more info.
boolean setFilterRegisters(
uint16_t mask0, uint16_t filter0, uint16_t filter1,
uint16_t mask1, uint16_t filter2, uint16_t filter3, uint16_t filter4, uint16_t filter5,
bool allowRollover);

using CANControllerClass::filterExtended;
virtual int filterExtended(long id, long mask);
// TODO: add setFilterRegistersExtended().

virtual int observe();
virtual int loopback();
Expand Down