Skip to content

Commit

Permalink
i2c: Implement i2c-write-iter traits
Browse files Browse the repository at this point in the history
  • Loading branch information
ithinuel committed Jan 31, 2024
1 parent 56462c6 commit e6d3616
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 3 deletions.
9 changes: 6 additions & 3 deletions on-target-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ defmt-test = "0.3.1"
panic-probe = { version = "0.3", features = ["print-defmt"] }

rp2040-hal = { path = "../rp2040-hal", features = [
"defmt",
"critical-section-impl",
"rt",
"critical-section-impl",
"defmt",
"rt",
"i2c-write-iter",
] }
# Needed to set spi frequencies
fugit = "0.3.6"
Expand All @@ -70,4 +71,6 @@ nostd_async = { version = "0.6.1", features = ["wfe"] }
futures = { version = "0.3.30", default-features = false, features = [
"async-await",
] }
i2c-write-iter = "1.0.0"
itertools = { version = "0.12.0", default-features = false }
portable-atomic = { version = "1.6.0", features = ["critical-section"] }
5 changes: 5 additions & 0 deletions rp2040-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ frunk = { version = "0.4.1", default-features = false }

bitfield = { version = "0.14.0" }

i2c-write-iter = { version = "1.0.0", features = ["async"], optional = true }

[dev-dependencies]
cortex-m-rt = "0.7"
cortex-m-rtic = "1.1.4"
Expand Down Expand Up @@ -93,6 +95,9 @@ defmt = ["dep:defmt"]
# Implement `rtic_monotonic::Monotonic` based on the RP2040 timer peripheral
rtic-monotonic = ["dep:rtic-monotonic"]

# Implement `i2c-write-iter` traits
i2c-write-iter = ["dep:i2c-write-iter"]

[[example]]
# irq example uses cortex-m-rt::interrupt, need rt feature for that
name = "gpio_irq_example"
Expand Down
36 changes: 36 additions & 0 deletions rp2040-hal/src/i2c/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,29 @@ impl<T: Deref<Target = Block>, PINS> I2C<T, PINS, Controller> {
}
Ok(())
}

#[cfg(feature = "i2c-write-iter")]
fn transaction_iter<'op, A, O, B>(&mut self, address: A, operations: O) -> Result<(), Error>
where
A: ValidAddress,
O: IntoIterator<Item = i2c_write_iter::Operation<'op, B>>,
B: IntoIterator<Item = u8>,
{
use i2c_write_iter::Operation;
self.setup(address)?;

let mut first = true;
let mut operations = operations.into_iter().peekable();
while let Some(operation) = operations.next() {
let last = operations.peek().is_none();
match operation {
Operation::Read(buf) => self.read_internal(first, buf, last)?,
Operation::WriteIter(buf) => self.write_internal(first, buf, last)?,
}
first = false;
}
Ok(())
}
}

impl<A: ValidAddress, T: Deref<Target = Block>, PINS> Read<A> for I2C<T, PINS, Controller> {
Expand Down Expand Up @@ -458,3 +481,16 @@ impl<A: ValidAddress, T: Deref<Target = Block>, PINS> eh1::I2c<A> for I2C<T, PIN
self.transaction(address, operations.iter_mut())
}
}

#[cfg(feature = "i2c-write-iter")]
impl<A: i2c_write_iter::AddressMode + ValidAddress, T: Deref<Target = Block>, PINS>
i2c_write_iter::I2cIter<A> for I2C<T, PINS, Controller>
{
fn transaction_iter<'a, O, B>(&mut self, address: A, operations: O) -> Result<(), Self::Error>
where
O: IntoIterator<Item = i2c_write_iter::Operation<'a, B>>,
B: IntoIterator<Item = u8>,
{
self.transaction_iter(address, operations)
}
}
52 changes: 52 additions & 0 deletions rp2040-hal/src/i2c/controller/non_blocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,38 @@ where
self.non_blocking_write_internal(true, bytes, false).await?;
self.non_blocking_read_internal(false, read, true).await
}

/// Writes to the i2c bus taking operations from and iterator, writing from iterator of bytes,
/// reading to slices of bytes.
#[cfg(feature = "i2c-write-iter")]
pub async fn transaction_iter_async<'b, A, O, B>(
&mut self,
address: A,
operations: O,
) -> Result<(), super::Error>
where
A: ValidAddress,
O: IntoIterator<Item = i2c_write_iter::Operation<'b, B>>,
B: IntoIterator<Item = u8>,
{
self.setup(address)?;

let mut first = true;
let mut operations = operations.into_iter().peekable();
while let Some(operation) = operations.next() {
let last = operations.peek().is_none();
match operation {
i2c_write_iter::Operation::Read(buf) => {
self.non_blocking_read_internal(first, buf, last).await?
}
i2c_write_iter::Operation::WriteIter(buf) => {
self.non_blocking_write_internal(first, buf, last).await?
}
}
first = false;
}
Ok(())
}
}

impl<T, PINS, A> embedded_hal_async::i2c::I2c<A> for I2C<T, PINS, Controller>
Expand Down Expand Up @@ -291,3 +323,23 @@ where
Ok(())
}
}

#[cfg(feature = "i2c-write-iter")]
impl<T, PINS, A> i2c_write_iter::non_blocking::I2cIter<A> for I2C<T, PINS, Controller>
where
Self: AsyncPeripheral,
A: 'static + ValidAddress + AddressMode,
T: Deref<Target = RegisterBlock>,
{
async fn transaction_iter<'a, O, B>(
&mut self,
address: A,
operations: O,
) -> Result<(), Self::Error>
where
O: IntoIterator<Item = i2c_write_iter::Operation<'a, B>>,
B: IntoIterator<Item = u8>,
{
self.transaction_iter_async(address, operations).await
}
}
2 changes: 2 additions & 0 deletions rp2040-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
//! * **rtic-monotonic** -
//! Implement
//! `rtic_monotonic::Monotonic` based on the RP2040 timer peripheral
//! * **i2c-write-iter** -
//! Implement `i2c_write_iter` traits for `I2C<_, _, Controller>`.

#![warn(missing_docs)]
#![no_std]
Expand Down

0 comments on commit e6d3616

Please sign in to comment.