Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 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,5 @@ nostd_async = { version = "0.6.1", features = ["wfe"] }
futures = { version = "0.3.30", default-features = false, features = [
"async-await",
] }
i2c-write-iter = { version = "1.0.0", features = ["async"] }
itertools = { version = "0.12.0", default-features = false }
6 changes: 6 additions & 0 deletions on-target-tests/tests/i2c_loopback_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ mod tests {
run_test(non_blocking::transaction(state, ADDR_10BIT, 7..=14));
}

#[test]
fn i2c_write_iter(state: &mut State) {
run_test(non_blocking::transaction_iter(state, ADDR_7BIT));
run_test(non_blocking::transaction_iter(state, ADDR_10BIT));
}

// Sad paths:
// invalid tx buf on write
// invalid rx buf on read
Expand Down
30 changes: 30 additions & 0 deletions on-target-tests/tests/i2c_tests/non_blocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,3 +359,33 @@ pub async fn transaction<A: ValidAddress>(
.collect();
assert_eq!(g, h);
}

pub async fn transaction_iter<A: ValidAddress>(state: &mut State, addr: A) {
use i2c_write_iter::non_blocking::I2cIter;
reset(state, addr);

let samples: FIFOBuffer = Generator::seq().take(25).collect();
let controller = state.controller.as_mut().expect("controller's missing.");
let case = async {
controller
.transaction_iter(
addr,
[i2c_write_iter::Operation::WriteIter(
samples.iter().cloned(),
)],
)
.await
.expect("Successful write_iter");
wait_with(&state.payload, |p| p.stop_cnt != 1).await;
};

futures::select_biased! {
_ = case.fuse() => {}
_ = target_handler(
&state.payload,
state.target.as_mut().take().expect("target’s missing"),
).fuse() => {}
}

assert_eq!(samples, state.payload.borrow().vec);
}
5 changes: 5 additions & 0 deletions rp2040-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,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 @@ -98,6 +100,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)
}
}
63 changes: 58 additions & 5 deletions rp2040-hal/src/i2c/controller/non_blocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,13 @@ where
T: Deref<Target = RegisterBlock>,
Self: AsyncPeripheral,
{
/// `tx_empty`: true to unmask tx_empty
#[inline]
fn unmask_intr(&mut self) {
fn unmask_intr(&mut self, tx_empty: bool) {
unsafe {
self.i2c.ic_intr_mask.write_with_zero(|w| {
w.m_tx_empty()
.disabled()
.bit(tx_empty)
.m_rx_full()
.disabled()
.m_tx_abrt()
Expand All @@ -73,18 +74,18 @@ where
#[inline]
fn unmask_tx_empty(&mut self) {
self.configure_tx_empty(TxEmptyConfig::Empty);
self.unmask_intr()
self.unmask_intr(true)
}

#[inline]
fn unmask_tx_not_full(&mut self) {
self.configure_tx_empty(TxEmptyConfig::NotFull);
self.unmask_intr()
self.unmask_intr(true)
}

#[inline]
fn unmask_stop_det(&mut self) {
self.unmask_intr();
self.unmask_intr(false);
}

#[inline]
Expand Down Expand Up @@ -259,6 +260,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 @@ -292,3 +325,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