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