Repository navigation
STM32 pyb.CAN: Instantiating one CAN instance can corrupts settings of another instance. #18922
Description
Activity
The issue also occurs with CAN3 on STM32F413, even though it is somewhat independant of CAN1 and CAN2. Creating an instance of CAN3 corrupts CAN1 and CAN2 settings.
Thanks for the very clear report, @chrismas9! I was able to fix the issue for CAN2, although I'm not sure what will be the correct fix for CAN3 (similar, I expect.)
I'm not sure what will be the correct fix for CAN3 (similar, I expect.)
Looking at the HAL, it looks like the same problem shouldn't reoccur for CAN3 (as it has fully independent filter indexes). So the root cause of CAN3 corruption may be something else. I unfortunately don't have a CAN3-enabled board to test with.
I unfortunately don't have a CAN3-enabled board to test with.
Have ordered a NUCLEO-F413ZH board to add to my collection of ST Nucleo boards!
Reacted by Damien George@chrismas9 Are you able to easily check if the CAN3 corruption still occurs on master? If it's still there then I can reopen this issue (maybe with an edited title.)
- added a commit that references this issue
on Mar 18, 2026 @projectgus Your fix works for CAN2 corrupting CAN1, but CAN1 still corrupts CAN2 and CAN3 corrupts CAN1 and CAN2.
In
pyb_can2.pyYou create CAN2 after CAN1. For a complete regression test you may want to test with each CAN last. e.g.
CAN1, CAN2, CAN3
CAN1, CAN3, CAN2
CAN2, CAN3, CAN1I'm happy to do further tesing before your F413 board arrives.
Test results for F413:
MicroPython v1.28.0-preview.270.gd1c936db73 on 2026-03-19; NUCLEO-F413ZH with STM32F413CAN1 last:
CAN2, CAN1fails. CAN2 fails, CAN1 passes. CAN1 corrupts CAN2.
CAN3, CAN1passes. CAN1 doesn't corrupt CAN3.
CAN2, CAN3, CAN1fails. CAN2 fails, CAN1 & CAN3 pass. CAN1 corrupts CAN2, CAN1 doesn't corrupt CAN3.
CAN3, CAN2, CAN1fails. CAN2 fails, CAN1 & CAN3 pass. CAN1 corrupts CAN2, CAN1 doesn't corrupt CAN3.
Result. CAN1 corrupts CAN2, but not CAN3.CAN2 last:
CAN1, CAN2passes. CAN2 doesn't corrupt CAN1.
CAN3, CAN2passes. CAN2 doesn't corrupt CAN3.
CAN1, CAN3, CAN2fails. CAN1 fails, CAN2 & CAN3 pass. CAN3 corrupts CAN1, CAN2 doesn't corrupt CAN3.
CAN3, CAN1, CAN2passes. CAN2 doesn't corrupt CAN1 or CAN3.
Result. CAN2 doesn't corrupt CAN1 or CAN3.CAN3 last:
CAN1, CAN3fails. CAN1 fails. CAN3 corrupts CAN1.
CAN2, CAN3fails. CAN2 fails. CAN3 corrupts CAN2.
CAN1, CAN2, CAN3fails. CAN1 & CAN2 fail, CAN3 passes. CAN3 corrupts CAN1 & CAN2.
CAN2, CAN1, CAN3fails. CAN1 & CAN2 fail, CAN3 passes. CAN3 corrupts CAN1 & CAN2.
Result. CAN3 corrupts CAN1 & CAN2.CAN1, CAN2 tests on PYBv1.0
MicroPython v1.28.0-preview.270.gd1c936db73 on 2026-03-19; PYBv1.0 with STM32F405RGCAN2, CAN1fails. CAN2 fails, CAN1 passes. CAN1 corrupts CAN2.
CAN1, CAN2passes. CAN2 doesn't corrupt CAN1.Summary.
CAN1 corrupts CAN2, but not CAN3.
CAN2 doesn't corrupt anything. Fixed in latest.
CAN3 corrupts CAN1 & CAN2.from pyb import CAN # List up to 3 CAN channels in any order. Unavailable channels will be ignored. # They will be instantiated and initialised in the order listed. test_cans = [1, 2, 3] cans = [] print('------------------------------------------------------------------------------------------------------------------------') j = 0 for i in test_cans: cans.append([i,None]) try: cans[j][1] = CAN(i, CAN.LOOPBACK) cans[j][1].setfilter(0, CAN.LIST16, 0, (123, 124, 125, 126)) except: print('can' + str(i), 'not available') j +=1 print('Test order:\n', cans) print('------------------------------------------------------------------------------------------------------------------------') for i in range(0, j): can_msg = 'can' + str(cans[i][0]) if cans[i][1] is not None: try: cans[i][1].send(can_msg, 123) try: print(can_msg, cans[i][1].recv(0, timeout=50)) except: print(can_msg, 'receive failed') except: print(can_msg, 'send failed')- changed the title
[-]STM32 pyb.CAN: Intantiating second instance corrupts settings of first instance.[/-][+]STM32 pyb.CAN: Intantiating one CAN instance can corrupts settings of another instance.[/+]on Mar 20, 2026 @projectgus Your fix works for CAN2 corrupting CAN1, but CAN1 still corrupts CAN2 and CAN3 corrupts CAN1 and CAN2.
Sorry, my mistake - I clearly didn't read the whole issue as submitted, only the first part. Have reopened, and I'll try and take another look soon.
While testing machine.CAN I did find and fix a problem with FDCAN losing state as the deinit functions were resetting the entire peripheral block in RCC even when another instance was active. It might be something similar is happening with bxCAN, somehow.
I wasn't very clear about the reverse order. I also found that my original test script reordered the creation numerically, so I probably didn't even test CAN2 before CAN1. The ordering is fixed in my latest test.
Reacted by Angus Gratton- changed the title
[-]STM32 pyb.CAN: Intantiating one CAN instance can corrupts settings of another instance.[/-][+]STM32 pyb.CAN: Instantiating one CAN instance can corrupts settings of another instance.[/+]on Mar 20, 2026 - added a commit that references this issue
on Sep 21, 2026
Port, board and/or hardware
STM32 PYBv1.0
MicroPython version
MicroPython v1.28.0-preview.259.g4625f97d09.dirty on 2026-03-13; PYBv1.0 with STM32F405RG
Reproduction
I found a problem with my pyb.CAN test script. Creating an instance of CAN2 corrupts the settings of CAN1, probably because they share a hardware block. I wrote the test way back when I did the F413 port. F413 has three CAN ports. I create and initialise up to three instances in a loop. It works on 1.17, but not on 1.28, possibly since the introduction of FDCAN.
Minimum code demonstrating the problem. This runs on PYBv1.0
Expected behaviour
Works on 1.17
Observed behaviour
Fails on 1.28
Additional Information
Moving can1.setfilter fixes it.
I don't think I can help debug this, but I am happy to help with testing on different STM32 MCUs.
This is my original loopback test script for F413. It is a cutdown version of an external CAN test that requires CAN tranceivers.
available_CANs = [1, 2, 3]is for F413.available_CANs = [1, 2]works on PYBv3 1.14, fails on PYBv1.0 1.28available_CANs = [2,1]passes for CAN2, then fails for CAN1available_CANs = [1,]passes.Note also that the receive message position changed in1.19 and I have updated th script to handle that.
Code of Conduct
Yes, I agree