nrf: add blocking TWIM
This commit is contained in:
parent
bd9589d0ce
commit
eb4571dc4c
8 changed files with 548 additions and 0 deletions
|
@ -114,6 +114,8 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
|
|||
|
||||
impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0);
|
||||
|
||||
impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0);
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
|
|
@ -115,6 +115,8 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
|
|||
impl_spim!(TWISPI0, SPIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
|
||||
impl_spim!(SPI1, SPIM1, SPIM1_SPIS1_SPI1);
|
||||
|
||||
impl_twim!(TWISPI0, TWIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
|
|
@ -116,6 +116,9 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
|
|||
impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
||||
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_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
|
|
@ -121,6 +121,9 @@ impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
|||
impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
|
||||
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_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
|
|
@ -142,6 +142,9 @@ impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
|
|||
impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2);
|
||||
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_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
|
|
@ -145,6 +145,9 @@ impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
|
|||
impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2);
|
||||
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_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
|
|
@ -37,6 +37,7 @@ pub mod saadc;
|
|||
pub mod spim;
|
||||
pub mod system;
|
||||
pub mod timer;
|
||||
pub mod twim;
|
||||
pub mod uarte;
|
||||
|
||||
// This mod MUST go last, so that it sees all the `impl_foo!` macros
|
||||
|
|
531
embassy-nrf/src/twim.rs
Normal file
531
embassy-nrf/src/twim.rs
Normal file
|
@ -0,0 +1,531 @@
|
|||
#![macro_use]
|
||||
|
||||
//! HAL interface to the TWIM peripheral.
|
||||
//!
|
||||
//! See product specification:
|
||||
//!
|
||||
//! - nRF52832: Section 33
|
||||
//! - nRF52840: Section 6.31
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::{compiler_fence, Ordering::SeqCst};
|
||||
use embassy::interrupt::{Interrupt, InterruptExt};
|
||||
use embassy::util::{AtomicWaker, Unborrow};
|
||||
use embassy_extras::unborrow;
|
||||
|
||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||
use crate::fmt::*;
|
||||
use crate::gpio::Pin as GpioPin;
|
||||
use crate::pac;
|
||||
use crate::util::{slice_in_ram, slice_in_ram_or};
|
||||
|
||||
pub enum Frequency {
|
||||
#[doc = "26738688: 100 kbps"]
|
||||
K100 = 26738688,
|
||||
#[doc = "67108864: 250 kbps"]
|
||||
K250 = 67108864,
|
||||
#[doc = "104857600: 400 kbps"]
|
||||
K400 = 104857600,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct Config {
|
||||
pub frequency: Frequency,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
frequency: Frequency::K100,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface to a TWIM instance.
|
||||
pub struct Twim<'d, T: Instance> {
|
||||
peri: T,
|
||||
irq: T::Interrupt,
|
||||
phantom: PhantomData<&'d mut T>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Twim<'d, T> {
|
||||
pub fn new(
|
||||
twim: impl Unborrow<Target = T> + 'd,
|
||||
irq: impl Unborrow<Target = T::Interrupt> + 'd,
|
||||
sda: impl Unborrow<Target = impl GpioPin> + 'd,
|
||||
scl: impl Unborrow<Target = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
unborrow!(twim, irq, sda, scl);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
// Configure pins
|
||||
sda.conf().write(|w| {
|
||||
w.dir().input();
|
||||
w.input().connect();
|
||||
w.pull().pullup();
|
||||
w.drive().s0d1();
|
||||
w
|
||||
});
|
||||
scl.conf().write(|w| {
|
||||
w.dir().input();
|
||||
w.input().connect();
|
||||
w.pull().pullup();
|
||||
w.drive().s0d1();
|
||||
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 TWIM instance.
|
||||
r.enable.write(|w| w.enable().enabled());
|
||||
|
||||
// Configure frequency.
|
||||
r.frequency
|
||||
.write(|w| unsafe { w.frequency().bits(config.frequency as u32) });
|
||||
|
||||
// Disable all events interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
|
||||
Self {
|
||||
peri: twim,
|
||||
irq,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.stopped().clear());
|
||||
}
|
||||
if r.events_error.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|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() == 0 {
|
||||
return Err(Error::TxBufferZeroLength);
|
||||
}
|
||||
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() == 0 {
|
||||
return Err(Error::RxBufferZeroLength);
|
||||
}
|
||||
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.anack().bit(true).dnack().bit(true).overrun().bit(true));
|
||||
}
|
||||
|
||||
/// Get Error instance, if any occurred.
|
||||
fn read_errorsrc(&self) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
|
||||
let err = r.errorsrc.read();
|
||||
if err.anack().is_received() {
|
||||
return Err(Error::AddressNack);
|
||||
}
|
||||
if err.dnack().is_received() {
|
||||
return Err(Error::DataNack);
|
||||
}
|
||||
if err.overrun().is_received() {
|
||||
return Err(Error::DataNack);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Wait for stop or error
|
||||
fn wait(&mut self) {
|
||||
let r = T::regs();
|
||||
loop {
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
r.events_stopped.reset();
|
||||
break;
|
||||
}
|
||||
if r.events_error.read().bits() != 0 {
|
||||
r.events_error.reset();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Write to an I2C slave.
|
||||
///
|
||||
/// The buffer must have a length of at most 255 bytes on the nRF52832
|
||||
/// and at most 65535 bytes on the nRF52840.
|
||||
pub fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
|
||||
// Conservative compiler fence to prevent optimizations that do not
|
||||
// take in to account actions by DMA. The fence has been placed here,
|
||||
// before any DMA action has started.
|
||||
compiler_fence(SeqCst);
|
||||
|
||||
r.address.write(|w| unsafe { w.address().bits(address) });
|
||||
|
||||
// Set up the DMA write.
|
||||
unsafe { self.set_tx_buffer(buffer)? };
|
||||
|
||||
// Clear events
|
||||
r.events_stopped.reset();
|
||||
r.events_error.reset();
|
||||
r.events_lasttx.reset();
|
||||
self.clear_errorsrc();
|
||||
|
||||
// Start write operation.
|
||||
r.shorts.write(|w| w.lasttx_stop().enabled());
|
||||
r.tasks_starttx.write(|w|
|
||||
// `1` is a valid value to write to task registers.
|
||||
unsafe { w.bits(1) });
|
||||
|
||||
self.wait();
|
||||
|
||||
// Conservative compiler fence to prevent optimizations that do not
|
||||
// take in to account actions by DMA. The fence has been placed here,
|
||||
// after all possible DMA actions have completed.
|
||||
compiler_fence(SeqCst);
|
||||
|
||||
self.read_errorsrc()?;
|
||||
|
||||
if r.txd.amount.read().bits() != buffer.len() as u32 {
|
||||
return Err(Error::Transmit);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read from an I2C slave.
|
||||
///
|
||||
/// The buffer must have a length of at most 255 bytes on the nRF52832
|
||||
/// and at most 65535 bytes on the nRF52840.
|
||||
pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
|
||||
// Conservative compiler fence to prevent optimizations that do not
|
||||
// take in to account actions by DMA. The fence has been placed here,
|
||||
// before any DMA action has started.
|
||||
compiler_fence(SeqCst);
|
||||
|
||||
r.address.write(|w| unsafe { w.address().bits(address) });
|
||||
|
||||
// Set up the DMA read.
|
||||
unsafe { self.set_rx_buffer(buffer)? };
|
||||
|
||||
// Clear events
|
||||
r.events_stopped.reset();
|
||||
r.events_error.reset();
|
||||
self.clear_errorsrc();
|
||||
|
||||
// Start read operation.
|
||||
r.shorts.write(|w| w.lastrx_stop().enabled());
|
||||
r.tasks_startrx.write(|w|
|
||||
// `1` is a valid value to write to task registers.
|
||||
unsafe { w.bits(1) });
|
||||
|
||||
self.wait();
|
||||
|
||||
// Conservative compiler fence to prevent optimizations that do not
|
||||
// take in to account actions by DMA. The fence has been placed here,
|
||||
// after all possible DMA actions have completed.
|
||||
compiler_fence(SeqCst);
|
||||
|
||||
self.read_errorsrc()?;
|
||||
|
||||
if r.rxd.amount.read().bits() != buffer.len() as u32 {
|
||||
return Err(Error::Receive);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Write data to an I2C slave, then read data from the slave without
|
||||
/// triggering a stop condition between the two.
|
||||
///
|
||||
/// The buffers must have a length of at most 255 bytes on the nRF52832
|
||||
/// and at most 65535 bytes on the nRF52840.
|
||||
pub fn write_then_read(
|
||||
&mut self,
|
||||
address: u8,
|
||||
wr_buffer: &[u8],
|
||||
rd_buffer: &mut [u8],
|
||||
) -> Result<(), Error> {
|
||||
let r = T::regs();
|
||||
|
||||
// Conservative compiler fence to prevent optimizations that do not
|
||||
// take in to account actions by DMA. The fence has been placed here,
|
||||
// before any DMA action has started.
|
||||
compiler_fence(SeqCst);
|
||||
|
||||
r.address.write(|w| unsafe { w.address().bits(address) });
|
||||
|
||||
// Set up DMA buffers.
|
||||
unsafe {
|
||||
self.set_tx_buffer(wr_buffer)?;
|
||||
self.set_rx_buffer(rd_buffer)?;
|
||||
}
|
||||
|
||||
// Clear events
|
||||
r.events_stopped.reset();
|
||||
r.events_error.reset();
|
||||
self.clear_errorsrc();
|
||||
|
||||
// Start write+read operation.
|
||||
r.shorts.write(|w| {
|
||||
w.lasttx_startrx().enabled();
|
||||
w.lastrx_stop().enabled();
|
||||
w
|
||||
});
|
||||
// `1` is a valid value to write to task registers.
|
||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||
|
||||
self.wait();
|
||||
|
||||
// Conservative compiler fence to prevent optimizations that do not
|
||||
// take in to account actions by DMA. The fence has been placed here,
|
||||
// after all possible DMA actions have completed.
|
||||
compiler_fence(SeqCst);
|
||||
|
||||
self.read_errorsrc()?;
|
||||
|
||||
let bad_write = r.txd.amount.read().bits() != wr_buffer.len() as u32;
|
||||
let bad_read = r.rxd.amount.read().bits() != rd_buffer.len() as u32;
|
||||
|
||||
if bad_write {
|
||||
return Err(Error::Transmit);
|
||||
}
|
||||
|
||||
if bad_read {
|
||||
return Err(Error::Receive);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Copy data into RAM and write to an I2C slave.
|
||||
///
|
||||
/// The write buffer must have a length of at most 255 bytes on the nRF52832
|
||||
/// and at most 1024 bytes on the nRF52840.
|
||||
pub fn copy_write(&mut self, address: u8, wr_buffer: &[u8]) -> Result<(), Error> {
|
||||
if wr_buffer.len() > FORCE_COPY_BUFFER_SIZE {
|
||||
return Err(Error::TxBufferTooLong);
|
||||
}
|
||||
|
||||
// Copy to RAM
|
||||
let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
|
||||
wr_ram_buffer.copy_from_slice(wr_buffer);
|
||||
|
||||
self.write(address, wr_ram_buffer)
|
||||
}
|
||||
|
||||
/// Copy data into RAM and write to an I2C slave, then read data from the slave without
|
||||
/// triggering a stop condition between the two.
|
||||
///
|
||||
/// The write buffer must have a length of at most 255 bytes on the nRF52832
|
||||
/// and at most 1024 bytes on the nRF52840.
|
||||
///
|
||||
/// The read buffer must have a length of at most 255 bytes on the nRF52832
|
||||
/// and at most 65535 bytes on the nRF52840.
|
||||
pub fn copy_write_then_read(
|
||||
&mut self,
|
||||
address: u8,
|
||||
wr_buffer: &[u8],
|
||||
rd_buffer: &mut [u8],
|
||||
) -> Result<(), Error> {
|
||||
if wr_buffer.len() > FORCE_COPY_BUFFER_SIZE {
|
||||
return Err(Error::TxBufferTooLong);
|
||||
}
|
||||
|
||||
// Copy to RAM
|
||||
let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
|
||||
wr_ram_buffer.copy_from_slice(wr_buffer);
|
||||
|
||||
self.write_then_read(address, wr_ram_buffer, rd_buffer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Instance> Drop for Twim<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
info!("twim drop");
|
||||
|
||||
// TODO when implementing async here, check for abort
|
||||
|
||||
// disable!
|
||||
let r = T::regs();
|
||||
r.enable.write(|w| w.enable().disabled());
|
||||
|
||||
info!("uarte drop: done");
|
||||
|
||||
// TODO: disable pins
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Instance> embedded_hal::blocking::i2c::Write for Twim<'a, T> {
|
||||
type Error = Error;
|
||||
|
||||
fn write<'w>(&mut self, addr: u8, bytes: &'w [u8]) -> Result<(), Error> {
|
||||
if slice_in_ram(bytes) {
|
||||
self.write(addr, bytes)
|
||||
} else {
|
||||
let buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..];
|
||||
for chunk in bytes.chunks(FORCE_COPY_BUFFER_SIZE) {
|
||||
buf[..chunk.len()].copy_from_slice(chunk);
|
||||
self.write(addr, &buf[..chunk.len()])?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Instance> embedded_hal::blocking::i2c::Read for Twim<'a, T> {
|
||||
type Error = Error;
|
||||
|
||||
fn read<'w>(&mut self, addr: u8, bytes: &'w mut [u8]) -> Result<(), Error> {
|
||||
self.read(addr, bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Instance> embedded_hal::blocking::i2c::WriteRead for Twim<'a, T> {
|
||||
type Error = Error;
|
||||
|
||||
fn write_read<'w>(
|
||||
&mut self,
|
||||
addr: u8,
|
||||
bytes: &'w [u8],
|
||||
buffer: &'w mut [u8],
|
||||
) -> Result<(), Error> {
|
||||
if slice_in_ram(bytes) {
|
||||
self.write_then_read(addr, bytes, buffer)
|
||||
} else {
|
||||
self.copy_write_then_read(addr, bytes, buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum Error {
|
||||
TxBufferTooLong,
|
||||
RxBufferTooLong,
|
||||
TxBufferZeroLength,
|
||||
RxBufferZeroLength,
|
||||
Transmit,
|
||||
Receive,
|
||||
DMABufferNotInDataMemory,
|
||||
AddressNack,
|
||||
DataNack,
|
||||
Overrun,
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use super::*;
|
||||
|
||||
pub struct State {
|
||||
pub end_waker: AtomicWaker,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
end_waker: AtomicWaker::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Instance {
|
||||
fn regs() -> &'static pac::twim0::RegisterBlock;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Instance: sealed::Instance + 'static {
|
||||
type Interrupt: Interrupt;
|
||||
}
|
||||
|
||||
macro_rules! impl_twim {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::twim::sealed::Instance for peripherals::$type {
|
||||
fn regs() -> &'static pac::twim0::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
}
|
||||
fn state() -> &'static crate::twim::sealed::State {
|
||||
static STATE: crate::twim::sealed::State = crate::twim::sealed::State::new();
|
||||
&STATE
|
||||
}
|
||||
}
|
||||
impl crate::twim::Instance for peripherals::$type {
|
||||
type Interrupt = crate::interrupt::$irq;
|
||||
}
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue