Ken CTO of Canis Automotive Labs

Using a CANPico as a USB CAN bus adapter for Wireshark

Here I will explain how one of our CANPico boards can be made into a USB CAN adapter firmware to display CAN frames on the bus in Wireshark.

First, let’s look at building the simplest possible CAN bus monitor:

The mon() function

This function just receives all the CAN frames via the recv() call then prints them out. Really easy. It’s included in the Python examples library. Also included is a simple function called periodic() that just sends a CAN frame periodically with a 4-byte payload that’s an incrementing integer, which saves us a bit of typing and we can test out the monitor by altering the rate we receive CAN frames.

It’s very simple to run too: just invoke mon() in the library instance.

The mon() example

If the bus traffic is high then this monitor doesn’t work very well: the time taken by the print() function is huge: it has to work out how to print a frame, copy them to a buffer, then push them over a serial port (that’s connected to the REPL command line), which can take several milliseconds, far longer than the time between frames. So we want a better monitor and to move the displaying of frames to a faster host. The host I’m using is a Raspberry Pi 4.

To get data from a microcontroller to a host PC requires a serial link and a protocol to run over the link. In our case the serial link is a second USB serial port (this is baked into the CANPico MicroPython firmware). The protocol for the serial line is the MIN protocol. This was designed a few ago back to address a fairly common problem: a way for an embedded microcontroller (including small 8-bit ones) to talk reliably to a host (like a PC) over serial.

All the common serial protocols are either too heavyweight to run in software (like HDLC) or require deep control of the serial line (like LIN) or are just inappropriate for a small device with tiny amounts of RAM (like zmodem). So Microcontroller Interconnect Network was born. It’s been used for a while, and Canis Labs has used it for automating tests by sending commands to and from a CAN-connected device. It’s so useful that we embedded it into the MicroPython firmware for our CANPico boards.

MIN comes in two layers: the bottom layer is a simple framing system that uses character stuffing to delimit frame headers (avoiding the common problem of starting communication part way through a frame and mistaking a payload for a start of frame). This frame protocol is designed to be secure, with a strong CRC so that a frame is discarded if it has errors. It suits an application where a small microcontroller is sending sensor data periodically, and dropping a frame from noise isn’t a problem because the next reading will be ready shortly. But some applications require much higher reliability (e.g. uploading logs) and so MIN has the MIN-T layer: a reliable transport protocol with a sliding window and acknowledgements. This is the API baked into the CANPico MicroPython firmware.

Back to turning CANPico into a USB CAN bus adapter. It’s really simple: just use the minmon() function in the library. This is a really simple function:

The minmon function

We just initialize an instance of the MIN class, then read the CAN frames with the normal MicroPython CAN function recv() but with one extra parameter: as_bytes=True. This tells the CAN API to return received CAN frames not as a list of CANFrame instances but as a block of bytes (each CAN frame is encoded as 19 bytes). The bytes are then sent over MIN to the host. Here a MIN ID of 1 is used to indicate the payload contains byte-encoded CAN frames (in the future we are going to use other MIN IDs to add support for transmitting frames from the host and for indicating when frame was been transmitted).

The MIN repository includes a Python implementation of MIN which the host can use to talk to the embedded side. I’ve just uploaded to the MIN repository a simple commandline tool in Python that connects to a CANPico board over a serial port, receives MIN frames containing CAN frames from the minmon() function running on the CANPico board. This tool is implemented in and is straightforward. The MIN handling is really easy:

The host MIN function

We just open a connection to the board (sending it a transport reset to sync the transport layer in the CANPico). The MIN frame payloads are then sent to be decoded into CAN frames and then encoded into the PCAPNG packet capture format that Wireshark understands.

To run the commandline tool just specify the serial port to use (normally the second of a pair created when the CANPico is plugged in) and then pipe the output into Wireshark:

Launching Wireshark

And that’s it! Wireshark will display the CAN frames on the bus:

Running Wireshark

I’ve made a short video demo of this working:

This bus analyzer is already quite sophisticated: the timestamps are to microsecond resolution (taken directly from the CAN controller) and it even handles error frames. There are some things that need to be done to polish it, such as creating 64-bit timestamps rather than just passing in the raw 32-bit timestamps (which overflow and become negative after 35 minutes). But it’s the basis of a sophisticated open-source CAN tool.

The CANPico board is a really versatile CAN solution: it can be used as a probe for a logic analyzer (especially when used with our sophisticated Sigrok can2 CAN protocol decoder) and now it can be used as a bus monitor with Wireshark. And we have future plans to add support for making our CAN Python API available on a host by using MIN to communicate with a proxy on the CANPico.

comments powered by Disqus