// SPDX-FileCopyrightText: 2025 Tomasz Kramkowski // SPDX-License-Identifier: GPL-3.0-or-later //! Driver for reading from two HX711 ADCs with a shared clock. //! //! (Datasheet)[https://cdn.sparkfun.com/assets/b/f/5/a/e/hx711F_EN.pdf] //! //! Existing implementations could not handle a combined setup. use embassy_stm32::timer::GeneralInstance4Channel; use embedded_hal::digital::InputPin; use embedded_hal_async::digital::Wait; use crate::pulse::Pulse; /// Dual HX711 driver pub struct DualHx711<'a, T: GeneralInstance4Channel, A: InputPin + Wait, B: InputPin + Wait> { clock: Pulse<'a, T>, a: A, b: B, } /// Sign extend a two's complement number stored in the low 24 bits of a u32 to /// an i32 fn convert_c24_to_i32(n: u32) -> i32 { ((n << 8) as i32) >> 8 } impl< 'a, T: GeneralInstance4Channel, E, A: InputPin + Wait, B: InputPin + Wait, > DualHx711<'a, T, A, B> { /// Create a new driver from clock and data pins /// /// Clock pin must be a `Pulse` configured to produce an appropriately timed /// clock signal. Refer to the HX711 datasheet for more details. /// /// Currently only implements CH.A, Gain:128 mode pub fn new(clock: Pulse<'a, T>, a: A, b: B) -> Self { Self { clock, a, b } } /// Read the next available conversion from both HX711s pub async fn read(&mut self) -> Result<(i32, i32), E> { self.a.wait_for_low().await?; self.b.wait_for_low().await?; let mut val = (0, 0); for _ in 0..24 { self.clock.trigger_and_wait().await; val.0 <<= 1; val.0 |= self.a.is_high()? as u32; val.1 <<= 1; val.1 |= self.b.is_high()? as u32; } // Only implement CH.A, Gain:128 mode self.clock.trigger_and_wait().await; Ok((convert_c24_to_i32(val.0), convert_c24_to_i32(val.1))) } } #[cfg(test)] mod tests { use super::*; fn convert_twos_complement() { assert_eq!(convert_c24_to_i32(0), 0); assert_eq!(convert_c24_to_i32(0x7fffff), 8388607); assert_eq!(convert_c24_to_i32(0x800000), -8388608); assert_eq!(convert_c24_to_i32(0xffffff), -1); } }