AD7124 Driver
A platform-independent Rust driver for the Analog Devices AD7124 family (AD7124-4/AD7124-8), precision 24-bit sigma-delta ADCs with integrated PGA and reference.
Features
- Zero Dependencies: Core driver works without external dependencies
- Optional embedded-hal Integration: Seamless integration when needed
- Sync & Async Support: Both synchronous and asynchronous operations
no_stdCompatible: Perfect for embedded systems- C FFI Ready: Prepared for C/C++ integration with full API support
- Simple API: Clean and intuitive interface
- High Precision: 24-bit resolution with low noise
- Temperature Sensor: Built-in temperature measurement
- Embassy Ready: Full async/await support with Embassy templates
- Enhanced Channel Management: Real-time status, non-blocking ops, multi-channel batch
- Direct Hardware Access: No stale cache, always accurate status readings
Hardware Features
The AD7124 family supports:
- 24-bit resolution
- Up to 19,200 SPS sample rate (AD7124-8)
- Integrated PGA (1x to 128x gain)
- Internal 2.5V reference
- 4 channels (AD7124-4) or 8 channels (AD7124-8)
- 16 differential or 32 single-ended inputs
- Built-in temperature sensor
- Digital filter with 50/60Hz rejection
- SPI interface up to 5MHz
- Low power consumption
Installation
Add to your Cargo.toml:
[]
= "0.4.0"
Or with specific features:
[]
= { = "0.4.0", = ["full-async", "defmt"] }
Quick Start
Basic Synchronous Usage
use ;
// Create SPI transport (example with embedded-hal)
let transport = new;
// Create and initialize driver
let mut adc = new?;
adc.init?;
// Setup single-ended measurement on channel 0
adc.setup_single_ended?;
// Read voltage
let voltage = adc.read_voltage?;
println!;
Asynchronous Usage with Embassy
use ;
use ;
// Create SPI transport with DMA
let spi = new;
let transport = new;
// Create and initialize async driver
let mut adc = new?;
adc.init.await?;
// Setup differential measurement
adc.setup_differential.await?;
// Continuous measurement loop
loop
Device Type Detection
use ;
let transport = new;
// Auto-detect device type
let mut adc = new_with_detection?;
adc.init?;
// Or specify device type explicitly
let mut adc = new?;
// Manual initialization when needed
adc.init?;
Advanced Configuration
use ;
// Configure ADC control settings
let adc_config = AD7124Config ;
adc.configure_adc.await?;
// Configure setup (PGA, reference, etc.)
let setup_config = SetupConfig ;
adc.configure_setup.await?;
// Configure digital filter
let filter_config = FilterConfig ;
adc.configure_filter.await?;
Enhanced Channel Management
The driver provides advanced channel management and data reading capabilities:
// Enhanced Channel Control
adc.enable_channel?; // Enable/disable specific channel
let enabled = adc.is_channel_enabled?; // Check if channel is enabled (real-time)
let active = adc.get_active_channel?; // Get currently active channel
let current = adc.current_channel?; // Read current channel from status register
// Non-blocking Operations
if adc.is_data_ready?
let = adc.read_data_with_status?; // Read with channel info
adc.wait_conv_ready?; // Wait with optional timeout (ms)
// Channel-Specific Reading
let raw = adc.read_channel_data?; // Read specific channel raw data
let voltage = adc.read_channel_voltage?; // Read specific channel voltage
// Multi-Channel Operations
let channels = ;
let data = adc.read_multi_channel?; // Read multiple channels
let voltages = adc.read_multi_voltage?; // Read multiple voltages
let enabled = adc.get_enabled_channels?; // Get all enabled channels
let scan = adc.scan_enabled_channels?; // Scan & read all enabled channels
Key Features
- Real-time Hardware Access: All status queries read directly from hardware registers (no stale cache)
- Non-blocking Operations: Check data ready status without blocking
- Channel-Specific Operations: Read from specific channels without manual switching
- Batch Operations: Efficiently read multiple channels in one call
- Fast Data Access: Bypass status checks for high-speed acquisition
- ✅ Dynamic Channel Management: Enable/disable channels at runtime
Examples
The repository includes comprehensive examples:
Rust Examples
embassy_usage- Complete Embassy async example with enhanced channel management features
C FFI Examples
c_ffi_example- Basic C FFI usage with static memory allocationc_embedded_example- Embedded-specific patterns with HAL simulation
Run examples with:
# Rust Embassy Example
# C FFI Examples
# Basic C FFI example
# Embedded C example
Features
Available Features
embedded-hal- embedded-hal integration (default)embedded-hal-async- async embedded-hal supportasync- async/await support (requires embedded-hal-async)full-async- complete async functionalitydefmt- defmt logging supportcapi- C FFI interfacepanic-handler- Basic panic handler for testing (applications should provide their own)
Feature Combinations
- Default:
embedded-hal - Full Async:
full-async - Embassy Ready:
full-async,defmt - Minimal:
default-features = false - C FFI:
capi
Device Variants
ad7124-4- Enable AD7124-4 specific featuresad7124-8- Enable AD7124-8 specific features
Architecture
The driver follows a modern layered architecture with core-transport separation:
┌─────────────────────────────────────┐
│ Application Layer │
├─────────────────────────────────────┤
│ High-Level API Layer │
├─────────────────────────────────────┤
│ AD7124Sync/Async Drivers │
├─────────────────────────────────────┤
│ AD7124Core Logic │
│ (Transport Independent) │
├─────────────────────────────────────┤
│ Transport Abstraction │
│ (SyncSpiTransport/AsyncSpi) │
├─────────────────────────────────────┤
│ Hardware Implementation │
│ (embedded-hal SPI) │
└─────────────────────────────────────┘
Key Architecture Benefits
- Core-Transport Separation: Business logic completely independent of transport layer
- Unified Naming: Family-consistent type naming (AD7124xxx throughout)
- Simple Construction: Direct driver construction for both sync and async
- Three-Layer Error Model: Core, Transport, and Pin errors cleanly separated
- Embassy Ready: Full async/await support with DMA templates
C FFI Interface
The driver provides a complete C-compatible interface with zero-allocation embedded-friendly design:
Key Features
- Zero Heap Allocation: All memory managed by C application
- Static Memory Support: Compile-time memory size calculation
- Multi-Instance Support: Independent driver instances with separate memory buffers
- Embedded-Friendly: Suitable for resource-constrained environments
- Instance-Based Design: Clear and intuitive API using "instance" terminology
Quick Start
// Declare static driver instance (176 bytes, 8-byte aligned)
;
// Setup SPI interface (no context parameter needed)
ad7124_spi_interface_t spi = ;
// Initialize driver in static memory
int result = ;
if
// Configure and read
;
float voltage;
;
// Enhanced Channel Management
; // Enable channel
bool enabled = ; // Check status
uint8_t active_ch;
; // Get active channel
// Non-blocking Operations
if
// Channel-Specific Reading
uint32_t ch_data;
; // Read channel 2
float ch_voltage;
; // Channel 2 voltage
// Multi-Channel Operations
uint8_t channels = ;
uint32_t multi_data;
;
float multi_voltages;
;
// Cleanup (memory managed by C)
;
Memory Management
The FFI uses a placement new pattern for efficient memory management:
// Convenience macros handle size and alignment automatically
// Declare driver instance
;
// Initialize in existing memory buffer
;
Multi-Instance Support
// Multiple independent instances
;
;
// Different SPI interfaces
;
;
// Use independently
;
;
Building C FFI
The crate-type is already configured for FFI builds:
# Build Rust static library
# Compile C example (Windows)
# Run example
Available Examples
Two comprehensive C examples are provided:
c_ffi_example/- Basic C FFI usage with dynamic memory patternsc_embedded_example/- Embedded-specific patterns with static allocation and HAL simulation
Both examples demonstrate:
- Static memory allocation and management
- Multi-instance usage patterns
- Error handling
- Real embedded system integration patterns
- Hardware abstraction layer (HAL) integration
Architecture Benefits
- Zero Heap: All memory allocated statically by C application
- Fast: Placement new pattern for zero-copy construction
- Safe: Compile-time size and alignment checks
- Compact: Only 176 bytes per driver instance
- Flexible: Support for multiple independent instances
- Embedded: Designed for resource-constrained systems
Platform Support
The C FFI has been tested on:
- Embedded Systems (ARM Cortex-M , RISC-V ...)
- Windows (MSVC/MinGW)
- Linux (GCC)
For detailed implementation guidance, see:
FFI_USAGE_EN.md- User manualexamples/c_ffi_example/README.md- Basic usageexamples/c_embedded_example/README.md- Embedded patterns
📄 License
This project is licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.
🔗 References
Documentation
- FFI Usage Manual (English) - Comprehensive C FFI user guide
- FFI Usage Manual (Chinese) - 中文 C FFI 用户指南