stm32 i2c slave

This commit is contained in:
jrmoulton 2024-06-17 20:56:40 -06:00
parent 65b98f2f07
commit 967fa1b2a2
No known key found for this signature in database
3 changed files with 681 additions and 71 deletions

View File

@ -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<AddrMask> 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<u8> for Address {
fn from(value: u8) -> Self {
Address::SevenBit(value)
}
}
impl From<u16> 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,
}
}
}

View File

@ -5,14 +5,18 @@
#[cfg_attr(any(i2c_v2, i2c_v3), path = "v2.rs")] #[cfg_attr(any(i2c_v2, i2c_v3), path = "v2.rs")]
mod _version; mod _version;
mod config;
use core::future::Future; use core::future::Future;
use core::iter; use core::iter;
use core::marker::PhantomData; use core::marker::PhantomData;
pub use config::*;
use embassy_hal_internal::{Peripheral, PeripheralRef}; use embassy_hal_internal::{Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
#[cfg(feature = "time")] #[cfg(feature = "time")]
use embassy_time::{Duration, Instant}; use embassy_time::{Duration, Instant};
use mode::{Master, MasterMode, MultiMaster};
use crate::dma::ChannelAndRequest; use crate::dma::ChannelAndRequest;
#[cfg(gpio_v2)] #[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. /// I2C driver.
pub struct I2c<'d, M: Mode> { pub struct I2c<'d, M: Mode, IM: MasterMode> {
info: &'static Info, info: &'static Info,
state: &'static State, state: &'static State,
kernel_clock: Hertz, kernel_clock: Hertz,
@ -120,9 +172,10 @@ pub struct I2c<'d, M: Mode> {
#[cfg(feature = "time")] #[cfg(feature = "time")]
timeout: Duration, timeout: Duration,
_phantom: PhantomData<M>, _phantom: PhantomData<M>,
_phantom2: PhantomData<IM>,
} }
impl<'d> I2c<'d, Async> { impl<'d> I2c<'d, Async, Master> {
/// Create a new I2C driver. /// Create a new I2C driver.
pub fn new<T: Instance>( pub fn new<T: Instance>(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + '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. /// Create a new blocking I2C driver.
pub fn new_blocking<T: Instance>( pub fn new_blocking<T: Instance>(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + '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. /// Create a new I2C driver.
fn new_inner<T: Instance>( fn new_inner<T: Instance>(
_peri: impl Peripheral<P = T> + 'd, _peri: impl Peripheral<P = T> + 'd,
@ -194,8 +247,10 @@ impl<'d, M: Mode> I2c<'d, M> {
#[cfg(feature = "time")] #[cfg(feature = "time")]
timeout: config.timeout, timeout: config.timeout,
_phantom: PhantomData, _phantom: PhantomData,
_phantom2: PhantomData,
}; };
this.enable_and_init(freq, config); this.enable_and_init(freq, config);
this this
} }
@ -203,7 +258,9 @@ impl<'d, M: Mode> I2c<'d, M> {
self.info.rcc.enable_and_reset(); self.info.rcc.enable_and_reset();
self.init(freq, config); self.init(freq, config);
} }
}
impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
fn timeout(&self) -> Timeout { fn timeout(&self) -> Timeout {
Timeout { Timeout {
#[cfg(feature = "time")] #[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) { fn drop(&mut self) {
self.scl.as_ref().map(|x| x.set_as_disconnected()); self.scl.as_ref().map(|x| x.set_as_disconnected());
self.sda.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<A> for I2c<'d, M, IM>
where
A: Into<Address>,
{
type Error = Error; type Error = Error;
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { fn read(&mut self, address: A, buffer: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_read(address, buffer) 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<A> for I2c<'d, M, IM>
where
A: Into<Address>,
{
type Error = Error; type Error = Error;
fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(address, write) 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<A> for I2c<'d, M, IM>
where
A: Into<Address>,
{
type Error = Error; type Error = Error;
fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { fn write_read(&mut self, address: A, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_write_read(address, write, read) 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; type Error = Error;
} }
impl<'d, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, M> { impl<'d, M: Mode, IM: MasterMode, A: embedded_hal_1::i2c::AddressMode> embedded_hal_1::i2c::I2c<A> for I2c<'d, M, IM>
fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { where
self.blocking_read(address, read) Address: From<A>,
{
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> { fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(address, write) self.blocking_write(address.into(), write)
} }
fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { fn write_read(&mut self, address: A, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_write_read(address, write, read) self.blocking_write_read(address.into(), write, read)
} }
fn transaction( fn transaction(
&mut self, &mut self,
address: u8, address: A,
operations: &mut [embedded_hal_1::i2c::Operation<'_>], operations: &mut [embedded_hal_1::i2c::Operation<'_>],
) -> Result<(), Self::Error> { ) -> 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> { impl<'d, IM: MasterMode, A: embedded_hal_async::i2c::AddressMode> embedded_hal_async::i2c::I2c<A> for I2c<'d, Async, IM>
async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { where
self.read(address, read).await Address: From<A>,
{
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> { async fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> {
self.write(address, write).await self.write(address.into(), write).await
} }
async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { async fn write_read(&mut self, address: A, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
self.write_read(address, write, read).await self.write_read(address.into(), write, read).await
} }
async fn transaction( async fn transaction(
&mut self, &mut self,
address: u8, address: A,
operations: &mut [embedded_hal_1::i2c::Operation<'_>], operations: &mut [embedded_hal_1::i2c::Operation<'_>],
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
self.transaction(address, operations).await self.transaction(address.into(), operations).await
} }
} }

View File

@ -2,9 +2,12 @@ use core::cmp;
use core::future::poll_fn; use core::future::poll_fn;
use core::task::Poll; use core::task::Poll;
use config::{Address, OwnAddresses, OA2};
use embassy_embedded_hal::SetConfig; use embassy_embedded_hal::SetConfig;
use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::drop::OnDrop;
use embedded_hal_1::i2c::Operation; use embedded_hal_1::i2c::Operation;
use mode::Master;
use stm32_metapac::i2c::vals::Addmode;
use super::*; use super::*;
use crate::pac::i2c; use crate::pac::i2c;
@ -13,17 +16,21 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() {
let regs = T::info().regs; let regs = T::info().regs;
let isr = regs.isr().read(); let isr = regs.isr().read();
if isr.tcr() || isr.tc() { if isr.tcr() || isr.tc() || isr.addr() || isr.stopf() {
T::state().waker.wake(); 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(|_| { 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) { pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
self.info.regs.cr1().modify(|reg| { self.info.regs.cr1().modify(|reg| {
reg.set_pe(false); reg.set_pe(false);
@ -51,7 +58,7 @@ impl<'d, M: Mode> I2c<'d, M> {
fn master_read( fn master_read(
info: &'static Info, info: &'static Info,
address: u8, address: Address,
length: usize, length: usize,
stop: Stop, stop: Stop,
reload: bool, reload: bool,
@ -80,8 +87,8 @@ impl<'d, M: Mode> I2c<'d, M> {
}; };
info.regs.cr2().modify(|w| { info.regs.cr2().modify(|w| {
w.set_sadd((address << 1 | 0) as u16); w.set_sadd(address.addr() << 1);
w.set_add10(i2c::vals::Addmode::BIT7); w.set_add10(address.add_mode());
w.set_dir(i2c::vals::Dir::READ); w.set_dir(i2c::vals::Dir::READ);
w.set_nbytes(length as u8); w.set_nbytes(length as u8);
w.set_start(true); w.set_start(true);
@ -94,7 +101,7 @@ impl<'d, M: Mode> I2c<'d, M> {
fn master_write( fn master_write(
info: &'static Info, info: &'static Info,
address: u8, address: Address,
length: usize, length: usize,
stop: Stop, stop: Stop,
reload: bool, 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 // START bit can be set even if the bus is BUSY or
// I2C is in slave mode. // I2C is in slave mode.
info.regs.cr2().modify(|w| { info.regs.cr2().modify(|w| {
w.set_sadd((address << 1 | 0) as u16); w.set_sadd(address.addr() << 1);
w.set_add10(i2c::vals::Addmode::BIT7); w.set_add10(address.add_mode());
w.set_dir(i2c::vals::Dir::WRITE); w.set_dir(i2c::vals::Dir::WRITE);
w.set_nbytes(length as u8); w.set_nbytes(length as u8);
w.set_start(true); w.set_start(true);
@ -136,14 +143,14 @@ impl<'d, M: Mode> I2c<'d, M> {
Ok(()) 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); assert!(length < 256 && length > 0);
while !info.regs.isr().read().tcr() { while !info.regs.isr().read().tcr() {
timeout.check()?; timeout.check()?;
} }
let reload = if reload { let will_reload = if will_reload {
i2c::vals::Reload::NOTCOMPLETED i2c::vals::Reload::NOTCOMPLETED
} else { } else {
i2c::vals::Reload::COMPLETED i2c::vals::Reload::COMPLETED
@ -151,7 +158,7 @@ impl<'d, M: Mode> I2c<'d, M> {
info.regs.cr2().modify(|w| { info.regs.cr2().modify(|w| {
w.set_nbytes(length as u8); w.set_nbytes(length as u8);
w.set_reload(reload); w.set_reload(will_reload);
}); });
Ok(()) 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 completed_chunks = read.len() / 255;
let total_chunks = if completed_chunks * 255 == read.len() { let total_chunks = if completed_chunks * 255 == read.len() {
completed_chunks completed_chunks
@ -250,7 +263,7 @@ impl<'d, M: Mode> I2c<'d, M> {
for (number, chunk) in read.chunks_mut(255).enumerate() { for (number, chunk) in read.chunks_mut(255).enumerate() {
if number != 0 { 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 { for byte in chunk {
@ -263,7 +276,13 @@ impl<'d, M: Mode> I2c<'d, M> {
Ok(()) 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 completed_chunks = write.len() / 255;
let total_chunks = if completed_chunks * 255 == write.len() { let total_chunks = if completed_chunks * 255 == write.len() {
completed_chunks completed_chunks
@ -291,7 +310,7 @@ impl<'d, M: Mode> I2c<'d, M> {
for (number, chunk) in write.chunks(255).enumerate() { for (number, chunk) in write.chunks(255).enumerate() {
if number != 0 { 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 { for byte in chunk {
@ -320,18 +339,18 @@ impl<'d, M: Mode> I2c<'d, M> {
// Blocking public API // Blocking public API
/// Blocking read. /// 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()) self.read_internal(address, read, false, self.timeout())
// Automatic Stop // Automatic Stop
} }
/// Blocking write. /// 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()) self.write_internal(address, write, true, self.timeout())
} }
/// Blocking write, restart, read. /// 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(); let timeout = self.timeout();
self.write_internal(address, write, false, timeout)?; self.write_internal(address, write, false, timeout)?;
self.read_internal(address, read, true, 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. /// Consecutive operations of same type are merged. See [transaction contract] for details.
/// ///
/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction /// [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 _ = addr;
let _ = operations; let _ = operations;
todo!() todo!()
@ -352,7 +371,7 @@ impl<'d, M: Mode> I2c<'d, M> {
/// Blocking write multiple buffers. /// Blocking write multiple buffers.
/// ///
/// The buffers are concatenated in a single write transaction. /// 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() { if write.is_empty() {
return Err(Error::ZeroLengthTransfer); return Err(Error::ZeroLengthTransfer);
} }
@ -385,7 +404,7 @@ impl<'d, M: Mode> I2c<'d, M> {
let last_chunk_idx = total_chunks.saturating_sub(1); let last_chunk_idx = total_chunks.saturating_sub(1);
if idx != 0 { if idx != 0 {
if let Err(err) = Self::master_continue( if let Err(err) = Self::reload(
self.info, self.info,
slice_len.min(255), slice_len.min(255),
(idx != last_slice_index) || (slice_len > 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() { for (number, chunk) in slice.chunks(255).enumerate() {
if number != 0 { if number != 0 {
if let Err(err) = Self::master_continue( if let Err(err) = Self::reload(
self.info, self.info,
chunk.len(), chunk.len(),
(number != last_chunk_idx) || (idx != last_slice_index), (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( async fn write_dma_internal(
&mut self, &mut self,
address: u8, address: Address,
write: &[u8], write: &[u8],
first_slice: bool, first_slice: bool,
last_slice: bool, last_slice: bool,
@ -482,7 +501,7 @@ impl<'d> I2c<'d, Async> {
timeout, timeout,
)?; )?;
} else { } 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)); self.info.regs.cr1().modify(|w| w.set_tcie(true));
} }
} else if !(isr.tcr() || isr.tc()) { } else if !(isr.tcr() || isr.tc()) {
@ -493,7 +512,7 @@ impl<'d> I2c<'d, Async> {
} else { } else {
let last_piece = (remaining_len <= 255) && last_slice; 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)); return Poll::Ready(Err(e));
} }
self.info.regs.cr1().modify(|w| w.set_tcie(true)); self.info.regs.cr1().modify(|w| w.set_tcie(true));
@ -519,7 +538,7 @@ impl<'d> I2c<'d, Async> {
async fn read_dma_internal( async fn read_dma_internal(
&mut self, &mut self,
address: u8, address: Address,
buffer: &mut [u8], buffer: &mut [u8],
restart: bool, restart: bool,
timeout: Timeout, timeout: Timeout,
@ -569,7 +588,7 @@ impl<'d> I2c<'d, Async> {
} else { } else {
let last_piece = remaining_len <= 255; 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)); return Poll::Ready(Err(e));
} }
self.info.regs.cr1().modify(|w| w.set_tcie(true)); self.info.regs.cr1().modify(|w| w.set_tcie(true));
@ -590,12 +609,11 @@ impl<'d> I2c<'d, Async> {
Ok(()) Ok(())
} }
// ========================= // =========================
// Async public API // Async public API
/// Write. /// 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(); let timeout = self.timeout();
if write.is_empty() { if write.is_empty() {
self.write_internal(address, write, true, timeout) self.write_internal(address, write, true, timeout)
@ -609,7 +627,7 @@ impl<'d> I2c<'d, Async> {
/// Write multiple buffers. /// Write multiple buffers.
/// ///
/// The buffers are concatenated in a single write transaction. /// 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(); let timeout = self.timeout();
if write.is_empty() { if write.is_empty() {
@ -632,7 +650,7 @@ impl<'d> I2c<'d, Async> {
} }
/// Read. /// 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(); let timeout = self.timeout();
if buffer.is_empty() { if buffer.is_empty() {
@ -644,7 +662,7 @@ impl<'d> I2c<'d, Async> {
} }
/// Write, restart, read. /// 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(); let timeout = self.timeout();
if write.is_empty() { 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. /// Consecutive operations of same type are merged. See [transaction contract] for details.
/// ///
/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction /// [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 _ = addr;
let _ = operations; let _ = operations;
todo!() 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<Address, Error> {
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<Command, Error> {
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<usize, Error> {
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<SendStatus, Error> {
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<usize, Error> {
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<SendStatus, Error> {
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 /// I2C Stop Configuration
/// ///
/// Peripheral options for generating the STOP condition /// 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 Config = Hertz;
type ConfigError = (); type ConfigError = ();
fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
@ -816,3 +1164,21 @@ impl<'d, M: Mode> SetConfig for I2c<'d, M> {
Ok(()) 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(())
}
}