summaryrefslogtreecommitdiff
path: root/embassy-rp
diff options
context:
space:
mode:
authorMathias <mk@blackbird.online>2022-09-27 07:55:28 +0200
committerDario Nieuwenhuis <dirbaio@dirbaio.net>2022-09-27 22:08:49 +0200
commit44c46e3c93ae0718110a8805cab4c6c8a9b5df55 (patch)
treec31ee1fecfd3dc8d1aa6dbdbbddf959543610e1c /embassy-rp
parentb0d91e9f310f86b4eb9d75c92471831f1656ed1b (diff)
downloadembassy-44c46e3c93ae0718110a8805cab4c6c8a9b5df55.zip
Move async i2c implementation to new PR, to merge working blocking implementation faster
Diffstat (limited to 'embassy-rp')
-rw-r--r--embassy-rp/src/i2c.rs179
1 files changed, 1 insertions, 178 deletions
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index 12fae3b7..d1ec77d3 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -1,11 +1,9 @@
use core::marker::PhantomData;
-use atomic_polyfill::Ordering;
-use embassy_cortex_m::interrupt::InterruptExt;
use embassy_hal_common::{into_ref, PeripheralRef};
use pac::i2c;
-use crate::dma::{AnyChannel, Channel};
+use crate::dma::AnyChannel;
use crate::gpio::sealed::Pin;
use crate::gpio::AnyPin;
use crate::{pac, peripherals, Peripheral};
@@ -60,159 +58,6 @@ pub struct I2c<'d, T: Instance, M: Mode> {
phantom: PhantomData<(&'d mut T, M)>,
}
-impl<'d, T: Instance> I2c<'d, T, Async> {
- pub fn new(
- _peri: impl Peripheral<P = T> + 'd,
- scl: impl Peripheral<P = impl SclPin<T>> + 'd,
- sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
- irq: impl Peripheral<P = T::Interrupt> + 'd,
- tx_dma: impl Peripheral<P = impl Channel> + 'd,
- rx_dma: impl Peripheral<P = impl Channel> + 'd,
- config: Config,
- ) -> Self {
- into_ref!(scl, sda, irq, tx_dma, rx_dma);
-
- // Enable interrupts
- unsafe {
- T::regs().ic_intr_mask().modify(|w| {
- w.set_m_rx_done(true);
- });
- }
-
- irq.set_handler(Self::on_interrupt);
- irq.unpend();
- irq.enable();
-
- Self::new_inner(
- _peri,
- scl.map_into(),
- sda.map_into(),
- Some(tx_dma.map_into()),
- Some(rx_dma.map_into()),
- config,
- )
- }
-
- unsafe fn on_interrupt(_: *mut ()) {
- let status = T::regs().ic_intr_stat().read();
-
- // FIXME:
- if status.tcr() || status.tc() {
- let state = T::state();
- state.chunks_transferred.fetch_add(1, Ordering::Relaxed);
- state.waker.wake();
- }
- // The flag can only be cleared by writting to nbytes, we won't do that here, so disable
- // the interrupt
- // critical_section::with(|_| {
- // regs.cr1().modify(|w| w.set_tcie(false));
- // });
- }
-
- async fn write_internal(&mut self, bytes: &[u8], send_stop: bool) -> Result<(), Error> {
- let len = bytes.len();
- for (idx, chunk) in bytes.chunks(self.dma_buf.len()).enumerate() {
- let first = idx == 0;
- let last = idx * self.dma_buf.len() + chunk.len() == len;
-
- for (i, byte) in chunk.iter().enumerate() {
- let mut b = i2c::regs::IcDataCmd::default();
- b.set_dat(*byte);
- b.set_stop(send_stop && last);
-
- self.dma_buf[i] = b.0 as u16;
- }
-
- // Note(safety): Unwrap should be safe, as this can only be called
- // when `Mode == Async`, where we have dma channels.
- let ch = self.tx_dma.as_mut().unwrap();
- let transfer = unsafe {
- T::regs().ic_dma_cr().modify(|w| {
- w.set_tdmae(true);
- });
-
- crate::dma::write(ch, &self.dma_buf, T::regs().ic_data_cmd().ptr() as *mut _, T::TX_DREQ)
- };
-
- transfer.await;
- }
-
- Ok(())
- }
-
- async fn read_internal(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
- let len = buffer.len();
- self.read_blocking_internal(&mut buffer[..1], true, len == 1)?;
-
- if len >= 2 {
- // Note(safety): Unwrap should be safe, as this can only be called
- // when `Mode == Async`, where we have dma channels.
- let ch = self.rx_dma.as_mut().unwrap();
- let transfer = unsafe {
- T::regs().ic_data_cmd().modify(|w| {
- w.set_cmd(true);
- });
-
- T::regs().ic_dma_cr().modify(|reg| {
- reg.set_rdmae(true);
- });
- // If we don't assign future to a variable, the data register pointer
- // is held across an await and makes the future non-Send.
- crate::dma::read(
- ch,
- T::regs().ic_data_cmd().ptr() as *const _,
- &mut buffer[1..len - 1],
- T::RX_DREQ,
- )
- };
- transfer.await;
- }
-
- if len >= 2 {
- self.read_blocking_internal(&mut buffer[len - 1..], false, true)?;
- }
-
- Ok(())
- }
-
- // =========================
- // Async public API
- // =========================
-
- pub async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> {
- Self::setup(address.into())?;
- if bytes.is_empty() {
- self.write_blocking_internal(bytes, true)
- } else {
- self.write_internal(bytes, true).await
- }
- }
-
- pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
- Self::setup(address.into())?;
- if buffer.is_empty() {
- self.read_blocking_internal(buffer, true, true)
- } else {
- self.read_internal(buffer).await
- }
- }
-
- pub async fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
- Self::setup(address.into())?;
- if bytes.is_empty() {
- self.write_blocking_internal(bytes, false)?;
- } else {
- self.write_internal(bytes, true).await?;
- }
-
- if buffer.is_empty() {
- self.read_blocking_internal(buffer, true, true)
- } else {
- self.read_internal(buffer).await
- }
- }
-}
-
impl<'d, T: Instance> I2c<'d, T, Blocking> {
pub fn new_blocking(
_peri: impl Peripheral<P = T> + 'd,
@@ -616,23 +461,7 @@ fn i2c_reserved_addr(addr: u16) -> bool {
}
mod sealed {
- use atomic_polyfill::AtomicUsize;
use embassy_cortex_m::interrupt::Interrupt;
- use embassy_sync::waitqueue::AtomicWaker;
-
- pub(crate) struct State {
- pub(crate) waker: AtomicWaker,
- pub(crate) chunks_transferred: AtomicUsize,
- }
-
- impl State {
- pub(crate) const fn new() -> Self {
- Self {
- waker: AtomicWaker::new(),
- chunks_transferred: AtomicUsize::new(0),
- }
- }
- }
pub trait Instance {
const TX_DREQ: u8;
@@ -641,7 +470,6 @@ mod sealed {
type Interrupt: Interrupt;
fn regs() -> crate::pac::i2c::I2c;
- fn state() -> &'static State;
}
pub trait Mode {}
@@ -678,11 +506,6 @@ macro_rules! impl_instance {
fn regs() -> pac::i2c::I2c {
pac::$type
}
-
- fn state() -> &'static sealed::State {
- static STATE: sealed::State = sealed::State::new();
- &STATE
- }
}
impl Instance for peripherals::$type {}
};