Generally I have found library support for the Arduino environment to be excellent. I’ve used a lot of different available libraries to support everything from sensors to networking protocols. I am currently using the ESP32 built-in CAN Bus support (known as the Two-wire Automotive Interface(TWAI)) for a distributed hardware system being developed for virtual pipe organs. My last post found a small bug in the Arduino CAN Bus library by Sandeep Mistry when setting the bit rate. Different ESP32 revisions ran at different rates because a configuration register previous reserve bit was being set. Recently I have found another bug when attempting to configure the extended ID acceptance filter.
The acceptance filter is used to only pass wanted received CAN Bus messages. Only accepted messages are stored in the receive FIFO. Acceptance filters are based on an CAN Bus ID and a mask. Filtering is ideal for reducing processor load by only passing desired CAN Bus messages.
The acceptance filter has two, 32-bit registers, acceptance code value and acceptance mask value. The code value specifies the ID bit pattern to match and the mask value allows the user to select the bits they want to match. The ESP32 Technical Manual Version 5.2 acceptance filter algorithm is shown below.

In the algorithm when a message bit and acceptance code bit matches then the XNOR output is true (1) and that bit is accepted. For bits the user wants to ignore the acceptance mask bit should be true (1) and that bit is accepted. For an extended CAN Bus ID, if all 29-bits are accepted, then the message is passed to the receive FIFO.
Previously with this library I used acceptance filtering on the 11-bit ID, which worked well. For this VPO system I’ve decided to used the CAN Bus extended 29-bit ID instead. For the Arduino CAN Bus library the method to setup the acceptance filtering is filterExtended() where the 29-bit ID and mask values are supplied. The Sandeep Mistry library version 0.3.1 filterExtended method is given below.
int ESP32SJA1000Class::filterExtended(long id, long mask)
{
id &= 0x1FFFFFFF;
mask &= ~(mask & 0x1FFFFFFF);
modifyRegister(REG_MOD, 0x17, 0x01); // reset
writeRegister(REG_ACRn(0), id >> 21);
writeRegister(REG_ACRn(1), id >> 13);
writeRegister(REG_ACRn(2), id >> 5);
writeRegister(REG_ACRn(3), id << 3);
writeRegister(REG_AMRn(0), mask >> 21);
writeRegister(REG_AMRn(1), mask >> 13);
writeRegister(REG_AMRn(2), mask >> 5);
writeRegister(REG_AMRn(3), (mask << 3) | 0x1f);
modifyRegister(REG_MOD, 0x17, 0x00); // normal
return 1;
}
The first issue is the forming of the 29-bit mask value. The mask value is AND’d with the inverted mask value resulting in a value of 0. This requires that all ID bits must matched for the message to be accepted. The mask value result should have 1’s in the bits you are not interested in. Changing the ‘&=’ to just ‘=’ solves this problem.
The second problem is writing the acceptance mask register(3). The current library puts 1’s in the lowest 5 bits. These five bits are:
- Bit 0 – unused
- Bit 1 – unused
- Bit 2 – RTR
- Bit 3 – ID0
- Bit 4 – ID1
By setting the lowest 5 bits to 1, the acceptance filter is now ignoring ID[1:0] and RTR. The code should only set RTR = 1, leaving ID[1:0] to the inverted mask bits values, and always use 0 for unused register bits. The updated code is shown below.
int ESP32SJA1000Class::filterExtended(long id, long mask)
{
id &= 0x1FFFFFFF;
mask = ~(mask & 0x1FFFFFFF);
modifyRegister(REG_MOD, 0x17, 0x01); // reset
writeRegister(REG_ACRn(0), id >> 21);
writeRegister(REG_ACRn(1), id >> 13);
writeRegister(REG_ACRn(2), id >> 5);
writeRegister(REG_ACRn(3), id << 3);
writeRegister(REG_AMRn(0), mask >> 21);
writeRegister(REG_AMRn(1), mask >> 13);
writeRegister(REG_AMRn(2), mask >> 5);
writeRegister(REG_AMRn(3), (mask << 3) | 0x04);
modifyRegister(REG_MOD, 0x17, 0x00); // normal
return 1;
}
Overall this library works well for my application. There have been just a few surprises along the way. With these changes I was successful in filtering extended ID CAN Bus messages.

















