Merge branch 'master' of https://github.com/embassy-rs/embassy into embassy-rp/flash
This commit is contained in:
@ -599,12 +599,12 @@ pub(crate) mod sealed {
|
||||
fn pin_bank(&self) -> u8;
|
||||
|
||||
#[inline]
|
||||
fn pin(&self) -> u8 {
|
||||
fn _pin(&self) -> u8 {
|
||||
self.pin_bank() & 0x1f
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bank(&self) -> Bank {
|
||||
fn _bank(&self) -> Bank {
|
||||
if self.pin_bank() & 0x20 == 0 {
|
||||
Bank::Bank0
|
||||
} else {
|
||||
@ -613,35 +613,35 @@ pub(crate) mod sealed {
|
||||
}
|
||||
|
||||
fn io(&self) -> pac::io::Gpio {
|
||||
let block = match self.bank() {
|
||||
let block = match self._bank() {
|
||||
Bank::Bank0 => crate::pac::IO_BANK0,
|
||||
Bank::Qspi => crate::pac::IO_QSPI,
|
||||
};
|
||||
block.gpio(self.pin() as _)
|
||||
block.gpio(self._pin() as _)
|
||||
}
|
||||
|
||||
fn pad_ctrl(&self) -> Reg<pac::pads::regs::GpioCtrl, RW> {
|
||||
let block = match self.bank() {
|
||||
let block = match self._bank() {
|
||||
Bank::Bank0 => crate::pac::PADS_BANK0,
|
||||
Bank::Qspi => crate::pac::PADS_QSPI,
|
||||
};
|
||||
block.gpio(self.pin() as _)
|
||||
block.gpio(self._pin() as _)
|
||||
}
|
||||
|
||||
fn sio_out(&self) -> pac::sio::Gpio {
|
||||
SIO.gpio_out(self.bank() as _)
|
||||
SIO.gpio_out(self._bank() as _)
|
||||
}
|
||||
|
||||
fn sio_oe(&self) -> pac::sio::Gpio {
|
||||
SIO.gpio_oe(self.bank() as _)
|
||||
SIO.gpio_oe(self._bank() as _)
|
||||
}
|
||||
|
||||
fn sio_in(&self) -> Reg<u32, RW> {
|
||||
SIO.gpio_in(self.bank() as _)
|
||||
SIO.gpio_in(self._bank() as _)
|
||||
}
|
||||
|
||||
fn int_proc(&self) -> pac::io::Int {
|
||||
let io_block = match self.bank() {
|
||||
let io_block = match self._bank() {
|
||||
Bank::Bank0 => crate::pac::IO_BANK0,
|
||||
Bank::Qspi => crate::pac::IO_QSPI,
|
||||
};
|
||||
@ -658,6 +658,18 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat
|
||||
pin_bank: self.pin_bank(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the pin number within a bank
|
||||
#[inline]
|
||||
fn pin(&self) -> u8 {
|
||||
self._pin()
|
||||
}
|
||||
|
||||
/// Returns the bank of this pin
|
||||
#[inline]
|
||||
fn bank(&self) -> Bank {
|
||||
self._bank()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AnyPin {
|
||||
@ -867,7 +879,7 @@ mod eh1 {
|
||||
type Error = Infallible;
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::blocking::InputPin for Input<'d, T> {
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> {
|
||||
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.is_high())
|
||||
}
|
||||
@ -881,7 +893,7 @@ mod eh1 {
|
||||
type Error = Infallible;
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::blocking::OutputPin for Output<'d, T> {
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> {
|
||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||
Ok(self.set_high())
|
||||
}
|
||||
@ -891,7 +903,7 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::blocking::StatefulOutputPin for Output<'d, T> {
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> {
|
||||
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.is_set_high())
|
||||
}
|
||||
@ -901,7 +913,7 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::blocking::ToggleableOutputPin for Output<'d, T> {
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::ToggleableOutputPin for Output<'d, T> {
|
||||
fn toggle(&mut self) -> Result<(), Self::Error> {
|
||||
Ok(self.toggle())
|
||||
}
|
||||
@ -911,7 +923,7 @@ mod eh1 {
|
||||
type Error = Infallible;
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::blocking::OutputPin for OutputOpenDrain<'d, T> {
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> {
|
||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||
Ok(self.set_high())
|
||||
}
|
||||
@ -921,7 +933,7 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::blocking::StatefulOutputPin for OutputOpenDrain<'d, T> {
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> {
|
||||
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.is_set_high())
|
||||
}
|
||||
@ -931,7 +943,7 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::blocking::ToggleableOutputPin for OutputOpenDrain<'d, T> {
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::ToggleableOutputPin for OutputOpenDrain<'d, T> {
|
||||
fn toggle(&mut self) -> Result<(), Self::Error> {
|
||||
Ok(self.toggle())
|
||||
}
|
||||
@ -941,7 +953,7 @@ mod eh1 {
|
||||
type Error = Infallible;
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::blocking::InputPin for Flex<'d, T> {
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> {
|
||||
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.is_high())
|
||||
}
|
||||
@ -951,7 +963,7 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::blocking::OutputPin for Flex<'d, T> {
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> {
|
||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||
Ok(self.set_high())
|
||||
}
|
||||
@ -961,7 +973,7 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::blocking::StatefulOutputPin for Flex<'d, T> {
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> {
|
||||
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.is_set_high())
|
||||
}
|
||||
@ -971,7 +983,7 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::blocking::ToggleableOutputPin for Flex<'d, T> {
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::ToggleableOutputPin for Flex<'d, T> {
|
||||
fn toggle(&mut self) -> Result<(), Self::Error> {
|
||||
Ok(self.toggle())
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
use core::future;
|
||||
use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_cortex_m::interrupt::InterruptExt;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use pac::i2c;
|
||||
|
||||
use crate::dma::AnyChannel;
|
||||
use crate::gpio::sealed::Pin;
|
||||
use crate::gpio::AnyPin;
|
||||
use crate::{pac, peripherals, Peripheral};
|
||||
@ -52,31 +55,276 @@ impl Default for Config {
|
||||
const FIFO_SIZE: u8 = 16;
|
||||
|
||||
pub struct I2c<'d, T: Instance, M: Mode> {
|
||||
_tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
|
||||
_rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
|
||||
_dma_buf: [u16; 256],
|
||||
phantom: PhantomData<(&'d mut T, M)>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> I2c<'d, T, Blocking> {
|
||||
pub fn new_blocking(
|
||||
_peri: impl Peripheral<P = T> + 'd,
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
|
||||
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(scl, sda);
|
||||
Self::new_inner(_peri, scl.map_into(), sda.map_into(), None, None, config)
|
||||
Self::new_inner(peri, scl.map_into(), sda.map_into(), config)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
|
||||
impl<'d, T: Instance> I2c<'d, T, Async> {
|
||||
pub fn new_async(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
|
||||
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(scl, sda, irq);
|
||||
|
||||
let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config);
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
unsafe {
|
||||
let i2c = T::regs();
|
||||
|
||||
// mask everything initially
|
||||
i2c.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0));
|
||||
}
|
||||
irq.unpend();
|
||||
debug_assert!(!irq.is_pending());
|
||||
irq.enable();
|
||||
|
||||
i2c
|
||||
}
|
||||
|
||||
/// Calls `f` to check if we are ready or not.
|
||||
/// If not, `g` is called once the waker is set (to eg enable the required interrupts).
|
||||
async fn wait_on<F, U, G>(&mut self, mut f: F, mut g: G) -> U
|
||||
where
|
||||
F: FnMut(&mut Self) -> Poll<U>,
|
||||
G: FnMut(&mut Self),
|
||||
{
|
||||
future::poll_fn(|cx| {
|
||||
let r = f(self);
|
||||
|
||||
if r.is_pending() {
|
||||
T::waker().register(cx.waker());
|
||||
g(self);
|
||||
}
|
||||
r
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
// Mask interrupts and wake any task waiting for this interrupt
|
||||
unsafe fn on_interrupt(_: *mut ()) {
|
||||
let i2c = T::regs();
|
||||
i2c.ic_intr_mask().write_value(pac::i2c::regs::IcIntrMask::default());
|
||||
|
||||
T::waker().wake();
|
||||
}
|
||||
|
||||
async fn read_async_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> {
|
||||
if buffer.is_empty() {
|
||||
return Err(Error::InvalidReadBufferLength);
|
||||
}
|
||||
|
||||
let p = T::regs();
|
||||
|
||||
let mut remaining = buffer.len();
|
||||
let mut remaining_queue = buffer.len();
|
||||
|
||||
let mut abort_reason = Ok(());
|
||||
|
||||
while remaining > 0 {
|
||||
// Waggle SCK - basically the same as write
|
||||
let tx_fifo_space = Self::tx_fifo_capacity();
|
||||
let mut batch = 0;
|
||||
|
||||
debug_assert!(remaining_queue > 0);
|
||||
|
||||
for _ in 0..remaining_queue.min(tx_fifo_space as usize) {
|
||||
remaining_queue -= 1;
|
||||
let last = remaining_queue == 0;
|
||||
batch += 1;
|
||||
|
||||
unsafe {
|
||||
p.ic_data_cmd().write(|w| {
|
||||
w.set_restart(restart && remaining_queue == buffer.len() - 1);
|
||||
w.set_stop(last && send_stop);
|
||||
w.set_cmd(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// We've either run out of txfifo or just plain finished setting up
|
||||
// the clocks for the message - either way we need to wait for rx
|
||||
// data.
|
||||
|
||||
debug_assert!(batch > 0);
|
||||
let res = self
|
||||
.wait_on(
|
||||
|me| {
|
||||
let rxfifo = Self::rx_fifo_len();
|
||||
if let Err(abort_reason) = me.read_and_clear_abort_reason() {
|
||||
Poll::Ready(Err(abort_reason))
|
||||
} else if rxfifo >= batch {
|
||||
Poll::Ready(Ok(rxfifo))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
},
|
||||
|_me| unsafe {
|
||||
// Set the read threshold to the number of bytes we're
|
||||
// expecting so we don't get spurious interrupts.
|
||||
p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1));
|
||||
|
||||
p.ic_intr_mask().modify(|w| {
|
||||
w.set_m_rx_full(true);
|
||||
w.set_m_tx_abrt(true);
|
||||
});
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
match res {
|
||||
Err(reason) => {
|
||||
abort_reason = Err(reason);
|
||||
break;
|
||||
}
|
||||
Ok(rxfifo) => {
|
||||
// Fetch things from rx fifo. We're assuming we're the only
|
||||
// rxfifo reader, so nothing else can take things from it.
|
||||
let rxbytes = (rxfifo as usize).min(remaining);
|
||||
let received = buffer.len() - remaining;
|
||||
for b in &mut buffer[received..received + rxbytes] {
|
||||
*b = unsafe { p.ic_data_cmd().read().dat() };
|
||||
}
|
||||
remaining -= rxbytes;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
self.wait_stop_det(abort_reason, send_stop).await
|
||||
}
|
||||
|
||||
async fn write_async_internal(
|
||||
&mut self,
|
||||
bytes: impl IntoIterator<Item = u8>,
|
||||
send_stop: bool,
|
||||
) -> Result<(), Error> {
|
||||
let p = T::regs();
|
||||
|
||||
let mut bytes = bytes.into_iter().peekable();
|
||||
|
||||
let res = 'xmit: loop {
|
||||
let tx_fifo_space = Self::tx_fifo_capacity();
|
||||
|
||||
for _ in 0..tx_fifo_space {
|
||||
if let Some(byte) = bytes.next() {
|
||||
let last = bytes.peek().is_none();
|
||||
|
||||
unsafe {
|
||||
p.ic_data_cmd().write(|w| {
|
||||
w.set_stop(last && send_stop);
|
||||
w.set_cmd(false);
|
||||
w.set_dat(byte);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
break 'xmit Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
let res = self
|
||||
.wait_on(
|
||||
|me| {
|
||||
if let abort_reason @ Err(_) = me.read_and_clear_abort_reason() {
|
||||
Poll::Ready(abort_reason)
|
||||
} else if !Self::tx_fifo_full() {
|
||||
// resume if there's any space free in the tx fifo
|
||||
Poll::Ready(Ok(()))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
},
|
||||
|_me| unsafe {
|
||||
// Set tx "free" threshold a little high so that we get
|
||||
// woken before the fifo completely drains to minimize
|
||||
// transfer stalls.
|
||||
p.ic_tx_tl().write(|w| w.set_tx_tl(1));
|
||||
|
||||
p.ic_intr_mask().modify(|w| {
|
||||
w.set_m_tx_empty(true);
|
||||
w.set_m_tx_abrt(true);
|
||||
})
|
||||
},
|
||||
)
|
||||
.await;
|
||||
if res.is_err() {
|
||||
break res;
|
||||
}
|
||||
};
|
||||
|
||||
self.wait_stop_det(res, send_stop).await
|
||||
}
|
||||
|
||||
/// Helper to wait for a stop bit, for both tx and rx. If we had an abort,
|
||||
/// then we'll get a hardware-generated stop, otherwise wait for a stop if
|
||||
/// we're expecting it.
|
||||
///
|
||||
/// Also handles an abort which arises while processing the tx fifo.
|
||||
async fn wait_stop_det(&mut self, had_abort: Result<(), Error>, do_stop: bool) -> Result<(), Error> {
|
||||
if had_abort.is_err() || do_stop {
|
||||
let p = T::regs();
|
||||
|
||||
let had_abort2 = self
|
||||
.wait_on(
|
||||
|me| unsafe {
|
||||
// We could see an abort while processing fifo backlog,
|
||||
// so handle it here.
|
||||
let abort = me.read_and_clear_abort_reason();
|
||||
if had_abort.is_ok() && abort.is_err() {
|
||||
Poll::Ready(abort)
|
||||
} else if p.ic_raw_intr_stat().read().stop_det() {
|
||||
Poll::Ready(Ok(()))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
},
|
||||
|_me| unsafe {
|
||||
p.ic_intr_mask().modify(|w| {
|
||||
w.set_m_stop_det(true);
|
||||
w.set_m_tx_abrt(true);
|
||||
});
|
||||
},
|
||||
)
|
||||
.await;
|
||||
unsafe {
|
||||
p.ic_clr_stop_det().read();
|
||||
}
|
||||
|
||||
had_abort.and(had_abort2)
|
||||
} else {
|
||||
had_abort
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
Self::setup(addr)?;
|
||||
self.read_async_internal(buffer, false, true).await
|
||||
}
|
||||
|
||||
pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator<Item = u8>) -> Result<(), Error> {
|
||||
Self::setup(addr)?;
|
||||
self.write_async_internal(bytes, true).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
|
||||
fn new_inner(
|
||||
_peri: impl Peripheral<P = T> + 'd,
|
||||
scl: PeripheralRef<'d, AnyPin>,
|
||||
sda: PeripheralRef<'d, AnyPin>,
|
||||
_tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
|
||||
_rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(_peri);
|
||||
@ -87,6 +335,10 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
|
||||
let p = T::regs();
|
||||
|
||||
unsafe {
|
||||
let reset = T::reset();
|
||||
crate::reset::reset(reset);
|
||||
crate::reset::unreset_wait(reset);
|
||||
|
||||
p.ic_enable().write(|w| w.set_enable(false));
|
||||
|
||||
// Select controller mode & speed
|
||||
@ -172,12 +424,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
|
||||
p.ic_enable().write(|w| w.set_enable(true));
|
||||
}
|
||||
|
||||
Self {
|
||||
_tx_dma,
|
||||
_rx_dma,
|
||||
_dma_buf: [0; 256],
|
||||
phantom: PhantomData,
|
||||
}
|
||||
Self { phantom: PhantomData }
|
||||
}
|
||||
|
||||
fn setup(addr: u16) -> Result<(), Error> {
|
||||
@ -198,6 +445,23 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn tx_fifo_full() -> bool {
|
||||
Self::tx_fifo_capacity() == 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn tx_fifo_capacity() -> u8 {
|
||||
let p = T::regs();
|
||||
unsafe { FIFO_SIZE - p.ic_txflr().read().txflr() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rx_fifo_len() -> u8 {
|
||||
let p = T::regs();
|
||||
unsafe { p.ic_rxflr().read().rxflr() }
|
||||
}
|
||||
|
||||
fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> {
|
||||
let p = T::regs();
|
||||
unsafe {
|
||||
@ -240,7 +504,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
|
||||
// NOTE(unsafe) We have &mut self
|
||||
unsafe {
|
||||
// wait until there is space in the FIFO to write the next byte
|
||||
while p.ic_txflr().read().txflr() == FIFO_SIZE {}
|
||||
while Self::tx_fifo_full() {}
|
||||
|
||||
p.ic_data_cmd().write(|w| {
|
||||
w.set_restart(restart && first);
|
||||
@ -249,7 +513,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
|
||||
w.set_cmd(true);
|
||||
});
|
||||
|
||||
while p.ic_rxflr().read().rxflr() == 0 {
|
||||
while Self::rx_fifo_len() == 0 {
|
||||
self.read_and_clear_abort_reason()?;
|
||||
}
|
||||
|
||||
@ -379,7 +643,7 @@ mod eh1 {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::blocking::I2c for I2c<'d, T, M> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> {
|
||||
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.blocking_read(address, buffer)
|
||||
}
|
||||
@ -421,16 +685,14 @@ mod eh1 {
|
||||
fn transaction<'a>(
|
||||
&mut self,
|
||||
address: u8,
|
||||
operations: &mut [embedded_hal_1::i2c::blocking::Operation<'a>],
|
||||
operations: &mut [embedded_hal_1::i2c::Operation<'a>],
|
||||
) -> Result<(), Self::Error> {
|
||||
Self::setup(address.into())?;
|
||||
for i in 0..operations.len() {
|
||||
let last = i == operations.len() - 1;
|
||||
match &mut operations[i] {
|
||||
embedded_hal_1::i2c::blocking::Operation::Read(buf) => {
|
||||
self.read_blocking_internal(buf, false, last)?
|
||||
}
|
||||
embedded_hal_1::i2c::blocking::Operation::Write(buf) => self.write_blocking_internal(buf, last)?,
|
||||
embedded_hal_1::i2c::Operation::Read(buf) => self.read_blocking_internal(buf, false, last)?,
|
||||
embedded_hal_1::i2c::Operation::Write(buf) => self.write_blocking_internal(buf, last)?,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@ -438,23 +700,106 @@ mod eh1 {
|
||||
|
||||
fn transaction_iter<'a, O>(&mut self, address: u8, operations: O) -> Result<(), Self::Error>
|
||||
where
|
||||
O: IntoIterator<Item = embedded_hal_1::i2c::blocking::Operation<'a>>,
|
||||
O: IntoIterator<Item = embedded_hal_1::i2c::Operation<'a>>,
|
||||
{
|
||||
Self::setup(address.into())?;
|
||||
let mut peekable = operations.into_iter().peekable();
|
||||
while let Some(operation) = peekable.next() {
|
||||
let last = peekable.peek().is_none();
|
||||
match operation {
|
||||
embedded_hal_1::i2c::blocking::Operation::Read(buf) => {
|
||||
self.read_blocking_internal(buf, false, last)?
|
||||
}
|
||||
embedded_hal_1::i2c::blocking::Operation::Write(buf) => self.write_blocking_internal(buf, last)?,
|
||||
embedded_hal_1::i2c::Operation::Read(buf) => self.read_blocking_internal(buf, false, last)?,
|
||||
embedded_hal_1::i2c::Operation::Write(buf) => self.write_blocking_internal(buf, last)?,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
|
||||
mod nightly {
|
||||
use core::future::Future;
|
||||
|
||||
use embedded_hal_1::i2c::Operation;
|
||||
use embedded_hal_async::i2c::AddressMode;
|
||||
|
||||
use super::*;
|
||||
|
||||
impl<'d, A, T> embedded_hal_async::i2c::I2c<A> for I2c<'d, T, Async>
|
||||
where
|
||||
A: AddressMode + Into<u16> + 'static,
|
||||
T: Instance + 'd,
|
||||
{
|
||||
type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
|
||||
where Self: 'a;
|
||||
type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
|
||||
where Self: 'a;
|
||||
type WriteReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
|
||||
where Self: 'a;
|
||||
type TransactionFuture<'a, 'b> = impl Future<Output = Result<(), Error>> + 'a
|
||||
where Self: 'a, 'b: 'a;
|
||||
|
||||
fn read<'a>(&'a mut self, address: A, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
||||
let addr: u16 = address.into();
|
||||
|
||||
async move {
|
||||
Self::setup(addr)?;
|
||||
self.read_async_internal(buffer, false, true).await
|
||||
}
|
||||
}
|
||||
|
||||
fn write<'a>(&'a mut self, address: A, write: &'a [u8]) -> Self::WriteFuture<'a> {
|
||||
let addr: u16 = address.into();
|
||||
|
||||
async move {
|
||||
Self::setup(addr)?;
|
||||
self.write_async_internal(write.iter().copied(), true).await
|
||||
}
|
||||
}
|
||||
|
||||
fn write_read<'a>(
|
||||
&'a mut self,
|
||||
address: A,
|
||||
bytes: &'a [u8],
|
||||
buffer: &'a mut [u8],
|
||||
) -> Self::WriteReadFuture<'a> {
|
||||
let addr: u16 = address.into();
|
||||
|
||||
async move {
|
||||
Self::setup(addr)?;
|
||||
self.write_async_internal(bytes.iter().cloned(), false).await?;
|
||||
self.read_async_internal(buffer, false, true).await
|
||||
}
|
||||
}
|
||||
|
||||
fn transaction<'a, 'b>(
|
||||
&'a mut self,
|
||||
address: A,
|
||||
operations: &'a mut [Operation<'b>],
|
||||
) -> Self::TransactionFuture<'a, 'b> {
|
||||
let addr: u16 = address.into();
|
||||
|
||||
async move {
|
||||
let mut iterator = operations.iter_mut();
|
||||
|
||||
while let Some(op) = iterator.next() {
|
||||
let last = iterator.len() == 0;
|
||||
|
||||
match op {
|
||||
Operation::Read(buffer) => {
|
||||
Self::setup(addr)?;
|
||||
self.read_async_internal(buffer, false, last).await?;
|
||||
}
|
||||
Operation::Write(buffer) => {
|
||||
Self::setup(addr)?;
|
||||
self.write_async_internal(buffer.into_iter().cloned(), last).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn i2c_reserved_addr(addr: u16) -> bool {
|
||||
(addr & 0x78) == 0 || (addr & 0x78) == 0x78
|
||||
@ -462,6 +807,7 @@ fn i2c_reserved_addr(addr: u16) -> bool {
|
||||
|
||||
mod sealed {
|
||||
use embassy_cortex_m::interrupt::Interrupt;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
pub trait Instance {
|
||||
const TX_DREQ: u8;
|
||||
@ -470,6 +816,8 @@ mod sealed {
|
||||
type Interrupt: Interrupt;
|
||||
|
||||
fn regs() -> crate::pac::i2c::I2c;
|
||||
fn reset() -> crate::pac::resets::regs::Peripherals;
|
||||
fn waker() -> &'static AtomicWaker;
|
||||
}
|
||||
|
||||
pub trait Mode {}
|
||||
@ -496,23 +844,38 @@ impl_mode!(Async);
|
||||
pub trait Instance: sealed::Instance {}
|
||||
|
||||
macro_rules! impl_instance {
|
||||
($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
|
||||
($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => {
|
||||
impl sealed::Instance for peripherals::$type {
|
||||
const TX_DREQ: u8 = $tx_dreq;
|
||||
const RX_DREQ: u8 = $rx_dreq;
|
||||
|
||||
type Interrupt = crate::interrupt::$irq;
|
||||
|
||||
#[inline]
|
||||
fn regs() -> pac::i2c::I2c {
|
||||
pac::$type
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reset() -> pac::resets::regs::Peripherals {
|
||||
let mut ret = pac::resets::regs::Peripherals::default();
|
||||
ret.$reset(true);
|
||||
ret
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn waker() -> &'static AtomicWaker {
|
||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||
|
||||
&WAKER
|
||||
}
|
||||
}
|
||||
impl Instance for peripherals::$type {}
|
||||
};
|
||||
}
|
||||
|
||||
impl_instance!(I2C0, I2C0_IRQ, 32, 33);
|
||||
impl_instance!(I2C1, I2C1_IRQ, 34, 35);
|
||||
impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33);
|
||||
impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35);
|
||||
|
||||
pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {}
|
||||
pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {}
|
||||
|
@ -145,6 +145,8 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
|
||||
filter.write_setup_1(w);
|
||||
});
|
||||
|
||||
self.inner.regs().inte().modify(|w| w.set_rtc(true));
|
||||
|
||||
// Set the enable bit and check if it is set
|
||||
self.inner.regs().irq_setup_0().modify(|w| w.set_match_ena(true));
|
||||
while !self.inner.regs().irq_setup_0().read().match_active() {
|
||||
|
@ -523,25 +523,25 @@ mod eh1 {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::blocking::SpiBusFlush for Spi<'d, T, M> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBusFlush for Spi<'d, T, M> {
|
||||
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::blocking::SpiBusRead<u8> for Spi<'d, T, M> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBusRead<u8> for Spi<'d, T, M> {
|
||||
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.blocking_transfer(words, &[])
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::blocking::SpiBusWrite<u8> for Spi<'d, T, M> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBusWrite<u8> for Spi<'d, T, M> {
|
||||
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
|
||||
self.blocking_write(words)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::blocking::SpiBus<u8> for Spi<'d, T, M> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBus<u8> for Spi<'d, T, M> {
|
||||
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
|
||||
self.blocking_transfer(read, write)
|
||||
}
|
||||
|
@ -486,7 +486,7 @@ mod eh1 {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for UartRx<'d, T, M> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> {
|
||||
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||
let r = T::regs();
|
||||
unsafe {
|
||||
@ -509,7 +509,7 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for UartTx<'d, T, M> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::Write for UartTx<'d, T, M> {
|
||||
fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||
self.blocking_write(buffer)
|
||||
}
|
||||
@ -519,7 +519,7 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for UartTx<'d, T, M> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> {
|
||||
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||
self.blocking_write(&[char]).map_err(nb::Error::Other)
|
||||
}
|
||||
@ -529,13 +529,13 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for Uart<'d, T, M> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, T, M> {
|
||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||
embedded_hal_02::serial::Read::read(&mut self.rx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for Uart<'d, T, M> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::Write for Uart<'d, T, M> {
|
||||
fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||
self.blocking_write(buffer)
|
||||
}
|
||||
@ -545,7 +545,7 @@ mod eh1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for Uart<'d, T, M> {
|
||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> {
|
||||
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||
self.blocking_write(&[char]).map_err(nb::Error::Other)
|
||||
}
|
||||
|
@ -522,7 +522,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
|
||||
trace!("wait_enabled IN WAITING");
|
||||
let index = self.info.addr.index();
|
||||
poll_fn(|cx| {
|
||||
EP_OUT_WAKERS[index].register(cx.waker());
|
||||
EP_IN_WAKERS[index].register(cx.waker());
|
||||
let val = unsafe { T::dpram().ep_in_control(self.info.addr.index() - 1).read() };
|
||||
if val.enable() {
|
||||
Poll::Ready(())
|
||||
@ -811,8 +811,8 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
||||
async move {
|
||||
trace!("control: accept");
|
||||
|
||||
let bufcontrol = T::dpram().ep_in_buffer_control(0);
|
||||
unsafe {
|
||||
let bufcontrol = T::dpram().ep_in_buffer_control(0);
|
||||
bufcontrol.write(|w| {
|
||||
w.set_length(0, 0);
|
||||
w.set_pid(0, true);
|
||||
@ -826,6 +826,18 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
||||
w.set_available(0, true);
|
||||
});
|
||||
}
|
||||
|
||||
// wait for completion before returning, needed so
|
||||
// set_address() doesn't happen early.
|
||||
poll_fn(|cx| {
|
||||
EP_IN_WAKERS[0].register(cx.waker());
|
||||
if unsafe { bufcontrol.read().available(0) } {
|
||||
Poll::Pending
|
||||
} else {
|
||||
Poll::Ready(())
|
||||
}
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user