Did you know? Initializing CAN interfaces with systemd-networkd

End of January systemd 250 was added to Debian bullseye backports. With a lots of new features and fixes now comes the possibility to set the timing of CAN bus interfaces with systemd-networkd. In this blogpost I will take a look at why this helps us maintain our embedded Linux labs.

Why CAN in our labs?

At Pengutronix we run a lot of labs where we can remote control embedded Linux devices. We use these labs for interactive development and continuous testing. If you want to have a closer look at our lab infrastructure you should take a look at my talk from ELC 2021 or into our blogpost about remote working.

tl;dr: Our labs are build around a 19" server rack, an Ethernet switch, a mains power switch, a fanless x64 mini-server, and lots of USB hubs and USB devices.

One thing we learned over the years: Do not use USB if you want your embedded Linux lab to be reliable. So we started to reduce the number of USB devices where possible. Whereever we need GPIOs (for example to control the boot mode or reset of a device under test) we nowadays use the CAN-based LXA IOBus in our labs.

So reducing the number of USB devices comes at the price of maintaining a new bus in our labs.

In our labs we use Peak Systems Mini-PCIe CAN FD cards. (But to be honest: On our developer's desk we often use the more cost-sensitive and Open Source and Open Hardware candleLight.)

The old way

Until now configuring this bus was a mishmash of systemd-networkd and some additional commands. networkd renamed the network device to a well-known name and set up the bitrate:

cfi@rlabA-srv:~$ cat /etc/systemd/network/80_can0-iobus.link
# This file is managed by ptx-admin-ansible. Changes will be overwritten.
[Match]
OriginalName=can0

[Link]
Name=can0_iobus

cfi@rlabA-srv:~$ cat /etc/systemd/network/80_can0-iobus.network
# This file is managed by ptx-admin-ansible. Changes will be overwritten.
[Match]
Name=can0_iobus

[CAN]
BitRate=100000
FDMode=False
RestartSec=10s

But: Timing on a CAN bus is defined by a lot more parameters than just the bitrate. Other important parameters are:

  • Sampling Point: The point in time inside a bit on the bus at which the value of the bit is determined.
  • Time Quanta: The length of a sub-bit. Usually given in nanoseconds.
  • Synchronization Jump Width: The number of time quanta the clocks of sending and receiving node are allowed to deviate. Especially important if some nodes on the bus derive their clock from a trimmed RC-oscillator rather than a crystal.

Since we want to set a specific sampling point and synchronization jump width for the LXA IOBus we had to set these parameters after systemd-networkd has already set up our interface. This was cumbersome done as ExecStartPre-statements in the LXA IOBus Server service-unit:

cfi@rlabA-srv:~$ cat /etc/systemd/system/lxa-iobus.service
# This file is managed by ptx-admin-ansible. Changes will be overwritten.
[Unit]
Description=LXA iobus Server
After=network.target

[Service]
Type=simple
ExecStartPre=/bin/mkdir -p /var/cache/lxa-iobus
ExecStartPre=/bin/ip l set can0_iobus down
ExecStart=/bin/ip link set can0_iobus type can tq 500 prop-seg 9 phase-seg1 5 phase-seg2 5 sjw 4
ExecStartPre=/bin/ip l set can0_iobus up
ExecStart=/usr/ptx-venvs/lxa-iobus/bin/lxa-iobus-server -l WARN --lss-address-cache-file /var/cache/lxa-iobus/lss-cache --host "*" can0_iobus
Environment="PYTHONUNBUFFERED=1"
Restart=always
RestartSec=30

[Install]
WantedBy=multi-user.target

While writing this blogpost I even realized that setting the detailed timing in the lxa-iobus.service -unit overrides the bitrate set in the .network -file. So consolidating this seems a good idea 😀.

The new way

Thanks to yuwata for PR 20442! This change now allow us to set these additional timing parameters using systemd-networkd.

Taking a look into the documentation we can change our .network file as follows:

cfi@rlabA-srv:~$ cat /etc/systemd/network/80_can0-iobus.network
[Match]
Name=can0_iobus

[CAN]
TimeQuantaNSec=500
PropagationSegment=9
PhaseBufferSegment1=5
PhaseBufferSegment2=2
SyncJumpWidth=4
RestartSec=10

Note that you can only define the bitrate or the detailed timing parameters since defining both would be overdetermined. In this case we define the detailed timing parameters. We can control the actual bitrate using:

cfi@rlabA-srv:~$ ip -detail link show dev can0_iobus
5: can0_iobus: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10
    link/can  promiscuity 0 minmtu 0 maxmtu 0
    can state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 10000
      bitrate 100000 sample-point 0.750
      tq 500 prop-seg 9 phase-seg1 5 phase-seg2 5 sjw 4
      peak_canfd: tseg1 1..256 tseg2 1..128 sjw 1..128 brp 1..1024 brp-inc 1
      peak_canfd: dtseg1 1..32 dtseg2 1..16 dsjw 1..16 dbrp 1..1024 dbrp-inc 1
      clock 80000000 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535

Weiterführende Links

labgrid Tutorials

This week, we started our series of YouTube labgrid tutorials. In the next few weeks we will publish more video tutorials showing you labgrid's features and giving you handy tips and tricks.


Lab-Automatisierung mit LXA IOBus

Etwas über dreieinhalb Jahre sind seit unserer letzten Produktankündigung vergangen, seitdem haben wir viele Normen gelesen, Dinge über Webshops und den Alltag der Elektronikfertigung gelernt und still und heimlich an neuen Produkten getüftelt. Heute möchte ich das LXA IOBus-System vorstellen, bestehend aus einem CAN-basierten Kommunikationsprotokoll, einem zugehörigen Gateway-Server und einer neuen Klasse an Linux Automation GmbH Produkten. Zwei dieser neuen Produkte sind der Ethernet-Mux und das 4DO-3DI-3AI Input/Output-Board.


First Steps using the candleLight

So you went and got yourself one of our fancy rocket-penguin branded CandleLight dongles or, being the die hard hacker you are, went and soldered one up in your toaster oven labeled "not food safe". What's next then? How do you use this thing? Let's answer these question by grabbing a Raspberry Pi and exploring some of the possibilities.


Showcase: Fail-Safe (OTA) Field Updating

Eingebettete Systeme und IoT-Geräte robust und sicher im Feld updaten zu können ist heute eine Kernanforderung jedes Produkts. Das Update-Framework RAUC ist die Basis für eine moderne und zukunftsfähige Lösung. In diesem Showcase zeigen wir die Grundprinzipien eines ausfallsicheren Update-Systems und wie Sie dieses mit Unterstützung von Pengutronix für Ihre Plattform realisieren können.


Showcase: Grafik auf i.MX8MP

Die Inbetriebnahme der Grafikausgabepipeline auf dem i.MX8M Plus (kurz i.MX8MP) ist ein aktuelles Beispiel dafür, wie Open Source und Upstream-Treiber für GPUs und Displayeinheiten Aufwand und Risiko im Projekt reduzieren können.