diff --git a/embassy-stm32/src/i2c/config.rs b/embassy-stm32/src/i2c/config.rs new file mode 100644 index 000000000..eba14f6e0 --- /dev/null +++ b/embassy-stm32/src/i2c/config.rs @@ -0,0 +1,149 @@ +use stm32_metapac::i2c::vals::Oamsk; + +use crate::gpio::Pull; + +#[repr(u8)] +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum AddrMask { + NOMASK, + MASK1, + MASK2, + MASK3, + MASK4, + MASK5, + MASK6, + MASK7, +} +impl From for Oamsk { + fn from(value: AddrMask) -> Self { + match value { + AddrMask::NOMASK => Oamsk::NOMASK, + AddrMask::MASK1 => Oamsk::MASK1, + AddrMask::MASK2 => Oamsk::MASK2, + AddrMask::MASK3 => Oamsk::MASK3, + AddrMask::MASK4 => Oamsk::MASK4, + AddrMask::MASK5 => Oamsk::MASK5, + AddrMask::MASK6 => Oamsk::MASK6, + AddrMask::MASK7 => Oamsk::MASK7, + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Address { + SevenBit(u8), + TenBit(u16), +} +impl From for Address { + fn from(value: u8) -> Self { + Address::SevenBit(value) + } +} +impl From for Address { + fn from(value: u16) -> Self { + assert!(value < 0x400, "Ten bit address must be less than 0x400"); + Address::TenBit(value) + } +} +impl Address { + pub(super) fn add_mode(&self) -> stm32_metapac::i2c::vals::Addmode { + match self { + Address::SevenBit(_) => stm32_metapac::i2c::vals::Addmode::BIT7, + Address::TenBit(_) => stm32_metapac::i2c::vals::Addmode::BIT10, + } + } + pub fn addr(&self) -> u16 { + match self { + Address::SevenBit(addr) => *addr as u16, + Address::TenBit(addr) => *addr, + } + } +} + +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OA2 { + pub addr: u8, + pub mask: AddrMask, +} + +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum OwnAddresses { + OA1(Address), + OA2(OA2), + Both { oa1: Address, oa2: OA2 }, +} + +/// Slave Configuration +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct SlaveAddrConfig { + /// Target Address(es) + pub addr: OwnAddresses, + /// Control if the peripheral should respond to the general call address + pub general_call: bool, +} +impl SlaveAddrConfig { + pub fn new_oa1(addr: Address, general_call: bool) -> Self { + Self { + addr: OwnAddresses::OA1(addr), + general_call, + } + } + + pub fn basic(addr: Address) -> Self { + Self { + addr: OwnAddresses::OA1(addr), + general_call: false, + } + } +} + +/// I2C config +#[non_exhaustive] +#[derive(Copy, Clone)] +pub struct Config { + /// Enable internal pullup on SDA. + /// + /// Using external pullup resistors is recommended for I2C. If you do + /// have external pullups you should not enable this. + pub sda_pullup: bool, + /// Enable internal pullup on SCL. + /// + /// Using external pullup resistors is recommended for I2C. If you do + /// have external pullups you should not enable this. + pub scl_pullup: bool, + /// Timeout. + #[cfg(feature = "time")] + pub timeout: embassy_time::Duration, +} + +impl Default for Config { + fn default() -> Self { + Self { + sda_pullup: false, + scl_pullup: false, + #[cfg(feature = "time")] + timeout: embassy_time::Duration::from_millis(1000), + } + } +} + +impl Config { + pub(super) fn scl_pull_mode(&self) -> Pull { + match self.scl_pullup { + true => Pull::Up, + false => Pull::Down, + } + } + + pub(super) fn sda_pull_mode(&self) -> Pull { + match self.sda_pullup { + true => Pull::Up, + false => Pull::Down, + } + } +} diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 739e960b9..0457595d2 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -5,14 +5,18 @@ #[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::{Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; #[cfg(feature = "time")] use embassy_time::{Duration, Instant}; +use mode::{Master, MasterMode, MultiMaster}; use crate::dma::ChannelAndRequest; #[cfg(gpio_v2)] @@ -108,8 +112,56 @@ impl Config { } } +/// I2C modes +pub mod mode { + trait SealedMode {} + + /// Trait for I2C master operations. + #[allow(private_bounds)] + pub trait MasterMode: SealedMode {} + + /// Mode allowing for I2C master operations. + pub struct Master; + /// Mode allowing for I2C master and slave operations. + 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))] +/// The command kind to the slave from the master +pub enum CommandKind { + /// Write to the slave + SlaveReceive, + /// Read from the slave + SlaveSend, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// The command kind to the slave from the master and the address that the slave matched +pub struct Command { + pub kind: CommandKind, + pub address: Address, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// The status of the slave send operation +pub enum SendStatus { + /// The slave send operation is done, all bytes have been sent and the master is not requesting more + Done, + /// The slave send operation is done, but there are leftover bytes that the master did not read + LeftoverBytes(usize), +} + /// I2C driver. -pub struct I2c<'d, M: Mode> { +pub struct I2c<'d, M: Mode, IM: MasterMode> { info: &'static Info, state: &'static State, kernel_clock: Hertz, @@ -120,9 +172,10 @@ pub struct I2c<'d, M: Mode> { #[cfg(feature = "time")] timeout: Duration, _phantom: PhantomData, + _phantom2: PhantomData, } -impl<'d> I2c<'d, Async> { +impl<'d> I2c<'d, Async, Master> { /// Create a new I2C driver. pub fn new( peri: impl Peripheral

+ 'd, @@ -148,7 +201,7 @@ impl<'d> I2c<'d, Async> { } } -impl<'d> I2c<'d, Blocking> { +impl<'d> I2c<'d, Blocking, Master> { /// Create a new blocking I2C driver. pub fn new_blocking( peri: impl Peripheral

+ 'd, @@ -169,7 +222,7 @@ impl<'d> I2c<'d, Blocking> { } } -impl<'d, M: Mode> I2c<'d, M> { +impl<'d, M: Mode> I2c<'d, M, Master> { /// Create a new I2C driver. fn new_inner( _peri: impl Peripheral

+ 'd, @@ -194,8 +247,10 @@ impl<'d, M: Mode> I2c<'d, M> { #[cfg(feature = "time")] timeout: config.timeout, _phantom: PhantomData, + _phantom2: PhantomData, }; this.enable_and_init(freq, config); + this } @@ -203,7 +258,9 @@ impl<'d, M: Mode> I2c<'d, M> { self.info.rcc.enable_and_reset(); self.init(freq, config); } +} +impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { fn timeout(&self) -> Timeout { Timeout { #[cfg(feature = "time")] @@ -211,8 +268,28 @@ impl<'d, M: Mode> I2c<'d, M> { } } } +impl<'d, M: Mode> I2c<'d, M, Master> { + /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster) + pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> { + let mut slave = I2c { + info: self.info, + state: self.state, + kernel_clock: self.kernel_clock, + scl: self.scl.take(), + sda: self.sda.take(), + tx_dma: self.tx_dma.take(), + rx_dma: self.rx_dma.take(), + #[cfg(feature = "time")] + timeout: self.timeout, + _phantom: PhantomData, + _phantom2: PhantomData, + }; + slave.init_slave(slave_addr_config); + slave + } +} -impl<'d, M: Mode> Drop for I2c<'d, M> { +impl<'d, M: Mode, IM: MasterMode> Drop for I2c<'d, M, IM> { fn drop(&mut self) { self.scl.as_ref().map(|x| x.set_as_disconnected()); self.sda.as_ref().map(|x| x.set_as_disconnected()); @@ -329,27 +406,39 @@ foreach_peripheral!( }; ); -impl<'d, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, M> { +impl<'d, M: Mode, IM: MasterMode, A: embedded_hal_02::blocking::i2c::AddressMode> + embedded_hal_02::blocking::i2c::Read for I2c<'d, M, IM> +where + A: Into

, +{ type Error = Error; - fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(address, buffer) + fn read(&mut self, address: A, buffer: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_read(address.into(), buffer) } } -impl<'d, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, M> { +impl<'d, M: Mode, IM: MasterMode, A: embedded_hal_02::blocking::i2c::AddressMode> + embedded_hal_02::blocking::i2c::Write for I2c<'d, M, IM> +where + A: Into
, +{ type Error = Error; - fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(address, write) + fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(address.into(), write) } } -impl<'d, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, M> { +impl<'d, M: Mode, IM: MasterMode, A: embedded_hal_02::blocking::i2c::AddressMode> + embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, M, IM> +where + A: Into
, +{ 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) + fn write_read(&mut self, address: A, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_write_read(address.into(), write, read) } } @@ -369,51 +458,57 @@ impl embedded_hal_1::i2c::Error for Error { } } -impl<'d, M: Mode> embedded_hal_1::i2c::ErrorType for I2c<'d, M> { +impl<'d, M: Mode, IM: MasterMode> embedded_hal_1::i2c::ErrorType for I2c<'d, M, IM> { type Error = Error; } -impl<'d, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, M> { - fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(address, read) +impl<'d, M: Mode, IM: MasterMode, A: embedded_hal_1::i2c::AddressMode> embedded_hal_1::i2c::I2c for I2c<'d, M, IM> +where + Address: From, +{ + fn read(&mut self, address: A, read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_read(address.into(), read) } - fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(address, write) + fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(address.into(), write) } - fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_write_read(address, write, read) + fn write_read(&mut self, address: A, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_write_read(address.into(), write, read) } fn transaction( &mut self, - address: u8, + address: A, operations: &mut [embedded_hal_1::i2c::Operation<'_>], ) -> Result<(), Self::Error> { - self.blocking_transaction(address, operations) + self.blocking_transaction(address.into(), operations) } } -impl<'d> embedded_hal_async::i2c::I2c for I2c<'d, Async> { - async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { - self.read(address, read).await +impl<'d, IM: MasterMode, A: embedded_hal_async::i2c::AddressMode> embedded_hal_async::i2c::I2c for I2c<'d, Async, IM> +where + Address: From, +{ + async fn read(&mut self, address: A, read: &mut [u8]) -> Result<(), Self::Error> { + self.read(address.into(), read).await } - async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { - self.write(address, write).await + async fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> { + self.write(address.into(), 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 write_read(&mut self, address: A, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { + self.write_read(address.into(), write, read).await } async fn transaction( &mut self, - address: u8, + address: A, operations: &mut [embedded_hal_1::i2c::Operation<'_>], ) -> Result<(), Self::Error> { - self.transaction(address, operations).await + self.transaction(address.into(), operations).await } } diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 8c8df79dd..c2560d819 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -2,9 +2,12 @@ use core::cmp; use core::future::poll_fn; use core::task::Poll; +use config::{Address, OwnAddresses, OA2}; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::drop::OnDrop; use embedded_hal_1::i2c::Operation; +use mode::Master; +use stm32_metapac::i2c::vals::Addmode; use super::*; use crate::pac::i2c; @@ -13,17 +16,21 @@ pub(crate) unsafe fn on_interrupt() { let regs = T::info().regs; let isr = regs.isr().read(); - if isr.tcr() || isr.tc() { + if isr.tcr() || isr.tc() || isr.addr() || isr.stopf() { T::state().waker.wake(); } - // The flag can only be cleared by writting to nbytes, we won't do that here, so disable - // the interrupt + critical_section::with(|_| { - regs.cr1().modify(|w| w.set_tcie(false)); + regs.cr1().modify(|w| { + w.set_addrie(false); + // The flag can only be cleared by writting to nbytes, we won't do that here, so disable + // the interrupt + w.set_tcie(false); + }); }); } -impl<'d, M: Mode> I2c<'d, M> { +impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { self.info.regs.cr1().modify(|reg| { reg.set_pe(false); @@ -51,7 +58,7 @@ impl<'d, M: Mode> I2c<'d, M> { fn master_read( info: &'static Info, - address: u8, + address: Address, length: usize, stop: Stop, reload: bool, @@ -80,8 +87,8 @@ impl<'d, M: Mode> I2c<'d, M> { }; info.regs.cr2().modify(|w| { - w.set_sadd((address << 1 | 0) as u16); - w.set_add10(i2c::vals::Addmode::BIT7); + w.set_sadd(address.addr() << 1); + w.set_add10(address.add_mode()); w.set_dir(i2c::vals::Dir::READ); w.set_nbytes(length as u8); w.set_start(true); @@ -94,7 +101,7 @@ impl<'d, M: Mode> I2c<'d, M> { fn master_write( info: &'static Info, - address: u8, + address: Address, length: usize, stop: Stop, reload: bool, @@ -124,8 +131,8 @@ impl<'d, M: Mode> I2c<'d, M> { // START bit can be set even if the bus is BUSY or // I2C is in slave mode. info.regs.cr2().modify(|w| { - w.set_sadd((address << 1 | 0) as u16); - w.set_add10(i2c::vals::Addmode::BIT7); + w.set_sadd(address.addr() << 1); + w.set_add10(address.add_mode()); w.set_dir(i2c::vals::Dir::WRITE); w.set_nbytes(length as u8); w.set_start(true); @@ -136,14 +143,14 @@ impl<'d, M: Mode> I2c<'d, M> { Ok(()) } - fn master_continue(info: &'static Info, length: usize, reload: bool, timeout: Timeout) -> Result<(), Error> { + fn reload(info: &'static Info, length: usize, will_reload: bool, timeout: Timeout) -> Result<(), Error> { assert!(length < 256 && length > 0); while !info.regs.isr().read().tcr() { timeout.check()?; } - let reload = if reload { + let will_reload = if will_reload { i2c::vals::Reload::NOTCOMPLETED } else { i2c::vals::Reload::COMPLETED @@ -151,7 +158,7 @@ impl<'d, M: Mode> I2c<'d, M> { info.regs.cr2().modify(|w| { w.set_nbytes(length as u8); - w.set_reload(reload); + w.set_reload(will_reload); }); Ok(()) @@ -229,7 +236,13 @@ impl<'d, M: Mode> I2c<'d, M> { } } - fn read_internal(&mut self, address: u8, read: &mut [u8], restart: bool, timeout: Timeout) -> Result<(), Error> { + fn read_internal( + &mut self, + address: Address, + read: &mut [u8], + restart: bool, + timeout: Timeout, + ) -> Result<(), Error> { let completed_chunks = read.len() / 255; let total_chunks = if completed_chunks * 255 == read.len() { completed_chunks @@ -250,7 +263,7 @@ impl<'d, M: Mode> I2c<'d, M> { for (number, chunk) in read.chunks_mut(255).enumerate() { if number != 0 { - Self::master_continue(self.info, chunk.len(), number != last_chunk_idx, timeout)?; + Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; } for byte in chunk { @@ -263,7 +276,13 @@ impl<'d, M: Mode> I2c<'d, M> { Ok(()) } - fn write_internal(&mut self, address: u8, write: &[u8], send_stop: bool, timeout: Timeout) -> Result<(), Error> { + fn write_internal( + &mut self, + address: Address, + write: &[u8], + send_stop: bool, + timeout: Timeout, + ) -> Result<(), Error> { let completed_chunks = write.len() / 255; let total_chunks = if completed_chunks * 255 == write.len() { completed_chunks @@ -291,7 +310,7 @@ impl<'d, M: Mode> I2c<'d, M> { for (number, chunk) in write.chunks(255).enumerate() { if number != 0 { - Self::master_continue(self.info, chunk.len(), number != last_chunk_idx, timeout)?; + Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; } for byte in chunk { @@ -320,18 +339,18 @@ impl<'d, M: Mode> I2c<'d, M> { // Blocking public API /// Blocking read. - pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { + pub fn blocking_read(&mut self, address: Address, read: &mut [u8]) -> Result<(), Error> { self.read_internal(address, read, false, self.timeout()) // Automatic Stop } /// Blocking write. - pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { + pub fn blocking_write(&mut self, address: Address, write: &[u8]) -> Result<(), Error> { self.write_internal(address, write, true, self.timeout()) } /// Blocking write, restart, read. - pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { + pub fn blocking_write_read(&mut self, address: Address, write: &[u8], read: &mut [u8]) -> Result<(), Error> { let timeout = self.timeout(); self.write_internal(address, write, false, timeout)?; self.read_internal(address, read, true, timeout) @@ -343,7 +362,7 @@ impl<'d, M: Mode> I2c<'d, M> { /// Consecutive operations of same type are merged. See [transaction contract] for details. /// /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction - pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { + pub fn blocking_transaction(&mut self, addr: Address, operations: &mut [Operation<'_>]) -> Result<(), Error> { let _ = addr; let _ = operations; todo!() @@ -352,7 +371,7 @@ impl<'d, M: Mode> I2c<'d, M> { /// Blocking write multiple buffers. /// /// The buffers are concatenated in a single write transaction. - pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { + pub fn blocking_write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { if write.is_empty() { return Err(Error::ZeroLengthTransfer); } @@ -385,7 +404,7 @@ impl<'d, M: Mode> I2c<'d, M> { let last_chunk_idx = total_chunks.saturating_sub(1); if idx != 0 { - if let Err(err) = Self::master_continue( + if let Err(err) = Self::reload( self.info, slice_len.min(255), (idx != last_slice_index) || (slice_len > 255), @@ -398,7 +417,7 @@ impl<'d, M: Mode> I2c<'d, M> { for (number, chunk) in slice.chunks(255).enumerate() { if number != 0 { - if let Err(err) = Self::master_continue( + if let Err(err) = Self::reload( self.info, chunk.len(), (number != last_chunk_idx) || (idx != last_slice_index), @@ -431,10 +450,10 @@ impl<'d, M: Mode> I2c<'d, M> { } } -impl<'d> I2c<'d, Async> { +impl<'d, IM: MasterMode> I2c<'d, Async, IM> { async fn write_dma_internal( &mut self, - address: u8, + address: Address, write: &[u8], first_slice: bool, last_slice: bool, @@ -482,7 +501,7 @@ impl<'d> I2c<'d, Async> { timeout, )?; } else { - Self::master_continue(self.info, total_len.min(255), (total_len > 255) || !last_slice, timeout)?; + Self::reload(self.info, total_len.min(255), (total_len > 255) || !last_slice, timeout)?; self.info.regs.cr1().modify(|w| w.set_tcie(true)); } } else if !(isr.tcr() || isr.tc()) { @@ -493,7 +512,7 @@ impl<'d> I2c<'d, Async> { } else { let last_piece = (remaining_len <= 255) && last_slice; - if let Err(e) = Self::master_continue(self.info, remaining_len.min(255), !last_piece, timeout) { + if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { return Poll::Ready(Err(e)); } self.info.regs.cr1().modify(|w| w.set_tcie(true)); @@ -519,7 +538,7 @@ impl<'d> I2c<'d, Async> { async fn read_dma_internal( &mut self, - address: u8, + address: Address, buffer: &mut [u8], restart: bool, timeout: Timeout, @@ -569,7 +588,7 @@ impl<'d> I2c<'d, Async> { } else { let last_piece = remaining_len <= 255; - if let Err(e) = Self::master_continue(self.info, remaining_len.min(255), !last_piece, timeout) { + if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { return Poll::Ready(Err(e)); } self.info.regs.cr1().modify(|w| w.set_tcie(true)); @@ -590,12 +609,11 @@ impl<'d> I2c<'d, Async> { Ok(()) } - // ========================= // Async public API /// Write. - pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { + pub async fn write(&mut self, address: Address, write: &[u8]) -> Result<(), Error> { let timeout = self.timeout(); if write.is_empty() { self.write_internal(address, write, true, timeout) @@ -609,7 +627,7 @@ impl<'d> I2c<'d, Async> { /// Write multiple buffers. /// /// The buffers are concatenated in a single write transaction. - pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { + pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { let timeout = self.timeout(); if write.is_empty() { @@ -632,7 +650,7 @@ impl<'d> I2c<'d, Async> { } /// Read. - pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { + pub async fn read(&mut self, address: Address, buffer: &mut [u8]) -> Result<(), Error> { let timeout = self.timeout(); if buffer.is_empty() { @@ -644,7 +662,7 @@ impl<'d> I2c<'d, Async> { } /// Write, restart, read. - pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { + pub async fn write_read(&mut self, address: Address, write: &[u8], read: &mut [u8]) -> Result<(), Error> { let timeout = self.timeout(); if write.is_empty() { @@ -669,13 +687,343 @@ impl<'d> I2c<'d, Async> { /// Consecutive operations of same type are merged. See [transaction contract] for details. /// /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction - pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { + pub async fn transaction(&mut self, addr: Address, operations: &mut [Operation<'_>]) -> Result<(), Error> { let _ = addr; let _ = operations; todo!() } } +impl<'d, M: Mode> I2c<'d, M, MultiMaster> { + pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { + self.info.regs.cr1().modify(|reg| { + reg.set_pe(false); + }); + + self.info.regs.cr1().modify(|reg| { + reg.set_nostretch(false); + reg.set_gcen(config.general_call); + reg.set_sbc(true); + reg.set_pe(true); + }); + + self.reconfigure_addresses(config.addr); + } + + /// Configure the slave address. + pub fn reconfigure_addresses(&mut self, addresses: OwnAddresses) { + match addresses { + OwnAddresses::OA1(oa1) => self.configure_oa1(oa1), + OwnAddresses::OA2(oa2) => self.configure_oa2(oa2), + OwnAddresses::Both { oa1, oa2 } => { + self.configure_oa1(oa1); + self.configure_oa2(oa2); + } + } + } + + fn configure_oa1(&mut self, oa1: Address) { + match oa1 { + Address::SevenBit(addr) => self.info.regs.oar1().write(|reg| { + reg.set_oa1en(false); + reg.set_oa1((addr << 1) as u16); + reg.set_oa1mode(Addmode::BIT7); + reg.set_oa1en(true); + }), + Address::TenBit(addr) => self.info.regs.oar1().write(|reg| { + reg.set_oa1en(false); + reg.set_oa1(addr); + reg.set_oa1mode(Addmode::BIT10); + reg.set_oa1en(true); + }), + } + } + + fn configure_oa2(&mut self, oa2: OA2) { + self.info.regs.oar2().write(|reg| { + reg.set_oa2en(false); + reg.set_oa2msk(oa2.mask.into()); + reg.set_oa2(oa2.addr << 1); + reg.set_oa2en(true); + }); + } + + fn determine_matched_address(&self) -> Result { + let matched = self.info.regs.isr().read().addcode(); + + if matched >> 3 == 0b11110 { + // is 10-bit address and we need to get the other 8 bits from the rxdr + // we do this by doing a blocking read of 1 byte + let mut buffer = [0]; + self.slave_read_internal(&mut buffer, self.timeout())?; + Ok(Address::TenBit((matched as u16) << 6 | buffer[0] as u16)) + } else { + Ok(Address::SevenBit(matched)) + } + } +} + +impl<'d, M: Mode> I2c<'d, M, MultiMaster> { + /// # Safety + /// This function will clear the address flag which will stop the clock stretching. + /// This should only be done after the dma transfer has been set up. + fn slave_start(info: &'static Info, length: usize, reload: bool) { + assert!(length < 256); + + let reload = if reload { + i2c::vals::Reload::NOTCOMPLETED + } else { + i2c::vals::Reload::COMPLETED + }; + + info.regs.cr2().modify(|w| { + w.set_nbytes(length as u8); + w.set_reload(reload); + }); + + // clear the address flag, will stop the clock stretching. + // this should only be done after the dma transfer has been set up. + info.regs.icr().modify(|reg| reg.set_addrcf(true)); + } + + // A blocking read operation + fn slave_read_internal(&self, read: &mut [u8], timeout: Timeout) -> Result<(), Error> { + let completed_chunks = read.len() / 255; + let total_chunks = if completed_chunks * 255 == read.len() { + completed_chunks + } else { + completed_chunks + 1 + }; + let last_chunk_idx = total_chunks.saturating_sub(1); + for (number, chunk) in read.chunks_mut(255).enumerate() { + if number != 0 { + Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; + } + + for byte in chunk { + // Wait until we have received something + self.wait_rxne(timeout)?; + + *byte = self.info.regs.rxdr().read().rxdata(); + } + } + + Ok(()) + } + + // A blocking write operation + fn slave_write_internal(&mut self, write: &[u8], timeout: Timeout) -> Result<(), Error> { + let completed_chunks = write.len() / 255; + let total_chunks = if completed_chunks * 255 == write.len() { + completed_chunks + } else { + completed_chunks + 1 + }; + let last_chunk_idx = total_chunks.saturating_sub(1); + + for (number, chunk) in write.chunks(255).enumerate() { + if number != 0 { + Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; + } + + for byte in chunk { + // Wait until we are allowed to send data + // (START has been ACKed or last byte when + // through) + self.wait_txe(timeout)?; + + self.info.regs.txdr().write(|w| w.set_txdata(*byte)); + } + } + Ok(()) + } + + /// Listen for incoming I2C messages. + /// + /// The listen method is an asynchronous method but it does not require DMA to be asynchronous. + pub async fn listen(&mut self) -> Result { + let state = self.state; + self.info.regs.cr1().modify(|reg| { + reg.set_addrie(true); + }); + + poll_fn(|cx| { + state.waker.register(cx.waker()); + let isr = self.info.regs.isr().read(); + if !isr.addr() { + Poll::Pending + } else { + // we do not clear the address flag here as it will be cleared by the dma read/write + // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it + match isr.dir() { + i2c::vals::Dir::WRITE => Poll::Ready(Ok(Command { + kind: CommandKind::SlaveReceive, + address: self.determine_matched_address()?, + })), + i2c::vals::Dir::READ => Poll::Ready(Ok(Command { + kind: CommandKind::SlaveSend, + address: self.determine_matched_address()?, + })), + } + } + }) + .await + } + + /// Respond to a receive command. + pub fn blocking_respond_to_receive(&self, read: &mut [u8]) -> Result<(), Error> { + let timeout = self.timeout(); + self.slave_read_internal(read, timeout) + } + + /// Respond to a send command. + pub fn blocking_respond_to_send(&mut self, write: &[u8]) -> Result<(), Error> { + let timeout = self.timeout(); + self.slave_write_internal(write, timeout) + } +} + +impl<'d> I2c<'d, Async, MultiMaster> { + /// Respond to a receive command. + pub async fn respond_to_receive(&mut self, buffer: &mut [u8]) -> Result { + let timeout = self.timeout(); + timeout.with(self.read_dma_internal_slave(buffer, timeout)).await + } + + /// Respond to a send request from an I2C master. + pub async fn respond_to_send(&mut self, write: &[u8]) -> Result { + let timeout = self.timeout(); + timeout.with(self.write_dma_internal_slave(write, timeout)).await + } + + // for data reception in slave mode + async fn read_dma_internal_slave(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result { + let total_len = buffer.len(); + let mut remaining_len = total_len; + + let regs = self.info.regs; + + let dma_transfer = unsafe { + regs.cr1().modify(|w| { + w.set_rxdmaen(true); + w.set_stopie(true); + w.set_tcie(true); + }); + let src = regs.rxdr().as_ptr() as *mut u8; + + self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) + }; + + let state = self.state; + + let on_drop = OnDrop::new(|| { + regs.cr1().modify(|w| { + w.set_rxdmaen(false); + w.set_stopie(false); + w.set_tcie(false); + }) + }); + + let total_received = poll_fn(|cx| { + state.waker.register(cx.waker()); + + let isr = regs.isr().read(); + + if remaining_len == total_len { + Self::slave_start(self.info, total_len.min(255), total_len > 255); + remaining_len = remaining_len.saturating_sub(255); + Poll::Pending + } else if isr.tcr() { + let is_last_slice = remaining_len <= 255; + if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { + return Poll::Ready(Err(e)); + } + remaining_len = remaining_len.saturating_sub(255); + regs.cr1().modify(|w| w.set_tcie(true)); + Poll::Pending + } else if isr.stopf() { + regs.icr().write(|reg| reg.set_stopcf(true)); + let poll = Poll::Ready(Ok(remaining_len)); + poll + } else { + Poll::Pending + } + }) + .await?; + + dma_transfer.await; + + drop(on_drop); + + Ok(total_received) + } + + async fn write_dma_internal_slave(&mut self, buffer: &[u8], timeout: Timeout) -> Result { + let total_len = buffer.len(); + let mut remaining_len = total_len; + + let mut dma_transfer = unsafe { + let regs = self.info.regs; + regs.cr1().modify(|w| { + w.set_txdmaen(true); + w.set_stopie(true); + w.set_tcie(true); + }); + let dst = regs.txdr().as_ptr() as *mut u8; + + self.tx_dma.as_mut().unwrap().write(buffer, dst, Default::default()) + }; + + let on_drop = OnDrop::new(|| { + let regs = self.info.regs; + regs.cr1().modify(|w| { + w.set_txdmaen(false); + w.set_stopie(false); + w.set_tcie(false); + }) + }); + + let state = self.state; + + let size = poll_fn(|cx| { + state.waker.register(cx.waker()); + + let isr = self.info.regs.isr().read(); + + if remaining_len == total_len { + Self::slave_start(self.info, total_len.min(255), total_len > 255); + remaining_len = remaining_len.saturating_sub(255); + Poll::Pending + } else if isr.tcr() { + let is_last_slice = remaining_len <= 255; + if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { + return Poll::Ready(Err(e)); + } + remaining_len = remaining_len.saturating_sub(255); + self.info.regs.cr1().modify(|w| w.set_tcie(true)); + Poll::Pending + } else if isr.stopf() { + self.info.regs.icr().write(|reg| reg.set_stopcf(true)); + if remaining_len > 0 { + dma_transfer.request_stop(); + Poll::Ready(Ok(SendStatus::LeftoverBytes(remaining_len as usize))) + } else { + Poll::Ready(Ok(SendStatus::Done)) + } + } else { + Poll::Pending + } + }) + .await?; + + dma_transfer.await; + + drop(on_drop); + + Ok(size) + } +} + /// I2C Stop Configuration /// /// Peripheral options for generating the STOP condition @@ -800,7 +1148,7 @@ impl Timings { } } -impl<'d, M: Mode> SetConfig for I2c<'d, M> { +impl<'d, M: Mode> SetConfig for I2c<'d, M, Master> { type Config = Hertz; type ConfigError = (); fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { @@ -816,3 +1164,21 @@ impl<'d, M: Mode> SetConfig for I2c<'d, M> { Ok(()) } } + +impl<'d, M: Mode> SetConfig for I2c<'d, M, MultiMaster> { + type Config = (Hertz, SlaveAddrConfig); + type ConfigError = (); + fn set_config(&mut self, (config, addr_config): &Self::Config) -> Result<(), ()> { + let timings = Timings::new(self.kernel_clock, *config); + self.info.regs.timingr().write(|reg| { + reg.set_presc(timings.prescale); + reg.set_scll(timings.scll); + reg.set_sclh(timings.sclh); + reg.set_sdadel(timings.sdadel); + reg.set_scldel(timings.scldel); + }); + self.init_slave(*addr_config); + + Ok(()) + } +}