From eba42cb5f4c4dc1be54c27729325e982d85fc8b0 Mon Sep 17 00:00:00 2001 From: kalkyl Date: Sun, 13 Nov 2022 22:15:19 +0100 Subject: [PATCH 1/4] embassy-nrf: Add TWIS module --- embassy-nrf/src/chips/nrf52805.rs | 2 + embassy-nrf/src/chips/nrf52810.rs | 2 + embassy-nrf/src/chips/nrf52811.rs | 2 + embassy-nrf/src/chips/nrf52820.rs | 3 + embassy-nrf/src/chips/nrf52832.rs | 3 + embassy-nrf/src/chips/nrf52833.rs | 3 + embassy-nrf/src/chips/nrf52840.rs | 3 + embassy-nrf/src/chips/nrf5340_app.rs | 5 + embassy-nrf/src/chips/nrf5340_net.rs | 1 + embassy-nrf/src/chips/nrf9160.rs | 5 + embassy-nrf/src/lib.rs | 7 + embassy-nrf/src/twis.rs | 734 +++++++++++++++++++++++++++ examples/nrf/src/bin/twis.rs | 45 ++ 13 files changed, 815 insertions(+) create mode 100644 embassy-nrf/src/twis.rs create mode 100644 examples/nrf/src/bin/twis.rs diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index dec31a84..0630c0fb 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -133,6 +133,8 @@ impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); +impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0); + impl_timer!(TIMER0, TIMER0, TIMER0); impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index e57a4a38..3867fbd9 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -139,6 +139,8 @@ impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); +impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0); + impl_pwm!(PWM0, PWM0, PWM0); impl_timer!(TIMER0, TIMER0, TIMER0); diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 918404cf..36efd1db 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -140,6 +140,8 @@ impl_spim!(SPI1, SPIM1, SPIM1_SPIS1_SPI1); impl_twim!(TWISPI0, TWIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); +impl_twis!(TWISPI0, TWIS0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); + impl_pwm!(PWM0, PWM0, PWM0); impl_timer!(TIMER0, TIMER0, TIMER0); diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index dba033b0..33a07bbc 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -139,6 +139,9 @@ impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); +impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); +impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); + impl_timer!(TIMER0, TIMER0, TIMER0); impl_timer!(TIMER1, TIMER1, TIMER1); impl_timer!(TIMER2, TIMER2, TIMER2); diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 81e66c19..b1c33c39 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -149,6 +149,9 @@ impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); +impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); +impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); + impl_pwm!(PWM0, PWM0, PWM0); impl_pwm!(PWM1, PWM1, PWM1); impl_pwm!(PWM2, PWM2, PWM2); diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 92499e3c..db0a87bd 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -177,6 +177,9 @@ impl_spim!(SPI3, SPIM3, SPIM3); impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); +impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); +impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); + impl_pwm!(PWM0, PWM0, PWM0); impl_pwm!(PWM1, PWM1, PWM1); impl_pwm!(PWM2, PWM2, PWM2); diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index 4beadfba..3f4c8b8f 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -180,6 +180,9 @@ impl_spim!(SPI3, SPIM3, SPIM3); impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); +impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); +impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); + impl_pwm!(PWM0, PWM0, PWM0); impl_pwm!(PWM1, PWM1, PWM1); impl_pwm!(PWM2, PWM2, PWM2); diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index 7845d4a8..632c02cc 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -366,6 +366,11 @@ impl_twim!(UARTETWISPI1, TWIM1, SERIAL1); impl_twim!(UARTETWISPI2, TWIM2, SERIAL2); impl_twim!(UARTETWISPI3, TWIM3, SERIAL3); +impl_twis!(UARTETWISPI0, TWIS0, SERIAL0); +impl_twis!(UARTETWISPI1, TWIS1, SERIAL1); +impl_twis!(UARTETWISPI2, TWIS2, SERIAL2); +impl_twis!(UARTETWISPI3, TWIS3, SERIAL3); + impl_pwm!(PWM0, PWM0, PWM0); impl_pwm!(PWM1, PWM1, PWM1); impl_pwm!(PWM2, PWM2, PWM2); diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index ae136e09..917d1a86 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs @@ -239,6 +239,7 @@ embassy_hal_common::peripherals! { impl_uarte!(UARTETWISPI0, UARTE0, SERIAL0); impl_spim!(UARTETWISPI0, SPIM0, SERIAL0); impl_twim!(UARTETWISPI0, TWIM0, SERIAL0); +impl_twis!(UARTETWISPI0, TWIS0, SERIAL0); impl_timer!(TIMER0, TIMER0, TIMER0); impl_timer!(TIMER1, TIMER1, TIMER1); diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs index b5a53ed8..70285531 100644 --- a/embassy-nrf/src/chips/nrf9160.rs +++ b/embassy-nrf/src/chips/nrf9160.rs @@ -280,6 +280,11 @@ impl_twim!(UARTETWISPI1, TWIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); impl_twim!(UARTETWISPI2, TWIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); impl_twim!(UARTETWISPI3, TWIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); +impl_twis!(UARTETWISPI0, TWIS0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); +impl_twis!(UARTETWISPI1, TWIS1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); +impl_twis!(UARTETWISPI2, TWIS2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); +impl_twis!(UARTETWISPI3, TWIS3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); + impl_pwm!(PWM0, PWM0, PWM0); impl_pwm!(PWM1, PWM1, PWM1); impl_pwm!(PWM2, PWM2, PWM2); diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index bc70fc2f..6c5a3202 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -100,6 +100,7 @@ pub mod spim; pub mod temp; pub mod timer; pub mod twim; +pub mod twis; pub mod uarte; #[cfg(any( feature = "_nrf5340-app", @@ -267,5 +268,11 @@ pub fn init(config: config::Config) -> Peripherals { #[cfg(feature = "_time-driver")] time_driver::init(config.time_interrupt_priority); + // Disable UARTE (enabled by default for some reason) + #[cfg(feature = "_nrf9160")] + unsafe { + (*pac::UARTE0::ptr()).enable.write(|w| w.enable().disabled()); + (*pac::UARTE1::ptr()).enable.write(|w| w.enable().disabled()); + } peripherals } diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs new file mode 100644 index 00000000..8c9cb54e --- /dev/null +++ b/embassy-nrf/src/twis.rs @@ -0,0 +1,734 @@ +#![macro_use] + +//! HAL interface to the TWIS peripheral. +//! +//! See product specification: +//! +//! - nRF52832: Section 33 +//! - nRF52840: Section 6.31 +use core::future::{poll_fn, Future}; +use core::sync::atomic::compiler_fence; +use core::sync::atomic::Ordering::SeqCst; +use core::task::Poll; + +use embassy_hal_common::{into_ref, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; +#[cfg(feature = "time")] +use embassy_time::{Duration, Instant}; + +use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; +use crate::gpio::Pin as GpioPin; +use crate::interrupt::{Interrupt, InterruptExt}; +use crate::util::slice_in_ram_or; +use crate::{gpio, pac, Peripheral}; + +#[non_exhaustive] +pub struct Config { + pub addr0: u8, + pub addr1: Option, + pub orc: u8, + pub sda_high_drive: bool, + pub sda_pullup: bool, + pub scl_high_drive: bool, + pub scl_pullup: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { + addr0: 0x55, + addr1: None, + orc: 0x00, + scl_high_drive: false, + sda_pullup: false, + sda_high_drive: false, + scl_pullup: false, + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +enum Status { + Read, + Write, +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + TxBufferTooLong, + RxBufferTooLong, + DataNack, + Bus, + DMABufferNotInDataMemory, + Overflow, + OverRead, + Timeout, +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Command { + Read, + WriteRead(usize), + Write(usize), +} + +/// Interface to a TWIS instance using EasyDMA to offload the transmission and reception workload. +/// +/// For more details about EasyDMA, consult the module documentation. +pub struct Twis<'d, T: Instance> { + _p: PeripheralRef<'d, T>, +} + +impl<'d, T: Instance> Twis<'d, T> { + pub fn new( + twis: impl Peripheral

+ 'd, + irq: impl Peripheral

+ 'd, + sda: impl Peripheral

+ 'd, + scl: impl Peripheral

+ 'd, + config: Config, + ) -> Self { + into_ref!(twis, irq, sda, scl); + + let r = T::regs(); + + // Configure pins + sda.conf().write(|w| { + w.dir().input(); + w.input().connect(); + if config.sda_high_drive { + w.drive().h0d1(); + } else { + w.drive().s0d1(); + } + if config.sda_pullup { + w.pull().pullup(); + } + w + }); + scl.conf().write(|w| { + w.dir().input(); + w.input().connect(); + if config.scl_high_drive { + w.drive().h0d1(); + } else { + w.drive().s0d1(); + } + if config.scl_pullup { + w.pull().pullup(); + } + w + }); + + // Select pins. + r.psel.sda.write(|w| unsafe { w.bits(sda.psel_bits()) }); + r.psel.scl.write(|w| unsafe { w.bits(scl.psel_bits()) }); + + // Enable TWIS instance. + r.enable.write(|w| w.enable().enabled()); + + // Disable all events interrupts + r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); + + // Set address + r.address[0].write(|w| unsafe { w.address().bits(config.addr0) }); + r.config.modify(|_r, w| w.address0().enabled()); + if let Some(addr1) = config.addr1 { + r.address[1].write(|w| unsafe { w.address().bits(addr1) }); + r.config.modify(|_r, w| w.address1().enabled()); + } + + // Set over-read character + r.orc.write(|w| unsafe { w.orc().bits(config.orc) }); + + // Generate suspend on read event + r.shorts.write(|w| w.read_suspend().enabled()); + + irq.set_handler(Self::on_interrupt); + irq.unpend(); + irq.enable(); + + Self { _p: twis } + } + + fn on_interrupt(_: *mut ()) { + let r = T::regs(); + let s = T::state(); + + if r.events_read.read().bits() != 0 || r.events_write.read().bits() != 0 { + s.waker.wake(); + r.intenclr.modify(|_r, w| w.read().clear().write().clear()); + } + if r.events_stopped.read().bits() != 0 { + s.waker.wake(); + r.intenclr.modify(|_r, w| w.stopped().clear()); + } + if r.events_error.read().bits() != 0 { + s.waker.wake(); + r.intenclr.modify(|_r, w| w.error().clear()); + } + } + + /// Set TX buffer, checking that it is in RAM and has suitable length. + unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { + slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?; + + if buffer.len() > EASY_DMA_SIZE { + return Err(Error::TxBufferTooLong); + } + + let r = T::regs(); + + r.txd.ptr.write(|w| + // We're giving the register a pointer to the stack. Since we're + // waiting for the I2C transaction to end before this stack pointer + // becomes invalid, there's nothing wrong here. + // + // The PTR field is a full 32 bits wide and accepts the full range + // of values. + w.ptr().bits(buffer.as_ptr() as u32)); + r.txd.maxcnt.write(|w| + // We're giving it the length of the buffer, so no danger of + // accessing invalid memory. We have verified that the length of the + // buffer fits in an `u8`, so the cast to `u8` is also fine. + // + // The MAXCNT field is 8 bits wide and accepts the full range of + // values. + w.maxcnt().bits(buffer.len() as _)); + + Ok(()) + } + + /// Set RX buffer, checking that it has suitable length. + unsafe fn set_rx_buffer(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + // NOTE: RAM slice check is not necessary, as a mutable + // slice can only be built from data located in RAM. + + if buffer.len() > EASY_DMA_SIZE { + return Err(Error::RxBufferTooLong); + } + + let r = T::regs(); + + r.rxd.ptr.write(|w| + // We're giving the register a pointer to the stack. Since we're + // waiting for the I2C transaction to end before this stack pointer + // becomes invalid, there's nothing wrong here. + // + // The PTR field is a full 32 bits wide and accepts the full range + // of values. + w.ptr().bits(buffer.as_mut_ptr() as u32)); + r.rxd.maxcnt.write(|w| + // We're giving it the length of the buffer, so no danger of + // accessing invalid memory. We have verified that the length of the + // buffer fits in an `u8`, so the cast to the type of maxcnt + // is also fine. + // + // Note that that nrf52840 maxcnt is a wider + // type than a u8, so we use a `_` cast rather than a `u8` cast. + // The MAXCNT field is thus at least 8 bits wide and accepts the + // full range of values that fit in a `u8`. + w.maxcnt().bits(buffer.len() as _)); + + Ok(()) + } + + fn clear_errorsrc(&mut self) { + let r = T::regs(); + r.errorsrc + .write(|w| w.overflow().bit(true).overread().bit(true).dnack().bit(true)); + } + + /// Wait for stop or error + fn blocking_listen_wait(&mut self) -> Result { + let r = T::regs(); + loop { + if r.events_error.read().bits() != 0 { + r.events_error.reset(); + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + while r.events_stopped.read().bits() == 0 {} + return Err(Error::Overflow); + } + if r.events_stopped.read().bits() != 0 { + r.events_stopped.reset(); + return Err(Error::Bus); + } + if r.events_read.read().bits() != 0 { + r.events_read.reset(); + return Ok(Status::Read); + } + if r.events_write.read().bits() != 0 { + r.events_write.reset(); + return Ok(Status::Write); + } + } + } + + /// Wait for stop or error + fn blocking_listen_wait_end(&mut self, status: Status) -> Result { + let r = T::regs(); + loop { + // stop if an error occured + if r.events_error.read().bits() != 0 { + r.events_error.reset(); + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + return Err(Error::Overflow); + } else if r.events_stopped.read().bits() != 0 { + r.events_stopped.reset(); + return match status { + Status::Read => Ok(Command::Read), + Status::Write => { + let n = r.rxd.amount.read().bits() as usize; + Ok(Command::Write(n)) + } + }; + } else if r.events_read.read().bits() != 0 { + r.events_read.reset(); + let n = r.rxd.amount.read().bits() as usize; + return Ok(Command::WriteRead(n)); + } + } + } + + /// Wait for stop or error + fn blocking_wait(&mut self) -> Result<(), Error> { + let r = T::regs(); + loop { + // stop if an error occured + if r.events_error.read().bits() != 0 { + r.events_error.reset(); + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + let errorsrc = r.errorsrc.read(); + if errorsrc.overread().is_detected() { + return Err(Error::OverRead); + } else if errorsrc.dnack().is_received() { + return Err(Error::DataNack); + } else { + return Err(Error::Bus); + } + } else if r.events_stopped.read().bits() != 0 { + r.events_stopped.reset(); + return Ok(()); + } + } + } + + /// Wait for stop or error + #[cfg(feature = "time")] + fn blocking_listen_wait_timeout(&mut self, timeout: Duration) -> Result { + let r = T::regs(); + let deadline = Instant::now() + timeout; + loop { + if r.events_error.read().bits() != 0 { + r.events_error.reset(); + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + while r.events_stopped.read().bits() == 0 {} + return Err(Error::Overflow); + } + if r.events_stopped.read().bits() != 0 { + r.events_stopped.reset(); + return Err(Error::Bus); + } + if r.events_read.read().bits() != 0 { + r.events_read.reset(); + return Ok(Status::Read); + } + if r.events_write.read().bits() != 0 { + r.events_write.reset(); + return Ok(Status::Write); + } + if Instant::now() > deadline { + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + return Err(Error::Timeout); + } + } + } + + /// Wait for stop or error + #[cfg(feature = "time")] + fn blocking_listen_wait_end_timeout(&mut self, status: Status, timeout: Duration) -> Result { + let r = T::regs(); + let deadline = Instant::now() + timeout; + loop { + // stop if an error occured + if r.events_error.read().bits() != 0 { + r.events_error.reset(); + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + return Err(Error::Overflow); + } else if r.events_stopped.read().bits() != 0 { + r.events_stopped.reset(); + return match status { + Status::Read => Ok(Command::Read), + Status::Write => { + let n = r.rxd.amount.read().bits() as usize; + Ok(Command::Write(n)) + } + }; + } else if r.events_read.read().bits() != 0 { + r.events_read.reset(); + let n = r.rxd.amount.read().bits() as usize; + return Ok(Command::WriteRead(n)); + } else if Instant::now() > deadline { + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + return Err(Error::Timeout); + } + } + } + + /// Wait for stop or error + #[cfg(feature = "time")] + fn blocking_wait_timeout(&mut self, timeout: Duration) -> Result<(), Error> { + let r = T::regs(); + let deadline = Instant::now() + timeout; + loop { + // stop if an error occured + if r.events_error.read().bits() != 0 { + r.events_error.reset(); + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + let errorsrc = r.errorsrc.read(); + if errorsrc.overread().is_detected() { + return Err(Error::OverRead); + } else if errorsrc.dnack().is_received() { + return Err(Error::DataNack); + } else { + return Err(Error::Bus); + } + } else if r.events_stopped.read().bits() != 0 { + r.events_stopped.reset(); + return Ok(()); + } else if Instant::now() > deadline { + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + return Err(Error::Timeout); + } + } + } + + /// Wait for stop or error + fn async_wait(&mut self) -> impl Future> { + poll_fn(move |cx| { + let r = T::regs(); + let s = T::state(); + + s.waker.register(cx.waker()); + + // stop if an error occured + if r.events_error.read().bits() != 0 { + r.events_error.reset(); + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + let errorsrc = r.errorsrc.read(); + if errorsrc.overread().is_detected() { + return Poll::Ready(Err(Error::OverRead)); + } else if errorsrc.dnack().is_received() { + return Poll::Ready(Err(Error::DataNack)); + } else { + return Poll::Ready(Err(Error::Bus)); + } + } else if r.events_stopped.read().bits() != 0 { + r.events_stopped.reset(); + return Poll::Ready(Ok(())); + } + + Poll::Pending + }) + } + + /// Wait for read or write + fn async_listen_wait(&mut self) -> impl Future> { + poll_fn(move |cx| { + let r = T::regs(); + let s = T::state(); + + s.waker.register(cx.waker()); + + // stop if an error occured + if r.events_error.read().bits() != 0 { + r.events_error.reset(); + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + return Poll::Ready(Err(Error::Overflow)); + } else if r.events_read.read().bits() != 0 { + r.events_read.reset(); + return Poll::Ready(Ok(Status::Read)); + } else if r.events_write.read().bits() != 0 { + r.events_write.reset(); + return Poll::Ready(Ok(Status::Write)); + } else if r.events_stopped.read().bits() != 0 { + r.events_stopped.reset(); + return Poll::Ready(Err(Error::Bus)); + } + Poll::Pending + }) + } + + /// Wait for stop or error + fn async_listen_wait_end(&mut self, status: Status) -> impl Future> { + poll_fn(move |cx| { + let r = T::regs(); + let s = T::state(); + + s.waker.register(cx.waker()); + + // stop if an error occured + if r.events_error.read().bits() != 0 { + r.events_error.reset(); + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + return Poll::Ready(Err(Error::Overflow)); + } else if r.events_stopped.read().bits() != 0 { + r.events_stopped.reset(); + return match status { + Status::Read => Poll::Ready(Ok(Command::Read)), + Status::Write => { + let n = r.rxd.amount.read().bits() as usize; + Poll::Ready(Ok(Command::Write(n))) + } + }; + } else if r.events_read.read().bits() != 0 { + r.events_read.reset(); + let n = r.rxd.amount.read().bits() as usize; + return Poll::Ready(Ok(Command::WriteRead(n))); + } + Poll::Pending + }) + } + + fn setup_write_from_ram(&mut self, buffer: &[u8], inten: bool) -> Result<(), Error> { + let r = T::regs(); + + compiler_fence(SeqCst); + + // Set up the DMA write. + unsafe { self.set_tx_buffer(buffer)? }; + + // Clear events + r.events_stopped.reset(); + r.events_error.reset(); + self.clear_errorsrc(); + + if inten { + r.intenset.write(|w| w.stopped().set().error().set()); + } else { + r.intenclr.write(|w| w.stopped().clear().error().clear()); + } + + // Start write operation. + r.tasks_preparetx.write(|w| unsafe { w.bits(1) }); + r.tasks_resume.write(|w| unsafe { w.bits(1) }); + Ok(()) + } + + fn setup_write(&mut self, wr_buffer: &[u8], inten: bool) -> Result<(), Error> { + match self.setup_write_from_ram(wr_buffer, inten) { + Ok(_) => Ok(()), + Err(Error::DMABufferNotInDataMemory) => { + trace!("Copying TWIS tx buffer into RAM for DMA"); + let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; + tx_ram_buf.copy_from_slice(wr_buffer); + self.setup_write_from_ram(&tx_ram_buf, inten) + } + Err(error) => Err(error), + } + } + + fn setup_listen(&mut self, buffer: &mut [u8], inten: bool) -> Result<(), Error> { + let r = T::regs(); + compiler_fence(SeqCst); + + // Set up the DMA read. + unsafe { self.set_rx_buffer(buffer)? }; + + // Clear events + r.events_read.reset(); + r.events_write.reset(); + r.events_stopped.reset(); + r.events_error.reset(); + self.clear_errorsrc(); + + if inten { + r.intenset + .write(|w| w.stopped().set().error().set().read().set().write().set()); + } else { + r.intenclr + .write(|w| w.stopped().clear().error().clear().read().clear().write().clear()); + } + + // Start read operation. + r.tasks_preparerx.write(|w| unsafe { w.bits(1) }); + + Ok(()) + } + + fn setup_listen_end(&mut self, inten: bool) -> Result<(), Error> { + let r = T::regs(); + compiler_fence(SeqCst); + + // Clear events + r.events_read.reset(); + r.events_write.reset(); + r.events_stopped.reset(); + r.events_error.reset(); + self.clear_errorsrc(); + + if inten { + r.intenset.write(|w| w.stopped().set().error().set().read().set()); + } else { + r.intenclr.write(|w| w.stopped().clear().error().clear().read().clear()); + } + + Ok(()) + } + + /// Listen for commands from an I2C master. + /// + /// The buffer must have a length of at most 255 bytes on the nRF52832 + /// and at most 65535 bytes on the nRF52840. + pub fn blocking_listen(&mut self, buffer: &mut [u8]) -> Result { + self.setup_listen(buffer, false)?; + let status = self.blocking_listen_wait()?; + if status == Status::Write { + self.setup_listen_end(false)?; + let command = self.blocking_listen_wait_end(status)?; + return Ok(command); + } + Ok(Command::Read) + } + + /// Write to an I2C master. + /// + /// The buffer must have a length of at most 255 bytes on the nRF52832 + /// and at most 65535 bytes on the nRF52840. + pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { + self.setup_write(buffer, false)?; + self.blocking_wait()?; + Ok(()) + } + + /// Same as [`blocking_write`](Twis::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. + pub fn blocking_write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { + self.setup_write_from_ram(buffer, false)?; + self.blocking_wait()?; + Ok(()) + } + + // =========================================== + + /// Listen for commands from an I2C master. + /// + /// The buffer must have a length of at most 255 bytes on the nRF52832 + /// and at most 65535 bytes on the nRF52840. + #[cfg(feature = "time")] + pub fn blocking_listen_timeout(&mut self, buffer: &mut [u8], timeout: Duration) -> Result { + self.setup_listen(buffer, false)?; + let status = self.blocking_listen_wait_timeout(timeout)?; + if status == Status::Write { + self.setup_listen_end(false)?; + let command = self.blocking_listen_wait_end_timeout(status, timeout)?; + return Ok(command); + } + Ok(Command::Read) + } + + /// Write to an I2C master with timeout. + /// + /// See [`blocking_write`]. + #[cfg(feature = "time")] + pub fn blocking_write_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result<(), Error> { + self.setup_write(buffer, false)?; + self.blocking_wait_timeout(timeout)?; + Ok(()) + } + + /// Same as [`blocking_write`](Twis::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. + #[cfg(feature = "time")] + pub fn blocking_write_from_ram_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result<(), Error> { + self.setup_write_from_ram(buffer, false)?; + self.blocking_wait_timeout(timeout)?; + Ok(()) + } + + // =========================================== + + pub async fn listen(&mut self, buffer: &mut [u8]) -> Result { + self.setup_listen(buffer, true)?; + let status = self.async_listen_wait().await?; + if status == Status::Write { + self.setup_listen_end(true)?; + let command = self.async_listen_wait_end(status).await?; + return Ok(command); + } + Ok(Command::Read) + } + + pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { + self.setup_write(buffer, true)?; + self.async_wait().await?; + Ok(()) + } + + /// Same as [`write`](Twis::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. + pub async fn write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { + self.setup_write_from_ram(buffer, true)?; + self.async_wait().await?; + Ok(()) + } +} + +impl<'a, T: Instance> Drop for Twis<'a, T> { + fn drop(&mut self) { + trace!("twis drop"); + + // TODO: check for abort + + // disable! + let r = T::regs(); + r.enable.write(|w| w.enable().disabled()); + + gpio::deconfigure_pin(r.psel.sda.read().bits()); + gpio::deconfigure_pin(r.psel.scl.read().bits()); + + trace!("twis drop: done"); + } +} + +pub(crate) mod sealed { + use super::*; + + pub struct State { + pub waker: AtomicWaker, + } + + impl State { + pub const fn new() -> Self { + Self { + waker: AtomicWaker::new(), + } + } + } + + pub trait Instance { + fn regs() -> &'static pac::twis0::RegisterBlock; + fn state() -> &'static State; + } +} + +pub trait Instance: Peripheral

+ sealed::Instance + 'static { + type Interrupt: Interrupt; +} + +macro_rules! impl_twis { + ($type:ident, $pac_type:ident, $irq:ident) => { + impl crate::twis::sealed::Instance for peripherals::$type { + fn regs() -> &'static pac::twis0::RegisterBlock { + unsafe { &*pac::$pac_type::ptr() } + } + fn state() -> &'static crate::twis::sealed::State { + static STATE: crate::twis::sealed::State = crate::twis::sealed::State::new(); + &STATE + } + } + impl crate::twis::Instance for peripherals::$type { + type Interrupt = crate::interrupt::$irq; + } + }; +} diff --git a/examples/nrf/src/bin/twis.rs b/examples/nrf/src/bin/twis.rs new file mode 100644 index 00000000..f85173c0 --- /dev/null +++ b/examples/nrf/src/bin/twis.rs @@ -0,0 +1,45 @@ +//! TWIS example + +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_nrf::interrupt; +use embassy_nrf::twis::{self, Command, Twis}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + + let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); + let mut config = twis::Config::default(); + // Set i2c address + config.addr0 = 0x55; + let mut i2c = Twis::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config); + + info!("Listening..."); + loop { + let mut buf = [0u8; 16]; + let tx_buf = [1, 2, 3, 4, 5, 6, 7, 8]; + match i2c.listen(&mut buf).await { + Ok(Command::Read) => { + info!("Got READ command. Writing back data:\n{:?}\n", tx_buf); + if let Err(e) = i2c.write(&tx_buf).await { + error!("{:?}", e); + } + } + Ok(Command::Write(n)) => info!("Got WRITE command with data:\n{:?}\n", buf[..n]), + Ok(Command::WriteRead(n)) => { + info!("Got WRITE/READ command with data:\n{:?}", buf[..n]); + info!("Writing back data:\n{:?}\n", tx_buf); + if let Err(e) = i2c.write(&tx_buf).await { + error!("{:?}", e); + } + } + Err(e) => error!("{:?}", e), + } + } +} From 43c1afb6a6b31a60f43b2faf8ca93bf5129e4d68 Mon Sep 17 00:00:00 2001 From: kalkyl Date: Mon, 14 Nov 2022 11:22:14 +0100 Subject: [PATCH 2/4] Return number of bytes written, add address match getter --- embassy-nrf/src/twis.rs | 141 +++++++++++++++++++---------------- examples/nrf/src/bin/twis.rs | 2 +- 2 files changed, 77 insertions(+), 66 deletions(-) diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs index 8c9cb54e..76952287 100644 --- a/embassy-nrf/src/twis.rs +++ b/embassy-nrf/src/twis.rs @@ -24,8 +24,8 @@ use crate::{gpio, pac, Peripheral}; #[non_exhaustive] pub struct Config { - pub addr0: u8, - pub addr1: Option, + pub address0: u8, + pub address1: Option, pub orc: u8, pub sda_high_drive: bool, pub sda_pullup: bool, @@ -36,8 +36,8 @@ pub struct Config { impl Default for Config { fn default() -> Self { Self { - addr0: 0x55, - addr1: None, + address0: 0x55, + address1: None, orc: 0x00, scl_high_drive: false, sda_pullup: false, @@ -134,10 +134,10 @@ impl<'d, T: Instance> Twis<'d, T> { r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); // Set address - r.address[0].write(|w| unsafe { w.address().bits(config.addr0) }); + r.address[0].write(|w| unsafe { w.address().bits(config.address0) }); r.config.modify(|_r, w| w.address0().enabled()); - if let Some(addr1) = config.addr1 { - r.address[1].write(|w| unsafe { w.address().bits(addr1) }); + if let Some(address1) = config.address1 { + r.address[1].write(|w| unsafe { w.address().bits(address1) }); r.config.modify(|_r, w| w.address1().enabled()); } @@ -242,7 +242,13 @@ impl<'d, T: Instance> Twis<'d, T> { .write(|w| w.overflow().bit(true).overread().bit(true).dnack().bit(true)); } - /// Wait for stop or error + /// Returns matched address for latest command. + pub fn address_match(&self) -> u8 { + let r = T::regs(); + r.address[r.match_.read().bits() as usize].read().address().bits() + } + + /// Wait for read, write, stop or error fn blocking_listen_wait(&mut self) -> Result { let r = T::regs(); loop { @@ -267,7 +273,7 @@ impl<'d, T: Instance> Twis<'d, T> { } } - /// Wait for stop or error + /// Wait for stop, repeated start or error fn blocking_listen_wait_end(&mut self, status: Status) -> Result { let r = T::regs(); loop { @@ -294,7 +300,7 @@ impl<'d, T: Instance> Twis<'d, T> { } /// Wait for stop or error - fn blocking_wait(&mut self) -> Result<(), Error> { + fn blocking_wait(&mut self) -> Result { let r = T::regs(); loop { // stop if an error occured @@ -311,12 +317,42 @@ impl<'d, T: Instance> Twis<'d, T> { } } else if r.events_stopped.read().bits() != 0 { r.events_stopped.reset(); - return Ok(()); + let n = r.txd.amount.read().bits() as usize; + return Ok(n); } } } - /// Wait for stop or error + /// Wait for stop or error with timeout + #[cfg(feature = "time")] + fn blocking_wait_timeout(&mut self, timeout: Duration) -> Result { + let r = T::regs(); + let deadline = Instant::now() + timeout; + loop { + // stop if an error occured + if r.events_error.read().bits() != 0 { + r.events_error.reset(); + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + let errorsrc = r.errorsrc.read(); + if errorsrc.overread().is_detected() { + return Err(Error::OverRead); + } else if errorsrc.dnack().is_received() { + return Err(Error::DataNack); + } else { + return Err(Error::Bus); + } + } else if r.events_stopped.read().bits() != 0 { + r.events_stopped.reset(); + let n = r.txd.amount.read().bits() as usize; + return Ok(n); + } else if Instant::now() > deadline { + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + return Err(Error::Timeout); + } + } + } + + /// Wait for read, write, stop or error with timeout #[cfg(feature = "time")] fn blocking_listen_wait_timeout(&mut self, timeout: Duration) -> Result { let r = T::regs(); @@ -347,7 +383,7 @@ impl<'d, T: Instance> Twis<'d, T> { } } - /// Wait for stop or error + /// Wait for stop, repeated start or error with timeout #[cfg(feature = "time")] fn blocking_listen_wait_end_timeout(&mut self, status: Status, timeout: Duration) -> Result { let r = T::regs(); @@ -379,35 +415,7 @@ impl<'d, T: Instance> Twis<'d, T> { } /// Wait for stop or error - #[cfg(feature = "time")] - fn blocking_wait_timeout(&mut self, timeout: Duration) -> Result<(), Error> { - let r = T::regs(); - let deadline = Instant::now() + timeout; - loop { - // stop if an error occured - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); - let errorsrc = r.errorsrc.read(); - if errorsrc.overread().is_detected() { - return Err(Error::OverRead); - } else if errorsrc.dnack().is_received() { - return Err(Error::DataNack); - } else { - return Err(Error::Bus); - } - } else if r.events_stopped.read().bits() != 0 { - r.events_stopped.reset(); - return Ok(()); - } else if Instant::now() > deadline { - r.tasks_stop.write(|w| unsafe { w.bits(1) }); - return Err(Error::Timeout); - } - } - } - - /// Wait for stop or error - fn async_wait(&mut self) -> impl Future> { + fn async_wait(&mut self) -> impl Future> { poll_fn(move |cx| { let r = T::regs(); let s = T::state(); @@ -428,7 +436,8 @@ impl<'d, T: Instance> Twis<'d, T> { } } else if r.events_stopped.read().bits() != 0 { r.events_stopped.reset(); - return Poll::Ready(Ok(())); + let n = r.txd.amount.read().bits() as usize; + return Poll::Ready(Ok(n)); } Poll::Pending @@ -462,7 +471,7 @@ impl<'d, T: Instance> Twis<'d, T> { }) } - /// Wait for stop or error + /// Wait for stop, repeated start or error fn async_listen_wait_end(&mut self, status: Status) -> impl Future> { poll_fn(move |cx| { let r = T::regs(); @@ -595,25 +604,23 @@ impl<'d, T: Instance> Twis<'d, T> { } /// Write to an I2C master. - /// + /// Returns the number of bytes written. /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. - pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { + pub fn blocking_write(&mut self, buffer: &[u8]) -> Result { self.setup_write(buffer, false)?; - self.blocking_wait()?; - Ok(()) + self.blocking_wait() } /// Same as [`blocking_write`](Twis::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. - pub fn blocking_write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { + pub fn blocking_write_from_ram(&mut self, buffer: &[u8]) -> Result { self.setup_write_from_ram(buffer, false)?; - self.blocking_wait()?; - Ok(()) + self.blocking_wait() } // =========================================== - /// Listen for commands from an I2C master. + /// Listen for commands from an I2C master with timeout. /// /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. @@ -630,25 +637,27 @@ impl<'d, T: Instance> Twis<'d, T> { } /// Write to an I2C master with timeout. - /// + /// Returns the number of bytes written. /// See [`blocking_write`]. #[cfg(feature = "time")] - pub fn blocking_write_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result<(), Error> { + pub fn blocking_write_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result { self.setup_write(buffer, false)?; - self.blocking_wait_timeout(timeout)?; - Ok(()) + self.blocking_wait_timeout(timeout) } /// Same as [`blocking_write`](Twis::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. #[cfg(feature = "time")] - pub fn blocking_write_from_ram_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result<(), Error> { + pub fn blocking_write_from_ram_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result { self.setup_write_from_ram(buffer, false)?; - self.blocking_wait_timeout(timeout)?; - Ok(()) + self.blocking_wait_timeout(timeout) } // =========================================== + /// Listen asynchronously for commands from an I2C master. + /// + /// The buffer must have a length of at most 255 bytes on the nRF52832 + /// and at most 65535 bytes on the nRF52840. pub async fn listen(&mut self, buffer: &mut [u8]) -> Result { self.setup_listen(buffer, true)?; let status = self.async_listen_wait().await?; @@ -660,17 +669,19 @@ impl<'d, T: Instance> Twis<'d, T> { Ok(Command::Read) } - pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { + /// Async write to an I2C master. + /// Returns the number of bytes written. + /// The buffer must have a length of at most 255 bytes on the nRF52832 + /// and at most 65535 bytes on the nRF52840. + pub async fn write(&mut self, buffer: &[u8]) -> Result { self.setup_write(buffer, true)?; - self.async_wait().await?; - Ok(()) + self.async_wait().await } /// Same as [`write`](Twis::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. - pub async fn write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { + pub async fn write_from_ram(&mut self, buffer: &[u8]) -> Result { self.setup_write_from_ram(buffer, true)?; - self.async_wait().await?; - Ok(()) + self.async_wait().await } } diff --git a/examples/nrf/src/bin/twis.rs b/examples/nrf/src/bin/twis.rs index f85173c0..a34bb271 100644 --- a/examples/nrf/src/bin/twis.rs +++ b/examples/nrf/src/bin/twis.rs @@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) { let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); let mut config = twis::Config::default(); // Set i2c address - config.addr0 = 0x55; + config.address0 = 0x55; let mut i2c = Twis::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config); info!("Listening..."); From 633ffe46aea29bb4c8eec030cbfd6b93867fe79c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Alse=CC=81r?= Date: Tue, 22 Nov 2022 01:57:00 +0100 Subject: [PATCH 3/4] config write, docs, add address_match_index --- embassy-nrf/src/lib.rs | 6 ------ embassy-nrf/src/twis.rs | 22 +++++++++++++++------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 6c5a3202..7f20f4fd 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -268,11 +268,5 @@ pub fn init(config: config::Config) -> Peripherals { #[cfg(feature = "_time-driver")] time_driver::init(config.time_interrupt_priority); - // Disable UARTE (enabled by default for some reason) - #[cfg(feature = "_nrf9160")] - unsafe { - (*pac::UARTE0::ptr()).enable.write(|w| w.enable().disabled()); - (*pac::UARTE1::ptr()).enable.write(|w| w.enable().disabled()); - } peripherals } diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs index 76952287..b8cb2eeb 100644 --- a/embassy-nrf/src/twis.rs +++ b/embassy-nrf/src/twis.rs @@ -135,7 +135,7 @@ impl<'d, T: Instance> Twis<'d, T> { // Set address r.address[0].write(|w| unsafe { w.address().bits(config.address0) }); - r.config.modify(|_r, w| w.address0().enabled()); + r.config.write(|w| w.address0().enabled()); if let Some(address1) = config.address1 { r.address[1].write(|w| unsafe { w.address().bits(address1) }); r.config.modify(|_r, w| w.address1().enabled()); @@ -248,6 +248,11 @@ impl<'d, T: Instance> Twis<'d, T> { r.address[r.match_.read().bits() as usize].read().address().bits() } + /// Returns the index of the address matched in the latest command. + pub fn address_match_index(&self) -> usize { + T::regs().match_.read().bits() as _ + } + /// Wait for read, write, stop or error fn blocking_listen_wait(&mut self) -> Result { let r = T::regs(); @@ -588,10 +593,11 @@ impl<'d, T: Instance> Twis<'d, T> { Ok(()) } - /// Listen for commands from an I2C master. - /// + /// Wait for commands from an I2C master. + /// `buffer` is provided in case master does a 'write' and is unused for 'read'. /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. + /// To know which one of the addresses were matched, call `address_match` or `address_match_index` pub fn blocking_listen(&mut self, buffer: &mut [u8]) -> Result { self.setup_listen(buffer, false)?; let status = self.blocking_listen_wait()?; @@ -620,10 +626,11 @@ impl<'d, T: Instance> Twis<'d, T> { // =========================================== - /// Listen for commands from an I2C master with timeout. - /// + /// Wait for commands from an I2C master, with timeout. + /// `buffer` is provided in case master does a 'write' and is unused for 'read'. /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. + /// To know which one of the addresses were matched, call `address_match` or `address_match_index` #[cfg(feature = "time")] pub fn blocking_listen_timeout(&mut self, buffer: &mut [u8], timeout: Duration) -> Result { self.setup_listen(buffer, false)?; @@ -654,10 +661,11 @@ impl<'d, T: Instance> Twis<'d, T> { // =========================================== - /// Listen asynchronously for commands from an I2C master. - /// + /// Wait asynchronously for commands from an I2C master. + /// `buffer` is provided in case master does a 'write' and is unused for 'read'. /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. + /// To know which one of the addresses were matched, call `address_match` or `address_match_index` pub async fn listen(&mut self, buffer: &mut [u8]) -> Result { self.setup_listen(buffer, true)?; let status = self.async_listen_wait().await?; From cf900a8a3f048428cc1209763f4188366818ab8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Alse=CC=81r?= Date: Tue, 22 Nov 2022 22:10:04 +0100 Subject: [PATCH 4/4] Rename write to respond_to_read --- embassy-nrf/src/twis.rs | 52 ++++++++++++++++++++---------------- examples/nrf/src/bin/twis.rs | 11 ++++---- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs index b8cb2eeb..4091b017 100644 --- a/embassy-nrf/src/twis.rs +++ b/embassy-nrf/src/twis.rs @@ -507,7 +507,7 @@ impl<'d, T: Instance> Twis<'d, T> { }) } - fn setup_write_from_ram(&mut self, buffer: &[u8], inten: bool) -> Result<(), Error> { + fn setup_respond_from_ram(&mut self, buffer: &[u8], inten: bool) -> Result<(), Error> { let r = T::regs(); compiler_fence(SeqCst); @@ -532,14 +532,14 @@ impl<'d, T: Instance> Twis<'d, T> { Ok(()) } - fn setup_write(&mut self, wr_buffer: &[u8], inten: bool) -> Result<(), Error> { - match self.setup_write_from_ram(wr_buffer, inten) { + fn setup_respond(&mut self, wr_buffer: &[u8], inten: bool) -> Result<(), Error> { + match self.setup_respond_from_ram(wr_buffer, inten) { Ok(_) => Ok(()), Err(Error::DMABufferNotInDataMemory) => { trace!("Copying TWIS tx buffer into RAM for DMA"); let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; tx_ram_buf.copy_from_slice(wr_buffer); - self.setup_write_from_ram(&tx_ram_buf, inten) + self.setup_respond_from_ram(&tx_ram_buf, inten) } Err(error) => Err(error), } @@ -609,18 +609,19 @@ impl<'d, T: Instance> Twis<'d, T> { Ok(Command::Read) } - /// Write to an I2C master. + /// Respond to an I2C master READ command. /// Returns the number of bytes written. /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. - pub fn blocking_write(&mut self, buffer: &[u8]) -> Result { - self.setup_write(buffer, false)?; + pub fn blocking_respond_to_read(&mut self, buffer: &[u8]) -> Result { + self.setup_respond(buffer, false)?; self.blocking_wait() } - /// Same as [`blocking_write`](Twis::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. - pub fn blocking_write_from_ram(&mut self, buffer: &[u8]) -> Result { - self.setup_write_from_ram(buffer, false)?; + /// Same as [`blocking_respond_to_read`](Twis::blocking_respond_to_read) but will fail instead of copying data into RAM. + /// Consult the module level documentation to learn more. + pub fn blocking_respond_to_read_from_ram(&mut self, buffer: &[u8]) -> Result { + self.setup_respond_from_ram(buffer, false)?; self.blocking_wait() } @@ -643,19 +644,24 @@ impl<'d, T: Instance> Twis<'d, T> { Ok(Command::Read) } - /// Write to an I2C master with timeout. + /// Respond to an I2C master READ command with timeout. /// Returns the number of bytes written. - /// See [`blocking_write`]. + /// See [`blocking_respond_to_read`]. #[cfg(feature = "time")] - pub fn blocking_write_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result { - self.setup_write(buffer, false)?; + pub fn blocking_respond_to_read_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result { + self.setup_respond(buffer, false)?; self.blocking_wait_timeout(timeout) } - /// Same as [`blocking_write`](Twis::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. + /// Same as [`blocking_respond_to_read_timeout`](Twis::blocking_respond_to_read_timeout) but will fail instead of copying data into RAM. + /// Consult the module level documentation to learn more. #[cfg(feature = "time")] - pub fn blocking_write_from_ram_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result { - self.setup_write_from_ram(buffer, false)?; + pub fn blocking_respond_to_read_from_ram_timeout( + &mut self, + buffer: &[u8], + timeout: Duration, + ) -> Result { + self.setup_respond_from_ram(buffer, false)?; self.blocking_wait_timeout(timeout) } @@ -677,18 +683,18 @@ impl<'d, T: Instance> Twis<'d, T> { Ok(Command::Read) } - /// Async write to an I2C master. + /// Respond to an I2C master READ command, asynchronously. /// Returns the number of bytes written. /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. - pub async fn write(&mut self, buffer: &[u8]) -> Result { - self.setup_write(buffer, true)?; + pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result { + self.setup_respond(buffer, true)?; self.async_wait().await } - /// Same as [`write`](Twis::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. - pub async fn write_from_ram(&mut self, buffer: &[u8]) -> Result { - self.setup_write_from_ram(buffer, true)?; + /// Same as [`respond_to_read`](Twis::respond_to_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. + pub async fn respond_to_read_from_ram(&mut self, buffer: &[u8]) -> Result { + self.setup_respond_from_ram(buffer, true)?; self.async_wait().await } } diff --git a/examples/nrf/src/bin/twis.rs b/examples/nrf/src/bin/twis.rs index a34bb271..54cba949 100644 --- a/examples/nrf/src/bin/twis.rs +++ b/examples/nrf/src/bin/twis.rs @@ -22,20 +22,21 @@ async fn main(_spawner: Spawner) { info!("Listening..."); loop { + let response = [1, 2, 3, 4, 5, 6, 7, 8]; + // This buffer is used if the i2c master performs a Write or WriteRead let mut buf = [0u8; 16]; - let tx_buf = [1, 2, 3, 4, 5, 6, 7, 8]; match i2c.listen(&mut buf).await { Ok(Command::Read) => { - info!("Got READ command. Writing back data:\n{:?}\n", tx_buf); - if let Err(e) = i2c.write(&tx_buf).await { + info!("Got READ command. Respond with data:\n{:?}\n", response); + if let Err(e) = i2c.respond_to_read(&response).await { error!("{:?}", e); } } Ok(Command::Write(n)) => info!("Got WRITE command with data:\n{:?}\n", buf[..n]), Ok(Command::WriteRead(n)) => { info!("Got WRITE/READ command with data:\n{:?}", buf[..n]); - info!("Writing back data:\n{:?}\n", tx_buf); - if let Err(e) = i2c.write(&tx_buf).await { + info!("Respond with data:\n{:?}\n", response); + if let Err(e) = i2c.respond_to_read(&response).await { error!("{:?}", e); } }