# max30101-rs
[](https://crates.io/crates/max30101-rs)
[](https://docs.rs/max30101-rs)
[](https://github.com/JeromeHen/max30101-rs/actions)
[](./LICENSE)
## MAX30101 Rust Driver
Pure-Rust, `no_std` (with `alloc`) driver for the MAX30101 PPG (photoplethysmography) sensor.
This crate is a low-level, register-oriented implementation derived from the MAX30101 datasheet. It exposes a compact, register-centric API and a small transport abstraction so you can plug in your preferred I2C implementation.
This Rust crate is licensed under MIT OR Apache-2.0.
## Design Goals
- `no_std` compatible (with `alloc`)
- Support both synchronous (`blocking`) and asynchronous (`async`) I2C usage
- Small, register-oriented API close to the datasheet
- Transport-agnostic: users provide the concrete I2C implementation
## Crate Features
- `async` — enable asynchronous transport support using `embedded-hal-async` and `async-trait`.
- `blocking` — enable blocking transport support using `embedded-hal` traits.
- `shared-bus` — enable support for sharing a single bus instance between drivers (uses `embassy-sync` mutex types).
## Quick Overview
### High-Level Device Object
The crate exposes `Max30101<T>`, where `T` is a transport implementation. The `reg` module exposes register addresses, bitflags and small newtypes (enums and wrappers) for convenient and type-safe register manipulation.
Commonly-used items:
- `max30101_rs::Max30101` — main driver type.
- `max30101_rs::transport::I2cTransport` — provided I2C transport adapter.
- `max30101_rs::reg::MAX30101_I2C_ADDR` — default 7-bit I2C address.
## API highlights
Below are some functions, types and registers you will likely use when integrating this driver:
- Driver construction
- `Max30101::new(transport)` — create the device instance.
- `Max30101::destroy(self)` — consume the driver and return the underlying transport.
- Register access helpers
- `read_reg` / `write_reg` — low-level register read/write helpers (async or blocking depending on feature).
- Interrupts
- `interrupts_st_get()` — read current interrupt status registers.
- `interrupts_en_set()` / `interrupts_en_get()` — enable/inspect enabled interrupt sources.
- Registers: `MAX30101_INTERRUPT_STATUS_1`, `MAX30101_INTERRUPT_STATUS_2`, `MAX30101_INTERRUPT_ENABLE_1`, `MAX30101_INTERRUPT_ENABLE_2`.
- FIFO / samples
- `fifo_config_set()` / `fifo_config_get()` — configure FIFO almost-full threshold, rollover and averaging.
- `MAX30101_FIFO_DATA` — FIFO sample read register.
- Mode & reset
- `mode_set()` / `mode_get()` — switch chip mode (`Mode` enum: `HeartRate`, `SpO2`, `MultiLED`).
- `reset_set(true)` / `reset_get()` — trigger and query chip reset.
- `shutdown_set()` / `shutdown_get()` — enter/exit shutdown mode.
- Registers: `MAX30101_MODE_CONFIG`, `MAX30101_PART_ID`, `MAX30101_REV_ID`.
- LED configuration
- `led_pw_set()` / `led_pw_get()` — set ADC resolution / LED pulse width (`LEDPW`).
- `ledx_pa_set()` / `ledx_pa_get()` and `led1_pa_set()` .. `led4_pa_set()` — set per-LED pulse amplitude (LED current).
- Registers: `MAX30101_LED1_PA` .. `MAX30101_LED4_PA`, `MAX30101_SPO2_CONFIG`.
- Sample rate & ADC range
- `sample_rate_set()` / `sample_rate_get()` — configure sample rate (`SampleRate` enum).
- `adc_range_set()` / `adc_range_get()` — configure ADC dynamic range (`ADCRange`).
- Transport helpers
- `transport::I2cTransport::new(bus, address)` — adapter the crate provides to wrap an I2C bus and device address.
See the `reg` module for bitflags and small enums (e.g. `Mode`, `LEDPW`, `SampleRate`, `SmpAve`, `ADCRange`) to work with register fields in a type-safe way.
### Transport Abstraction
`Max30101<T>` is generic over a `Transport` implementation exposed in `transport`. Depending on enabled features the expected bus type differs:
- Without `shared-bus`: pass your concrete I2C implementation directly (e.g. an `embedded-hal` type).
- With `shared-bus`: pass a shared/mutex-wrapped bus (the crate expects `embassy-sync` mutex types when `shared-bus` is enabled).
The crate provides `I2cTransport::new(bus, address)` to construct a transport wrapper; the `bus` argument type depends on active features as described above.
## Examples
Below are minimal examples showing how to construct the driver for the async feature. Replace the `...` with your platform's concrete I2C type.
The blocking example is similar, just replace the `async`/`await` keywords and use blocking I2C types.
```rust
use max30101_rs::{Max30101, transport::I2cTransport, reg::MAX30101_I2C_ADDR};
// `I2C` should implement the embedded-hal-async I2C traits
let i2c = /* your embedded-hal I2C instance */;
let transport = I2cTransport::new(i2c, MAX30101_I2C_ADDR);
let mut dev = Max30101::new(transport);
// Reset the device, and wait for it to be ready
loop {
if device.reset_set(true).await.is_ok() {
break;
}
// Wait some time before retrying
}
// Make sure the device is not in shutdown mode
device.shutdown_set(false).await.unwrap();
// Wait some time for the device to be ready after exiting shutdown mode
// Test reading some device information
let part_id = device.part_id_get().await.unwrap();
let rev_id = device.rev_id_get().await.unwrap();
// Perform the rest of the setup here
// Use the device as specified in the datasheet
```
## Contributing
Contributions are welcome — PRs that add missing register APIs, improve examples, or enhance documentation are especially appreciated.
## License
The crate is dual-licensed under MIT or Apache-2.0 — see `LICENSE` for details.
## Contact / Author
Author: Jérôme Hendrick <jerome.hendrick@gmail.com>
Thanks for checking out this driver!