2021-05-31 03:21:44 +02:00
|
|
|
use core::cmp;
|
2021-05-24 17:41:37 +02:00
|
|
|
use core::marker::PhantomData;
|
2021-07-18 06:07:34 +02:00
|
|
|
use core::task::Poll;
|
|
|
|
|
|
|
|
use atomic_polyfill::{AtomicUsize, Ordering};
|
2021-09-11 01:53:53 +02:00
|
|
|
use embassy::waitqueue::AtomicWaker;
|
|
|
|
use embassy_hal_common::drop::OnDrop;
|
2021-07-30 00:13:57 +02:00
|
|
|
use embassy_hal_common::unborrow;
|
2021-07-18 06:07:34 +02:00
|
|
|
use futures::future::poll_fn;
|
2021-05-24 17:41:37 +02:00
|
|
|
|
2021-07-18 06:07:34 +02:00
|
|
|
use crate::dma::NoDma;
|
2022-02-24 02:36:30 +01:00
|
|
|
use crate::gpio::sealed::AFType;
|
2021-05-31 03:21:44 +02:00
|
|
|
use crate::i2c::{Error, Instance, SclPin, SdaPin};
|
2022-06-12 22:15:44 +02:00
|
|
|
use crate::interrupt::InterruptExt;
|
2021-05-31 03:21:44 +02:00
|
|
|
use crate::pac::i2c;
|
|
|
|
use crate::time::Hertz;
|
2022-06-12 22:15:44 +02:00
|
|
|
use crate::Unborrow;
|
2021-05-24 17:41:37 +02:00
|
|
|
|
2021-07-18 06:07:34 +02:00
|
|
|
pub struct State {
|
2022-02-26 01:23:17 +01:00
|
|
|
waker: AtomicWaker,
|
|
|
|
chunks_transferred: AtomicUsize,
|
2021-07-18 06:07:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl State {
|
2022-02-26 01:23:17 +01:00
|
|
|
pub(crate) const fn new() -> Self {
|
2021-07-18 06:07:34 +02:00
|
|
|
Self {
|
2022-02-26 01:23:17 +01:00
|
|
|
waker: AtomicWaker::new(),
|
|
|
|
chunks_transferred: AtomicUsize::new(0),
|
2021-07-18 06:07:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
|
2021-05-24 17:41:37 +02:00
|
|
|
phantom: PhantomData<&'d mut T>,
|
2021-07-18 06:07:34 +02:00
|
|
|
tx_dma: TXDMA,
|
|
|
|
#[allow(dead_code)]
|
|
|
|
rx_dma: RXDMA,
|
2021-05-24 17:41:37 +02:00
|
|
|
}
|
|
|
|
|
2021-07-18 06:07:34 +02:00
|
|
|
impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
2021-05-24 17:41:37 +02:00
|
|
|
pub fn new<F>(
|
2021-06-05 10:15:35 +02:00
|
|
|
_peri: impl Unborrow<Target = T> + 'd,
|
2021-07-18 06:07:34 +02:00
|
|
|
scl: impl Unborrow<Target = impl SclPin<T>> + 'd,
|
|
|
|
sda: impl Unborrow<Target = impl SdaPin<T>> + 'd,
|
|
|
|
irq: impl Unborrow<Target = T::Interrupt> + 'd,
|
|
|
|
tx_dma: impl Unborrow<Target = TXDMA> + 'd,
|
|
|
|
rx_dma: impl Unborrow<Target = RXDMA> + 'd,
|
2021-07-02 19:54:07 +02:00
|
|
|
freq: F,
|
2021-05-24 17:41:37 +02:00
|
|
|
) -> Self
|
|
|
|
where
|
|
|
|
F: Into<Hertz>,
|
|
|
|
{
|
2021-07-18 06:07:34 +02:00
|
|
|
unborrow!(irq, scl, sda, tx_dma, rx_dma);
|
2021-05-24 17:41:37 +02:00
|
|
|
|
2021-07-01 19:53:57 +02:00
|
|
|
T::enable();
|
2022-03-17 23:46:46 +01:00
|
|
|
T::reset();
|
2021-07-01 19:53:57 +02:00
|
|
|
|
2021-05-24 17:41:37 +02:00
|
|
|
unsafe {
|
2022-02-24 02:36:30 +01:00
|
|
|
scl.set_as_af(scl.af_num(), AFType::OutputOpenDrain);
|
|
|
|
sda.set_as_af(sda.af_num(), AFType::OutputOpenDrain);
|
2021-05-24 17:41:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
T::regs().cr1().modify(|reg| {
|
|
|
|
reg.set_pe(false);
|
|
|
|
reg.set_anfoff(false);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-07-02 19:54:07 +02:00
|
|
|
let timings = Timings::new(T::frequency(), freq.into());
|
2021-05-24 17:41:37 +02:00
|
|
|
|
|
|
|
unsafe {
|
|
|
|
T::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);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
T::regs().cr1().modify(|reg| {
|
|
|
|
reg.set_pe(true);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-07-18 06:07:34 +02:00
|
|
|
irq.set_handler(Self::on_interrupt);
|
|
|
|
irq.unpend();
|
|
|
|
irq.enable();
|
|
|
|
|
2021-05-24 17:41:37 +02:00
|
|
|
Self {
|
|
|
|
phantom: PhantomData,
|
2021-07-18 06:07:34 +02:00
|
|
|
tx_dma,
|
|
|
|
rx_dma,
|
2021-05-24 17:41:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-18 06:07:34 +02:00
|
|
|
unsafe fn on_interrupt(_: *mut ()) {
|
|
|
|
let regs = T::regs();
|
|
|
|
let isr = regs.isr().read();
|
|
|
|
|
|
|
|
if isr.tcr() || isr.tc() {
|
2022-02-26 01:23:17 +01:00
|
|
|
let state = T::state();
|
|
|
|
state.chunks_transferred.fetch_add(1, Ordering::Relaxed);
|
|
|
|
state.waker.wake();
|
2021-07-18 06:07:34 +02:00
|
|
|
}
|
|
|
|
// 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));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-05-24 17:41:37 +02:00
|
|
|
fn master_stop(&mut self) {
|
|
|
|
unsafe {
|
2022-02-14 02:12:06 +01:00
|
|
|
T::regs().cr2().write(|w| w.set_stop(true));
|
2021-05-24 17:41:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-20 14:40:16 +02:00
|
|
|
unsafe fn master_read(address: u8, length: usize, stop: Stop, reload: bool, restart: bool) {
|
2022-01-25 16:28:49 +01:00
|
|
|
assert!(length < 256);
|
2021-05-24 17:41:37 +02:00
|
|
|
|
2021-07-08 02:35:56 +02:00
|
|
|
if !restart {
|
|
|
|
// Wait for any previous address sequence to end
|
|
|
|
// automatically. This could be up to 50% of a bus
|
|
|
|
// cycle (ie. up to 0.5/freq)
|
2022-02-14 02:12:06 +01:00
|
|
|
while T::regs().cr2().read().start() {}
|
2021-07-08 02:35:56 +02:00
|
|
|
}
|
2021-05-24 17:41:37 +02:00
|
|
|
|
|
|
|
// Set START and prepare to receive bytes into
|
|
|
|
// `buffer`. The START bit can be set even if the bus
|
|
|
|
// is BUSY or I2C is in slave mode.
|
|
|
|
|
2021-07-08 02:35:56 +02:00
|
|
|
let reload = if reload {
|
|
|
|
i2c::vals::Reload::NOTCOMPLETED
|
|
|
|
} else {
|
|
|
|
i2c::vals::Reload::COMPLETED
|
|
|
|
};
|
|
|
|
|
2021-10-20 14:40:16 +02:00
|
|
|
T::regs().cr2().modify(|w| {
|
|
|
|
w.set_sadd((address << 1 | 0) as u16);
|
2022-02-14 02:12:06 +01:00
|
|
|
w.set_add10(i2c::vals::Addmode::BIT7);
|
|
|
|
w.set_dir(i2c::vals::Dir::READ);
|
2021-10-20 14:40:16 +02:00
|
|
|
w.set_nbytes(length as u8);
|
2022-02-14 02:12:06 +01:00
|
|
|
w.set_start(true);
|
2021-10-20 14:40:16 +02:00
|
|
|
w.set_autoend(stop.autoend());
|
|
|
|
w.set_reload(reload);
|
|
|
|
});
|
2021-05-24 17:41:37 +02:00
|
|
|
}
|
|
|
|
|
2021-07-18 06:07:34 +02:00
|
|
|
unsafe fn master_write(address: u8, length: usize, stop: Stop, reload: bool) {
|
2022-01-25 16:28:49 +01:00
|
|
|
assert!(length < 256);
|
2021-05-24 17:41:37 +02:00
|
|
|
|
|
|
|
// Wait for any previous address sequence to end
|
|
|
|
// automatically. This could be up to 50% of a bus
|
|
|
|
// cycle (ie. up to 0.5/freq)
|
2022-02-14 02:12:06 +01:00
|
|
|
while T::regs().cr2().read().start() {}
|
2021-05-24 17:41:37 +02:00
|
|
|
|
2021-07-08 02:35:56 +02:00
|
|
|
let reload = if reload {
|
|
|
|
i2c::vals::Reload::NOTCOMPLETED
|
|
|
|
} else {
|
|
|
|
i2c::vals::Reload::COMPLETED
|
|
|
|
};
|
|
|
|
|
2021-05-24 17:41:37 +02:00
|
|
|
// Set START and prepare to send `bytes`. The
|
|
|
|
// START bit can be set even if the bus is BUSY or
|
|
|
|
// I2C is in slave mode.
|
2021-07-18 06:07:34 +02:00
|
|
|
T::regs().cr2().modify(|w| {
|
|
|
|
w.set_sadd((address << 1 | 0) as u16);
|
2022-02-14 02:12:06 +01:00
|
|
|
w.set_add10(i2c::vals::Addmode::BIT7);
|
|
|
|
w.set_dir(i2c::vals::Dir::WRITE);
|
2021-07-18 06:07:34 +02:00
|
|
|
w.set_nbytes(length as u8);
|
2022-02-14 02:12:06 +01:00
|
|
|
w.set_start(true);
|
2021-07-18 06:07:34 +02:00
|
|
|
w.set_autoend(stop.autoend());
|
|
|
|
w.set_reload(reload);
|
|
|
|
});
|
2021-05-24 17:41:37 +02:00
|
|
|
}
|
|
|
|
|
2021-07-18 06:07:34 +02:00
|
|
|
unsafe fn master_continue(length: usize, reload: bool) {
|
2021-05-24 17:41:37 +02:00
|
|
|
assert!(length < 256 && length > 0);
|
|
|
|
|
2021-07-18 06:07:34 +02:00
|
|
|
while !T::regs().isr().read().tcr() {}
|
2021-07-09 00:53:47 +02:00
|
|
|
|
2021-07-08 02:35:56 +02:00
|
|
|
let reload = if reload {
|
|
|
|
i2c::vals::Reload::NOTCOMPLETED
|
|
|
|
} else {
|
|
|
|
i2c::vals::Reload::COMPLETED
|
|
|
|
};
|
|
|
|
|
2021-07-18 06:07:34 +02:00
|
|
|
T::regs().cr2().modify(|w| {
|
|
|
|
w.set_nbytes(length as u8);
|
|
|
|
w.set_reload(reload);
|
|
|
|
});
|
2021-05-24 17:41:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn flush_txdr(&self) {
|
|
|
|
//if $i2c.isr.read().txis().bit_is_set() {
|
|
|
|
//$i2c.txdr.write(|w| w.txdata().bits(0));
|
|
|
|
//}
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
if T::regs().isr().read().txis() {
|
|
|
|
T::regs().txdr().write(|w| w.set_txdata(0));
|
|
|
|
}
|
|
|
|
if T::regs().isr().read().txe() {
|
|
|
|
T::regs().isr().modify(|w| w.set_txe(true))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If TXDR is not flagged as empty, write 1 to flush it
|
|
|
|
//if $i2c.isr.read().txe().is_not_empty() {
|
|
|
|
//$i2c.isr.write(|w| w.txe().set_bit());
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn wait_txe(&self) -> Result<(), Error> {
|
|
|
|
loop {
|
|
|
|
unsafe {
|
|
|
|
let isr = T::regs().isr().read();
|
|
|
|
if isr.txe() {
|
|
|
|
return Ok(());
|
|
|
|
} else if isr.berr() {
|
|
|
|
T::regs().icr().write(|reg| reg.set_berrcf(true));
|
|
|
|
return Err(Error::Bus);
|
|
|
|
} else if isr.arlo() {
|
|
|
|
T::regs().icr().write(|reg| reg.set_arlocf(true));
|
|
|
|
return Err(Error::Arbitration);
|
|
|
|
} else if isr.nackf() {
|
|
|
|
T::regs().icr().write(|reg| reg.set_nackcf(true));
|
|
|
|
self.flush_txdr();
|
|
|
|
return Err(Error::Nack);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn wait_rxne(&self) -> Result<(), Error> {
|
|
|
|
loop {
|
|
|
|
unsafe {
|
|
|
|
let isr = T::regs().isr().read();
|
|
|
|
if isr.rxne() {
|
|
|
|
return Ok(());
|
|
|
|
} else if isr.berr() {
|
|
|
|
T::regs().icr().write(|reg| reg.set_berrcf(true));
|
|
|
|
return Err(Error::Bus);
|
|
|
|
} else if isr.arlo() {
|
|
|
|
T::regs().icr().write(|reg| reg.set_arlocf(true));
|
|
|
|
return Err(Error::Arbitration);
|
|
|
|
} else if isr.nackf() {
|
|
|
|
T::regs().icr().write(|reg| reg.set_nackcf(true));
|
|
|
|
self.flush_txdr();
|
|
|
|
return Err(Error::Nack);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn wait_tc(&self) -> Result<(), Error> {
|
|
|
|
loop {
|
|
|
|
unsafe {
|
|
|
|
let isr = T::regs().isr().read();
|
|
|
|
if isr.tc() {
|
|
|
|
return Ok(());
|
|
|
|
} else if isr.berr() {
|
|
|
|
T::regs().icr().write(|reg| reg.set_berrcf(true));
|
|
|
|
return Err(Error::Bus);
|
|
|
|
} else if isr.arlo() {
|
|
|
|
T::regs().icr().write(|reg| reg.set_arlocf(true));
|
|
|
|
return Err(Error::Arbitration);
|
|
|
|
} else if isr.nackf() {
|
|
|
|
T::regs().icr().write(|reg| reg.set_nackcf(true));
|
|
|
|
self.flush_txdr();
|
|
|
|
return Err(Error::Nack);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-12 22:15:44 +02:00
|
|
|
fn read_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error> {
|
2021-07-09 00:53:47 +02:00
|
|
|
let completed_chunks = buffer.len() / 255;
|
|
|
|
let total_chunks = if completed_chunks * 255 == buffer.len() {
|
|
|
|
completed_chunks
|
|
|
|
} else {
|
|
|
|
completed_chunks + 1
|
|
|
|
};
|
|
|
|
let last_chunk_idx = total_chunks.saturating_sub(1);
|
2021-05-24 17:41:37 +02:00
|
|
|
|
2021-10-20 14:40:16 +02:00
|
|
|
unsafe {
|
|
|
|
Self::master_read(
|
|
|
|
address,
|
|
|
|
buffer.len().min(255),
|
|
|
|
Stop::Automatic,
|
|
|
|
last_chunk_idx != 0,
|
|
|
|
restart,
|
|
|
|
);
|
|
|
|
}
|
2021-05-24 17:41:37 +02:00
|
|
|
|
2021-07-08 02:35:56 +02:00
|
|
|
for (number, chunk) in buffer.chunks_mut(255).enumerate() {
|
|
|
|
if number != 0 {
|
2021-07-18 06:07:34 +02:00
|
|
|
// NOTE(unsafe) We have &mut self
|
|
|
|
unsafe {
|
|
|
|
Self::master_continue(chunk.len(), number != last_chunk_idx);
|
|
|
|
}
|
2021-07-08 02:35:56 +02:00
|
|
|
}
|
2021-05-24 17:41:37 +02:00
|
|
|
|
2021-07-08 02:35:56 +02:00
|
|
|
for byte in chunk {
|
|
|
|
// Wait until we have received something
|
|
|
|
self.wait_rxne()?;
|
2021-05-24 17:41:37 +02:00
|
|
|
|
2021-07-08 02:35:56 +02:00
|
|
|
unsafe {
|
|
|
|
*byte = T::regs().rxdr().read().rxdata();
|
|
|
|
}
|
2021-05-24 17:41:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-01-14 23:31:10 +01:00
|
|
|
fn write_internal(&mut self, address: u8, bytes: &[u8], send_stop: bool) -> Result<(), Error> {
|
2021-07-09 00:53:47 +02:00
|
|
|
let completed_chunks = bytes.len() / 255;
|
|
|
|
let total_chunks = if completed_chunks * 255 == bytes.len() {
|
|
|
|
completed_chunks
|
|
|
|
} else {
|
|
|
|
completed_chunks + 1
|
|
|
|
};
|
|
|
|
let last_chunk_idx = total_chunks.saturating_sub(1);
|
2021-05-24 17:41:37 +02:00
|
|
|
|
|
|
|
// I2C start
|
|
|
|
//
|
|
|
|
// ST SAD+W
|
2021-07-18 06:07:34 +02:00
|
|
|
// NOTE(unsafe) We have &mut self
|
|
|
|
unsafe {
|
2022-06-12 22:15:44 +02:00
|
|
|
Self::master_write(address, bytes.len().min(255), Stop::Software, last_chunk_idx != 0);
|
2021-07-18 06:07:34 +02:00
|
|
|
}
|
2021-07-08 02:35:56 +02:00
|
|
|
|
|
|
|
for (number, chunk) in bytes.chunks(255).enumerate() {
|
|
|
|
if number != 0 {
|
2021-07-18 06:07:34 +02:00
|
|
|
// NOTE(unsafe) We have &mut self
|
|
|
|
unsafe {
|
|
|
|
Self::master_continue(chunk.len(), number != last_chunk_idx);
|
|
|
|
}
|
2021-07-08 02:35:56 +02:00
|
|
|
}
|
2021-05-24 17:41:37 +02:00
|
|
|
|
2021-07-08 02:35:56 +02:00
|
|
|
for byte in chunk {
|
|
|
|
// Wait until we are allowed to send data
|
|
|
|
// (START has been ACKed or last byte when
|
|
|
|
// through)
|
|
|
|
self.wait_txe()?;
|
2021-05-24 17:41:37 +02:00
|
|
|
|
2021-07-08 02:35:56 +02:00
|
|
|
unsafe {
|
|
|
|
T::regs().txdr().write(|w| w.set_txdata(*byte));
|
|
|
|
}
|
2021-05-24 17:41:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Wait until the write finishes
|
|
|
|
self.wait_tc()?;
|
|
|
|
|
2021-07-08 02:35:56 +02:00
|
|
|
if send_stop {
|
|
|
|
self.master_stop();
|
|
|
|
}
|
2021-05-24 17:41:37 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
2021-07-09 07:57:34 +02:00
|
|
|
|
2021-07-18 06:07:34 +02:00
|
|
|
async fn write_dma_internal(
|
|
|
|
&mut self,
|
|
|
|
address: u8,
|
|
|
|
bytes: &[u8],
|
|
|
|
first_slice: bool,
|
|
|
|
last_slice: bool,
|
|
|
|
) -> Result<(), Error>
|
|
|
|
where
|
|
|
|
TXDMA: crate::i2c::TxDma<T>,
|
|
|
|
{
|
|
|
|
let total_len = bytes.len();
|
|
|
|
let completed_chunks = total_len / 255;
|
|
|
|
let total_chunks = if completed_chunks * 255 == total_len {
|
|
|
|
completed_chunks
|
|
|
|
} else {
|
|
|
|
completed_chunks + 1
|
|
|
|
};
|
|
|
|
|
|
|
|
let dma_transfer = unsafe {
|
|
|
|
let regs = T::regs();
|
|
|
|
regs.cr1().modify(|w| {
|
|
|
|
w.set_txdmaen(true);
|
2021-07-27 01:13:23 +02:00
|
|
|
if first_slice {
|
|
|
|
w.set_tcie(true);
|
|
|
|
}
|
2021-07-18 06:07:34 +02:00
|
|
|
});
|
2021-12-08 03:18:15 +01:00
|
|
|
let dst = regs.txdr().ptr() as *mut u8;
|
2021-07-18 06:07:34 +02:00
|
|
|
|
|
|
|
let ch = &mut self.tx_dma;
|
2021-11-19 19:15:55 +01:00
|
|
|
let request = ch.request();
|
|
|
|
crate::dma::write(ch, request, bytes, dst)
|
2021-07-18 06:07:34 +02:00
|
|
|
};
|
|
|
|
|
2022-02-26 01:23:17 +01:00
|
|
|
let state = T::state();
|
|
|
|
state.chunks_transferred.store(0, Ordering::Relaxed);
|
2021-07-18 06:07:34 +02:00
|
|
|
let mut remaining_len = total_len;
|
|
|
|
|
|
|
|
let _on_drop = OnDrop::new(|| {
|
|
|
|
let regs = T::regs();
|
|
|
|
unsafe {
|
|
|
|
regs.cr1().modify(|w| {
|
|
|
|
if last_slice {
|
|
|
|
w.set_txdmaen(false);
|
|
|
|
}
|
|
|
|
w.set_tcie(false);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers
|
|
|
|
if first_slice {
|
|
|
|
unsafe {
|
|
|
|
Self::master_write(
|
|
|
|
address,
|
|
|
|
total_len.min(255),
|
|
|
|
Stop::Software,
|
|
|
|
(total_chunks != 1) || !last_slice,
|
|
|
|
);
|
|
|
|
}
|
2021-07-18 17:21:36 +02:00
|
|
|
} else {
|
|
|
|
unsafe {
|
|
|
|
Self::master_continue(total_len.min(255), (total_chunks != 1) || !last_slice);
|
2021-07-27 01:13:23 +02:00
|
|
|
T::regs().cr1().modify(|w| w.set_tcie(true));
|
2021-07-18 17:21:36 +02:00
|
|
|
}
|
2021-07-18 06:07:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
poll_fn(|cx| {
|
2022-02-26 01:23:17 +01:00
|
|
|
state.waker.register(cx.waker());
|
|
|
|
let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed);
|
2021-07-18 06:07:34 +02:00
|
|
|
|
|
|
|
if chunks_transferred == total_chunks {
|
|
|
|
return Poll::Ready(());
|
|
|
|
} else if chunks_transferred != 0 {
|
|
|
|
remaining_len = remaining_len.saturating_sub(255);
|
|
|
|
let last_piece = (chunks_transferred + 1 == total_chunks) && last_slice;
|
|
|
|
|
|
|
|
// NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers
|
|
|
|
unsafe {
|
|
|
|
Self::master_continue(remaining_len.min(255), !last_piece);
|
|
|
|
T::regs().cr1().modify(|w| w.set_tcie(true));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Poll::Pending
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
|
|
|
|
dma_transfer.await;
|
|
|
|
|
|
|
|
if last_slice {
|
|
|
|
// This should be done already
|
|
|
|
self.wait_tc()?;
|
|
|
|
self.master_stop();
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-06-12 22:15:44 +02:00
|
|
|
async fn read_dma_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error>
|
2021-10-20 14:40:16 +02:00
|
|
|
where
|
|
|
|
RXDMA: crate::i2c::RxDma<T>,
|
|
|
|
{
|
|
|
|
let total_len = buffer.len();
|
|
|
|
let completed_chunks = total_len / 255;
|
|
|
|
let total_chunks = if completed_chunks * 255 == total_len {
|
|
|
|
completed_chunks
|
|
|
|
} else {
|
|
|
|
completed_chunks + 1
|
|
|
|
};
|
|
|
|
|
|
|
|
let dma_transfer = unsafe {
|
|
|
|
let regs = T::regs();
|
|
|
|
regs.cr1().modify(|w| {
|
|
|
|
w.set_rxdmaen(true);
|
|
|
|
w.set_tcie(true);
|
|
|
|
});
|
2021-12-08 03:18:15 +01:00
|
|
|
let src = regs.rxdr().ptr() as *mut u8;
|
2021-10-20 14:40:16 +02:00
|
|
|
|
|
|
|
let ch = &mut self.rx_dma;
|
2021-11-19 19:15:55 +01:00
|
|
|
let request = ch.request();
|
|
|
|
crate::dma::read(ch, request, src, buffer)
|
2021-10-20 14:40:16 +02:00
|
|
|
};
|
|
|
|
|
2022-02-26 01:23:17 +01:00
|
|
|
let state = T::state();
|
|
|
|
state.chunks_transferred.store(0, Ordering::Relaxed);
|
2021-10-20 14:40:16 +02:00
|
|
|
let mut remaining_len = total_len;
|
|
|
|
|
|
|
|
let _on_drop = OnDrop::new(|| {
|
|
|
|
let regs = T::regs();
|
|
|
|
unsafe {
|
|
|
|
regs.cr1().modify(|w| {
|
|
|
|
w.set_rxdmaen(false);
|
|
|
|
w.set_tcie(false);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers
|
|
|
|
unsafe {
|
2022-06-12 22:15:44 +02:00
|
|
|
Self::master_read(address, total_len.min(255), Stop::Software, total_chunks != 1, restart);
|
2021-10-20 14:40:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
poll_fn(|cx| {
|
2022-02-26 01:23:17 +01:00
|
|
|
state.waker.register(cx.waker());
|
|
|
|
let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed);
|
2021-10-20 14:40:16 +02:00
|
|
|
|
|
|
|
if chunks_transferred == total_chunks {
|
|
|
|
return Poll::Ready(());
|
|
|
|
} else if chunks_transferred != 0 {
|
|
|
|
remaining_len = remaining_len.saturating_sub(255);
|
|
|
|
let last_piece = chunks_transferred + 1 == total_chunks;
|
|
|
|
|
|
|
|
// NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers
|
|
|
|
unsafe {
|
|
|
|
Self::master_continue(remaining_len.min(255), !last_piece);
|
|
|
|
T::regs().cr1().modify(|w| w.set_tcie(true));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Poll::Pending
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
|
|
|
|
dma_transfer.await;
|
|
|
|
|
|
|
|
// This should be done already
|
|
|
|
self.wait_tc()?;
|
|
|
|
self.master_stop();
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-01-14 23:31:10 +01:00
|
|
|
// =========================
|
|
|
|
// Async public API
|
|
|
|
|
|
|
|
pub async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error>
|
2021-07-18 06:07:34 +02:00
|
|
|
where
|
|
|
|
TXDMA: crate::i2c::TxDma<T>,
|
|
|
|
{
|
2022-01-25 16:28:49 +01:00
|
|
|
if bytes.is_empty() {
|
|
|
|
self.write_internal(address, bytes, true)
|
|
|
|
} else {
|
|
|
|
self.write_dma_internal(address, bytes, true, true).await
|
|
|
|
}
|
2021-07-18 06:07:34 +02:00
|
|
|
}
|
|
|
|
|
2022-01-14 23:31:10 +01:00
|
|
|
pub async fn write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error>
|
2021-07-18 06:07:34 +02:00
|
|
|
where
|
|
|
|
TXDMA: crate::i2c::TxDma<T>,
|
|
|
|
{
|
|
|
|
if bytes.is_empty() {
|
|
|
|
return Err(Error::ZeroLengthTransfer);
|
|
|
|
}
|
2021-07-18 17:21:36 +02:00
|
|
|
let mut iter = bytes.iter();
|
2021-07-18 06:07:34 +02:00
|
|
|
|
|
|
|
let mut first = true;
|
|
|
|
let mut current = iter.next();
|
|
|
|
while let Some(c) = current {
|
|
|
|
let next = iter.next();
|
2021-07-18 17:21:36 +02:00
|
|
|
let is_last = next.is_none();
|
|
|
|
|
|
|
|
self.write_dma_internal(address, c, first, is_last).await?;
|
2021-07-18 06:07:34 +02:00
|
|
|
first = false;
|
|
|
|
current = next;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-01-14 23:31:10 +01:00
|
|
|
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
|
|
|
|
where
|
|
|
|
RXDMA: crate::i2c::RxDma<T>,
|
|
|
|
{
|
2022-01-25 16:28:49 +01:00
|
|
|
if buffer.is_empty() {
|
|
|
|
self.read_internal(address, buffer, false)
|
|
|
|
} else {
|
|
|
|
self.read_dma_internal(address, buffer, false).await
|
|
|
|
}
|
2022-01-14 23:31:10 +01:00
|
|
|
}
|
|
|
|
|
2022-06-12 22:15:44 +02:00
|
|
|
pub async fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error>
|
2021-10-20 14:40:16 +02:00
|
|
|
where
|
2022-01-14 23:31:10 +01:00
|
|
|
TXDMA: super::TxDma<T>,
|
|
|
|
RXDMA: super::RxDma<T>,
|
2021-10-20 14:40:16 +02:00
|
|
|
{
|
2022-01-25 16:28:49 +01:00
|
|
|
if bytes.is_empty() {
|
|
|
|
self.write_internal(address, bytes, false)?;
|
|
|
|
} else {
|
|
|
|
self.write_dma_internal(address, bytes, true, true).await?;
|
|
|
|
}
|
|
|
|
|
|
|
|
if buffer.is_empty() {
|
|
|
|
self.read_internal(address, buffer, true)?;
|
|
|
|
} else {
|
|
|
|
self.read_dma_internal(address, buffer, true).await?;
|
|
|
|
}
|
|
|
|
|
2022-01-14 23:31:10 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// =========================
|
|
|
|
// Blocking public API
|
|
|
|
|
|
|
|
pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
|
|
|
|
self.read_internal(address, buffer, false)
|
|
|
|
// Automatic Stop
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> {
|
|
|
|
self.write_internal(address, bytes, true)
|
2021-10-20 14:40:16 +02:00
|
|
|
}
|
|
|
|
|
2022-06-12 22:15:44 +02:00
|
|
|
pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
|
2022-01-14 23:31:10 +01:00
|
|
|
self.write_internal(address, bytes, false)?;
|
|
|
|
self.read_internal(address, buffer, true)
|
|
|
|
// Automatic Stop
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn blocking_write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> {
|
2021-07-09 07:57:34 +02:00
|
|
|
if bytes.is_empty() {
|
|
|
|
return Err(Error::ZeroLengthTransfer);
|
|
|
|
}
|
|
|
|
let first_length = bytes[0].len();
|
|
|
|
let last_slice_index = bytes.len() - 1;
|
|
|
|
|
2021-07-18 06:07:34 +02:00
|
|
|
// NOTE(unsafe) We have &mut self
|
|
|
|
unsafe {
|
|
|
|
Self::master_write(
|
|
|
|
address,
|
|
|
|
first_length.min(255),
|
|
|
|
Stop::Software,
|
|
|
|
(first_length > 255) || (last_slice_index != 0),
|
|
|
|
);
|
|
|
|
}
|
2021-07-09 07:57:34 +02:00
|
|
|
|
|
|
|
for (idx, slice) in bytes.iter().enumerate() {
|
|
|
|
let slice_len = slice.len();
|
|
|
|
let completed_chunks = slice_len / 255;
|
|
|
|
let total_chunks = if completed_chunks * 255 == slice_len {
|
|
|
|
completed_chunks
|
|
|
|
} else {
|
|
|
|
completed_chunks + 1
|
|
|
|
};
|
|
|
|
let last_chunk_idx = total_chunks.saturating_sub(1);
|
|
|
|
|
|
|
|
if idx != 0 {
|
2021-07-18 06:07:34 +02:00
|
|
|
// NOTE(unsafe) We have &mut self
|
|
|
|
unsafe {
|
2022-06-12 22:15:44 +02:00
|
|
|
Self::master_continue(slice_len.min(255), (idx != last_slice_index) || (slice_len > 255));
|
2021-07-18 06:07:34 +02:00
|
|
|
}
|
2021-07-09 07:57:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for (number, chunk) in slice.chunks(255).enumerate() {
|
|
|
|
if number != 0 {
|
2021-07-18 06:07:34 +02:00
|
|
|
// NOTE(unsafe) We have &mut self
|
|
|
|
unsafe {
|
2022-06-12 22:15:44 +02:00
|
|
|
Self::master_continue(chunk.len(), (number != last_chunk_idx) || (idx != last_slice_index));
|
2021-07-18 06:07:34 +02:00
|
|
|
}
|
2021-07-09 07:57:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for byte in chunk {
|
|
|
|
// Wait until we are allowed to send data
|
|
|
|
// (START has been ACKed or last byte when
|
|
|
|
// through)
|
|
|
|
self.wait_txe()?;
|
|
|
|
|
|
|
|
// Put byte on the wire
|
|
|
|
//self.i2c.txdr.write(|w| w.txdata().bits(*byte));
|
|
|
|
unsafe {
|
|
|
|
T::regs().txdr().write(|w| w.set_txdata(*byte));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Wait until the write finishes
|
|
|
|
self.wait_tc()?;
|
|
|
|
self.master_stop();
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2021-05-24 17:41:37 +02:00
|
|
|
}
|
|
|
|
|
2022-01-26 22:39:06 +01:00
|
|
|
mod eh02 {
|
|
|
|
use super::*;
|
2021-07-08 02:35:56 +02:00
|
|
|
|
2022-01-26 22:39:06 +01:00
|
|
|
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
|
|
|
|
type Error = Error;
|
|
|
|
|
|
|
|
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
|
|
|
|
self.blocking_read(address, buffer)
|
|
|
|
}
|
2021-07-08 02:35:56 +02:00
|
|
|
}
|
|
|
|
|
2022-01-26 22:39:06 +01:00
|
|
|
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> {
|
|
|
|
type Error = Error;
|
2021-07-08 02:35:56 +02:00
|
|
|
|
2022-01-26 22:39:06 +01:00
|
|
|
fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
|
|
|
|
self.blocking_write(address, bytes)
|
|
|
|
}
|
2021-07-08 02:35:56 +02:00
|
|
|
}
|
|
|
|
|
2022-01-26 22:39:06 +01:00
|
|
|
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> {
|
|
|
|
type Error = Error;
|
2021-05-24 17:41:37 +02:00
|
|
|
|
2022-06-12 22:15:44 +02:00
|
|
|
fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> {
|
2022-01-26 22:39:06 +01:00
|
|
|
self.blocking_write_read(address, bytes, buffer)
|
|
|
|
}
|
2021-05-24 17:41:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// I2C Stop Configuration
|
|
|
|
///
|
|
|
|
/// Peripheral options for generating the STOP condition
|
|
|
|
#[derive(Copy, Clone, PartialEq)]
|
2022-01-14 23:31:10 +01:00
|
|
|
enum Stop {
|
2021-05-24 17:41:37 +02:00
|
|
|
/// Software end mode: Must write register to generate STOP condition
|
|
|
|
Software,
|
|
|
|
/// Automatic end mode: A STOP condition is automatically generated once the
|
|
|
|
/// configured number of bytes have been transferred
|
|
|
|
Automatic,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Stop {
|
|
|
|
fn autoend(&self) -> i2c::vals::Autoend {
|
|
|
|
match self {
|
|
|
|
Stop::Software => i2c::vals::Autoend::SOFTWARE,
|
|
|
|
Stop::Automatic => i2c::vals::Autoend::AUTOMATIC,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Timings {
|
|
|
|
prescale: u8,
|
|
|
|
scll: u8,
|
|
|
|
sclh: u8,
|
|
|
|
sdadel: u8,
|
|
|
|
scldel: u8,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Timings {
|
|
|
|
fn new(i2cclk: Hertz, freq: Hertz) -> Self {
|
|
|
|
let i2cclk = i2cclk.0;
|
|
|
|
let freq = freq.0;
|
|
|
|
// Refer to RM0433 Rev 7 Figure 539 for setup and hold timing:
|
|
|
|
//
|
|
|
|
// t_I2CCLK = 1 / PCLK1
|
|
|
|
// t_PRESC = (PRESC + 1) * t_I2CCLK
|
|
|
|
// t_SCLL = (SCLL + 1) * t_PRESC
|
|
|
|
// t_SCLH = (SCLH + 1) * t_PRESC
|
|
|
|
//
|
|
|
|
// t_SYNC1 + t_SYNC2 > 4 * t_I2CCLK
|
|
|
|
// t_SCL ~= t_SYNC1 + t_SYNC2 + t_SCLL + t_SCLH
|
|
|
|
let ratio = i2cclk / freq;
|
|
|
|
|
|
|
|
// For the standard-mode configuration method, we must have a ratio of 4
|
|
|
|
// or higher
|
2022-06-12 22:15:44 +02:00
|
|
|
assert!(ratio >= 4, "The I2C PCLK must be at least 4 times the bus frequency!");
|
2021-05-24 17:41:37 +02:00
|
|
|
|
|
|
|
let (presc_reg, scll, sclh, sdadel, scldel) = if freq > 100_000 {
|
|
|
|
// Fast-mode (Fm) or Fast-mode Plus (Fm+)
|
|
|
|
// here we pick SCLL + 1 = 2 * (SCLH + 1)
|
|
|
|
|
|
|
|
// Prescaler, 384 ticks for sclh/scll. Round up then subtract 1
|
|
|
|
let presc_reg = ((ratio - 1) / 384) as u8;
|
|
|
|
// ratio < 1200 by pclk 120MHz max., therefore presc < 16
|
|
|
|
|
|
|
|
// Actual precale value selected
|
|
|
|
let presc = (presc_reg + 1) as u32;
|
|
|
|
|
|
|
|
let sclh = ((ratio / presc) - 3) / 3;
|
|
|
|
let scll = (2 * (sclh + 1)) - 1;
|
|
|
|
|
|
|
|
let (sdadel, scldel) = if freq > 400_000 {
|
|
|
|
// Fast-mode Plus (Fm+)
|
|
|
|
assert!(i2cclk >= 17_000_000); // See table in datsheet
|
|
|
|
|
|
|
|
let sdadel = i2cclk / 8_000_000 / presc;
|
|
|
|
let scldel = i2cclk / 4_000_000 / presc - 1;
|
|
|
|
|
|
|
|
(sdadel, scldel)
|
|
|
|
} else {
|
|
|
|
// Fast-mode (Fm)
|
|
|
|
assert!(i2cclk >= 8_000_000); // See table in datsheet
|
|
|
|
|
|
|
|
let sdadel = i2cclk / 4_000_000 / presc;
|
|
|
|
let scldel = i2cclk / 2_000_000 / presc - 1;
|
|
|
|
|
|
|
|
(sdadel, scldel)
|
|
|
|
};
|
|
|
|
|
2022-06-12 22:15:44 +02:00
|
|
|
(presc_reg, scll as u8, sclh as u8, sdadel as u8, scldel as u8)
|
2021-05-24 17:41:37 +02:00
|
|
|
} else {
|
|
|
|
// Standard-mode (Sm)
|
|
|
|
// here we pick SCLL = SCLH
|
|
|
|
assert!(i2cclk >= 2_000_000); // See table in datsheet
|
|
|
|
|
|
|
|
// Prescaler, 512 ticks for sclh/scll. Round up then
|
|
|
|
// subtract 1
|
|
|
|
let presc = (ratio - 1) / 512;
|
|
|
|
let presc_reg = cmp::min(presc, 15) as u8;
|
|
|
|
|
|
|
|
// Actual prescale value selected
|
|
|
|
let presc = (presc_reg + 1) as u32;
|
|
|
|
|
|
|
|
let sclh = ((ratio / presc) - 2) / 2;
|
|
|
|
let scll = sclh;
|
|
|
|
|
|
|
|
// Speed check
|
2022-06-12 22:15:44 +02:00
|
|
|
assert!(sclh < 256, "The I2C PCLK is too fast for this bus frequency!");
|
2021-05-24 17:41:37 +02:00
|
|
|
|
|
|
|
let sdadel = i2cclk / 2_000_000 / presc;
|
|
|
|
let scldel = i2cclk / 500_000 / presc - 1;
|
|
|
|
|
2022-06-12 22:15:44 +02:00
|
|
|
(presc_reg, scll as u8, sclh as u8, sdadel as u8, scldel as u8)
|
2021-05-24 17:41:37 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// Sanity check
|
|
|
|
assert!(presc_reg < 16);
|
|
|
|
|
|
|
|
// Keep values within reasonable limits for fast per_ck
|
|
|
|
let sdadel = cmp::max(sdadel, 2);
|
|
|
|
let scldel = cmp::max(scldel, 4);
|
|
|
|
|
|
|
|
//(presc_reg, scll, sclh, sdadel, scldel)
|
|
|
|
Self {
|
|
|
|
prescale: presc_reg,
|
|
|
|
scll,
|
|
|
|
sclh,
|
|
|
|
sdadel,
|
|
|
|
scldel,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-20 14:40:16 +02:00
|
|
|
|
2022-01-26 22:39:06 +01:00
|
|
|
#[cfg(feature = "unstable-traits")]
|
|
|
|
mod eh1 {
|
|
|
|
use super::super::{RxDma, TxDma};
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
impl embedded_hal_1::i2c::Error for Error {
|
|
|
|
fn kind(&self) -> embedded_hal_1::i2c::ErrorKind {
|
|
|
|
match *self {
|
|
|
|
Self::Bus => embedded_hal_1::i2c::ErrorKind::Bus,
|
|
|
|
Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss,
|
2022-06-12 22:15:44 +02:00
|
|
|
Self::Nack => {
|
|
|
|
embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Unknown)
|
|
|
|
}
|
2022-01-26 22:39:06 +01:00
|
|
|
Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other,
|
|
|
|
Self::Crc => embedded_hal_1::i2c::ErrorKind::Other,
|
|
|
|
Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun,
|
|
|
|
Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other,
|
|
|
|
}
|
|
|
|
}
|
2021-10-20 14:40:16 +02:00
|
|
|
}
|
|
|
|
|
2022-06-12 22:15:44 +02:00
|
|
|
impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_1::i2c::ErrorType for I2c<'d, T, TXDMA, RXDMA> {
|
2022-01-26 22:39:06 +01:00
|
|
|
type Error = Error;
|
2021-10-20 14:40:16 +02:00
|
|
|
}
|
2022-02-12 02:26:15 +01:00
|
|
|
}
|
|
|
|
|
2022-02-16 03:54:39 +01:00
|
|
|
cfg_if::cfg_if! {
|
|
|
|
if #[cfg(all(feature = "unstable-traits", feature = "nightly"))] {
|
|
|
|
use super::{RxDma, TxDma};
|
|
|
|
use core::future::Future;
|
|
|
|
|
|
|
|
impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c
|
|
|
|
for I2c<'d, T, TXDMA, RXDMA>
|
|
|
|
{
|
|
|
|
type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
|
|
|
|
|
|
|
|
fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
|
|
|
self.read(address, buffer)
|
|
|
|
}
|
2022-01-26 22:39:06 +01:00
|
|
|
|
2022-02-16 03:54:39 +01:00
|
|
|
type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
|
|
|
|
fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> {
|
|
|
|
self.write(address, bytes)
|
|
|
|
}
|
2022-01-26 22:39:06 +01:00
|
|
|
|
2022-02-16 03:54:39 +01:00
|
|
|
type WriteReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
|
|
|
|
fn write_read<'a>(
|
|
|
|
&'a mut self,
|
|
|
|
address: u8,
|
|
|
|
bytes: &'a [u8],
|
|
|
|
buffer: &'a mut [u8],
|
|
|
|
) -> Self::WriteReadFuture<'a> {
|
|
|
|
self.write_read(address, bytes, buffer)
|
|
|
|
}
|
2022-01-26 22:39:06 +01:00
|
|
|
|
2022-02-16 03:54:39 +01:00
|
|
|
type TransactionFuture<'a, 'b> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a, 'b: 'a;
|
2022-01-26 22:39:06 +01:00
|
|
|
|
2022-02-16 03:54:39 +01:00
|
|
|
fn transaction<'a, 'b>(
|
|
|
|
&'a mut self,
|
|
|
|
address: u8,
|
|
|
|
operations: &'a mut [embedded_hal_async::i2c::Operation<'b>],
|
|
|
|
) -> Self::TransactionFuture<'a, 'b> {
|
|
|
|
let _ = address;
|
|
|
|
let _ = operations;
|
|
|
|
async move { todo!() }
|
|
|
|
}
|
2022-01-26 22:39:06 +01:00
|
|
|
}
|
2021-10-20 14:40:16 +02:00
|
|
|
}
|
|
|
|
}
|