stm32 i2c slave
This commit is contained in:
parent
65b98f2f07
commit
967fa1b2a2
149
embassy-stm32/src/i2c/config.rs
Normal file
149
embassy-stm32/src/i2c/config.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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<M>,
|
||||
_phantom2: PhantomData<IM>,
|
||||
}
|
||||
|
||||
impl<'d> I2c<'d, Async> {
|
||||
impl<'d> I2c<'d, Async, Master> {
|
||||
/// Create a new I2C driver.
|
||||
pub fn new<T: Instance>(
|
||||
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.
|
||||
pub fn new_blocking<T: Instance>(
|
||||
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.
|
||||
fn new_inner<T: Instance>(
|
||||
_peri: impl Peripheral<P = T> + '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<A> for I2c<'d, M, IM>
|
||||
where
|
||||
A: Into<Address>,
|
||||
{
|
||||
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<A> for I2c<'d, M, IM>
|
||||
where
|
||||
A: Into<Address>,
|
||||
{
|
||||
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<A> for I2c<'d, M, IM>
|
||||
where
|
||||
A: Into<Address>,
|
||||
{
|
||||
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<A> for I2c<'d, M, IM>
|
||||
where
|
||||
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> {
|
||||
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<A> for I2c<'d, Async, IM>
|
||||
where
|
||||
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> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<T: Instance>() {
|
||||
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();
|
||||
}
|
||||
|
||||
critical_section::with(|_| {
|
||||
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
|
||||
critical_section::with(|_| {
|
||||
regs.cr1().modify(|w| w.set_tcie(false));
|
||||
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<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
|
||||
///
|
||||
/// 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(())
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user