It's easy to use the CAN Bus BFF with CircuitPython and the Adafruit_CircuitPython_MCP2515 module. This module allows you to easily write Python code that lets you utilize the MCP25625 CAN bus controller. In the example below, you'll connect an RP2040 CAN Bus Feather to a QT Py plugged into a CAN Bus BFF. The Feather will send CAN Bus messages whenever the seesaw rotary encoder is used and the QT Py will receive and display the messages on a STEMMA OLED.
CircuitPython Microcontroller Wiring
Plug an CAN Bus BFF into your QT Py or Xiao form factor board exactly as shown below. Here's an example of connecting a QT Py RP2040 to the BFF.
Connect the QT Py RP2040 with plug headers into the CAN Bus BFF with socket headers. They should be plugged in with the backs of the boards facing each other.
For more information on soldering socket headers, check out this Learn Guide.
Then, you'll connect the Feather and BFF CAN Bus connections to each other, followed by the STEMMA peripherals to the corresponding boards.
QT Py
-
Board STEMMA 3V to screen VIN (red wire)
-
Board STEMMA GND to screen GND (black wire)
-
Board STEMMA SCL to screen SCL (yellow wire)
- Board STEMMA SDA to screen SDA (blue wire)
CAN Bus
- Feather H terminal block to BFF H JST-PH (red wire)
- Feather middle (ground) terminal block to BFF ground JST-PH (black wire)
- Feather L terminal block to BFF L JST-PH (white wire)
Feather RP2040 CAN Bus
-
Feather STEMMA 3V to rotary encoder VIN (red wire)
-
Feather STEMMA GND to rotary encoder GND (black wire)
-
Feather STEMMA SCL to rotary encoder SCL (yellow wire)
- Feather STEMMA SDA to rotary encoder SDA (blue wire)
CircuitPython Usage
To use with CircuitPython, you need to first install the MCP2515 library, and its dependencies, into the lib folder onto both of your CIRCUITPY drives for this example. Then, load the different example code files onto the corresponding boards; one for the Feather RP2040 CAN Bus and one for the QT Py RP2040 with the CAN Bus BFF.
Thankfully, we can do this in one go. In the example below, click the Download Project Bundle button below to download the necessary libraries and Python files in a zip file. Extract the contents of the zip file, and copy the entire lib folder and can_bus_bff_receiver.py file to your QT Py RP2040 CIRCUITPY drive. Rename can_bus_bff_receiver.py to code.py.
Then, copy the entire lib folder and can_bus_feather_send.py file to your Feather RP2040 CAN Bus CIRCUITPY drive. Rename can_bus_feather_send.py to code.py.
Your QT Py RP2040 and Feather RP2040 CAN Bus CIRCUITPY/lib folders should contain the following folders and files:
- adafruit_bitmap_font/
- adafruit_bus_device/
- adafruit_display_text/
- adafruit_mcp2515/
- adafruit_seesaw/
- adafruit_displayio_ssd1306.mpy
- adafruit_pixelbuf.mpy
Once everything is saved to both CIRCUITPY drives, connect to the serial console to see the data printed out! The Feather will be sending CAN messages to the QT Py via the CAN Bus BFF.
Feather RP2040 CAN Bus Sender
# SPDX-FileCopyrightText: Copyright (c) 2024 ladyada for Adafruit Industries # # SPDX-License-Identifier: MIT import time import board from rainbowio import colorwheel from digitalio import DigitalInOut from adafruit_mcp2515 import MCP2515 as CAN from adafruit_mcp2515.canio import Message from adafruit_seesaw import seesaw, neopixel, rotaryio, digitalio cs = DigitalInOut(board.CAN_CS) cs.switch_to_output() spi = board.SPI() can_bus = CAN( spi, cs, loopback=False, silent=False ) # use loopback to test without another device i2c = board.I2C() # uses board.SCL and board.SDA # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller seesaw = seesaw.Seesaw(i2c, addr=0x36) seesaw_product = (seesaw.get_version() >> 16) & 0xFFFF print("Found product {}".format(seesaw_product)) if seesaw_product != 4991: print("Wrong firmware loaded? Expected 4991") seesaw.pin_mode(24, seesaw.INPUT_PULLUP) button = digitalio.DigitalIO(seesaw, 24) pixel = neopixel.NeoPixel(seesaw, 6, 1) pixel.brightness = 0.3 button_held = False color = 0 encoder = rotaryio.IncrementalEncoder(seesaw) last_position = 0 while True: with can_bus.listen(timeout=5.0) as listener: position = -encoder.position if position != last_position: if position > last_position: color += 5 else: color -= 5 color = (color + 256) % 256 # wrap around to 0-256 pixel.fill(colorwheel(color)) last_position = position str_pos = str(position) byte_pos = str_pos.encode() message = Message(id=0x1234ABCD, data=byte_pos, extended=True) send_success = can_bus.send(message) print("Send success:", send_success) if not button.value and not button_held: button_held = True message = Message(id=0x1234ABCD, data=b"pressed", extended=True) send_success = can_bus.send(message) print("Send success:", send_success) if button.value and button_held: button_held = False message = Message(id=0x1234ABCD, data=b"released", extended=True) send_success = can_bus.send(message) print("Send success:", send_success) time.sleep(0.1)
When you open the serial console for the Feather, you'll see confirmations that packets have been sent every time you turn the rotary encoder or press the button. As you turn the rotary encoder, the NeoPixels on the encoder and the Feather will advance thru the color wheel.
CAN Bus BFF Receiver
# SPDX-FileCopyrightText: 2024 ladyada for Adafruit Industries # # SPDX-License-Identifier: MIT import time import board import terminalio import displayio from digitalio import DigitalInOut from adafruit_mcp2515.canio import Message, RemoteTransmissionRequest from adafruit_mcp2515 import MCP2515 as CAN import adafruit_displayio_ssd1306 from adafruit_display_text import label displayio.release_displays() i2c = board.STEMMA_I2C() # STEMMA OLED setup display_bus = displayio.I2CDisplay(i2c, device_address=0x3D, reset=None) display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=64) cs = DigitalInOut(board.A3) cs.switch_to_output() spi = board.SPI() can_bus = CAN( spi, cs, loopback=False, silent=False ) # use loopback to test without another device splash = displayio.Group() display.root_group = splash font = terminalio.FONT main_area = label.Label( font, text="CAN Receiver", color=0xFFFFFF) main_area.anchor_point = (0.5, 0.0) main_area.anchored_position = (display.width / 2, 0) msg_area = label.Label( font, text="ID: ", color=0xFFFFFF) msg_area.anchor_point = (0.0, 0.5) msg_area.anchored_position = (0, display.height / 2) val_area = label.Label( font, text="Val: ", color=0xFFFFFF) val_area.anchor_point = (0.0, 1.0) val_area.anchored_position = (0, display.height) splash.append(main_area) splash.append(msg_area) splash.append(val_area) while True: with can_bus.listen(timeout=1.0) as listener: message_count = listener.in_waiting() for i in range(message_count): print(message_count, "messages available") msg = listener.receive() print("Message from ", hex(msg.id)) msg_area.text = f"ID: {hex(msg.id)}" if isinstance(msg, Message): print("message data:", msg.data) val_area.text = f"Val: {msg.data}" if isinstance(msg, RemoteTransmissionRequest): print("RTR length:", msg.length) time.sleep(0.1)
When you open the serial console for the QT Py RP2040, you'll see the messages coming in via CAN for the status of the encoder position and the push button. You'll also see them on the OLED along with "CAN Receiver" at the top.
Text editor powered by tinymce.