Skip to content

Commit

Permalink
Clean up the I2C impls.
Browse files Browse the repository at this point in the history
Also we have inherent methods, so you can ignore the Embedded HAL traits if you want (makes the examples simpler too).

Whilst doing this I found out we only support 7-bit I2C addresses. I'll come back and fix that later.
  • Loading branch information
jonathanpallant committed Mar 22, 2024
1 parent 413420a commit 87b286e
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 50 deletions.
3 changes: 1 addition & 2 deletions rp2040-hal/examples/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use panic_halt as _;
use rp2040_hal as hal;

// Some traits we need
use embedded_hal_0_2::blocking::i2c::Write;
use hal::fugit::RateExtU32;

// A shorter alias for the Peripheral Access Crate, which provides low-level
Expand Down Expand Up @@ -81,7 +80,7 @@ fn main() -> ! {
let scl_pin: Pin<_, FunctionI2C, _> = pins.gpio19.reconfigure();
// let not_an_scl_pin: Pin<_, FunctionI2C, PullUp> = pins.gpio20.reconfigure();

// Create the I²C drive, using the two pre-configured pins. This will fail
// Create the I²C driver, using the two pre-configured pins. This will fail
// at compile time if the pins are in the wrong mode, or if this I²C
// peripheral isn't available on these pins!
let mut i2c = hal::I2C::i2c1(
Expand Down
2 changes: 1 addition & 1 deletion rp2040-hal/examples/i2c_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ async fn demo() {
}

// Asynchronously write three bytes to the I²C device with 7-bit address 0x2C
i2c.write(0x76u8, &[1, 2, 3]).await.unwrap();
I2c::write(&mut i2c, 0x76u8, &[1, 2, 3]).await.unwrap();

// Demo finish - just loop until reset
core::future::pending().await
Expand Down
4 changes: 2 additions & 2 deletions rp2040-hal/examples/i2c_async_cancelled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,12 @@ async fn demo() {

// Asynchronously write three bytes to the I²C device with 7-bit address 0x2C
futures::select_biased! {
r = i2c.write(0x76u8, &v).fuse() => r.unwrap(),
r = I2c::write(&mut i2c, 0x76u8, &v).fuse() => r.unwrap(),
_ = timeout.fuse() => {
defmt::info!("Timed out.");
}
}
i2c.write(0x76u8, &v).await.unwrap();
I2c::write(&mut i2c, 0x76u8, &v).await.unwrap();

// Demo finish - just loop until reset
core::future::pending().await
Expand Down
39 changes: 21 additions & 18 deletions rp2040-hal/src/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
//! );
//!
//! // Scan for devices on the bus by attempting to read from them
//! use embedded_hal_0_2::prelude::_embedded_hal_blocking_i2c_Read;
//! for i in 0..=127u8 {
//! let mut readbuf: [u8; 1] = [0; 1];
//! let result = i2c.read(i, &mut readbuf);
Expand All @@ -30,14 +29,12 @@
//! }
//! }
//!
//! // Write some data to a device at 0x2c
//! use embedded_hal_0_2::prelude::_embedded_hal_blocking_i2c_Write;
//! i2c.write(0x2Cu8, &[1, 2, 3]).unwrap();
//! // Write some data to a device with 7-bit address 0x2c
//! i2c.write(0x2c_u8, &[1, 2, 3]).unwrap();
//!
//! // Write and then read from a device at 0x3a
//! use embedded_hal_0_2::prelude::_embedded_hal_blocking_i2c_WriteRead;
//! // Write and then read from a device with 7-bit address 0x3a
//! let mut readbuf: [u8; 1] = [0; 1];
//! i2c.write_read(0x2Cu8, &[1, 2, 3], &mut readbuf).unwrap();
//! i2c.write_read(0x3a_u8, &[1, 2, 3], &mut readbuf).unwrap();
//! ```
//!
//! See [examples/i2c.rs](https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal/examples/i2c.rs)
Expand Down Expand Up @@ -92,6 +89,7 @@ pub trait ValidAddress:
/// Validates the address against address ranges supported by the hardware.
fn is_valid(self) -> Result<(), Error>;
}

impl ValidAddress for u8 {
const BIT_ADDR_M: IC_10BITADDR_MASTER_A = IC_10BITADDR_MASTER_A::ADDR_7BITS;
const BIT_ADDR_S: IC_10BITADDR_SLAVE_A = IC_10BITADDR_SLAVE_A::ADDR_7BITS;
Expand All @@ -104,35 +102,40 @@ impl ValidAddress for u8 {
}
}
}

impl ValidAddress for u16 {
const BIT_ADDR_M: IC_10BITADDR_MASTER_A = IC_10BITADDR_MASTER_A::ADDR_10BITS;
const BIT_ADDR_S: IC_10BITADDR_SLAVE_A = IC_10BITADDR_SLAVE_A::ADDR_10BITS;

fn is_valid(self) -> Result<(), Error> {
Ok(())
if self >= 0x400 {
Err(Error::AddressOutOfRange(self))
} else {
Ok(())
}
}
}

/// I2C error
/// I²C Error
#[non_exhaustive]
pub enum Error {
/// I2C abort with error
/// I²C abort with error
Abort(u32),
/// User passed in a read buffer that was 0 length
///
/// This is a limitation of the RP2040 I2C peripheral.
/// If the slave ACKs its address, the I2C peripheral must read
/// This is a limitation of the RP2040 I²C peripheral.
/// If the slave ACKs its address, the I²C peripheral must read
/// at least one byte before sending the STOP condition.
InvalidReadBufferLength,
/// User passed in a write buffer that was 0 length
///
/// This is a limitation of the RP2040 I2C peripheral.
/// If the slave ACKs its address, the I2C peripheral must write
/// This is a limitation of the RP2040 I²C peripheral.
/// If the slave ACKs its address, the I²C peripheral must write
/// at least one byte before sending the STOP condition.
InvalidWriteBufferLength,
/// Target i2c address is out of range
/// Target I²C address is out of range
AddressOutOfRange(u16),
/// Target i2c address is reserved
/// Target I²C address is reserved
AddressReserved(u16),
}

Expand All @@ -142,8 +145,8 @@ impl core::fmt::Debug for Error {
match self {
Error::InvalidReadBufferLength => write!(fmt, "InvalidReadBufferLength"),
Error::InvalidWriteBufferLength => write!(fmt, "InvalidWriteBufferLength"),
Error::AddressOutOfRange(addr) => write!(fmt, "AddressOutOfRange({:x})", addr),
Error::AddressReserved(addr) => write!(fmt, "AddressReserved({:x})", addr),
Error::AddressOutOfRange(addr) => write!(fmt, "AddressOutOfRange({:?})", addr),
Error::AddressReserved(addr) => write!(fmt, "AddressReserved({:?})", addr),
Error::Abort(_) => {
write!(fmt, "{:?}", self.kind())
}
Expand Down
Loading

0 comments on commit 87b286e

Please sign in to comment.