# CAN Bus with CircuitPython: Using the canio module

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/096/814/medium800/circuitpython_CAN_Node.png?1604678470 CAN Node by EE JRW from Wikimedia)

In this guide you'll learn how to use CircuitPython's `canio` module to send and receive data between two supported boards, such as the Feather M4 CAN.

Are you new to using CircuitPython? No worries, [there is a full getting started guide here](https://learn.adafruit.com/welcome-to-circuitpython "Welcome to CircuitPython").

Adafruit suggests using the Mu editor to edit your code and have an interactive REPL in CircuitPython.&nbsp;[You can learn about Mu and installation in this tutorial](https://learn.adafruit.com/welcome-to-circuitpython/installing-mu-editor "Mu tutorial").

Primary: 

## CAN basics

According to Wikipedia,

> A **Controller Area Network** ( **CAN bus** ) is a robust [vehicle bus](https://en.wikipedia.org/wiki/Vehicle_bus "Vehicle bus") standard designed to allow [microcontrollers](https://en.wikipedia.org/wiki/Microcontroller "Microcontroller") and devices to communicate with each other's applications without a [host computer](https://en.wikipedia.org/wiki/Host_computer "Host computer"). It is a [message-based protocol](https://en.wikipedia.org/wiki/Message-based_protocol "Message-based protocol"), designed originally for [multiplex](https://en.wikipedia.org/wiki/Multiplexing "Multiplexing") electrical wiring within automobiles to save on copper, but can also be used in many other contexts.

The Controller Area Network is standardized as ISO 11898.

A CAN bus consists of 2 or more devices hooked together with a pair of wires, called H and L. Generally the devices will also share a common GND as well. We'll show networks with just 2 devices, but you can certainly have more. When you have a larger number of devices, you may have to modify the "bus termination resistors" according to the requirements of the CAN specification.

A CAN packet consists of an ID (a 11 or 29 bit number; 29 bit IDs are "extended IDs") which allows devices to listen only for message IDs they are interested in; a "Remote Transmission Request" (RTR) flag which allows one device to request data from another device; and (if it is not a Remote Transmission Request), a data payload of 0 to 8 bytes.

The whole packet is protected against corruption by a CRC (sometimes called a checksum). This means that while packets can sometimes go missing due to garbled transmission, almost all data transmission errors are caught and the invalid data discarded.

Since CAN does not include a way to be sure the intended recipient device has actually received a message, you may find it necessary to implement your own "reliable" transmission method by having the receiving device acknowledge that it has received a packet by sending a packet back. There are other ways of tackling potential lost packets; for instance, if you are a sensor you could just send your sensor data 10 times a second and not care whether just a few packets are lost. The right thing to do depends on your application.

## Compatible boards

Multiple Adafruit boards such as Feathers and Metros have a CAN bus peripheral. The Feather M4 CAN is the most convenient, as it also includes a CAN transceiver. Other boards need an external CAN transceiver. Supported boards include:

- Feather M4 CAN Express
- Feather STM32F405 Express (requires an external CAN transceiver)
- Metro ESP32-S2 Express (requires an external CAN transceiver)

### Adafruit Feather STM32F405 Express

[Adafruit Feather STM32F405 Express](https://www.adafruit.com/product/4382)
ST takes flight in this Feather board. The new STM32F405 Feather ([video](https://youtu.be/CZ6TtvYJTeI)) that we designed runs CircuitPython at a blistering 168MHz – our fastest CircuitPython board ever! We put a STEMMA QT / Qwiic port on the end, so you can really easily plug...

Out of Stock
[Buy Now](https://www.adafruit.com/product/4382)
[Related Guides to the Product](https://learn.adafruit.com/products/4382/guides)
![Angled shot of a blue rectangular microcontroller.](https://cdn-shop.adafruit.com/640x480/4382-16.jpg)

### Adafruit Metro ESP32-S2

[Adafruit Metro ESP32-S2](https://www.adafruit.com/product/4775)
What's Metro shaped and has an ESP32-S2 WiFi module? What has a STEMMA QT connector for I2C devices, and a Lipoly charger circuit? What has your favorite Espressif WiFi microcontroller and lots of memory for your next IoT project?

That's right - its the new Adafruit Metro...

In Stock
[Buy Now](https://www.adafruit.com/product/4775)
[Related Guides to the Product](https://learn.adafruit.com/products/4775/guides)
![Angled shot of Adafruit Metro esp32-s2 ](https://cdn-shop.adafruit.com/640x480/4775-06.jpg)

### Part: CAN Bus Module Transceiver TJA1050
quantity: 1
5V Can Bus Transceiver modules (pack of 5)
[CAN Bus Module Transceiver TJA1050](https://www.amazon.com/gp/product/B07W4VZ2F2)

# CAN Bus with CircuitPython: Using the canio module

## CircuitPython Docs

# CAN Bus with CircuitPython: Using the canio module

## Wiring

![](https://cdn-learn.adafruit.com/assets/assets/000/096/810/medium800/circuitpython_PXL_20201106_145653558.jpg?1604675407)

## Feather STM32F405 Express & External Transceiver

The Feather STM32F405 has a built in CAN peripheral, but it requires an external transceiver.

Wiring is reasonably straightforward, but you need to take note of the following:

- Whether the transceiver needs **5V** (more common) or **3.3V** (less common) on its power input pin. On my transceiver, **5V** is required, and comes from the **USB** pin on the Feather
- Whether the **TX** and **RX** pins refer to the microcontroller's point of view or the transceiver point of view. On my transceiver, **TX** and **RX** refer to the transceiver's point of view.
- Whether there is an **enable** pin, and whether to set it `True` or `False`

On an STM32F405 Feather, the pin marked D9 is the CAN TX (data FROM feather INTO transceiver); the pin marked D10 is the CAN RX (data INTO Feather FROM transceiver) pin.

Here's how to wire up two STM32 Feathers:

Feather 1 ↔ Transceiver 1 ↔ Transceiver 2 ↔ Feather 2

![](https://cdn-learn.adafruit.com/assets/assets/000/098/920/medium800/circuitpython_stm32f405-canbus_bb.png?1611680471)

After reviewing the CAN breakout board I used, I made the following connections between each Feather and its Transceiver:

- Feather **USB** to Transceiver **VCC**
- Feather **D9** to Transceiver **TX**
- Feather **D10** to Transceiver **RX**
- Feather **GND** to Transceiver **GND**

Make the following connections between the two transceivers:

- **H** to **H**
- **L** to **L**

Finally, we need a common GND between the two nodes on the network. If they are not already sharing a GND (for instance, plugged into the same USB hub or USB power bank, or connecting to a GND rail on a breadboard),

- _either_ connect **GND** from Feather 1 to Feather 2
- _or_ connect **GND** from Transceiver 1 to Transceiver 2

## ESP32S2 Metro & External Transceiver

The ESP32S2 has a built in CAN-compatible peripheral (called TWAI in the documentation from Espressif). You can choose any two pins to act as the **RX** and **TX** pins, but when it comes to the sample code you'll need to change&nbsp;`board.CAN_RX` and `board.CAN_TX` to the pins you wired up. I arbitrarily chose `IO05` and `IO06`.

Wiring is reasonably straightforward, but you need to take note of the following:

- Whether the transceiver needs **5V** (more common) or **3.3V** (less common) on its power input pin. On my transceiver, **5V** is required, and comes from the&nbsp; **V<sub>HI</sub>** pin on the Metro
- Whether the **TX** and **RX** pins refer to the microcontroller's point of view or the transceiver's point of view. On my transceiver, **TX** and **RX** refer to the microcontroller's point of view.
- Whether there is an **enable** pin, and whether to set it `True` or `False`

Here's how to wire up two Metro ESP32S2 Express board:

Metro 1 ↔ Transceiver 1 ↔ Transceiver 2 ↔ Metro 2

In the code samples, change the setup line for the CAN object according to the pins you chose, e.g.,:

`can = canio.CAN(rx=board.IO6, tx=board.IO5, baudrate=250_000, auto_restart=True)`

After reviewing the CAN breakout board I used, I made the following connections between each Feather and its Transceiver:

- Metro **V<sub>HI</sub>** to Transceiver **VCC**
- Metro **IO5** to Transceiver **TX**
- Metro **IO6** to Transceiver **RX**
- Metro **GND** to Transceiver **GND**

Make the following connections between the two transceivers:

- **H** to **H**
- **L** to **L**

![circuitpython_esp32s2-canbus_bb.png](https://cdn-learn.adafruit.com/assets/assets/000/096/813/medium640/circuitpython_esp32s2-canbus_bb.png?1604677192)

Finally, we need a common GND between the two nodes on the network. If they are not already sharing a GND (for instance, plugged into the same USB hub or USB power bank, or connecting to a GND rail on a breadboard),

- _either_ connect **GND** from Metro 1 to Metro 2
- _or_ connect **GND** from Transceiver 1 to Transceiver 2

## Feather M4 CAN
Because the transceiver is included, wiring a CAN bus is simple:

- Connect **H** to **H**
- Connect **L** to **L**
- Connect **GND** to **GND** (other ways of providing a common GND are also acceptable, such as powering both devices from the same computer or USB power bank)

![circuitpython_feather-can-2modules_bb.png](https://cdn-learn.adafruit.com/assets/assets/000/096/754/medium640/circuitpython_feather-can-2modules_bb.png?1604516888)

![circuitpython_feather-can-2modules_bb-crop.png](https://cdn-learn.adafruit.com/assets/assets/000/096/755/medium640/circuitpython_feather-can-2modules_bb-crop.png?1604517089)

In the case of the Feather M4 CAN, just insert wires into each screw terminal and then tighten the screw.

Make sure that **H** goes to **H** and **L** to **L** ; Otherwise, the devices will not be able to communicate.

## Mix and Match

Want to make a network out of different boards?&nbsp; Knock yourself out. Just wire each side as above, then connect the **H** , **L** , and **GND** wires between the nodes in the network. For example, you could wire

Metro ESP32S2 ↔ Transceiver 1 ↔ Transceiver 2 ↔ Feather STM32F405

or

Feather STM32F405 ↔ Transceiver ↔ Feather CAN

In principle, you can put more than two nodes on a network by connecting all the H wires together and all the L wires together. However, you also need to understand and may need to modify the "termination resistance" of the bus—that's beyond the scope of this guide (and indeed your humble author's experience)

# CAN Bus with CircuitPython: Using the canio module

## Send and Receive

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.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/FeatherCAN_CircuitPython/listener/code.py

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.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/FeatherCAN_CircuitPython/sender/code.py

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:

```python
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:

```python
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
```

# CAN Bus with CircuitPython: Using the canio module

## Reliable Transmission

This demo shows one of the possible ways you can verify that the intended node has received a message.

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.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/FeatherCAN_CircuitPython/listener-ack/code.py

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.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/FeatherCAN_CircuitPython/sender-ack/code.py

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.

When the receiver receives an acknowledgement packet (an ACK), it sends back one of its own, containing just the 4 byte count value. A different message ID (0x409) is also used.

The sender waits for the ACK. If it is not received shortly, then it re-sends the original message and waits for the ACK again. In this way, the sender knows the receiver has received each message.

Typical output on sending node:

```python
code.py output:
Bus state changed to canio.BusState.ERROR_ACTIVE
Sending message: count=0 now_ms=123231
Received ACK
Sending message: count=1 now_ms=123733
Received ACK
Sending message: count=2 now_ms=124235
Received ACK
```

Typical output on receiving node:

```python
code.py output:
Bus state changed to canio.BusState.ERROR_ACTIVE
No messsage received within timeout
received message: id=408 count=0 now_ms=123231
Sending ACK
received message: id=408 count=1 now_ms=123733
Sending ACK
received message: id=408 count=2 now_ms=124235
Sending ACK
```

# CAN Bus with CircuitPython: Using the canio module

## Code Walkthrough

The various programs share a lot of code, so let's look at what the building blocks are.

Begin by importing the modules that are needed by our code:

```python
import struct
import time

import board
import canio
import digitalio
```

Create the necessary digital pin settings needed to enable the CAN Transceiver chip:

```python
# 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)
```

Create the CAN bus object. Note that all devices on the same bus need to agree on the baudrate!

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

Construct a listener object. This listener will ONLY receive messages sent to the ID `0x408`. If no `matches=` was specified, it would receive all messages. The `timeout=` governs how long the listener will wait for a message. A `Match` object can also specify an optional mask to allow a range of related IDs to be received—see the full documentation for more details.

```python
listener = can.listen(matches=[canio.Match(0x408)], timeout=.1)
```

Now we're ready for the main loop of our program:

```python
while True:
    ...
```

The CAN object's state monitors the health of the bus. The confusingly-named `ERROR_ACTIVE` state actually indicates that all is well. A node that is `ERROR_PASSIVE` will not transmit messages, and one that is `BUS_OFF` will neither transmit messages nor acknowledge messages from other nodes. Because we specified `auto_restart=True` when we created our CAN object, our node will automatically restart itself a short time after entering the `BUS_OFF` state.

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

Create and send a message. In this case, we use the `struct` module to pack our integer data into a sequence of 8 bytes. Messages can range from 0 to 8 bytes of data.

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

Receive a message. One of several things can happen, and we need to deal with them:

- If no message is received before the timeout, message will be None
- If we were listening for more than one message ID, we would want to look at `message.id` and make decisions based on it.
- A message could come in, but not have the expected structure. Here, if the message is not the expected 8 bytes long, we ignore it
- If the message has the expected length, we can take the individual pieces of data out using `struct.unpack`, and act on them.

```python
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)
print(f"received message: count={count} now_ms={now_ms}")
```


## Featured Products

### Adafruit Feather M4 CAN Express with ATSAME51

[Adafruit Feather M4 CAN Express with ATSAME51](https://www.adafruit.com/product/4759)
One of our favorite Feathers, the Feather M4 Express, gets a glow-up here with an upgrade to the SAME51 chipset which has built-in CAN bus support!&nbsp; Like its SAMD51 cousin, the **ATSAME51J19** comes with a **120MHz Cortex M4** with floating point support and...

In Stock
[Buy Now](https://www.adafruit.com/product/4759)
[Related Guides to the Product](https://learn.adafruit.com/products/4759/guides)
### Adafruit Feather STM32F405 Express

[Adafruit Feather STM32F405 Express](https://www.adafruit.com/product/4382)
ST takes flight in this Feather board. The new STM32F405 Feather ([video](https://youtu.be/CZ6TtvYJTeI)) that we designed runs CircuitPython at a blistering 168MHz – our fastest CircuitPython board ever! We put a STEMMA QT / Qwiic port on the end, so you can really easily plug...

Out of Stock
[Buy Now](https://www.adafruit.com/product/4382)
[Related Guides to the Product](https://learn.adafruit.com/products/4382/guides)
### Adafruit Metro ESP32-S2

[Adafruit Metro ESP32-S2](https://www.adafruit.com/product/4775)
What's Metro shaped and has an ESP32-S2 WiFi module? What has a STEMMA QT connector for I2C devices, and a Lipoly charger circuit? What has your favorite Espressif WiFi microcontroller and lots of memory for your next IoT project?

That's right - its the new Adafruit Metro...

In Stock
[Buy Now](https://www.adafruit.com/product/4775)
[Related Guides to the Product](https://learn.adafruit.com/products/4775/guides)

## Related Guides

- [Adafruit STM32F405 Feather Express](https://learn.adafruit.com/adafruit-stm32f405-feather-express.md)
- [Adafruit Metro ESP32-S2](https://learn.adafruit.com/adafruit-metro-esp32-s2.md)
- [Adafruit Feather M4 CAN Express](https://learn.adafruit.com/adafruit-feather-m4-can-express.md)
- [Introducing Adafruit Feather](https://learn.adafruit.com/adafruit-feather.md)
- [MP3 Playback with CircuitPython](https://learn.adafruit.com/mp3-playback-with-circuitpython.md)
- [Animating Animatronics](https://learn.adafruit.com/animating-animatronics.md)
- [Networking in CircuitPython](https://learn.adafruit.com/networking-in-circuitpython.md)
- [No-Code WipperSnapper Summoning Horn](https://learn.adafruit.com/adafruit-io-wippersnapper-summoning-horn.md)
- [SD Card Performance in CircuitPython](https://learn.adafruit.com/microsd-optimization-circuitpython.md)
- [Temperature and Humidity Sensing in Home Assistant with CircuitPython](https://learn.adafruit.com/temperature-and-humidity-sensing-in-home-assistant-with-circuitpython.md)
- [CircuitPython Powered Sip & Puff with ST LPS33HW Pressure Sensor](https://learn.adafruit.com/st-lps33-and-circuitpython-sip-and-puff.md)
- [Blinking an LED with the Zephyr RTOS](https://learn.adafruit.com/blinking-led-with-zephyr-rtos.md)
- [WiFi-Controlled NeoPixel Matrix LED Sign](https://learn.adafruit.com/iot-led-sign.md)
- [Plotting Offline Data - JSONL to CSV files, filters and graphs](https://learn.adafruit.com/plotting-offline-data-jsonl-to-csv-files-filters-and-graphs.md)
- [Deep Sleep with CircuitPython](https://learn.adafruit.com/deep-sleep-with-circuitpython.md)
