CAN on STM32F4xx

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
kcoelho
Posts: 23
Joined: Fri Aug 02, 2019 5:40 pm

CAN on STM32F4xx

Post by kcoelho » Fri Nov 08, 2019 7:23 pm

Hello,

Has anyone succeeded in communicating between CAN1 and CAN2 using Micropython on an STM32F4?

Using 2 separate transceivers for each and using jumpers to connect them together. It should allow me to communicate back and forth but nothing works

Anyone have any thoughts?

Thanks

User avatar
emtee
Posts: 15
Joined: Thu Jun 14, 2018 4:55 pm
Location: West Kootenay, BC, Canada

Re: CAN on STM32F4xx

Post by emtee » Sat Nov 09, 2019 8:11 pm

I'll start with the obvious. You will need to post more detail with regards to type of transceivers, wiring of the CAN bus and the micropython code use are using that demonstrates the problem.

Without this information it is difficult to speculate on what the problem may be. :)

chrismas9
Posts: 152
Joined: Wed Jun 25, 2014 10:07 am

Re: CAN on STM32F4xx

Post by chrismas9 » Mon Nov 11, 2019 12:47 am

Do you have a termination resistor on the CANbus? CAN tranceivers are open collector and won't work without a termination resistor to define the recessive state. If you just connect two tranceivers together without a bus a single 50 to 100 ohm resistor should work.

Here is the test script I used to test the F413 port. Just remove 3 from the available_CANs list for devices like the F405 with only two CAN controllers.

Code: Select all

# MicroPython CAN external CANbus hardware test.
# This test only works on boards with more than one CAN port.
# All CAN ports must be connected to a terminated CANbus with CAN tranceivers.
# Set the CAN controllers to test in available_CANs.
import pyb
from pyb import CAN

# -----------------------------
available_CANs = [1, 2, 3]
# -----------------------------

cans = []

for i in range(0, max(available_CANs)):
    cans.append('none')
    if (i+1) in available_CANs:
        cans[i] = CAN(i+1, CAN.NORMAL)
        cans[i].setfilter(0, CAN.LIST16, 0, (123, 124, 125, 126))   # set a filter to receive messages with id=123, 124, 125 and 126

def CAN_Send(s):
    message = 'CAN ' + str(s) + '->'
    cans[s-1].send(message, 123)                            # send a message with id 123
        
def CAN_Recv(r):
    res = cans[r-1].recv(0, timeout=50)                     # receive message on FIFO 0
    return res

try:   
    while True:
        for i in available_CANs:
            CAN_Send(i)
            pyb.delay(100)
            for j in available_CANs:
                if (i != j):
                    res = CAN_Recv(j)
                    print(res[3].decode("utf-8") + str(j), " passed external loopback")
        print('----------------------------------')
                
finally:
    print('FAIL, send ', i, ' recv ', j, '\n')
    

kcoelho
Posts: 23
Joined: Fri Aug 02, 2019 5:40 pm

Re: CAN on STM32F4xx

Post by kcoelho » Mon Nov 11, 2019 6:52 pm

emtee wrote:
Sat Nov 09, 2019 8:11 pm
I'll start with the obvious. You will need to post more detail with regards to type of transceivers, wiring of the CAN bus and the micropython code use are using that demonstrates the problem.

Without this information it is difficult to speculate on what the problem may be. :)
The chip has the builtin CAN controllers and there are 2 CAN transceivers for CAN1 and CAN2.
A termination resistor is being used at 120 Ohms to terminate each of the lines.

In terms of wiring, CAN1-H --> CAN2-H and CAN1-L --> CAN2-L. Also connected the two grounds but not sure how much that helps.

In terms of code, trying to follow from the standard examples in the Micropython documentation. But nothing seems to work. Tried with standard recv() function as well as the rxcallback()

Thanks

kcoelho
Posts: 23
Joined: Fri Aug 02, 2019 5:40 pm

Re: CAN on STM32F4xx

Post by kcoelho » Mon Nov 11, 2019 7:30 pm

chrismas9 wrote:
Mon Nov 11, 2019 12:47 am
Do you have a termination resistor on the CANbus? CAN tranceivers are open collector and won't work without a termination resistor to define the recessive state. If you just connect two tranceivers together without a bus a single 50 to 100 ohm resistor should work.

Here is the test script I used to test the F413 port. Just remove 3 from the available_CANs list for devices like the F405 with only two CAN controllers.

Code: Select all

# MicroPython CAN external CANbus hardware test.
# This test only works on boards with more than one CAN port.
# All CAN ports must be connected to a terminated CANbus with CAN tranceivers.
# Set the CAN controllers to test in available_CANs.
import pyb
from pyb import CAN

# -----------------------------
available_CANs = [1, 2, 3]
# -----------------------------

cans = []

for i in range(0, max(available_CANs)):
    cans.append('none')
    if (i+1) in available_CANs:
        cans[i] = CAN(i+1, CAN.NORMAL)
        cans[i].setfilter(0, CAN.LIST16, 0, (123, 124, 125, 126))   # set a filter to receive messages with id=123, 124, 125 and 126

def CAN_Send(s):
    message = 'CAN ' + str(s) + '->'
    cans[s-1].send(message, 123)                            # send a message with id 123
        
def CAN_Recv(r):
    res = cans[r-1].recv(0, timeout=50)                     # receive message on FIFO 0
    return res

try:   
    while True:
        for i in available_CANs:
            CAN_Send(i)
            pyb.delay(100)
            for j in available_CANs:
                if (i != j):
                    res = CAN_Recv(j)
                    print(res[3].decode("utf-8") + str(j), " passed external loopback")
        print('----------------------------------')
                
finally:
    print('FAIL, send ', i, ' recv ', j, '\n')
    
Tried it and pretty much get the same error as always. That the receiving CAN times out.
The message doesn't get put into the FIFO on the receiving CAN for some reason.

Is there any configuration settings that have to be changed first?

chrismas9
Posts: 152
Joined: Wed Jun 25, 2014 10:07 am

Re: CAN on STM32F4xx

Post by chrismas9 » Tue Nov 12, 2019 5:31 am

I have used that test script on several Nucleo boards. What board and MicroPython version are you using? If it's custom post your mpconfigport.h

What CAN transceivers are you using? Are they powered from 3.3V or 5V? What is the logic 1 input threshold on the MCU side? TTL compatible parts are 2 to 2.4 and work with 3.3V CMOS. CMOS parts on 5V have a 3.7V threshold and may not be reliable with a 3V input.

It is ok to use 5V parts with TTL inputs because the STM32 has 5V tolerant inputs in CAN Rx.

kcoelho
Posts: 23
Joined: Fri Aug 02, 2019 5:40 pm

Re: CAN on STM32F4xx

Post by kcoelho » Tue Nov 12, 2019 4:59 pm

chrismas9 wrote:
Tue Nov 12, 2019 5:31 am
I have used that test script on several Nucleo boards. What board and MicroPython version are you using? If it's custom post your mpconfigport.h

What CAN transceivers are you using? Are they powered from 3.3V or 5V? What is the logic 1 input threshold on the MCU side? TTL compatible parts are 2 to 2.4 and work with 3.3V CMOS. CMOS parts on 5V have a 3.7V threshold and may not be reliable with a 3V input.

It is ok to use 5V parts with TTL inputs because the STM32 has 5V tolerant inputs in CAN Rx.
Using the MCP2562 transceiver. Powered off 5V.
Using it on a custom port with the STM32F437 chip.
I have not changed the mpconfigport.h in the /stm32 directory. Not entirely sure what Micropython version it is but I cloned the micropython repo sometime in August.

It's something on the receiver side because nothing ever shows up on the receiving FIFO. But the messages from the sender are always on the TX buffer to be sent

**Also to clarify, this is communication between CAN1 and CAN2 on the same STM32F4 chip**

Thanks so much for your help
Last edited by kcoelho on Tue Nov 12, 2019 9:46 pm, edited 1 time in total.

Planet9
Posts: 7
Joined: Tue Nov 12, 2019 7:10 pm

Re: CAN on STM32F4xx

Post by Planet9 » Tue Nov 12, 2019 7:36 pm

Another option for testing is to eliminate the CANbus driver ICs and use Single Wire CAN.

(1) Make the CAN TX lines open drain, as shown in this code (which is just a slight mod of previously posted code)
(2) Join all the TX and RX lines from the STM32 MCU together (this is the Single Wire CANbus line)
(3) Add a pullup resistor from 3v3 rail to the Single Wire CANbus, 1kOhm or so.

Tested OK on STM32F405.

This should also work fine for 1-wire CAN communication between two or more microcontrollers, although there is little noise immunity so just it's just for local PCB interconnect.

Code: Select all

# MicroPython CAN external CANbus hardware test.
# This test only works on boards with more than one CAN port.
# All MCU CAN port pins must be connected together for this Single Wire CANbus test
# No bus transcievers required
# Set the CAN controllers to test in available_CANs.
import pyb
from pyb import CAN

# -----------------------------
available_CANs = [1, 2]
# -----------------------------

cans = []

for i in range(0, max(available_CANs)):
    cans.append('none')
    if (i+1) in available_CANs:
        cans[i] = CAN(i+1, CAN.NORMAL)
        cans[i].setfilter(0, CAN.LIST16, 0, (123, 124, 125, 126))   # set a filter to receive messages with id=123, 124, 125 and 126

#Make TX pins open drain for single-wire CAN
pinCAN1TX = pyb.Pin(pyb.Pin.cpu.B9,mode=pyb.Pin.AF_OD, pull=pyb.Pin.PULL_UP, af=pyb.Pin.AF9_CAN1)
pinCAN2TX = pyb.Pin(pyb.Pin.cpu.B13,mode=pyb.Pin.AF_OD, pull=pyb.Pin.PULL_UP, af=pyb.Pin.AF9_CAN2)

def CAN_Send(s):
    message = 'CAN ' + str(s) + '->'
    cans[s-1].send(message, 123)                            # send a message with id 123
        
def CAN_Recv(r):
    res = cans[r-1].recv(0, timeout=50)                     # receive message on FIFO 0
    return res

try:   
    while True:
        for i in available_CANs:
            CAN_Send(i)
            pyb.delay(100)
            for j in available_CANs:
                if (i != j):
                    res = CAN_Recv(j)
                    print(res[3].decode("utf-8") + str(j), " passed external loopback")
        print('----------------------------------')
                
finally:
    print('FAIL, send ', i, ' recv ', j, '\n')

chrismas9
Posts: 152
Joined: Wed Jun 25, 2014 10:07 am

Re: CAN on STM32F4xx

Post by chrismas9 » Tue Nov 12, 2019 10:41 pm

I used a similar CN transceiver from Microchip. Yours needs dual supplies and enable, mine had slope control. Shouldn't make any difference as long as all 8 pins are connected.

I presume you are using STM32F439 port as a starting point for your board. Are you using the same pins as specified in mpconfigboard.h? There are lots of af options. For example CAN2 can be on PB5/6 or PB12/13.

kcoelho
Posts: 23
Joined: Fri Aug 02, 2019 5:40 pm

Re: CAN on STM32F4xx

Post by kcoelho » Wed Nov 13, 2019 2:16 pm

chrismas9 wrote:
Tue Nov 12, 2019 10:41 pm
I used a similar CN transceiver from Microchip. Yours needs dual supplies and enable, mine had slope control. Shouldn't make any difference as long as all 8 pins are connected.

I presume you are using STM32F439 port as a starting point for your board. Are you using the same pins as specified in mpconfigboard.h? There are lots of af options. For example CAN2 can be on PB5/6 or PB12/13.
Yup. They are all connected as per the datasheet. Yes, using the port as a starting point.

I am using the same pins as in the mpconfigboard.h, B6,B12 and D1,D0

Post Reply