A comprehensive, low-level, platform-agnostic Rust driver for the AS5600 magnetic rotary encoder (12-bit contactless potentiometer). Built on embedded-hal 1.0, it provides direct access to all device registers and OTP programming functions.
- Features
- Installation
- Usage Examples
- Interface Abstraction
- I2C Bus Sharing
- Safety Warning (OTP)
- Support
- License
- no_std Support: Ready for bare-metal microcontrollers (ESP32, STM32, nRF, etc.).
- Full Register Map: Complete coverage of ZPOS, MPOS, MANG, CONF, STATUS, RAW_ANGLE, ANGLE, AGC, and MAGNITUDE.
- Hardware Configuration: Support for Hysteresis, Power Modes, PWM settings, and Fast/Slow Filters.
- Diagnostics: Methods to monitor magnet detection, magnetic field strength, and Automatic Gain Control (AGC).
- OTP Programming: Permanent burning of settings protected by a Command Token pattern to prevent accidental execution.
- AS5600L Support: Change and permanently store custom I2C addresses (requires
AS5600Lfeature). - Unified Async/Sync: Identical logic for both modes thanks to internal macro unification. Full compatibility with
embedded-hal-async1.0. - Optimized Reads: Fetch both angle and magnet status in a single I2C transaction via
read_angle_with_status. - Fluent Validation: Chainable health checks for magnet detection and field strength.
- Mocking Support: Built-in hardware emulator for testing and simulation, including I2C bus failure simulation.
- defmt Support: High-efficiency logging for embedded systems (behind the
defmtfeature). - Smart Configuration: Builder pattern with intelligent Read-Modify-Write logic to preserve unedited settings.
- Trait-based Interface:
AS5600InterfaceandAS5600AsyncInterfacetraits allow easy swapping between real hardware and mocks. - Cross-Platform: Support for Linux (SBCs like Raspberry Pi), ESP32 (std & no_std), and any other platform implementing
embedded-hal.
Add this to your Cargo.toml:
[dependencies]
# Minimal synchronous version (no-std compatible by default)
AS5600-Driver = "0.1.2"
# Full version with async, mock and AS5600L support
AS5600-Driver = { version = "0.1.2", features = ["async", "mock", "AS5600L"] }async: Enables asynchronous support usingembedded-hal-async.mock: Enables the hardware mock emulator (requiresstd).std: Enables standard library support.anyhow: Enables integration withanyhowcrate (requiresstd).defmt: Enablesdefmt::Formatimplementation for all public structures.AS5600L: Enables support for AS5600L specific features (I2C address management).
This method is the most efficient and safest way to get data, as it verifies magnet health and reads the angle in one I2C go.
// Chainable validation: check if magnet exists and field strength is OK
let result = encoder.read_angle_with_status()?
.check_magnet_all()?;
println!("Angle: {}, Magnet Detected: {}", result.angle, result.status.detected);let i2c = I2cdev::new("/dev/i2c-1")?;
// Use default address (0x36)
let mut encoder = AS5600Driver::new(i2c);
// OR use a custom address (useful for AS5600L)
// let mut encoder = AS5600Driver::with_address(i2c, 0x42);
let raw = encoder.read_raw_angle()?;
let filtered = encoder.read_angle()?;
let status = encoder.get_magnet_status()?;
let magnitude = encoder.get_magnitude()?;
let agc = encoder.get_agc()?;
let burn_count = encoder.get_burn_count()?;
let conf = encoder.get_config()?;
let det_sym = if status.detected { "โ
YES" } else { "โ NO " };
let low_sym = if status.too_weak { "โ ๏ธ LOW " } else { "โ
OK " };
let high_sym = if status.too_strong { "โ ๏ธ HIGH" } else { "โ
OK " };
let wd_status = if conf.watchdog { "โก ON " } else { "๐ค OFF" };
let pm_str = format!("{:?}", conf.power_mode);
let hyst_str = format!("{:?}", conf.hysteresis);
let out_str = format!("{:?}", conf.output_stage);
let pwm_str = format!("{:?}", conf.pwm_frequency);
let slow_str = format!("{:?}", conf.slow_filter);
let fast_str = format!("{:?}", conf.fast_filter_threshold);All examples provide a real-time monitoring dashboard as shown below:
Typical real-time diagnostic output from the provided examples.
We provide several ready-to-use examples for different environments:
- ESP32 Dashboard (std): A real-time terminal dashboard for ESP32 using the
stdlibrary andesp-idf-hal. - ESP32 Dashboard (no_std): Bare-metal implementation for ESP32 using
esp-hal(no operating system). - Linux Dashboard: Using the sensor on Linux-based SBCs (Raspberry Pi, etc.) via
/dev/i2c-x. - Mock Simulation: Hardware-free simulation for testing UI and logic on your PC.
- Async Mock Simulation: Demonstrates asynchronous usage with
tokioandembedded-hal-async.
The driver features a "smart" configuration system that minimizes I2C traffic and prevents accidental overwriting of settings. Using the apply_config method with a ConfigurationBuilder, only the registers containing modified fields are accessed.
If a register needs partial update, the driver performs a Read-Modify-Write cycle; if all fields in a register are set, it performs a direct Write.
// Only changes watchdog and power mode, preserving other settings
encoder.apply_config(
Configuration::builder()
.watchdog(false)
.power_mode(PowerMode::LPM1)
)?;// 1. Change address in volatile memory (applied immediately)
encoder.set_address(0x42)?;
// 2. (Optional) Burn the new address permanently
let token = BurnToken::confirm_permanent_burn();
encoder.permanent_burn_address(token)?;Using AS5600Interface or AS5600AsyncInterface allows your application logic to be independent of the specific I2C implementation.
use AS5600_Driver::AS5600Interface;
// This function works with ANY synchronous sensor implementation (Real or Mock)
fn run_diagnostic(encoder: &mut impl AS5600Interface) -> anyhow::Result<()> {
let diag = encoder.read_all_diagnostics()?;
println!("Position: {}, Detected: {}", diag.angle, diag.magnet_status.detected);
Ok(())
}The AS5600 has a fixed I2C address (0x36).
To use multiple AS5600 sensors on the same bus, you must use an I2C multiplexer (e.g., TCA9548A).
To share the bus with other device types, use a bus manager like embedded-hal-bus:
// Using a reference (&mut) to the I2C bus
let mut bus = I2cDriver::new(...)?;
let mut encoder1 = AS5600Driver::new(&mut bus);
// Other sensors on the same bus must have different addresses
let mut other_sensor = OtherSensor::new(&mut bus, 0x42); The AS5600 supports permanent burning of settings to its One-Time Programmable (OTP) memory. This is an irreversible operation. To prevent accidental execution, the driver uses the Command Token pattern.
use AS5600_Driver::BurnToken;
// 1. Create a token to confirm your intent
let token = BurnToken::confirm_permanent_burn();
// 2. Perform the burn
sensor.permanent_burn_settings(token)?;permanent_burn_settings(token): Programs ZPOS and MPOS. Max 3 times.permanent_burn_config(token): Programs CONF register. ONLY ONCE.
If you find this extension useful and want to support development or speed up new features:
Donate via:
- ๐บ๐ฆ Donatello โ Ukrainian service supporting:
- ๐ณ Visa/Mastercard
- ๐ช Cryptocurrency (USDT)
- ๐ฆ Other payment methods
- ๐ PayPal: [email protected]
Your support helps keep this project alive and growing. Thank you! / ะัะบัั ะทะฐ ะฟัะดััะธะผะบั! ๐๐
You can contact me via telegram or [email protected].
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.