#[cfg(dma)]
use core::future::poll_fn;
#[cfg(dma)]
use core::task::Poll;
use embassy_embedded_hal::SetConfig;
#[cfg(dma)]
use embassy_futures::select::{select, Either};
#[cfg(dma)]
use embassy_hal_internal::drop::OnDrop;
use embedded_hal_1::i2c::Operation;
use super::*;
use crate::mode::Mode as PeriMode;
use crate::pac::i2c;
pub unsafe fn on_interrupt<T: Instance>() {
let regs = T::info().regs;
T::state().waker.wake();
critical_section::with(|_| {
regs.cr2().modify(|w| {
w.set_itevten(false);
w.set_iterren(false);
});
});
}
impl<'d, M: PeriMode> I2c<'d, M> {
pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
self.info.regs.cr1().modify(|reg| {
reg.set_pe(false);
});
self.info.regs.cr1().modify(|reg| {
reg.set_swrst(true);
});
self.info.regs.cr1().modify(|reg| {
reg.set_swrst(false);
});
let timings = Timings::new(self.kernel_clock, freq);
self.info.regs.cr2().modify(|reg| {
reg.set_freq(timings.freq);
});
self.info.regs.ccr().modify(|reg| {
reg.set_f_s(timings.mode.f_s());
reg.set_duty(timings.duty.duty());
reg.set_ccr(timings.ccr);
});
self.info.regs.trise().modify(|reg| {
reg.set_trise(timings.trise);
});
self.info.regs.cr1().modify(|reg| {
reg.set_pe(true);
});
}
fn check_and_clear_error_flags(info: &'static Info) -> Result<i2c::regs::Sr1, Error> {
let sr1 = info.regs.sr1().read();
if sr1.pecerr() {
info.regs.sr1().write(|reg| {
reg.0 = !0;
reg.set_pecerr(false);
});
return Err(Error::Crc);
}
if sr1.ovr() {
info.regs.sr1().write(|reg| {
reg.0 = !0;
reg.set_ovr(false);
});
return Err(Error::Overrun);
}
if sr1.af() {
info.regs.sr1().write(|reg| {
reg.0 = !0;
reg.set_af(false);
});
return Err(Error::Nack);
}
if sr1.arlo() {
info.regs.sr1().write(|reg| {
reg.0 = !0;
reg.set_arlo(false);
});
return Err(Error::Arbitration);
}
if sr1.berr() {
info.regs.sr1().write(|reg| {
reg.0 = !0;
reg.set_berr(false);
});
}
Ok(sr1)
}
fn write_bytes(
&mut self,
addr: u8,
bytes: &[u8],
timeout: Timeout,
frame: FrameOptions,
) -> Result<(), Error> {
if frame.send_start() {
self.info.regs.cr1().modify(|reg| {
reg.set_start(true);
});
while !Self::check_and_clear_error_flags(self.info)?.start() {
timeout.check()?;
}
if self.info.regs.cr1().read().start() || !self.info.regs.sr2().read().msl() {
return Err(Error::Arbitration);
}
self.info.regs.dr().write(|reg| reg.set_dr(addr << 1));
while !Self::check_and_clear_error_flags(self.info)?.addr() {
timeout.check()?;
}
let _ = self.info.regs.sr2().read();
}
for c in bytes {
self.send_byte(*c, timeout)?;
}
if frame.send_stop() {
self.info.regs.cr1().modify(|reg| reg.set_stop(true));
}
Ok(())
}
fn send_byte(&self, byte: u8, timeout: Timeout) -> Result<(), Error> {
while {
!Self::check_and_clear_error_flags(self.info)?.txe()
} {
timeout.check()?;
}
self.info.regs.dr().write(|reg| reg.set_dr(byte));
while {
!Self::check_and_clear_error_flags(self.info)?.btf()
} {
timeout.check()?;
}
Ok(())
}
fn recv_byte(&self, timeout: Timeout) -> Result<u8, Error> {
while {
Self::check_and_clear_error_flags(self.info)?;
!self.info.regs.sr1().read().rxne()
} {
timeout.check()?;
}
let value = self.info.regs.dr().read().dr();
Ok(value)
}
fn blocking_read_timeout(
&mut self,
addr: u8,
buffer: &mut [u8],
timeout: Timeout,
frame: FrameOptions,
) -> Result<(), Error> {
let Some((last, buffer)) = buffer.split_last_mut() else {
return Err(Error::Overrun);
};
if frame.send_start() {
self.info.regs.cr1().modify(|reg| {
reg.set_start(true);
reg.set_ack(true);
});
while !Self::check_and_clear_error_flags(self.info)?.start() {
timeout.check()?;
}
if self.info.regs.cr1().read().start() || !self.info.regs.sr2().read().msl() {
return Err(Error::Arbitration);
}
self.info.regs.dr().write(|reg| reg.set_dr((addr << 1) + 1));
while !Self::check_and_clear_error_flags(self.info)?.addr() {
timeout.check()?;
}
let _ = self.info.regs.sr2().read();
}
for c in buffer {
*c = self.recv_byte(timeout)?;
}
self.info.regs.cr1().modify(|reg| {
if frame.send_nack() {
reg.set_ack(false);
}
if frame.send_stop() {
reg.set_stop(true);
}
});
*last = self.recv_byte(timeout)?;
Ok(())
}
pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> {
self.blocking_read_timeout(addr, read, self.timeout(), FrameOptions::FirstAndLastFrame)
}
pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> {
self.write_bytes(addr, write, self.timeout(), FrameOptions::FirstAndLastFrame)?;
Ok(())
}
pub fn blocking_write_read(
&mut self,
addr: u8,
write: &[u8],
read: &mut [u8],
) -> Result<(), Error> {
if read.is_empty() {
return Err(Error::Overrun);
}
let timeout = self.timeout();
self.write_bytes(addr, write, timeout, FrameOptions::FirstFrame)?;
self.blocking_read_timeout(addr, read, timeout, FrameOptions::FirstAndLastFrame)?;
Ok(())
}
pub fn blocking_transaction(
&mut self,
addr: u8,
operations: &mut [Operation<'_>],
) -> Result<(), Error> {
let timeout = self.timeout();
for (op, frame) in operation_frames(operations)? {
match op {
Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?,
Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?,
}
}
Ok(())
}
#[cfg(dma)]
#[inline] fn enable_interrupts(info: &'static Info) -> () {
info.regs.cr2().modify(|w| {
w.set_iterren(true);
w.set_itevten(true);
});
}
}
#[cfg(dma)]
impl<'d> I2c<'d, Async> {
async fn write_frame(
&mut self,
address: u8,
write: &[u8],
frame: FrameOptions,
) -> Result<(), Error> {
self.info.regs.cr2().modify(|w| {
w.set_itbufen(false);
w.set_dmaen(true);
w.set_last(false);
});
let on_drop = OnDrop::new(|| {
self.info.regs.cr2().modify(|w| {
w.set_dmaen(false);
w.set_iterren(false);
w.set_itevten(false);
})
});
if frame.send_start() {
self.info.regs.cr1().modify(|reg| {
reg.set_start(true);
});
poll_fn(|cx| {
self.state.waker.register(cx.waker());
match Self::check_and_clear_error_flags(self.info) {
Err(e) => Poll::Ready(Err(e)),
Ok(sr1) => {
if sr1.start() {
Poll::Ready(Ok(()))
} else {
Self::enable_interrupts(self.info);
Poll::Pending
}
}
}
})
.await?;
if self.info.regs.cr1().read().start() || !self.info.regs.sr2().read().msl() {
return Err(Error::Arbitration);
}
self.info.regs.dr().write(|reg| reg.set_dr(address << 1));
poll_fn(|cx| {
self.state.waker.register(cx.waker());
match Self::check_and_clear_error_flags(self.info) {
Err(e) => Poll::Ready(Err(e)),
Ok(sr1) => {
if sr1.addr() {
Poll::Ready(Ok(()))
} else {
Self::enable_interrupts(self.info);
Poll::Pending
}
}
}
})
.await?;
self.info.regs.sr2().read();
}
let dma_transfer = unsafe {
let dst = self.info.regs.dr().as_ptr() as *mut u8;
self.tx_dma
.as_mut()
.unwrap()
.write(write, dst, Default::default())
};
let poll_error = poll_fn(|cx| {
self.state.waker.register(cx.waker());
match Self::check_and_clear_error_flags(self.info) {
Err(e) => Poll::Ready(Err::<(), Error>(e)),
Ok(_) => {
Self::enable_interrupts(self.info);
Poll::Pending
}
}
});
match select(dma_transfer, poll_error).await {
Either::Second(Err(e)) => Err(e),
_ => Ok(()),
}?;
self.info.regs.cr2().modify(|w| {
w.set_dmaen(false);
});
if frame.send_stop() {
poll_fn(|cx| {
self.state.waker.register(cx.waker());
match Self::check_and_clear_error_flags(self.info) {
Err(e) => Poll::Ready(Err(e)),
Ok(sr1) => {
if sr1.btf() {
Poll::Ready(Ok(()))
} else {
Self::enable_interrupts(self.info);
Poll::Pending
}
}
}
})
.await?;
self.info.regs.cr1().modify(|w| {
w.set_stop(true);
});
}
drop(on_drop);
Ok(())
}
pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
self.write_frame(address, write, FrameOptions::FirstAndLastFrame)
.await?;
Ok(())
}
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
self.read_frame(address, buffer, FrameOptions::FirstAndLastFrame)
.await?;
Ok(())
}
async fn read_frame(
&mut self,
address: u8,
buffer: &mut [u8],
frame: FrameOptions,
) -> Result<(), Error> {
if buffer.is_empty() {
return Err(Error::Overrun);
}
let single_byte = buffer.len() == 1;
self.info.regs.cr2().modify(|w| {
w.set_itbufen(false);
w.set_dmaen(true);
w.set_last(frame.send_nack() && !single_byte);
});
let on_drop = OnDrop::new(|| {
self.info.regs.cr2().modify(|w| {
w.set_dmaen(false);
w.set_iterren(false);
w.set_itevten(false);
})
});
if frame.send_start() {
self.info.regs.cr1().modify(|reg| {
reg.set_start(true);
reg.set_ack(true);
});
poll_fn(|cx| {
self.state.waker.register(cx.waker());
match Self::check_and_clear_error_flags(self.info) {
Err(e) => Poll::Ready(Err(e)),
Ok(sr1) => {
if sr1.start() {
Poll::Ready(Ok(()))
} else {
Self::enable_interrupts(self.info);
Poll::Pending
}
}
}
})
.await?;
if self.info.regs.cr1().read().start() || !self.info.regs.sr2().read().msl() {
return Err(Error::Arbitration);
}
self.info
.regs
.dr()
.write(|reg| reg.set_dr((address << 1) + 1));
poll_fn(|cx| {
self.state.waker.register(cx.waker());
match Self::check_and_clear_error_flags(self.info) {
Err(e) => Poll::Ready(Err(e)),
Ok(sr1) => {
if sr1.addr() {
Poll::Ready(Ok(()))
} else {
Self::enable_interrupts(self.info);
Poll::Pending
}
}
}
})
.await?;
if frame.send_nack() && single_byte {
self.info.regs.cr1().modify(|w| {
w.set_ack(false);
});
}
self.info.regs.sr2().read();
} else {
if frame.send_nack() && single_byte {
self.info.regs.cr1().modify(|w| {
w.set_ack(false);
});
}
}
if frame.send_stop() && single_byte {
self.info.regs.cr1().modify(|w| {
w.set_stop(true);
});
}
let dma_transfer = unsafe {
let src = self.info.regs.dr().as_ptr() as *mut u8;
self.rx_dma
.as_mut()
.unwrap()
.read(src, buffer, Default::default())
};
let poll_error = poll_fn(|cx| {
self.state.waker.register(cx.waker());
match Self::check_and_clear_error_flags(self.info) {
Err(e) => Poll::Ready(Err::<(), Error>(e)),
_ => {
Self::enable_interrupts(self.info);
Poll::Pending
}
}
});
match select(dma_transfer, poll_error).await {
Either::Second(Err(e)) => Err(e),
_ => Ok(()),
}?;
self.info.regs.cr2().modify(|w| {
w.set_dmaen(false);
});
if frame.send_stop() && !single_byte {
self.info.regs.cr1().modify(|w| {
w.set_stop(true);
});
}
drop(on_drop);
Ok(())
}
pub async fn write_read(
&mut self,
address: u8,
write: &[u8],
read: &mut [u8],
) -> Result<(), Error> {
if read.is_empty() {
return Err(Error::Overrun);
}
self.write_frame(address, write, FrameOptions::FirstFrame)
.await?;
self.read_frame(address, read, FrameOptions::FirstAndLastFrame)
.await
}
pub async fn transaction(
&mut self,
addr: u8,
operations: &mut [Operation<'_>],
) -> Result<(), Error> {
for (op, frame) in operation_frames(operations)? {
match op {
Operation::Read(read) => self.read_frame(addr, read, frame).await?,
Operation::Write(write) => self.write_frame(addr, write, frame).await?,
}
}
Ok(())
}
}
enum Mode {
Fast,
Standard,
}
impl Mode {
fn f_s(&self) -> i2c::vals::FS {
match self {
Mode::Fast => i2c::vals::FS::FAST,
Mode::Standard => i2c::vals::FS::STANDARD,
}
}
}
enum Duty {
Duty2_1,
Duty16_9,
}
impl Duty {
fn duty(&self) -> i2c::vals::Duty {
match self {
Duty::Duty2_1 => i2c::vals::Duty::DUTY2_1,
Duty::Duty16_9 => i2c::vals::Duty::DUTY16_9,
}
}
}
struct Timings {
freq: u8,
mode: Mode,
trise: u8,
ccr: u16,
duty: Duty,
}
impl Timings {
fn new(i2cclk: Hertz, speed: Hertz) -> Self {
let speed = speed.0;
let clock = i2cclk.0;
let freq = clock / 1_000_000;
assert!((2..=50).contains(&freq));
let trise = if speed <= 100_000 {
freq + 1
} else {
(freq * 300) / 1000 + 1
};
let mut ccr;
let duty;
let mode;
if speed <= 100_000 {
duty = Duty::Duty2_1;
mode = Mode::Standard;
ccr = {
let ccr = clock / (speed * 2);
if ccr < 4 {
4
} else {
ccr
}
};
} else {
const DUTYCYCLE: u8 = 0;
mode = Mode::Fast;
if DUTYCYCLE == 0 {
duty = Duty::Duty2_1;
ccr = clock / (speed * 3);
ccr = if ccr < 1 { 1 } else { ccr };
} else {
duty = Duty::Duty16_9;
ccr = clock / (speed * 25);
ccr = if ccr < 1 { 1 } else { ccr };
}
}
Self {
freq: freq as u8,
trise: trise as u8,
ccr: ccr as u16,
duty,
mode,
}
}
}
impl<'d, M: PeriMode> SetConfig for I2c<'d, M> {
type Config = Hertz;
type ConfigError = ();
fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
let timings = Timings::new(self.kernel_clock, *config);
self.info.regs.cr2().modify(|reg| {
reg.set_freq(timings.freq);
});
self.info.regs.ccr().modify(|reg| {
reg.set_f_s(timings.mode.f_s());
reg.set_duty(timings.duty.duty());
reg.set_ccr(timings.ccr);
});
self.info.regs.trise().modify(|reg| {
reg.set_trise(timings.trise);
});
Ok(())
}
}