embassy-nrf: Add TWIS module
This commit is contained in:
		@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										734
									
								
								embassy-nrf/src/twis.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										734
									
								
								embassy-nrf/src/twis.rs
									
									
									
									
									
										Normal file
									
								
							@@ -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<u8>,
 | 
			
		||||
    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<P = T> + 'd,
 | 
			
		||||
        irq: impl Peripheral<P = T::Interrupt> + 'd,
 | 
			
		||||
        sda: impl Peripheral<P = impl GpioPin> + 'd,
 | 
			
		||||
        scl: impl Peripheral<P = impl GpioPin> + '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<Status, Error> {
 | 
			
		||||
        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<Command, 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) });
 | 
			
		||||
                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<Status, Error> {
 | 
			
		||||
        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<Command, 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) });
 | 
			
		||||
                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<Output = Result<(), Error>> {
 | 
			
		||||
        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<Output = Result<Status, Error>> {
 | 
			
		||||
        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<Output = Result<Command, Error>> {
 | 
			
		||||
        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<Command, Error> {
 | 
			
		||||
        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<Command, Error> {
 | 
			
		||||
        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<Command, Error> {
 | 
			
		||||
        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<P = Self> + 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;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								examples/nrf/src/bin/twis.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								examples/nrf/src/bin/twis.rs
									
									
									
									
									
										Normal file
									
								
							@@ -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),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user