use core::{ops::Deref, task::Poll};
use embedded_hal::i2c::AddressMode;
use super::{Peripheral, ValidAddress, ValidPinScl, ValidPinSda, I2C};
use crate::{
async_utils::{sealed::Wakeable, AsyncPeripheral, CancellablePollFn},
pac::{i2c0::RegisterBlock, RESETS},
resets::SubsystemReset,
};
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Event {
Start,
Restart,
TransferRead,
TransferWrite,
Stop,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub(crate) enum State {
Idle,
Active,
Read,
Write,
}
impl<T, Sda, Scl> I2C<T, (Sda, Scl), Peripheral>
where
T: SubsystemReset + Deref<Target = RegisterBlock>,
Sda: ValidPinSda<T>,
Scl: ValidPinScl<T>,
{
#[allow(clippy::type_complexity)]
pub fn new_peripheral_event_iterator<A: ValidAddress + AddressMode>(
i2c: T,
sda_pin: Sda,
scl_pin: Scl,
resets: &mut RESETS,
addr: A,
) -> Self {
i2c.reset_bring_down(resets);
i2c.reset_bring_up(resets);
i2c.ic_enable().write(|w| w.enable().disabled());
let addr = addr.into();
i2c.ic_sar().write(|w| unsafe { w.ic_sar().bits(addr) });
i2c.ic_con().modify(|_, w| {
w.speed().fast();
w.master_mode().disabled();
w.ic_slave_disable().slave_enabled();
w.rx_fifo_full_hld_ctrl().enabled();
w.ic_restart_en().enabled();
w.ic_10bitaddr_slave().variant(A::BIT_ADDR_S);
w
});
i2c.ic_tx_tl().write(|w| unsafe { w.tx_tl().bits(0) });
i2c.ic_rx_tl().write(|w| unsafe { w.rx_tl().bits(0) });
i2c.ic_clr_intr().read();
let mut me = Self {
i2c,
pins: (sda_pin, scl_pin),
mode: Peripheral { state: State::Idle },
};
me.unmask_intr();
me.i2c.ic_enable().write(|w| w.enable().enabled());
me
}
}
fn unmask_intr(i2c: &RegisterBlock) {
unsafe {
i2c.ic_intr_mask().write_with_zero(|w| {
w.m_start_det()
.disabled()
.m_rd_req()
.disabled()
.m_rx_full()
.disabled()
.m_stop_det()
.disabled()
});
}
}
unsafe fn mask_intr(i2c: &RegisterBlock) {
unsafe { i2c.ic_intr_mask().write_with_zero(|w| w) }
}
impl<T: Deref<Target = RegisterBlock>, PINS> I2C<T, PINS, Peripheral> {
fn unmask_intr(&mut self) {
unmask_intr(&self.i2c)
}
fn mask_intr(&mut self) {
unsafe { mask_intr(&self.i2c) }
}
pub fn write(&mut self, buf: &[u8]) -> usize {
self.i2c.ic_clr_tx_abrt().read();
let mut sent = 0;
for &b in buf.iter() {
if self.tx_fifo_full() {
break;
}
self.i2c.ic_data_cmd().write(|w| unsafe { w.dat().bits(b) });
sent += 1;
}
self.i2c.ic_clr_rd_req().read();
sent
}
pub fn read(&mut self, buf: &mut [u8]) -> usize {
buf.iter_mut().zip(self).map(|(b, r)| *b = r).count()
}
}
impl<T: Deref<Target = RegisterBlock>, PINS> Iterator for I2C<T, PINS, Peripheral> {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
if self.rx_fifo_empty() {
None
} else {
Some(self.i2c.ic_data_cmd().read().dat().bits())
}
}
}
impl<T: Deref<Target = RegisterBlock>, PINS> I2C<T, PINS, Peripheral> {
pub fn next_event(&mut self) -> Option<Event> {
let stat = self.i2c.ic_raw_intr_stat().read();
match self.mode.state {
State::Idle if stat.start_det().bit_is_set() => {
self.i2c.ic_clr_start_det().read();
self.mode.state = State::Active;
Some(Event::Start)
}
State::Active if stat.rd_req().bit_is_set() => {
self.mode.state = State::Read;
if stat.stop_det().bit_is_set() {
self.i2c.ic_clr_stop_det().read();
}
Some(Event::TransferRead)
}
State::Active if !self.rx_fifo_empty() => {
self.mode.state = State::Write;
Some(Event::TransferWrite)
}
State::Read if stat.rd_req().bit_is_set() => Some(Event::TransferRead),
State::Write if !self.rx_fifo_empty() => Some(Event::TransferWrite),
State::Read | State::Write if stat.restart_det().bit_is_set() => {
self.i2c.ic_clr_restart_det().read();
self.i2c.ic_clr_start_det().read();
self.mode.state = State::Active;
Some(Event::Restart)
}
_ if stat.stop_det().bit_is_set() => {
self.i2c.ic_clr_stop_det().read();
self.i2c.ic_clr_tx_abrt().read();
self.mode.state = State::Idle;
Some(Event::Stop)
}
_ => None,
}
}
}
macro_rules! impl_wakeable {
($i2c:ty) => {
impl<PINS> AsyncPeripheral for I2C<$i2c, PINS, Peripheral>
where
I2C<$i2c, PINS, Peripheral>: $crate::async_utils::sealed::Wakeable,
{
fn on_interrupt() {
unsafe {
let i2c = &*<$i2c>::ptr();
mask_intr(i2c);
}
Self::waker().wake();
}
}
};
}
impl_wakeable!(rp235x_pac::I2C0);
impl_wakeable!(rp235x_pac::I2C1);
impl<T, PINS> I2C<T, PINS, Peripheral>
where
I2C<T, PINS, Peripheral>: AsyncPeripheral,
T: Deref<Target = RegisterBlock>,
{
pub async fn wait_next(&mut self) -> Event {
loop {
if let Some(evt) = self.next_event() {
return evt;
}
CancellablePollFn::new(
self,
|me| {
let stat = me.i2c.ic_raw_intr_stat().read();
if stat.start_det().bit_is_set()
|| stat.restart_det().bit_is_set()
|| stat.stop_det().bit_is_set()
|| stat.rd_req().bit_is_set()
|| stat.rx_full().bit_is_set()
{
Poll::Ready(())
} else {
Poll::Pending
}
},
Self::unmask_intr,
Self::mask_intr,
)
.await;
}
}
}