From 04b9250992879321e861543b3cf0c9f57a9baba0 Mon Sep 17 00:00:00 2001 From: Timo Date: Thu, 25 Jan 2024 11:57:26 +0100 Subject: [PATCH] Add Pull-Up/Pull-Down traits --- CHANGELOG.md | 1 + src/common.rs | 10 ++++++++ src/dev/pi4ioe5v6408.rs | 53 ++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 2 ++ src/pin.rs | 22 +++++++++++++++++ 5 files changed, 87 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 549d075..477715f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- Added `PortDriverPullDown` and `PortDriverPullUp` traits for port-expander ([#17]). - Added support for `PI4IOE5V6408` ([#17]). diff --git a/src/common.rs b/src/common.rs index 5f22ebc..502fe94 100644 --- a/src/common.rs +++ b/src/common.rs @@ -39,6 +39,16 @@ pub trait PortDriverTotemPole: PortDriver { fn set_direction(&mut self, mask: u32, dir: Direction, state: bool) -> Result<(), Self::Error>; } +pub trait PortDriverPullDown: PortDriver { + /// Enable pull-downs for pins in mask or set the pin to floating if enable is false. + fn set_pull_down(&mut self, mask: u32, enable: bool) -> Result<(), Self::Error>; +} + +pub trait PortDriverPullUp: PortDriver { + /// Enable pull-ups for pins in mask or set the pin to floating if enable is false. + fn set_pull_up(&mut self, mask: u32, enable: bool) -> Result<(), Self::Error>; +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Direction { Input, diff --git a/src/dev/pi4ioe5v6408.rs b/src/dev/pi4ioe5v6408.rs index 565f54a..d3485a2 100644 --- a/src/dev/pi4ioe5v6408.rs +++ b/src/dev/pi4ioe5v6408.rs @@ -204,6 +204,36 @@ impl crate::PortDriverTotemPole for Driver { } } +impl crate::PortDriverPullDown for Driver { + fn set_pull_down(&mut self, mask: u32, enable: bool) -> Result<(), Self::Error> { + if enable { + self.i2c + .update_reg(self.addr, Regs::PullUpPullDownSelection, 0, mask as u8)?; + self.i2c + .update_reg(self.addr, Regs::PullUpPullDownEnable, mask as u8, 0)?; + } else { + self.i2c + .update_reg(self.addr, Regs::PullUpPullDownEnable, 0, mask as u8)?; + } + Ok(()) + } +} + +impl crate::PortDriverPullUp for Driver { + fn set_pull_up(&mut self, mask: u32, enable: bool) -> Result<(), Self::Error> { + if enable { + self.i2c + .update_reg(self.addr, Regs::PullUpPullDownSelection, mask as u8, 0)?; + self.i2c + .update_reg(self.addr, Regs::PullUpPullDownEnable, mask as u8, 0)?; + } else { + self.i2c + .update_reg(self.addr, Regs::PullUpPullDownEnable, 0, mask as u8)?; + } + Ok(()) + } +} + #[cfg(test)] mod tests { use super::PullMode; @@ -233,6 +263,22 @@ mod tests { // io0 reads mock_i2c::Transaction::write_read(0x43, vec![0x0f], vec![0x01]), mock_i2c::Transaction::write_read(0x43, vec![0x0f], vec![0x00]), + // io0 activate pull-up + mock_i2c::Transaction::write_read(0x43, vec![0x0d], vec![0b10101010]), + mock_i2c::Transaction::write(0x43, vec![0x0d, 0b10101011]), + mock_i2c::Transaction::write_read(0x43, vec![0x0b], vec![0b00001010]), + mock_i2c::Transaction::write(0x43, vec![0x0b, 0b00001011]), + // io0 disable pull-up + mock_i2c::Transaction::write_read(0x43, vec![0x0b], vec![0b00001011]), + mock_i2c::Transaction::write(0x43, vec![0x0b, 0b00001010]), + // io0 activate pull-down + mock_i2c::Transaction::write_read(0x43, vec![0x0d], vec![0b10101011]), + mock_i2c::Transaction::write(0x43, vec![0x0d, 0b10101010]), + mock_i2c::Transaction::write_read(0x43, vec![0x0b], vec![0b00001010]), + mock_i2c::Transaction::write(0x43, vec![0x0b, 0b00001011]), + // io0 disable pull-down + mock_i2c::Transaction::write_read(0x43, vec![0x0b], vec![0b00001011]), + mock_i2c::Transaction::write(0x43, vec![0x0b, 0b00001010]), ]; let mut bus = mock_i2c::Mock::new(&expectations); @@ -242,7 +288,7 @@ mod tests { let io0 = pca_pins.io0.into_output().unwrap(); let mut io1 = pca_pins.io1.into_output_high().unwrap(); - let io0 = io0.into_input().unwrap(); + let mut io0 = io0.into_input().unwrap(); io1.set_low().unwrap(); io1.set_high().unwrap(); @@ -251,6 +297,11 @@ mod tests { assert!(io0.is_high().unwrap()); assert!(io0.is_low().unwrap()); + io0.enable_pull_up(true).unwrap(); + io0.enable_pull_up(false).unwrap(); + io0.enable_pull_down(true).unwrap(); + io0.enable_pull_down(false).unwrap(); + bus.done(); } diff --git a/src/lib.rs b/src/lib.rs index 9d14d6b..91909e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,6 +73,8 @@ pub(crate) use bus::I2cExt; pub(crate) use common::Direction; pub(crate) use common::PortDriver; pub(crate) use common::PortDriverPolarity; +pub(crate) use common::PortDriverPullDown; +pub(crate) use common::PortDriverPullUp; pub(crate) use common::PortDriverTotemPole; pub use dev::max7321::Max7321; diff --git a/src/pin.rs b/src/pin.rs index 2eba4d2..02ca77b 100644 --- a/src/pin.rs +++ b/src/pin.rs @@ -119,6 +119,28 @@ where } } +impl<'a, MODE: crate::mode::HasInput, MUTEX, PD> Pin<'a, MODE, MUTEX> +where + PD: crate::PortDriver + crate::PortDriverPullUp, + MUTEX: shared_bus::BusMutex, +{ + pub fn enable_pull_up(&mut self, enable: bool) -> Result<(), PD::Error> { + self.port_driver + .lock(|drv| drv.set_pull_up(self.pin_mask, enable)) + } +} + +impl<'a, MODE: crate::mode::HasInput, MUTEX, PD> Pin<'a, MODE, MUTEX> +where + PD: crate::PortDriver + crate::PortDriverPullDown, + MUTEX: shared_bus::BusMutex, +{ + pub fn enable_pull_down(&mut self, enable: bool) -> Result<(), PD::Error> { + self.port_driver + .lock(|drv| drv.set_pull_down(self.pin_mask, enable)) + } +} + impl<'a, MODE: crate::mode::HasInput, MUTEX, PD> hal_digital::InputPin for Pin<'a, MODE, MUTEX> where PD: crate::PortDriver,