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.
# SPDX-FileCopyrightText: 2020 Jeff Epler for Adafruit Industries # # SPDX-License-Identifier: MIT 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) # Use this line if your board has dedicated CAN pins. (Feather M4 CAN and Feather STM32F405) can = canio.CAN(rx=board.CAN_RX, tx=board.CAN_TX, baudrate=250_000, auto_restart=True) # On ESP32S2 most pins can be used for CAN. Uncomment the following line to use IO5 and IO6 #can = canio.CAN(rx=board.IO6, tx=board.IO5, 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.
# SPDX-FileCopyrightText: 2020 Jeff Epler for Adafruit Industries # # SPDX-License-Identifier: MIT 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) # Use this line if your board has dedicated CAN pins. (Feather M4 CAN and Feather STM32F405) can = canio.CAN(rx=board.CAN_RX, tx=board.CAN_TX, baudrate=250_000, auto_restart=True) # On ESP32S2 most pins can be used for CAN. Uncomment the following line to use IO5 and IO6 #can = canio.CAN(rx=board.IO6, tx=board.IO5, 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:
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:
code.py output: Bus state changed to canio.BusState.ERROR_ACTIVE received message: count=0 now_ms=372429 received message: count=1 now_ms=372929 received message: count=2 now_ms=373429 received message: count=3 now_ms=373929
Text editor powered by tinymce.