Home

Announcing libhwpwm

The way userspace programs can interact with PWM hardware on a Linux system is via the files in /sys/class/pwm directory. This is really convenient for shell scripts, however, most robotics projects that make use of PWM devices (such as the PCA9685) are not written in bare sh, so this subsystem is often unutilised. Most hobbyists opt for bit-banging a PWM signal instead, using a GPIO pin, but this is not just wasteful, it’s also inaccurate (Linux isn’t hard real-time).

I use C for all the robot code I write, because it’s almost never a pleasant experience, dealing with Python libraries that use nonstandard interfaces (RPi.GPIO comes to mind) to control hardware. By using C, I can easily use close-to-the-kernel libraries like libgpiod, and libi2c (part of i2c-tools) that are guaranteed to work on any platform assuming they use the standard kernel interfaces to do their bidding.

One thing that I have not found a small and simple library for is PWM (there is sysfspwm but that one is written in C++ and uses libudev under the hood, which has been deprecated and it uses CMake as it’s build system instead of a simple Makefile), and dealing with filepaths is clunky in C.

Hence, libhwpwm was born. This library aims to be a very thin abstraction layer over the sysfs interface (really, just a few functions that read from and write to sysfs nodes). The build system is just a single POSIX Makefile, to simplify packaging. The user-facing API might receive slight changes until we hit 1.0. All functions are documented, however you should keep the kernel’s documentation on using PWM close to know which attribute does what. It doesn’t require anything special, aside from scdoc to generate man pages from markdown.

In the future, I would also like to make bindings for Python and maybe find some way to integrate it into existing libraries like gpiozero, so people can automatically use the PWM hardware on their SBCs without code changes.

The library is already packaged for Alpine Linux, and I will make a Debian package for Raspberry Pi OS once I stop being lazy :P