summaryrefslogtreecommitdiffstats
path: root/src/dual_hx711.rs
diff options
context:
space:
mode:
authorTomasz Kramkowski <tomasz@kramkow.ski>2025-10-16 19:33:17 +0100
committerTomasz Kramkowski <tomasz@kramkow.ski>2025-10-16 19:33:17 +0100
commitcdf2a5026e45ac2b65001ed41cc67d86590a681a (patch)
tree56fda9ee1cc0159e725952802547e5e6d327428e /src/dual_hx711.rs
downloadscale-drv-example-master.tar.gz
scale-drv-example-master.tar.xz
scale-drv-example-master.zip
Driver exampleHEADmaster
Diffstat (limited to 'src/dual_hx711.rs')
-rw-r--r--src/dual_hx711.rs75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/dual_hx711.rs b/src/dual_hx711.rs
new file mode 100644
index 0000000..13ec247
--- /dev/null
+++ b/src/dual_hx711.rs
@@ -0,0 +1,75 @@
+// SPDX-FileCopyrightText: 2025 Tomasz Kramkowski <tomasz@kramkow.ski>
+// 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<Error = E> + Wait,
+ B: InputPin<Error = E> + 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);
+ }
+}