Possible hardware issue with CAN peripheral on ATSAM3x8e - clobbering 29-bit identifiers

I just spent today tracking down a weird bug I found on a CAN bus that has both 11 and 29-bit identifiers. It appears to be a hardware issue with the CAN peripheral on the ATSAM3x8e, but the long and short of it is that if you have a mailbox configured to receive 11-bit CAN frames that comes before a mailbox configured to receive 29-bit CAN frames, the first 29-bit CAN frame will wind up in the mailbox set up for 11-bit CAN frames with the bottom 18 bits discarded, and that mailbox gets re-configured to receive the 29-bit CAN frames, and the rest of the 29-bit CAN frames end up in that mailbox as well, instead of the mailbox they are supposed to be in. This process then repeats each time an 11-bit CAN frame is received, that frame is properly received in the proper mailbox, and then the next 29-bit CAN frame gets mangled again.

So, basically, before I get into all the gritty detail, if you’re expecting both basic and extended CAN frames, make sure that your mailboxes are configured so that the mailboxes expecting extended CAN frames come first, and the mailboxes for basic frames come second.

I’ve opened a support ticket with Microchip, and I’ll keep this thread updated with any response I hear from them, but here’s the detail I provided in that support ticket:

I am configuring the mailboxes on the CAN peripheral as follows: Mailboxes 0-4 are disabled, Mailbox 5 is configured to accept all 11-bit (basic) CAN frames and Mailbox 6 is configured to receive all 29-bit (extended) CAN frames. The relevant CAN registers are below:

Mailbox 5:
CAN_MMR = 0x01000000
CAN_MAM = 0x00000000
CAN_MID = 0x00000000

Mailbox 6:
CAN_MMR = 0x01000000
CAN_MAM = 0x20000000
CAN_MID = 0x20000000

I start by transmitting a single CAN frame from another CAN device to be received by the device I am having problems with. The first CAN frame transmitted is a basic CAN frame with an arbitration ID of 0x123 and 8 bytes of data, 0x00AAAAAAAAAAAAAA. This is received as expected, Mailbox 6 registers do not change, mailbox 5 shows successful reception of this message:

Mailbox 5 after reception of basic CAN Frame:
CAN_MMR: 0x01000000
CAN_MAM: 0x00000000
CAN_MID: 0x048C0000
CAN_MFID: 0x00000123
CAN_MSR: 0x000842B9
CAN_MDL: 0xAAAAAA00
CAN_MDH: 0xAAAAAAAA

I then proceed to send another CAN frame, this time an extended CAN frame with an arbitration ID of 0x1576 and an 8 byte message of 0x01AAAAAAAAAAAAAA. I expect to see this message show up in mailbox 6, instead, it ends up in mailbox 5, showing an arbitration ID of 0x000. The registers in mailbox 6 are unchanged.

Mailbox 5, after erroneous reception of extended CAN frame:
CAN_MMR: 0x01000000
CAN_MAM: 0x00000000
CAN_MID: 0x20000000 // The MIDE bit is now set, but the MIDvA and MIDvB are both 0.
CAN_MFID: 0x00000000
CAN_MSR: 0x0008568E
CAN_MDL: 0xAAAAAA01
CAN_MDH: 0xAAAAAAAA

If I send another extended CAN frame, same arbitration ID of 0x1576 and data of 0x02AAAAAAAAAAAAAA mailbox 6 remains untouched, but mailbox 5 now receives the message properly (presumably because the MIDE bit in the CAN_MID register got set from the previous message?). Mailbox 6 remains unchanged:

Mailbox 5 after successful reception of 2nd extended CAN Frame:
CAN_MMR: 0x01000000
CAN_MAM: 0x00000000
CAN_MID: 0x20001576
CAN_MFID: 0x00001576
CAN_MSR: 0x000842B0
CAN_MDL: 0xAAAAAA02
CAN_MDH: 0xAAAAAAAA

Sending another extended CAN frame, this time with an arbitration ID of 0x15761234 and data of 0x03AAAAAAAAAAAAAA also ends up being properly received by mailbox 5. If I switch back to basic CAN frames, and re-send a basic CAN frame with an arbitration ID of 0x123 and data of 0x04AAAAAAAAAAAAAA that message also gets received by mailbox 5, and the MIDE bit of the CAN_MID register is cleared:

Mailbox 5 after reception of basic CAN Frame:
CAN_MMR: 0x01000000
CAN_MAM: 0x00000000
CAN_MID: 0x048E1234 // MIDE bit is cleared, junk data in MIDvB from previous message
CAN_MFID: 0x00000123
CAN_MSR: 0x0008D2DC
CAN_MDL: 0xAAAAAA04
CAN_MDH: 0xAAAAAAAA

If I then go back to extended CAN Frames, I see the same issue as before, the frame is received by Mailbox 5 and the extended CAN Frame arbitration ID is mangled . This time I send a CAN Frame with an arbitration ID of 0x15761234 (so that the upper 11 bits of the extended arbitration ID are not zero) and data of 0x05AAAAAAAAAAAAAA. Mailbox 6 is, again, unchanged, and mailbox 5 registers are now:

Mailbox 5 after reception of extended CAN Frame:
CAN_MMR: 0x01000000
CAN_MAM: 0x00000000
CAN_MID: 0x35740000 // MIDE is set, MIDvA populated, but MIDvB is not
CAN_MFID: 0x15740000
CAN_MSR: 0x000890BE
CAN_MDL: 0xAAAAAA05
CAN_MDH: 0xAAAAAAAA

The rest of the CAN peripheral registers are below, if needed:
CAN_MR: 0x00000001
CAN_IMR: 0x00000060
CAN_SR: 0x00610080
CAN_BR: 0x00142211
CAN_TIM: 0x0000620D
CAN_TIMESTP: 0x000090BE
CAN_ECR: 0x00000000
CAN_WPMR: 0x00000000
CAN_WPSR: 0x00000000

I do have a workaround that is acceptable to me for this project, and that is switching the order of the extended catch-all mailbox and the basic catch-all mailbox. If I configure mailbox 5 to receive all extended CAN frames, and mailbox 6 to receive all basic CAN frames, i.e:

Mailbox 5:
CAN_MMR = 0x01000000
CAN_MAM = 0x20000000
CAN_MID = 0x20000000

Mailbox 6:
CAN_MMR = 0x01000000
CAN_MAM = 0x00000000
CAN_MID = 0x00000000

Then everything works as expected, all of the basic CAN frames go into mailbox 6 and all of the extended CAN frames go into mailbox 5 and no mangling of arbitration IDs occurs, and the MIDE bit of CAN_MID doesn’t get changed.

1 Like

Wow, interesting! I guess I never noticed for two reasons. 1: I rarely ever work with extended frames. They’ve always been pretty rare in general usage (well, J1939 certainly uses extended frames though) and 2: I try not to use hardware filtering. Most everything I do is general capture and I do processing after the fact so it’s just a open spigot. But, it certainly is good to know that you found the problem and the solution. I am curious what the chip manufacturer has to say about this.

I got a response from Microchip that they’re looking into it, along with an intelligent follow-up question so they’re /actually/ looking into it. Collin, I fired up an M2 with m2ret and SavvyCAN and did not see the issue, so however you have the M2 configured there seems to work.

The key there is that I don’t use hardware filtering. M2RET sets one filter for all extended frames and one filter for all standard frames. Then you can do filtering in software but the hardware is always sending all frames. You can do the same thing on an M2 directly - just accept all frames and immediately discard anything you don’t actually care about - software filtering. It isn’t as nice as being able to use hardware filters but it is pretty foolproof.

Ah, I found where you set it in your code, in the setPromiscuousMode() function. You have it set to receive the extended fames in mailboxes 1-3 and basic in 4-7, which works. If you reversed the order and had basic frames followed by extended frames you would have run into this bug too. I’m also accepting all arbitration IDs in my code (though I have the ability to set a hardware filter if needed).