Did you know? Initializing CAN interfaces with systemd-networkd

Chris Fiege | | didyouknow, iobus, can-bus

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

Further Readings

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.


The LXA IOBus line of lab automation devices

I would like to present to you the LXA IOBus, a CAN-based ecosystem consisting of a protocol, a gateway server and new class of Linux Automation GmbH devices, including the Ethernet-Mux and the 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

Enrico Jörns | | didyouknow, rauc

Being able to robustly and securely update embedded systems and IoT devices in the field is a key requirement of every product today. The update framework RAUC is the basis for a modern and future-proof solution. In this showcase we present the basic principles of a fail-safe update system and how Pengutronix can support you with implement this for your platform.


Showcase: Graphics on i.MX8MP

Enabling the graphics output pipeline on the i.MX8M Plus (i.MX8MP for short), is the most recent example on how open-source and upstream driver support for GPU and display engines can reduce effort and risk in a new project.