#![macro_use]
#[cfg_attr(i2c_v1, path = "v1.rs")]
#[cfg_attr(any(i2c_v2, i2c_v3), path = "v2.rs")]
mod _version;
mod config;
use core::future::Future;
use core::iter;
use core::marker::PhantomData;
pub use config::*;
use embassy_hal_internal::Peri;
use embassy_sync::waitqueue::AtomicWaker;
#[cfg(feature = "time")]
use embassy_time::{Duration, Instant};
use mode::MasterMode;
pub use mode::{Master, MultiMaster};
use crate::dma::ChannelAndRequest;
use crate::gpio::Flex;
use crate::interrupt::typelevel::Interrupt;
use crate::mode::{Async, Blocking, Mode};
use crate::rcc::{RccInfo, SealedRccPeripheral};
use crate::time::Hertz;
use crate::{interrupt, peripherals};
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
Bus,
Arbitration,
Nack,
Timeout,
Crc,
Overrun,
ZeroLengthTransfer,
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let message = match self {
Self::Bus => "Bus Error",
Self::Arbitration => "Arbitration Lost",
Self::Nack => "ACK Not Received",
Self::Timeout => "Request Timed Out",
Self::Crc => "CRC Mismatch",
Self::Overrun => "Buffer Overrun",
Self::ZeroLengthTransfer => "Zero-Length Transfers are not allowed",
};
write!(f, "{}", message)
}
}
impl core::error::Error for Error {}
pub mod mode {
trait SealedMode {}
#[allow(private_bounds)]
pub trait MasterMode: SealedMode {}
pub struct Master;
pub struct MultiMaster;
impl SealedMode for Master {}
impl MasterMode for Master {}
impl SealedMode for MultiMaster {}
impl MasterMode for MultiMaster {}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SlaveCommandKind {
Write,
Read,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SlaveCommand {
pub kind: SlaveCommandKind,
pub address: Address,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SendStatus {
Done,
LeftoverBytes(usize),
}
struct I2CDropGuard<'d> {
info: &'static Info,
_scl: Option<Flex<'d>>,
_sda: Option<Flex<'d>>,
}
impl<'d> Drop for I2CDropGuard<'d> {
fn drop(&mut self) {
self.info.rcc.disable_without_stop();
}
}
pub struct I2c<'d, M: Mode, IM: MasterMode> {
info: &'static Info,
state: &'static State,
kernel_clock: Hertz,
tx_dma: Option<ChannelAndRequest<'d>>,
rx_dma: Option<ChannelAndRequest<'d>>,
#[cfg(feature = "time")]
timeout: Duration,
_phantom: PhantomData<M>,
_phantom2: PhantomData<IM>,
_drop_guard: I2CDropGuard<'d>,
}
impl<'d> I2c<'d, Async, Master> {
pub fn new<T: Instance, D1: TxDma<T>, D2: RxDma<T>, #[cfg(afio)] A>(
peri: Peri<'d, T>,
scl: Peri<'d, if_afio!(impl SclPin<T, A>)>,
sda: Peri<'d, if_afio!(impl SdaPin<T, A>)>,
tx_dma: Peri<'d, D1>,
rx_dma: Peri<'d, D2>,
_irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
+ interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
+ interrupt::typelevel::Binding<D1::Interrupt, crate::dma::InterruptHandler<D1>>
+ interrupt::typelevel::Binding<D2::Interrupt, crate::dma::InterruptHandler<D2>>
+ 'd,
config: Config,
) -> Self {
Self::new_inner(
peri,
new_pin!(scl, config.scl_af()),
new_pin!(sda, config.sda_af()),
new_dma!(tx_dma, _irq),
new_dma!(rx_dma, _irq),
config,
)
}
}
impl<'d> I2c<'d, Blocking, Master> {
pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
peri: Peri<'d, T>,
scl: Peri<'d, if_afio!(impl SclPin<T, A>)>,
sda: Peri<'d, if_afio!(impl SdaPin<T, A>)>,
config: Config,
) -> Self {
Self::new_inner(
peri,
new_pin!(scl, config.scl_af()),
new_pin!(sda, config.sda_af()),
None,
None,
config,
)
}
}
impl<'d, M: Mode> I2c<'d, M, Master> {
fn new_inner<T: Instance>(
_peri: Peri<'d, T>,
_scl: Option<Flex<'d>>,
_sda: Option<Flex<'d>>,
tx_dma: Option<ChannelAndRequest<'d>>,
rx_dma: Option<ChannelAndRequest<'d>>,
config: Config,
) -> Self {
unsafe { T::EventInterrupt::enable() };
unsafe { T::ErrorInterrupt::enable() };
let mut this = Self {
info: T::info(),
state: T::state(),
kernel_clock: T::frequency(),
tx_dma,
rx_dma,
#[cfg(feature = "time")]
timeout: config.timeout,
_phantom: PhantomData,
_phantom2: PhantomData,
_drop_guard: I2CDropGuard {
info: T::info(),
_scl,
_sda,
},
};
this.enable_and_init(config);
this
}
fn enable_and_init(&mut self, config: Config) {
self.info.rcc.enable_and_reset_without_stop();
self.init(config);
}
}
impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
fn timeout(&self) -> Timeout {
Timeout {
#[cfg(feature = "time")]
deadline: Instant::now() + self.timeout,
}
}
}
#[derive(Copy, Clone)]
struct Timeout {
#[cfg(feature = "time")]
deadline: Instant,
}
#[allow(dead_code)]
impl Timeout {
#[inline]
fn check(self) -> Result<(), Error> {
#[cfg(feature = "time")]
if Instant::now() > self.deadline {
return Err(Error::Timeout);
}
Ok(())
}
#[inline]
fn with<R>(self, fut: impl Future<Output = Result<R, Error>>) -> impl Future<Output = Result<R, Error>> {
#[cfg(feature = "time")]
{
use futures_util::FutureExt;
embassy_futures::select::select(embassy_time::Timer::at(self.deadline), fut).map(|r| match r {
embassy_futures::select::Either::First(_) => Err(Error::Timeout),
embassy_futures::select::Either::Second(r) => r,
})
}
#[cfg(not(feature = "time"))]
fut
}
}
struct State {
#[allow(unused)]
waker: AtomicWaker,
}
impl State {
const fn new() -> Self {
Self {
waker: AtomicWaker::new(),
}
}
}
struct Info {
regs: crate::pac::i2c::I2c,
rcc: RccInfo,
}
peri_trait!(
irqs: [EventInterrupt, ErrorInterrupt],
);
pin_trait!(SclPin, Instance, @A);
pin_trait!(SdaPin, Instance, @A);
dma_trait!(RxDma, Instance);
dma_trait!(TxDma, Instance);
pub struct EventInterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::typelevel::Handler<T::EventInterrupt> for EventInterruptHandler<T> {
unsafe fn on_interrupt() {
_version::on_interrupt::<T>()
}
}
pub struct ErrorInterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::typelevel::Handler<T::ErrorInterrupt> for ErrorInterruptHandler<T> {
unsafe fn on_interrupt() {
_version::on_interrupt::<T>()
}
}
foreach_peripheral!(
(i2c, $inst:ident) => {
#[allow(private_interfaces)]
impl SealedInstance for peripherals::$inst {
fn info() -> &'static Info {
static INFO: Info = Info{
regs: crate::pac::$inst,
rcc: crate::peripherals::$inst::RCC_INFO,
};
&INFO
}
fn state() -> &'static State {
static STATE: State = State::new();
&STATE
}
}
impl Instance for peripherals::$inst {
type EventInterrupt = crate::_generated::peripheral_interrupts::$inst::EV;
type ErrorInterrupt = crate::_generated::peripheral_interrupts::$inst::ER;
}
};
);
impl<'d, M: Mode, IM: MasterMode> embedded_hal_02::blocking::i2c::Read for I2c<'d, M, IM> {
type Error = Error;
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_read(address, buffer)
}
}
impl<'d, M: Mode, IM: MasterMode> embedded_hal_02::blocking::i2c::Write for I2c<'d, M, IM> {
type Error = Error;
fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(address, write)
}
}
impl<'d, M: Mode, IM: MasterMode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, M, IM> {
type Error = Error;
fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_write_read(address, write, read)
}
}
impl embedded_hal_1::i2c::Error for Error {
fn kind(&self) -> embedded_hal_1::i2c::ErrorKind {
match *self {
Self::Bus => embedded_hal_1::i2c::ErrorKind::Bus,
Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss,
Self::Nack => {
embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Unknown)
}
Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other,
Self::Crc => embedded_hal_1::i2c::ErrorKind::Other,
Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun,
Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other,
}
}
}
impl<'d, M: Mode, IM: MasterMode> embedded_hal_1::i2c::ErrorType for I2c<'d, M, IM> {
type Error = Error;
}
impl<'d, M: Mode, IM: MasterMode> embedded_hal_1::i2c::I2c for I2c<'d, M, IM> {
fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_read(address, read)
}
fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(address, write)
}
fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_write_read(address, write, read)
}
fn transaction(
&mut self,
address: u8,
operations: &mut [embedded_hal_1::i2c::Operation<'_>],
) -> Result<(), Self::Error> {
self.blocking_transaction(address, operations)
}
}
impl<'d, IM: MasterMode> embedded_hal_async::i2c::I2c for I2c<'d, Async, IM> {
async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
self.read(address, read).await
}
async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
self.write(address, write).await
}
async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
self.write_read(address, write, read).await
}
async fn transaction(
&mut self,
address: u8,
operations: &mut [embedded_hal_1::i2c::Operation<'_>],
) -> Result<(), Self::Error> {
self.transaction(address, operations).await
}
}
#[derive(Copy, Clone)]
#[allow(dead_code)]
enum FrameOptions {
FirstAndLastFrame,
FirstFrame,
FirstAndNextFrame,
NextFrame,
LastFrame,
LastFrameNoStop,
}
#[allow(dead_code)]
impl FrameOptions {
fn send_start(self) -> bool {
match self {
Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true,
Self::NextFrame | Self::LastFrame | Self::LastFrameNoStop => false,
}
}
fn send_stop(self) -> bool {
match self {
Self::FirstAndLastFrame | Self::LastFrame => true,
Self::FirstFrame | Self::FirstAndNextFrame | Self::NextFrame | Self::LastFrameNoStop => false,
}
}
fn send_nack(self) -> bool {
match self {
Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true,
Self::FirstAndNextFrame | Self::NextFrame => false,
}
}
}
#[allow(dead_code)]
fn operation_frames<'a, 'b: 'a>(
operations: &'a mut [embedded_hal_1::i2c::Operation<'b>],
) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> {
use embedded_hal_1::i2c::Operation::{Read, Write};
if operations.iter().any(|op| match op {
Read(read) => read.is_empty(),
Write(_) => false,
}) {
return Err(Error::Overrun);
}
let mut operations = operations.iter_mut().peekable();
let mut next_first_operation = true;
Ok(iter::from_fn(move || {
let current_op = operations.next()?;
let is_first_of_type = next_first_operation;
let next_op = operations.peek();
let frame = match (is_first_of_type, next_op) {
(true, None) => FrameOptions::FirstAndLastFrame,
(true, Some(Read(_))) => FrameOptions::FirstAndNextFrame,
(true, Some(Write(_))) => FrameOptions::FirstFrame,
(false, None) => FrameOptions::LastFrame,
(false, Some(Read(_))) => FrameOptions::NextFrame,
(false, Some(Write(_))) => FrameOptions::LastFrameNoStop,
};
next_first_operation = match (¤t_op, next_op) {
(_, None) => false,
(Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true,
(Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false,
};
Some((current_op, frame))
}))
}