Skip to content

Soccentric/simple-device-driver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

simple-device-driver

Software‑based PWM driver for Raspberry Pi – flexible, multi‑channel, user‑space configurable


Overview

simple-device-driver is a Linux kernel module that implements a custom PWM (Pulse‑Width Modulation) generator by bit‑banging GPIO pins on a Raspberry Pi. Unlike the limited hardware PWM channels built into the SoC, this driver creates PWM signals entirely in software using high‑resolution kernel timers and tight timing loops. The driver exposes a clean user‑space interface (via ioctl and a sysfs attribute directory) that lets applications set the PWM frequency and duty cycle on any GPIO pin at runtime. This makes it possible to drive dozens of independent PWM outputs simultaneously, which is invaluable for robotics, LED lighting, motor control, or any project where the number of hardware PWM channels is a bottleneck.

The core idea is simple: the driver schedules periodic timer callbacks that toggle the chosen GPIO pin high for a calculated “on‑time” and low for the remainder of the period. By adjusting the on‑time and the period length on the fly, the PWM characteristics can be changed without unloading the module. The implementation carefully balances CPU usage with timing accuracy, using hrtimer in nanosecond mode and locking mechanisms to avoid race conditions.

Because the driver lives in kernel space, it can achieve sub‑microsecond timing resolution that would be difficult to obtain from pure user‑space busy‑loops. At the same time, the user‑space API keeps development straightforward: a small C library or even shell scripts can open /dev/simple_pwm and issue ioctl commands, or write to /sys/class/simple_pwm/... files. The project is fully open‑source, well‑documented, and designed for easy extension to support additional features such as PWM chaining, polarity inversion, or per‑channel enable/disable flags.


Key Features

  • GPIO‑agnostic PWM – any GPIO pin can be turned into a PWM output, bypassing the limited hardware PWM resources.
  • Dynamic configuration – change frequency (1 Hz – 20 kHz) and duty cycle (0 % – 100 %) on the fly via ioctl or sysfs.
  • Multi‑channel support – instantiate multiple PWM channels concurrently, each with independent parameters.
  • High‑resolution timing – uses Linux hrtimer with nanosecond granularity for precise edge placement.
  • Simple user‑space API/dev/simple_pwm character device + ioctl commands; optional sysfs entries for scripting.
  • Kernel‑safe operation – employs spinlocks and atomic variables to protect shared state, preventing deadlocks.
  • Debug facilities – debugfs entries provide real‑time statistics (runtime, jitter, missed deadlines).

Benefits

  • Scalability – eliminates the hardware PWM channel limit; you can drive dozens of LEDs, servos, or fans simultaneously.
  • Flexibility – adjust PWM parameters without recompiling or reloading the driver, ideal for prototyping and adaptive control loops.
  • Portability – the driver is written against the generic GPIO API, making it easy to port to other SBCs (e.g., BeagleBone, Odroid).
  • Educational value – showcases kernel‑timer programming, GPIO handling, and character‑device interfacing for developers learning kernel module development.
  • Open source – freely available under the MIT license, encouraging community contributions and custom extensions.

Getting Started

Prerequisites

  • Raspberry Pi running a recent Debian‑based distro (e.g., Raspberry Pi OS) with kernel headers installed: sudo apt-get install raspberrypi-kernel-headers build-essential.
  • A user with sudo privileges to load/unload kernel modules.

Build the Module

git clone https://github.com/yourname/simple-device-driver.git
cd simple-device-driver
make

The Makefile automatically picks up the correct kernel source directory via $(KERNELDIR).

Load / Unload

sudo insmod simple_pwm.ko
# Verify loading
dmesg | tail

To unload:

sudo rmmod simple_pwm

User‑Space Interaction

Using ioctl (C example)

#include <fcntl.h>
#include <sys/ioctl.h>
#include "simple_pwm.h"   // generated header with ioctl numbers

int fd = open("/dev/simple_pwm", O_RDWR);
struct pwm_config cfg = { .gpio = 18, .freq_hz = 1000, .duty = 50 };
ioctl(fd, SIMPLE_PWM_SET_CONFIG, &cfg);
close(fd);

Using sysfs

# List available channels
ls /sys/class/simple_pwm/
# Set parameters
echo 18 > /sys/class/simple_pwm/pwm0/gpio
echo 2000 > /sys/class/simple_pwm/pwm0/frequency
echo 75 > /sys/class/simple_pwm/pwm0/duty_cycle

Both methods apply changes instantly.


Performance Considerations

Because PWM is generated in software, each active channel consumes CPU cycles proportional to its frequency. For low‑frequency signals (< 1 kHz) the impact is negligible, but high‑frequency or many concurrent channels can saturate a single CPU core. The driver mitigates this by using a single high‑resolution timer that schedules the next edge for the earliest pending channel, reducing context switches. Users should monitor the cpu_load debugfs entry and adjust the number of active channels or lower the frequency if the system becomes CPU‑bound.


Contributing

Contributions are welcome! Please fork the repository, create a feature branch, and submit a pull request. Guidelines:

  1. Follow the Linux kernel coding style (scripts/checkpatch.pl).
  2. Add or update documentation in README.md and doc/.
  3. Include unit tests where possible (e.g., using kselftest).

License

This project is released under the MIT License – see the LICENSE file for details.


Acknowledgments

  • The Raspberry Pi Foundation for providing excellent GPIO documentation.
  • The Linux kernel community for the robust hrtimer and GPIO subsystems.

Happy hacking!

About

Kernel module and application for simple-device-driver

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published