Page 1 of 2

CAN on STM32F4xx

Posted: Fri Nov 08, 2019 7:23 pm
by kcoelho
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

Re: CAN on STM32F4xx

Posted: Sat Nov 09, 2019 8:11 pm
by emtee
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. :)

Re: CAN on STM32F4xx

Posted: Mon Nov 11, 2019 12:47 am
by chrismas9
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')
    

Re: CAN on STM32F4xx

Posted: Mon Nov 11, 2019 6:52 pm
by kcoelho
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

Re: CAN on STM32F4xx

Posted: Mon Nov 11, 2019 7:30 pm
by kcoelho
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?

Re: CAN on STM32F4xx

Posted: Tue Nov 12, 2019 5:31 am
by chrismas9
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.

Re: CAN on STM32F4xx

Posted: Tue Nov 12, 2019 4:59 pm
by kcoelho
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

Re: CAN on STM32F4xx

Posted: Tue Nov 12, 2019 7:36 pm
by Planet9
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')

Re: CAN on STM32F4xx

Posted: Tue Nov 12, 2019 10:41 pm
by chrismas9
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.

Re: CAN on STM32F4xx

Posted: Wed Nov 13, 2019 2:16 pm
by kcoelho
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