This demo shows how to set up one Feather M4 CAN as a sender and another as a receiver. They will print messages on the serial terminal (REPL) to show what is going on.

Before trying this demo, make sure you have the right version of CircuitPython, that import canio succeeds, and that you've wired the two Feathers together as shown on the Wiring page.

First, we'll set up the listening (receiving) node. Put the text below in that device's code.py and open up the serial terminal. When the program restarts, it will display "No messsage received within timeout" until our second device is up and running.

import struct

import board
import canio
import digitalio

# If the CAN transceiver has a standby pin, bring it out of standby mode
if hasattr(board, 'CAN_STANDBY'):
    standby = digitalio.DigitalInOut(board.CAN_STANDBY)
    standby.switch_to_output(False)

# If the CAN transceiver is powered by a boost converter, turn on its supply
if hasattr(board, 'BOOST_ENABLE'):
    boost_enable = digitalio.DigitalInOut(board.BOOST_ENABLE)
    boost_enable.switch_to_output(True)

can = canio.CAN(rx=board.CAN_RX, tx=board.CAN_TX, baudrate=250_000, auto_restart=True)
listener = can.listen(matches=[canio.Match(0x408)], timeout=.9)

old_bus_state = None
old_count = -1

while True:
    bus_state = can.state
    if bus_state != old_bus_state:
        print(f"Bus state changed to {bus_state}")
        old_bus_state = bus_state

    message = listener.receive()
    if message is None:
        print("No messsage received within timeout")
        continue

    data = message.data
    if len(data) != 8:
        print(f"Unusual message length {len(data)}")
        continue

    count, now_ms = struct.unpack("<II", data)
    gap = count - old_count
    old_count = count
    print(f"received message: count={count} now_ms={now_ms}")
    if gap != 1:
        print(f"gap: {gap}")

Next, set up the transmitting (sending) node. Put the text below in that device's code.py and open up a second serial terminal. Once both programs are running, you should see the sender and receiver printing the same information.

import struct
import time

import board
import canio
import digitalio

# If the CAN transceiver has a standby pin, bring it out of standby mode
if hasattr(board, 'CAN_STANDBY'):
    standby = digitalio.DigitalInOut(board.CAN_STANDBY)
    standby.switch_to_output(False)

# If the CAN transceiver is powered by a boost converter, turn on its supply
if hasattr(board, 'BOOST_ENABLE'):
    boost_enable = digitalio.DigitalInOut(board.BOOST_ENABLE)
    boost_enable.switch_to_output(True)

can = canio.CAN(rx=board.CAN_RX, tx=board.CAN_TX, baudrate=250_000, auto_restart=True)

old_bus_state = None
count = 0

while True:
    bus_state = can.state
    if bus_state != old_bus_state:
        print(f"Bus state changed to {bus_state}")
        old_bus_state = bus_state

    now_ms = (time.monotonic_ns() // 1_000_000) & 0xffffffff
    print(f"Sending message: count={count} now_ms={now_ms}")

    message = canio.Message(id=0x408, data=struct.pack("<II", count, now_ms))
    can.send(message)

    time.sleep(.5)
    count += 1

In this case, the data being transmitted is a packet counter which starts at 0 and counts up 1 for each transmitted packet; and a timestamp which counts up by 1000 each second. These are sent as 4 byte values, for a total of 8 bytes—the maximum for a packet on the CAN bus.

If there are problems affecting the bus (such as a disconnected wire) then various error information will also be displayed. However, after fixing the wiring the devices should automatically recover and begin communicating again.

Typical output from sender:

Download: file
code.py output:
Bus state changed to canio.BusState.ERROR_ACTIVE
Sending message: count=0 now_ms=372429
Sending message: count=1 now_ms=372929
Sending message: count=2 now_ms=373429
Sending message: count=3 now_ms=373929

Typical output from receiver:

Download: file
code.py output:
Bus state changed to canio.BusState.ERROR_ACTIVE
Sending message: count=0 now_ms=372429
Sending message: count=1 now_ms=372929
Sending message: count=2 now_ms=373429
Sending message: count=3 now_ms=373929

This guide was first published on Nov 11, 2020. It was last updated on Nov 11, 2020.

This page (Send and Receive) was last updated on Nov 29, 2020.