1 unstable release
Uses new Rust 2024
| 0.1.0 | Dec 28, 2025 |
|---|
#630 in Embedded development
45KB
806 lines
pot-head
A no_std Rust library for processing potentiometer inputs in embedded systems.
Overview
pot-head transforms raw ADC values into clean, processed output values through configurable filters, curves, and response modes.
The library provides a complete processing pipeline for analog inputs in resource-constrained embedded systems. Perfect for audio equipment, industrial control panels, and any embedded device with physical controls.
Design Philosophy: Pure mathematical abstraction—no I/O, no interrupts, no HAL integration. Just transformations.
Key Features
Core Functionality
- ✅ Dual type parameters - Separate input (ADC) and output types (
PotHead<u16, f32>) - ✅ Response curves - Linear and logarithmic
- ✅ Noise filtering - Exponential moving average and moving average
- ✅ Hysteresis modes - Schmitt trigger and change threshold for stability
- ✅ Snap zones - Snap-to values and dead zones for flexible control configuration
- ✅ Grab modes - Pickup and PassThrough for avoiding output jumps
- ✅ Static ROM config - Zero-copy configuration in flash memory
What This Library Excludes
- ❌ Hardware I/O (ADC reads, GPIO, timers)
- ❌ HAL integration
- ❌ Interrupt handling
- ❌ Dynamic memory allocation
See docs/FEATURES.md for complete feature documentation.
Processing Pipeline
Input processing follows a fixed order:
Input (TIn)
→ Normalize to f32 (0.0-1.0)
→ Noise Filter
→ Response Curve
→ Hysteresis
→ Snap Zones
→ Grab Mode
→ Denormalize to TOut
→ Output (TOut)
Quick Start
Add Dependency
[dependencies]
pot-head = "0.1"
# Optional features
pot-head = { version = "0.1", features = ["std-math", "moving-average", "grab-mode"] }
Example - Logarithmic Volume Control
use pot_head::{PotHead, Config, ResponseCurve, NoiseFilter, HysteresisMode, SnapZone, SnapZoneType};
// Define static configuration (stored in flash)
static VOLUME_CONFIG: Config<u16, f32> = Config {
input_min: 0,
input_max: 4095, // 12-bit ADC
output_min: -60.0, // -60dB to 0dB (silence to unity gain)
output_max: 0.0,
curve: ResponseCurve::Logarithmic, // Requires 'std-math' feature
filter: NoiseFilter::ExponentialMovingAverage { alpha: 0.3 },
hysteresis: HysteresisMode::ChangeThreshold { threshold: 0.01 }, // 1% threshold
snap_zones: &[
SnapZone::new(-60.0, 0.02, SnapZoneType::Snap), // Snap to min below 2%
SnapZone::new(0.0, 0.02, SnapZoneType::Snap), // Snap to max above 98%
],
grab_mode: GrabMode::PassThrough,
};
// Validate at compile time
const _: () = {
match VOLUME_CONFIG.validate() {
Ok(()) => {},
Err(e) => panic!("Invalid config"),
}
};
// Create potentiometer instance from static config
let mut volume_pot = PotHead::new(&VOLUME_CONFIG);
// In your main loop:
loop {
let adc_value: u16 = read_adc(); // Your hardware-specific ADC read
let volume_db: f32 = volume_pot.update(adc_value);
set_audio_volume(volume_db); // Your application logic
}
Documentation
- FEATURES.md - Complete feature reference with usage examples
- Interactive Example - Full working demonstration (terminal-based)
cargo doc --open- API documentation
Feature Flags
| Feature | Description | Dependencies | Default |
|---|---|---|---|
std-math |
Logarithmic response curves | libm |
✅ |
grab-mode |
Pickup/PassThrough modes | None | ✅ |
moving-average |
Moving average filter | heapless |
❌ |
Memory Footprint
Static ROM Configuration:
- Config stored in flash: 40-44 bytes (depends on type parameters)
- Runtime state in RAM: 188 bytes per instance
Typical costs:
PotHead<u16, u16>(integer scaling): 188 bytes RAMPotHead<u16, f32>(typical audio/control): 188 bytes RAM- Filter state: Included in base cost
- Moving average buffer:
WINDOW_SIZE × 4bytes additional (if enabled)
Binary sizes (library logic):
- Cortex-M0+ (no FPU): 1.7KB (minimal) to 2.9KB (default with std-math)
- Cortex-M4F (with FPU): 198B (minimal) to 624B (full features)
Measured on ARM Cortex-M4F/M7 (thumbv7em-none-eabihf). See reports/sizeof_report.md and reports/binary_report.md for detailed analysis.
Performance
Update cycle (update() call):
| Platform | Configuration | Time | Cycles |
|---|---|---|---|
| RP2040 (Cortex-M0+, 125 MHz, no FPU) | Baseline (linear, no filter) | 8.99µs | 1,123 |
| With EMA filter | 12.72µs | 1,590 | |
| With logarithmic curve | 32.52µs | 4,065 | |
| Full featured | 47.02µs | 5,877 | |
| RP2350 (Cortex-M33F, 150 MHz, with FPU) | Baseline (linear, no filter) | 0.86µs | 128 |
| With EMA filter | 1.00µs | 150 | |
| With logarithmic curve | 1.76µs | 264 | |
| Full featured | 2.28µs | 341 |
See reports/rp2040_benchmarks.md and reports/rp2350_benchmarks.md for complete benchmark data.
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Acknowledgments
Designed for the Rust embedded ecosystem.
Maintained by: Esben Dueholm Nørgaard (HybridChild)
Dependencies
~79–450KB