Skip to content

Commit

Permalink
Master changes for supporting i2c 10 bit addressing
Browse files Browse the repository at this point in the history
  • Loading branch information
akshat2112 committed Feb 13, 2025
1 parent 89a782a commit 2c3cc21
Show file tree
Hide file tree
Showing 2 changed files with 274 additions and 16 deletions.
288 changes: 272 additions & 16 deletions src/i2c/master.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use embassy_hal_internal::into_ref;

use super::{
Async, Blocking, Error, Info, Instance, InterruptHandler, MasterDma, Mode, Result, SclPin, SdaPin, TransferError,
I2C_WAKERS,
I2C_WAKERS, TEN_BIT_PREFIX,
};
use crate::interrupt::typelevel::Interrupt;
use crate::{dma, interrupt, Peripheral};
Expand Down Expand Up @@ -133,7 +133,19 @@ impl<'a> I2cMaster<'a, Blocking> {
Ok(this)
}

fn start(&mut self, address: u8, is_read: bool) -> Result<()> {
fn start(&mut self, address: u16, is_read: bool) -> Result<()> {
// check if the address is 10-bit
let is_10bit = address > 0x7F;

// start with the correct address
if is_10bit {
self.start_10bit(address, is_read)
} else {
self.start_7bit(address as u8, is_read)
}
}

fn start_7bit(&mut self, address: u8, is_read: bool) -> Result<()> {
let i2cregs = self.info.regs;

self.poll_ready()?;
Expand Down Expand Up @@ -169,7 +181,64 @@ impl<'a> I2cMaster<'a, Blocking> {
self.check_for_bus_errors()
}

fn read_no_stop(&mut self, address: u8, read: &mut [u8]) -> Result<()> {
fn start_10bit(&mut self, address: u16, is_read: bool) -> Result<()> {
// check if the address is 10-bit and within the valid range
if address > 0x3FF {
return Err(Error::UnsupportedConfiguration);
}
let i2cregs = self.info.regs;

self.poll_ready()?;

// cannot start if the the bus is already busy
if i2cregs.stat().read().mstpending().is_in_progress() {
return Err(TransferError::OtherBusError.into());
}

// The first byte of a 10-bit address is 11110XXX,
// where XXX are the 2 most significant bits of the 10-bit address
// followed by the read/write bit
let addr_high = TEN_BIT_PREFIX | (((address >> 8) as u8) << 1);
i2cregs.mstdat().write(|w|
// SAFETY: only unsafe due to .bits usage
unsafe { w.data().bits(addr_high) });
i2cregs.mstctl().write(|w| w.mststart().set_bit());

self.poll_ready()?;
self.check_for_bus_errors()?;

// Send the second part of the 10-bit address
let addr_low = (address & 0xFF) as u8;
i2cregs.mstdat().write(|w|
// SAFETY: only unsafe due to .bits usage
unsafe { w.data().bits(addr_low) });
i2cregs.mstctl().write(|w| w.mstcontinue().set_bit());

self.poll_ready()?;
self.check_for_bus_errors()?;

// If this is a read operation, send a repeated start with the read bit set
if is_read {
let addr_high_read = addr_high | 0b1;
i2cregs.mstdat().write(|w| unsafe { w.data().bits(addr_high_read) });
i2cregs.mstctl().write(|w| w.mststart().set_bit());

self.poll_ready()?;
self.check_for_bus_errors()?;
}

if is_read && !i2cregs.stat().read().mststate().is_receive_ready() {
return Err(TransferError::ReadFail.into());
}

if !is_read && !i2cregs.stat().read().mststate().is_transmit_ready() {
return Err(TransferError::WriteFail.into());
}

Ok(())
}

fn read_no_stop(&mut self, address: u16, read: &mut [u8]) -> Result<()> {
let i2cregs = self.info.regs;

// read of 0 size is not allowed according to i2c spec
Expand Down Expand Up @@ -202,7 +271,7 @@ impl<'a> I2cMaster<'a, Blocking> {
Ok(())
}

fn write_no_stop(&mut self, address: u8, write: &[u8]) -> Result<()> {
fn write_no_stop(&mut self, address: u16, write: &[u8]) -> Result<()> {
// Procedure from 24.3.1.1 pg 545
let i2cregs = self.info.regs;

Expand Down Expand Up @@ -270,7 +339,19 @@ impl<'a> I2cMaster<'a, Async> {
Ok(this)
}

async fn start(&mut self, address: u8, is_read: bool) -> Result<()> {
async fn start(&mut self, address: u16, is_read: bool) -> Result<()> {
// check if the address is 10-bit
let is_10bit = address > 0x7F;

// start with the correct address
if is_10bit {
self.start_10bit(address, is_read).await
} else {
self.start_7bit(address as u8, is_read).await
}
}

async fn start_7bit(&mut self, address: u8, is_read: bool) -> Result<()> {
let i2cregs = self.info.regs;

self.wait_on(
Expand Down Expand Up @@ -362,7 +443,143 @@ impl<'a> I2cMaster<'a, Async> {
res
}

async fn read_no_stop(&mut self, address: u8, read: &mut [u8]) -> Result<()> {
async fn start_10bit(&mut self, address: u16, is_read: bool) -> Result<()> {
// check if the address is 10-bit and within the valid range
if address > 0x3FF {
return Err(Error::UnsupportedConfiguration);
}
let i2cregs = self.info.regs;

self.wait_on(
|me| {
let stat = me.info.regs.stat().read();

if stat.mstpending().is_pending() {
Poll::Ready(Ok::<(), Error>(()))
} else if stat.mstarbloss().is_arbitration_loss() {
Poll::Ready(Err(TransferError::ArbitrationLoss.into()))
} else if stat.mstststperr().is_error() {
Poll::Ready(Err(TransferError::StartStopError.into()))
} else {
Poll::Pending
}
},
|me| {
me.info.regs.intenset().write(|w| {
w.mstpendingen()
.set_bit()
.mstarblossen()
.set_bit()
.mstststperren()
.set_bit()
});
},
)
.await?;

// The first byte of a 10-bit address is 11110XXX,
// where XXX are the 2 most significant bits of the 10-bit address
// followed by the read/write bit
let addr_high = TEN_BIT_PREFIX | (((address >> 8) as u8) << 1);
i2cregs.mstdat().write(|w| unsafe { w.data().bits(addr_high) });
i2cregs.mstctl().write(|w| w.mststart().set_bit());

self.wait_on(
|me| {
let stat = me.info.regs.stat().read();

if stat.mstpending().is_pending() {
Poll::Ready(Ok::<(), Error>(()))
} else if stat.mstarbloss().is_arbitration_loss() {
Poll::Ready(Err(TransferError::ArbitrationLoss.into()))
} else if stat.mstststperr().is_error() {
Poll::Ready(Err(TransferError::StartStopError.into()))
} else {
Poll::Pending
}
},
|me| {
me.info.regs.intenset().write(|w| {
w.mstpendingen()
.set_bit()
.mstarblossen()
.set_bit()
.mstststperren()
.set_bit()
});
},
)
.await?;

// Send the second part of the 10-bit address
let addr_low = (address & 0xFF) as u8;
i2cregs.mstdat().write(|w| unsafe { w.data().bits(addr_low) });
i2cregs.mstctl().write(|w| w.mstcontinue().set_bit());

self.wait_on(
|me| {
let stat = me.info.regs.stat().read();

if stat.mstpending().is_pending() {
Poll::Ready(Ok::<(), Error>(()))
} else if stat.mstarbloss().is_arbitration_loss() {
Poll::Ready(Err(TransferError::ArbitrationLoss.into()))
} else if stat.mstststperr().is_error() {
Poll::Ready(Err(TransferError::StartStopError.into()))
} else {
Poll::Pending
}
},
|me| {
me.info.regs.intenset().write(|w| {
w.mstpendingen()
.set_bit()
.mstarblossen()
.set_bit()
.mstststperren()
.set_bit()
});
},
)
.await?;

// If this is a read operation, send a repeated start with the read bit set
if is_read {
let addr_high_read = addr_high | 0b1;
i2cregs.mstdat().write(|w| unsafe { w.data().bits(addr_high_read) });
i2cregs.mstctl().write(|w| w.mststart().set_bit());

self.wait_on(
|me| {
let stat = me.info.regs.stat().read();

if stat.mstpending().is_pending() {
Poll::Ready(Ok::<(), Error>(()))
} else if stat.mstarbloss().is_arbitration_loss() {
Poll::Ready(Err(TransferError::ArbitrationLoss.into()))
} else if stat.mstststperr().is_error() {
Poll::Ready(Err(TransferError::StartStopError.into()))
} else {
Poll::Pending
}
},
|me| {
me.info.regs.intenset().write(|w| {
w.mstpendingen()
.set_bit()
.mstarblossen()
.set_bit()
.mstststperren()
.set_bit()
});
},
)
.await?;
}
Ok(())
}

async fn read_no_stop(&mut self, address: u16, read: &mut [u8]) -> Result<()> {
let i2cregs = self.info.regs;

// read of 0 size is not allowed according to i2c spec
Expand Down Expand Up @@ -448,7 +665,7 @@ impl<'a> I2cMaster<'a, Async> {
.await
}

async fn write_no_stop(&mut self, address: u8, write: &[u8]) -> Result<()> {
async fn write_no_stop(&mut self, address: u16, write: &[u8]) -> Result<()> {
// Procedure from 24.3.1.1 pg 545
let i2cregs = self.info.regs;

Expand Down Expand Up @@ -622,18 +839,18 @@ impl<M: Mode> embedded_hal_1::i2c::ErrorType for I2cMaster<'_, M> {
// implement generic i2c interface for peripheral master type
impl embedded_hal_1::i2c::I2c for I2cMaster<'_, Blocking> {
fn read(&mut self, address: u8, read: &mut [u8]) -> Result<()> {
self.read_no_stop(address, read)?;
self.read_no_stop(address.into(), read)?;
self.stop()
}

fn write(&mut self, address: u8, write: &[u8]) -> Result<()> {
self.write_no_stop(address, write)?;
self.write_no_stop(address.into(), write)?;
self.stop()
}

fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<()> {
self.write_no_stop(address, write)?;
self.read_no_stop(address, read)?;
self.write_no_stop(address.into(), write)?;
self.read_no_stop(address.into(), read)?;
self.stop()
}

Expand All @@ -643,10 +860,10 @@ impl embedded_hal_1::i2c::I2c for I2cMaster<'_, Blocking> {
for op in operations {
match op {
embedded_hal_1::i2c::Operation::Read(read) => {
self.read_no_stop(address, read)?;
self.read_no_stop(address.into(), read)?;
}
embedded_hal_1::i2c::Operation::Write(write) => {
self.write_no_stop(address, write)?;
self.write_no_stop(address.into(), write)?;
}
}
}
Expand All @@ -661,22 +878,61 @@ impl embedded_hal_1::i2c::I2c for I2cMaster<'_, Blocking> {

impl embedded_hal_async::i2c::I2c<embedded_hal_async::i2c::SevenBitAddress> for I2cMaster<'_, Async> {
async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<()> {
self.read_no_stop(address, read).await?;
self.read_no_stop(address.into(), read).await?;
self.stop().await
}

async fn write(&mut self, address: u8, write: &[u8]) -> Result<()> {
self.write_no_stop(address, write).await?;
self.write_no_stop(address.into(), write).await?;
self.stop().await
}

async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<()> {
self.write_no_stop(address.into(), write).await?;
self.read_no_stop(address.into(), read).await?;
self.stop().await
}

async fn transaction(&mut self, address: u8, operations: &mut [embedded_hal_1::i2c::Operation<'_>]) -> Result<()> {
let needs_stop = !operations.is_empty();

for op in operations {
match op {
embedded_hal_1::i2c::Operation::Read(read) => {
self.read_no_stop(address.into(), read).await?;
}
embedded_hal_1::i2c::Operation::Write(write) => {
self.write_no_stop(address.into(), write).await?;
}
}
}

if needs_stop {
self.stop().await?;
}

Ok(())
}
}

impl embedded_hal_async::i2c::I2c<embedded_hal_async::i2c::TenBitAddress> for I2cMaster<'_, Async> {
async fn read(&mut self, address: u16, read: &mut [u8]) -> Result<()> {
self.read_no_stop(address, read).await?;
self.stop().await
}

async fn write(&mut self, address: u16, write: &[u8]) -> Result<()> {
self.write_no_stop(address, write).await?;
self.stop().await
}

async fn write_read(&mut self, address: u16, write: &[u8], read: &mut [u8]) -> Result<()> {
self.write_no_stop(address, write).await?;
self.read_no_stop(address, read).await?;
self.stop().await
}

async fn transaction(&mut self, address: u8, operations: &mut [embedded_hal_1::i2c::Operation<'_>]) -> Result<()> {
async fn transaction(&mut self, address: u16, operations: &mut [embedded_hal_1::i2c::Operation<'_>]) -> Result<()> {
let needs_stop = !operations.is_empty();

for op in operations {
Expand Down
2 changes: 2 additions & 0 deletions src/i2c/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ impl_instance!(0, 1, 2, 3, 4, 5, 6, 7);

const I2C_COUNT: usize = 8;
static I2C_WAKERS: [AtomicWaker; I2C_COUNT] = [const { AtomicWaker::new() }; I2C_COUNT];
/// Ten bit address start with first byte 0b11110XXX
pub const TEN_BIT_PREFIX: u8 = 0b11110 << 3;

/// I2C interrupt handler.
pub struct InterruptHandler<T: Instance> {
Expand Down

0 comments on commit 2c3cc21

Please sign in to comment.