use core::{ops::Deref, task::Poll};
use embedded_hal_0_2::blocking::i2c::{Read, Write, WriteIter, WriteIterRead, WriteRead};
use fugit::HertzU32;
use embedded_hal::i2c as eh1;
use crate::{
i2c::{Controller, Error, ValidAddress, ValidPinScl, ValidPinSda, I2C},
pac::{i2c0::RegisterBlock as Block, RESETS},
resets::SubsystemReset,
};
pub(crate) mod non_blocking;
impl<T, Sda, Scl> I2C<T, (Sda, Scl), Controller>
where
T: SubsystemReset + Deref<Target = Block>,
Sda: ValidPinSda<T>,
Scl: ValidPinScl<T>,
{
pub fn new_controller(
i2c: T,
sda_pin: Sda,
scl_pin: Scl,
freq: HertzU32,
resets: &mut RESETS,
system_clock: HertzU32,
) -> Self {
let freq = freq.to_Hz();
assert!(freq <= 1_000_000);
assert!(freq > 0);
i2c.reset_bring_down(resets);
i2c.reset_bring_up(resets);
i2c.ic_enable().write(|w| w.enable().disabled());
i2c.ic_con().modify(|_, w| {
w.speed().fast();
w.master_mode().enabled();
w.ic_slave_disable().slave_disabled();
w.ic_restart_en().enabled();
w.tx_empty_ctrl().enabled()
});
i2c.ic_tx_tl().write(|w| unsafe { w.tx_tl().bits(0) });
i2c.ic_rx_tl().write(|w| unsafe { w.rx_tl().bits(0) });
let freq_in = system_clock.to_Hz();
let period = (freq_in + freq / 2) / freq;
let lcnt = period * 3 / 5; let hcnt = period - lcnt;
assert!(hcnt <= 0xffff);
assert!(lcnt <= 0xffff);
assert!(hcnt >= 8);
assert!(lcnt >= 8);
let sda_tx_hold_count = if freq < 1000000 {
((freq_in * 3) / 10000000) + 1
} else {
assert!(freq_in >= 32_000_000);
((freq_in * 3) / 25000000) + 1
};
assert!(sda_tx_hold_count <= lcnt - 2);
unsafe {
i2c.ic_fs_scl_hcnt()
.write(|w| w.ic_fs_scl_hcnt().bits(hcnt as u16));
i2c.ic_fs_scl_lcnt()
.write(|w| w.ic_fs_scl_lcnt().bits(lcnt as u16));
i2c.ic_fs_spklen().write(|w| {
let ticks = if lcnt < 16 { 1 } else { (lcnt / 16) as u8 };
w.ic_fs_spklen().bits(ticks)
});
i2c.ic_sda_hold()
.modify(|_r, w| w.ic_sda_tx_hold().bits(sda_tx_hold_count as u16));
i2c.ic_tx_tl()
.write(|w| w.tx_tl().bits(Self::TX_FIFO_DEPTH));
i2c.ic_rx_tl().write(|w| w.rx_tl().bits(0));
i2c.ic_con()
.modify(|_, w| w.rx_fifo_full_hld_ctrl().enabled());
}
i2c.ic_enable().write(|w| w.enable().enabled());
Self {
i2c,
pins: (sda_pin, scl_pin),
mode: Controller {},
}
}
}
impl<T: Deref<Target = Block>, PINS> I2C<T, PINS, Controller> {
fn validate_buffer<U>(
&mut self,
first: bool,
buf: &mut core::iter::Peekable<U>,
err: Error,
) -> Result<(), Error>
where
U: Iterator,
{
if buf.peek().is_some() {
Ok(())
} else {
if !first {
self.abort();
}
Err(err)
}
}
fn setup<A: ValidAddress>(&mut self, addr: A) -> Result<(), Error> {
addr.is_valid()?;
self.i2c.ic_enable().write(|w| w.enable().disabled());
self.i2c
.ic_con()
.modify(|_, w| w.ic_10bitaddr_master().variant(A::BIT_ADDR_M));
let addr = addr.into();
self.i2c
.ic_tar()
.write(|w| unsafe { w.ic_tar().bits(addr) });
self.i2c.ic_enable().write(|w| w.enable().enabled());
Ok(())
}
#[inline]
fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> {
let abort_reason = self.i2c.ic_tx_abrt_source().read().bits();
if abort_reason != 0 {
self.i2c.ic_clr_tx_abrt().read();
Err(Error::Abort(abort_reason))
} else {
Ok(())
}
}
#[inline]
fn poll_tx_not_full(&mut self) -> Poll<Result<(), Error>> {
self.read_and_clear_abort_reason()?;
if !self.tx_fifo_full() {
Poll::Ready(Ok(()))
} else {
Poll::Pending
}
}
#[inline]
fn poll_tx_empty(&mut self) -> Poll<()> {
if self.i2c.ic_raw_intr_stat().read().tx_empty().is_inactive() {
Poll::Pending
} else {
Poll::Ready(())
}
}
#[inline]
fn poll_stop_detected(&mut self) -> Poll<()> {
if self.i2c.ic_raw_intr_stat().read().stop_det().is_inactive() {
Poll::Pending
} else {
Poll::Ready(())
}
}
#[inline]
fn abort(&mut self) {
self.i2c.ic_enable().modify(|_, w| w.abort().set_bit());
while self.i2c.ic_enable().read().abort().bit_is_set() {
crate::arch::nop()
}
while self.i2c.ic_raw_intr_stat().read().tx_abrt().bit_is_clear() {
crate::arch::nop()
}
self.i2c.ic_clr_tx_abrt().read();
self.i2c.ic_tx_abrt_source().read();
}
fn read_internal(
&mut self,
first_transaction: bool,
buffer: &mut [u8],
do_stop: bool,
) -> Result<(), Error> {
self.validate_buffer(
first_transaction,
&mut buffer.iter().peekable(),
Error::InvalidReadBufferLength,
)?;
let lastindex = buffer.len() - 1;
for (i, byte) in buffer.iter_mut().enumerate() {
let last_byte = i == lastindex;
while self.i2c.ic_status().read().tfnf().bit_is_clear() {}
self.i2c.ic_data_cmd().write(|w| {
w.stop().bit(do_stop && last_byte);
w.cmd().read()
});
while self.i2c.ic_rxflr().read().bits() == 0 {
self.read_and_clear_abort_reason()?;
}
*byte = self.i2c.ic_data_cmd().read().dat().bits();
}
Ok(())
}
fn write_internal(
&mut self,
first_transaction: bool,
bytes: impl IntoIterator<Item = u8>,
do_stop: bool,
) -> Result<(), Error> {
let mut peekable = bytes.into_iter().peekable();
self.validate_buffer(
first_transaction,
&mut peekable,
Error::InvalidWriteBufferLength,
)?;
let mut abort_reason = Ok(());
'outer: while let Some(byte) = peekable.next() {
if self.tx_fifo_full() {
loop {
match self.poll_tx_not_full() {
Poll::Pending => continue,
Poll::Ready(Ok(())) => break,
Poll::Ready(r) => {
abort_reason = r;
break 'outer;
}
}
}
}
let last = peekable.peek().is_none();
self.i2c.ic_data_cmd().write(|w| {
w.stop().bit(do_stop && last);
unsafe { w.dat().bits(byte) }
});
}
if abort_reason.is_err() {
while self.poll_tx_empty().is_pending() {}
abort_reason = self.read_and_clear_abort_reason();
}
if abort_reason.is_err() || do_stop {
while self.poll_stop_detected().is_pending() {}
self.i2c.ic_clr_stop_det().read().clr_stop_det();
}
abort_reason
}
}
impl<T: Deref<Target = Block>, PINS> I2C<T, PINS, Controller> {
pub fn write_iter<A: ValidAddress, B>(&mut self, address: A, bytes: B) -> Result<(), Error>
where
B: IntoIterator<Item = u8>,
{
self.setup(address)?;
self.write_internal(true, bytes, true)
}
pub fn write_iter_read<A: ValidAddress, B>(
&mut self,
address: A,
bytes: B,
buffer: &mut [u8],
) -> Result<(), Error>
where
B: IntoIterator<Item = u8>,
{
self.setup(address)?;
self.write_internal(true, bytes, false)?;
self.read_internal(false, buffer, true)
}
fn transaction<'op: 'iter, 'iter, A: ValidAddress>(
&mut self,
address: A,
operations: impl IntoIterator<Item = &'iter mut eh1::Operation<'op>>,
) -> Result<(), Error> {
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 {
eh1::Operation::Read(buf) => self.read_internal(first, buf, last)?,
eh1::Operation::Write(buf) => {
self.write_internal(first, buf.iter().cloned(), last)?
}
}
first = false;
}
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> {
type Error = Error;
fn read(&mut self, addr: A, buffer: &mut [u8]) -> Result<(), Error> {
self.setup(addr)?;
self.read_internal(true, buffer, true)
}
}
impl<A: ValidAddress, T: Deref<Target = Block>, PINS> WriteRead<A> for I2C<T, PINS, Controller> {
type Error = Error;
fn write_read(&mut self, addr: A, tx: &[u8], rx: &mut [u8]) -> Result<(), Error> {
self.setup(addr)?;
self.write_internal(true, tx.iter().cloned(), false)?;
self.read_internal(false, rx, true)
}
}
impl<A: ValidAddress, T: Deref<Target = Block>, PINS> Write<A> for I2C<T, PINS, Controller> {
type Error = Error;
fn write(&mut self, addr: A, tx: &[u8]) -> Result<(), Error> {
self.setup(addr)?;
self.write_internal(true, tx.iter().cloned(), true)
}
}
impl<A: ValidAddress, T: Deref<Target = Block>, PINS> WriteIter<A> for I2C<T, PINS, Controller> {
type Error = Error;
fn write<B>(&mut self, address: A, bytes: B) -> Result<(), Self::Error>
where
B: IntoIterator<Item = u8>,
{
self.write_iter(address, bytes)
}
}
impl<A: ValidAddress, T: Deref<Target = Block>, PINS> WriteIterRead<A>
for I2C<T, PINS, Controller>
{
type Error = Error;
fn write_iter_read<B>(
&mut self,
address: A,
bytes: B,
buffer: &mut [u8],
) -> Result<(), Self::Error>
where
B: IntoIterator<Item = u8>,
{
self.write_iter_read(address, bytes, buffer)
}
}
impl<T: Deref<Target = Block>, PINS> eh1::ErrorType for I2C<T, PINS, Controller> {
type Error = Error;
}
impl<A: ValidAddress, T: Deref<Target = Block>, PINS> eh1::I2c<A> for I2C<T, PINS, Controller> {
fn transaction(
&mut self,
address: A,
operations: &mut [eh1::Operation<'_>],
) -> Result<(), Self::Error> {
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)
}
}