Merge #552
552: embassy-nrf: migrate to embedded-hal 1.0, embedded-hal-async r=Dirbaio a=Dirbaio Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
This commit is contained in:
commit
2310003f39
22 changed files with 1655 additions and 1146 deletions
|
@ -12,6 +12,9 @@ edition = "2018"
|
||||||
# There are no plans to make this stable.
|
# There are no plans to make this stable.
|
||||||
unstable-pac = []
|
unstable-pac = []
|
||||||
|
|
||||||
|
# Implement embedded-hal 1.0 alpha and embedded-hal-async traits.
|
||||||
|
unstable-traits = ["embedded-hal-1", "embedded-hal-async"]
|
||||||
|
|
||||||
nrf52805 = ["nrf52805-pac", "_ppi"]
|
nrf52805 = ["nrf52805-pac", "_ppi"]
|
||||||
nrf52810 = ["nrf52810-pac", "_ppi"]
|
nrf52810 = ["nrf52810-pac", "_ppi"]
|
||||||
nrf52811 = ["nrf52811-pac", "_ppi"]
|
nrf52811 = ["nrf52811-pac", "_ppi"]
|
||||||
|
@ -47,11 +50,14 @@ embassy = { version = "0.1.0", path = "../embassy" }
|
||||||
embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["nrf"]}
|
embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["nrf"]}
|
||||||
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
|
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
|
||||||
|
|
||||||
|
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" }
|
||||||
|
embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.6", git = "https://github.com/embassy-rs/embedded-hal", branch = "embassy", optional = true}
|
||||||
|
embedded-hal-async = { version = "0.0.1", git = "https://github.com/embassy-rs/embedded-hal", branch = "embassy", optional = true}
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
cortex-m-rt = ">=0.6.15,<0.8"
|
cortex-m-rt = ">=0.6.15,<0.8"
|
||||||
cortex-m = "0.7.3"
|
cortex-m = "0.7.3"
|
||||||
embedded-hal = "0.2.6"
|
|
||||||
embedded-dma = "0.1.2"
|
embedded-dma = "0.1.2"
|
||||||
futures = { version = "0.3.17", default-features = false }
|
futures = { version = "0.3.17", default-features = false }
|
||||||
critical-section = "0.2.5"
|
critical-section = "0.2.5"
|
||||||
|
|
|
@ -213,9 +213,6 @@ impl<'d, U: UarteInstance, T: TimerInstance> AsyncBufRead for BufferedUarte<'d,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
) -> Poll<embassy::io::Result<&[u8]>> {
|
) -> Poll<embassy::io::Result<&[u8]>> {
|
||||||
self.inner.with(|state| {
|
self.inner.with(|state| {
|
||||||
// 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(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
trace!("poll_read");
|
trace!("poll_read");
|
||||||
|
|
||||||
|
@ -265,9 +262,6 @@ impl<'d, U: UarteInstance, T: TimerInstance> AsyncWrite for BufferedUarte<'d, U,
|
||||||
|
|
||||||
trace!("poll_write: queued {:?}", n);
|
trace!("poll_write: queued {:?}", n);
|
||||||
|
|
||||||
// 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(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
Poll::Ready(Ok(n))
|
Poll::Ready(Ok(n))
|
||||||
|
@ -347,9 +341,7 @@ impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for StateInner<'a,
|
||||||
trace!(" irq_rx: buf {:?} {:?}", buf.as_ptr() as u32, buf.len());
|
trace!(" irq_rx: buf {:?} {:?}", buf.as_ptr() as u32, buf.len());
|
||||||
|
|
||||||
// Start UARTE Receive transaction
|
// Start UARTE Receive transaction
|
||||||
r.tasks_startrx.write(|w|
|
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||||
// `1` is a valid value to write to task registers.
|
|
||||||
unsafe { w.bits(1) });
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -397,9 +389,7 @@ impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for StateInner<'a,
|
||||||
unsafe { w.maxcnt().bits(buf.len() as _) });
|
unsafe { w.maxcnt().bits(buf.len() as _) });
|
||||||
|
|
||||||
// Start UARTE Transmit transaction
|
// Start UARTE Transmit transaction
|
||||||
r.tasks_starttx.write(|w|
|
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||||
// `1` is a valid value to write to task registers.
|
|
||||||
unsafe { w.bits(1) });
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ use core::marker::PhantomData;
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use embassy::util::Unborrow;
|
use embassy::util::Unborrow;
|
||||||
use embassy_hal_common::{unborrow, unsafe_impl_unborrow};
|
use embassy_hal_common::{unborrow, unsafe_impl_unborrow};
|
||||||
use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin};
|
|
||||||
use gpio::pin_cnf::DRIVE_A;
|
use gpio::pin_cnf::DRIVE_A;
|
||||||
|
|
||||||
use crate::pac;
|
use crate::pac;
|
||||||
|
@ -37,12 +36,12 @@ pub enum Pull {
|
||||||
|
|
||||||
/// GPIO input driver.
|
/// GPIO input driver.
|
||||||
pub struct Input<'d, T: Pin> {
|
pub struct Input<'d, T: Pin> {
|
||||||
pub(crate) pin: FlexPin<'d, T>,
|
pub(crate) pin: Flex<'d, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Pin> Input<'d, T> {
|
impl<'d, T: Pin> Input<'d, T> {
|
||||||
pub fn new(pin: impl Unborrow<Target = T> + 'd, pull: Pull) -> Self {
|
pub fn new(pin: impl Unborrow<Target = T> + 'd, pull: Pull) -> Self {
|
||||||
let mut pin = FlexPin::new(pin);
|
let mut pin = Flex::new(pin);
|
||||||
pin.set_as_input(pull);
|
pin.set_as_input(pull);
|
||||||
|
|
||||||
Self { pin }
|
Self { pin }
|
||||||
|
@ -57,18 +56,6 @@ impl<'d, T: Pin> Input<'d, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Pin> InputPin for Input<'d, T> {
|
|
||||||
type Error = Infallible;
|
|
||||||
|
|
||||||
fn is_high(&self) -> Result<bool, Self::Error> {
|
|
||||||
Ok(self.is_high())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_low(&self) -> Result<bool, Self::Error> {
|
|
||||||
Ok(self.is_low())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Digital input or output level.
|
/// Digital input or output level.
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
@ -102,7 +89,7 @@ pub enum OutputDrive {
|
||||||
|
|
||||||
/// GPIO output driver.
|
/// GPIO output driver.
|
||||||
pub struct Output<'d, T: Pin> {
|
pub struct Output<'d, T: Pin> {
|
||||||
pub(crate) pin: FlexPin<'d, T>,
|
pub(crate) pin: Flex<'d, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Pin> Output<'d, T> {
|
impl<'d, T: Pin> Output<'d, T> {
|
||||||
|
@ -111,7 +98,7 @@ impl<'d, T: Pin> Output<'d, T> {
|
||||||
initial_output: Level,
|
initial_output: Level,
|
||||||
drive: OutputDrive,
|
drive: OutputDrive,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut pin = FlexPin::new(pin);
|
let mut pin = Flex::new(pin);
|
||||||
match initial_output {
|
match initial_output {
|
||||||
Level::High => pin.set_high(),
|
Level::High => pin.set_high(),
|
||||||
Level::Low => pin.set_low(),
|
Level::Low => pin.set_low(),
|
||||||
|
@ -142,40 +129,18 @@ impl<'d, T: Pin> Output<'d, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Pin> OutputPin for Output<'d, T> {
|
|
||||||
type Error = Infallible;
|
|
||||||
|
|
||||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
|
||||||
Ok(self.set_high())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
|
||||||
Ok(self.set_low())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Pin> StatefulOutputPin for Output<'d, T> {
|
|
||||||
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
|
||||||
Ok(self.is_set_high())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
|
||||||
Ok(self.is_set_low())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// GPIO flexible pin.
|
/// GPIO flexible pin.
|
||||||
///
|
///
|
||||||
/// This pin can either be a disconnected, input, or output pin. The level register bit will remain
|
/// This pin can either be a disconnected, input, or output pin. The level register bit will remain
|
||||||
/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
|
/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
|
||||||
/// mode.
|
/// mode.
|
||||||
pub struct FlexPin<'d, T: Pin> {
|
pub struct Flex<'d, T: Pin> {
|
||||||
pub(crate) pin: T,
|
pub(crate) pin: T,
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Pin> FlexPin<'d, T> {
|
impl<'d, T: Pin> Flex<'d, T> {
|
||||||
/// Wrap the pin in a `FlexPin`.
|
/// Wrap the pin in a `Flex`.
|
||||||
///
|
///
|
||||||
/// The pin remains disconnected. The initial output level is unspecified, but can be changed
|
/// The pin remains disconnected. The initial output level is unspecified, but can be changed
|
||||||
/// before the pin is put into output mode.
|
/// before the pin is put into output mode.
|
||||||
|
@ -270,49 +235,12 @@ impl<'d, T: Pin> FlexPin<'d, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Pin> Drop for FlexPin<'d, T> {
|
impl<'d, T: Pin> Drop for Flex<'d, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.pin.conf().reset();
|
self.pin.conf().reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implement [`InputPin`] for [`FlexPin`];
|
|
||||||
///
|
|
||||||
/// If the pin is not in input mode the result is unspecified.
|
|
||||||
impl<'d, T: Pin> InputPin for FlexPin<'d, T> {
|
|
||||||
type Error = Infallible;
|
|
||||||
|
|
||||||
fn is_high(&self) -> Result<bool, Self::Error> {
|
|
||||||
Ok(self.is_high())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_low(&self) -> Result<bool, Self::Error> {
|
|
||||||
Ok(self.is_low())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Pin> OutputPin for FlexPin<'d, T> {
|
|
||||||
type Error = Infallible;
|
|
||||||
|
|
||||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
|
||||||
Ok(self.set_high())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
|
||||||
Ok(self.set_low())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Pin> StatefulOutputPin for FlexPin<'d, T> {
|
|
||||||
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
|
||||||
Ok(self.is_set_high())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
|
||||||
Ok(self.is_set_low())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -350,17 +278,13 @@ pub(crate) mod sealed {
|
||||||
/// Set the output as high.
|
/// Set the output as high.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn set_high(&self) {
|
fn set_high(&self) {
|
||||||
unsafe {
|
unsafe { self.block().outset.write(|w| w.bits(1u32 << self._pin())) }
|
||||||
self.block().outset.write(|w| w.bits(1u32 << self._pin()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the output as low.
|
/// Set the output as low.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn set_low(&self) {
|
fn set_low(&self) {
|
||||||
unsafe {
|
unsafe { self.block().outclr.write(|w| w.bits(1u32 << self._pin())) }
|
||||||
self.block().outclr.write(|w| w.bits(1u32 << self._pin()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,3 +419,160 @@ macro_rules! impl_pin {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====================
|
||||||
|
|
||||||
|
mod eh02 {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_high())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_low(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_low())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Output<'d, T> {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(self.set_high())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(self.set_low())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> {
|
||||||
|
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_set_high())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_set_low())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implement [`InputPin`] for [`Flex`];
|
||||||
|
///
|
||||||
|
/// If the pin is not in input mode the result is unspecified.
|
||||||
|
impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_high())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_low(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_low())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(self.set_high())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(self.set_low())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> {
|
||||||
|
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_set_high())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_set_low())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "unstable-traits")]
|
||||||
|
mod eh1 {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> {
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Pin> embedded_hal_1::digital::blocking::InputPin for Input<'d, T> {
|
||||||
|
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_high())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_low(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_low())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Output<'d, T> {
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Pin> embedded_hal_1::digital::blocking::OutputPin for Output<'d, T> {
|
||||||
|
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(self.set_high())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(self.set_low())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Pin> embedded_hal_1::digital::blocking::StatefulOutputPin for Output<'d, T> {
|
||||||
|
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_set_high())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_set_low())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> {
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implement [`InputPin`] for [`Flex`];
|
||||||
|
///
|
||||||
|
/// If the pin is not in input mode the result is unspecified.
|
||||||
|
impl<'d, T: Pin> embedded_hal_1::digital::blocking::InputPin for Flex<'d, T> {
|
||||||
|
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_high())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_low(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_low())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Pin> embedded_hal_1::digital::blocking::OutputPin for Flex<'d, T> {
|
||||||
|
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(self.set_high())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(self.set_low())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Pin> embedded_hal_1::digital::blocking::StatefulOutputPin for Flex<'d, T> {
|
||||||
|
fn is_set_high(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_set_high())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_set_low(&self) -> Result<bool, Self::Error> {
|
||||||
|
Ok(self.is_set_low())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,11 +5,10 @@ use core::task::{Context, Poll};
|
||||||
use embassy::interrupt::{Interrupt, InterruptExt};
|
use embassy::interrupt::{Interrupt, InterruptExt};
|
||||||
use embassy::waitqueue::AtomicWaker;
|
use embassy::waitqueue::AtomicWaker;
|
||||||
use embassy_hal_common::unsafe_impl_unborrow;
|
use embassy_hal_common::unsafe_impl_unborrow;
|
||||||
use embedded_hal::digital::v2::InputPin;
|
|
||||||
use futures::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
|
|
||||||
use crate::gpio::sealed::Pin as _;
|
use crate::gpio::sealed::Pin as _;
|
||||||
use crate::gpio::{AnyPin, FlexPin, Input, Output, Pin as GpioPin};
|
use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin};
|
||||||
use crate::pac;
|
use crate::pac;
|
||||||
use crate::ppi::{Event, Task};
|
use crate::ppi::{Event, Task};
|
||||||
use crate::{interrupt, peripherals};
|
use crate::{interrupt, peripherals};
|
||||||
|
@ -216,18 +215,6 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, C: Channel, T: GpioPin> InputPin for InputChannel<'d, C, T> {
|
|
||||||
type Error = Infallible;
|
|
||||||
|
|
||||||
fn is_high(&self) -> Result<bool, Self::Error> {
|
|
||||||
self.pin.is_high()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_low(&self) -> Result<bool, Self::Error> {
|
|
||||||
self.pin.is_low()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// GPIOTE channel driver in output mode
|
/// GPIOTE channel driver in output mode
|
||||||
pub struct OutputChannel<'d, C: Channel, T: GpioPin> {
|
pub struct OutputChannel<'d, C: Channel, T: GpioPin> {
|
||||||
ch: C,
|
ch: C,
|
||||||
|
@ -342,78 +329,60 @@ impl<'a> Future for PortInputFuture<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: GpioPin> embassy::traits::gpio::WaitForHigh for Input<'d, T> {
|
impl<'d, T: GpioPin> Input<'d, T> {
|
||||||
type Future<'a>
|
pub async fn wait_for_high(&mut self) {
|
||||||
where
|
self.pin.wait_for_high().await
|
||||||
Self: 'a,
|
}
|
||||||
= impl Future<Output = ()> + Unpin + 'a;
|
|
||||||
|
|
||||||
fn wait_for_high<'a>(&'a mut self) -> Self::Future<'a> {
|
pub async fn wait_for_low(&mut self) {
|
||||||
self.pin.wait_for_high()
|
self.pin.wait_for_low().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn wait_for_rising_edge(&mut self) {
|
||||||
|
self.pin.wait_for_rising_edge().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn wait_for_falling_edge(&mut self) {
|
||||||
|
self.pin.wait_for_falling_edge().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn wait_for_any_edge(&mut self) {
|
||||||
|
self.pin.wait_for_any_edge().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: GpioPin> embassy::traits::gpio::WaitForLow for Input<'d, T> {
|
impl<'d, T: GpioPin> Flex<'d, T> {
|
||||||
type Future<'a>
|
pub async fn wait_for_high(&mut self) {
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = ()> + Unpin + 'a;
|
|
||||||
|
|
||||||
fn wait_for_low<'a>(&'a mut self) -> Self::Future<'a> {
|
|
||||||
self.pin.wait_for_low()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: GpioPin> embassy::traits::gpio::WaitForAnyEdge for Input<'d, T> {
|
|
||||||
type Future<'a>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = ()> + Unpin + 'a;
|
|
||||||
|
|
||||||
fn wait_for_any_edge<'a>(&'a mut self) -> Self::Future<'a> {
|
|
||||||
self.pin.wait_for_any_edge()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: GpioPin> embassy::traits::gpio::WaitForHigh for FlexPin<'d, T> {
|
|
||||||
type Future<'a>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = ()> + Unpin + 'a;
|
|
||||||
|
|
||||||
fn wait_for_high<'a>(&'a mut self) -> Self::Future<'a> {
|
|
||||||
self.pin.conf().modify(|_, w| w.sense().high());
|
self.pin.conf().modify(|_, w| w.sense().high());
|
||||||
|
|
||||||
PortInputFuture {
|
PortInputFuture {
|
||||||
pin_port: self.pin.pin_port(),
|
pin_port: self.pin.pin_port(),
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: GpioPin> embassy::traits::gpio::WaitForLow for FlexPin<'d, T> {
|
pub async fn wait_for_low(&mut self) {
|
||||||
type Future<'a>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = ()> + Unpin + 'a;
|
|
||||||
|
|
||||||
fn wait_for_low<'a>(&'a mut self) -> Self::Future<'a> {
|
|
||||||
self.pin.conf().modify(|_, w| w.sense().low());
|
self.pin.conf().modify(|_, w| w.sense().low());
|
||||||
|
|
||||||
PortInputFuture {
|
PortInputFuture {
|
||||||
pin_port: self.pin.pin_port(),
|
pin_port: self.pin.pin_port(),
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: GpioPin> embassy::traits::gpio::WaitForAnyEdge for FlexPin<'d, T> {
|
pub async fn wait_for_rising_edge(&mut self) {
|
||||||
type Future<'a>
|
self.wait_for_low().await;
|
||||||
where
|
self.wait_for_high().await;
|
||||||
Self: 'a,
|
}
|
||||||
= impl Future<Output = ()> + Unpin + 'a;
|
|
||||||
|
|
||||||
fn wait_for_any_edge<'a>(&'a mut self) -> Self::Future<'a> {
|
pub async fn wait_for_falling_edge(&mut self) {
|
||||||
|
self.wait_for_high().await;
|
||||||
|
self.wait_for_low().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn wait_for_any_edge(&mut self) {
|
||||||
if self.is_high() {
|
if self.is_high() {
|
||||||
self.pin.conf().modify(|_, w| w.sense().low());
|
self.pin.conf().modify(|_, w| w.sense().low());
|
||||||
} else {
|
} else {
|
||||||
|
@ -423,6 +392,7 @@ impl<'d, T: GpioPin> embassy::traits::gpio::WaitForAnyEdge for FlexPin<'d, T> {
|
||||||
pin_port: self.pin.pin_port(),
|
pin_port: self.pin.pin_port(),
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,3 +441,137 @@ impl_channel!(GPIOTE_CH4, 4);
|
||||||
impl_channel!(GPIOTE_CH5, 5);
|
impl_channel!(GPIOTE_CH5, 5);
|
||||||
impl_channel!(GPIOTE_CH6, 6);
|
impl_channel!(GPIOTE_CH6, 6);
|
||||||
impl_channel!(GPIOTE_CH7, 7);
|
impl_channel!(GPIOTE_CH7, 7);
|
||||||
|
|
||||||
|
// ====================
|
||||||
|
|
||||||
|
mod eh02 {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl<'d, C: Channel, T: GpioPin> embedded_hal_02::digital::v2::InputPin for InputChannel<'d, C, T> {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||||
|
self.pin.is_high()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_low(&self) -> Result<bool, Self::Error> {
|
||||||
|
self.pin.is_low()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "unstable-traits")]
|
||||||
|
mod eh1 {
|
||||||
|
use super::*;
|
||||||
|
use futures::FutureExt;
|
||||||
|
|
||||||
|
impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::ErrorType for InputChannel<'d, C, T> {
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::blocking::InputPin
|
||||||
|
for InputChannel<'d, C, T>
|
||||||
|
{
|
||||||
|
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||||
|
self.pin.is_high()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_low(&self) -> Result<bool, Self::Error> {
|
||||||
|
self.pin.is_low()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Input<'d, T> {
|
||||||
|
type WaitForHighFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> {
|
||||||
|
self.wait_for_high().map(Ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WaitForLowFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> {
|
||||||
|
self.wait_for_low().map(Ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WaitForRisingEdgeFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> {
|
||||||
|
self.wait_for_rising_edge().map(Ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WaitForFallingEdgeFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> {
|
||||||
|
self.wait_for_falling_edge().map(Ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WaitForAnyEdgeFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> {
|
||||||
|
self.wait_for_any_edge().map(Ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Flex<'d, T> {
|
||||||
|
type WaitForHighFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> {
|
||||||
|
self.wait_for_high().map(Ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WaitForLowFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> {
|
||||||
|
self.wait_for_low().map(Ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WaitForRisingEdgeFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> {
|
||||||
|
self.wait_for_rising_edge().map(Ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WaitForFallingEdgeFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> {
|
||||||
|
self.wait_for_falling_edge().map(Ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WaitForAnyEdgeFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> {
|
||||||
|
self.wait_for_any_edge().map(Ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
use core::future::Future;
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
use embassy::interrupt::{Interrupt, InterruptExt};
|
use embassy::interrupt::{Interrupt, InterruptExt};
|
||||||
use embassy::traits::flash::{Error, Flash};
|
|
||||||
use embassy::util::Unborrow;
|
use embassy::util::Unborrow;
|
||||||
use embassy_hal_common::drop::DropBomb;
|
use embassy_hal_common::drop::DropBomb;
|
||||||
use embassy_hal_common::unborrow;
|
use embassy_hal_common::unborrow;
|
||||||
|
@ -58,6 +56,13 @@ impl Default for Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum Error {
|
||||||
|
// TODO add "not in data memory" error and check for it
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Qspi<'d, T: Instance> {
|
pub struct Qspi<'d, T: Instance> {
|
||||||
dpm_enabled: bool,
|
dpm_enabled: bool,
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
|
@ -240,6 +245,87 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
|
||||||
|
let bomb = DropBomb::new();
|
||||||
|
|
||||||
|
assert_eq!(data.as_ptr() as u32 % 4, 0);
|
||||||
|
assert_eq!(data.len() as u32 % 4, 0);
|
||||||
|
assert_eq!(address as u32 % 4, 0);
|
||||||
|
|
||||||
|
let r = T::regs();
|
||||||
|
|
||||||
|
r.read
|
||||||
|
.src
|
||||||
|
.write(|w| unsafe { w.src().bits(address as u32) });
|
||||||
|
r.read
|
||||||
|
.dst
|
||||||
|
.write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) });
|
||||||
|
r.read
|
||||||
|
.cnt
|
||||||
|
.write(|w| unsafe { w.cnt().bits(data.len() as u32) });
|
||||||
|
|
||||||
|
r.events_ready.reset();
|
||||||
|
r.intenset.write(|w| w.ready().set());
|
||||||
|
r.tasks_readstart.write(|w| w.tasks_readstart().bit(true));
|
||||||
|
|
||||||
|
self.wait_ready().await;
|
||||||
|
|
||||||
|
bomb.defuse();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
|
||||||
|
let bomb = DropBomb::new();
|
||||||
|
|
||||||
|
assert_eq!(data.as_ptr() as u32 % 4, 0);
|
||||||
|
assert_eq!(data.len() as u32 % 4, 0);
|
||||||
|
assert_eq!(address as u32 % 4, 0);
|
||||||
|
|
||||||
|
let r = T::regs();
|
||||||
|
r.write
|
||||||
|
.src
|
||||||
|
.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) });
|
||||||
|
r.write
|
||||||
|
.dst
|
||||||
|
.write(|w| unsafe { w.dst().bits(address as u32) });
|
||||||
|
r.write
|
||||||
|
.cnt
|
||||||
|
.write(|w| unsafe { w.cnt().bits(data.len() as u32) });
|
||||||
|
|
||||||
|
r.events_ready.reset();
|
||||||
|
r.intenset.write(|w| w.ready().set());
|
||||||
|
r.tasks_writestart.write(|w| w.tasks_writestart().bit(true));
|
||||||
|
|
||||||
|
self.wait_ready().await;
|
||||||
|
|
||||||
|
bomb.defuse();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn erase(&mut self, address: usize) -> Result<(), Error> {
|
||||||
|
let bomb = DropBomb::new();
|
||||||
|
|
||||||
|
assert_eq!(address as u32 % 4096, 0);
|
||||||
|
|
||||||
|
let r = T::regs();
|
||||||
|
r.erase
|
||||||
|
.ptr
|
||||||
|
.write(|w| unsafe { w.ptr().bits(address as u32) });
|
||||||
|
r.erase.len.write(|w| w.len()._4kb());
|
||||||
|
|
||||||
|
r.events_ready.reset();
|
||||||
|
r.intenset.write(|w| w.ready().set());
|
||||||
|
r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true));
|
||||||
|
|
||||||
|
self.wait_ready().await;
|
||||||
|
|
||||||
|
bomb.defuse();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Drop for Qspi<'d, T> {
|
impl<'d, T: Instance> Drop for Qspi<'d, T> {
|
||||||
|
@ -285,124 +371,6 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Flash for Qspi<'d, T> {
|
|
||||||
type ReadFuture<'a>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = Result<(), Error>> + 'a;
|
|
||||||
type WriteFuture<'a>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = Result<(), Error>> + 'a;
|
|
||||||
type ErasePageFuture<'a>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = Result<(), Error>> + 'a;
|
|
||||||
|
|
||||||
fn read<'a>(&'a mut self, address: usize, data: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
|
||||||
async move {
|
|
||||||
let bomb = DropBomb::new();
|
|
||||||
|
|
||||||
assert_eq!(data.as_ptr() as u32 % 4, 0);
|
|
||||||
assert_eq!(data.len() as u32 % 4, 0);
|
|
||||||
assert_eq!(address as u32 % 4, 0);
|
|
||||||
|
|
||||||
let r = T::regs();
|
|
||||||
|
|
||||||
r.read
|
|
||||||
.src
|
|
||||||
.write(|w| unsafe { w.src().bits(address as u32) });
|
|
||||||
r.read
|
|
||||||
.dst
|
|
||||||
.write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) });
|
|
||||||
r.read
|
|
||||||
.cnt
|
|
||||||
.write(|w| unsafe { w.cnt().bits(data.len() as u32) });
|
|
||||||
|
|
||||||
r.events_ready.reset();
|
|
||||||
r.intenset.write(|w| w.ready().set());
|
|
||||||
r.tasks_readstart.write(|w| w.tasks_readstart().bit(true));
|
|
||||||
|
|
||||||
self.wait_ready().await;
|
|
||||||
|
|
||||||
bomb.defuse();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write<'a>(&'a mut self, address: usize, data: &'a [u8]) -> Self::WriteFuture<'a> {
|
|
||||||
async move {
|
|
||||||
let bomb = DropBomb::new();
|
|
||||||
|
|
||||||
assert_eq!(data.as_ptr() as u32 % 4, 0);
|
|
||||||
assert_eq!(data.len() as u32 % 4, 0);
|
|
||||||
assert_eq!(address as u32 % 4, 0);
|
|
||||||
|
|
||||||
let r = T::regs();
|
|
||||||
r.write
|
|
||||||
.src
|
|
||||||
.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) });
|
|
||||||
r.write
|
|
||||||
.dst
|
|
||||||
.write(|w| unsafe { w.dst().bits(address as u32) });
|
|
||||||
r.write
|
|
||||||
.cnt
|
|
||||||
.write(|w| unsafe { w.cnt().bits(data.len() as u32) });
|
|
||||||
|
|
||||||
r.events_ready.reset();
|
|
||||||
r.intenset.write(|w| w.ready().set());
|
|
||||||
r.tasks_writestart.write(|w| w.tasks_writestart().bit(true));
|
|
||||||
|
|
||||||
self.wait_ready().await;
|
|
||||||
|
|
||||||
bomb.defuse();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn erase<'a>(&'a mut self, address: usize) -> Self::ErasePageFuture<'a> {
|
|
||||||
async move {
|
|
||||||
let bomb = DropBomb::new();
|
|
||||||
|
|
||||||
assert_eq!(address as u32 % 4096, 0);
|
|
||||||
|
|
||||||
let r = T::regs();
|
|
||||||
r.erase
|
|
||||||
.ptr
|
|
||||||
.write(|w| unsafe { w.ptr().bits(address as u32) });
|
|
||||||
r.erase.len.write(|w| w.len()._4kb());
|
|
||||||
|
|
||||||
r.events_ready.reset();
|
|
||||||
r.intenset.write(|w| w.ready().set());
|
|
||||||
r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true));
|
|
||||||
|
|
||||||
self.wait_ready().await;
|
|
||||||
|
|
||||||
bomb.defuse();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size(&self) -> usize {
|
|
||||||
256 * 4096 // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_size(&self) -> usize {
|
|
||||||
4 // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_size(&self) -> usize {
|
|
||||||
4 // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
fn erase_size(&self) -> usize {
|
|
||||||
4096 // TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
use embassy::waitqueue::AtomicWaker;
|
use embassy::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use core::convert::Infallible;
|
|
||||||
use core::future::Future;
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use core::sync::atomic::AtomicPtr;
|
use core::sync::atomic::AtomicPtr;
|
||||||
|
@ -7,13 +5,11 @@ use core::sync::atomic::Ordering;
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy::interrupt::InterruptExt;
|
use embassy::interrupt::InterruptExt;
|
||||||
use embassy::traits;
|
|
||||||
use embassy::util::Unborrow;
|
use embassy::util::Unborrow;
|
||||||
use embassy::waitqueue::AtomicWaker;
|
use embassy::waitqueue::AtomicWaker;
|
||||||
use embassy_hal_common::drop::OnDrop;
|
use embassy_hal_common::drop::OnDrop;
|
||||||
use embassy_hal_common::unborrow;
|
use embassy_hal_common::unborrow;
|
||||||
use futures::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
use rand_core::RngCore;
|
|
||||||
|
|
||||||
use crate::interrupt;
|
use crate::interrupt;
|
||||||
use crate::pac;
|
use crate::pac;
|
||||||
|
@ -39,7 +35,7 @@ struct State {
|
||||||
|
|
||||||
/// A wrapper around an nRF RNG peripheral.
|
/// A wrapper around an nRF RNG peripheral.
|
||||||
///
|
///
|
||||||
/// It has a non-blocking API, through `embassy::traits::Rng`, and a blocking api through `rand`.
|
/// It has a non-blocking API, and a blocking api through `rand`.
|
||||||
pub struct Rng<'d> {
|
pub struct Rng<'d> {
|
||||||
irq: interrupt::RNG,
|
irq: interrupt::RNG,
|
||||||
phantom: PhantomData<(&'d mut RNG, &'d mut interrupt::RNG)>,
|
phantom: PhantomData<(&'d mut RNG, &'d mut interrupt::RNG)>,
|
||||||
|
@ -146,72 +142,51 @@ impl<'d> Rng<'d> {
|
||||||
pub fn bias_correction(&self, enable: bool) {
|
pub fn bias_correction(&self, enable: bool) {
|
||||||
RNG::regs().config.write(|w| w.dercen().bit(enable))
|
RNG::regs().config.write(|w| w.dercen().bit(enable))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d> Drop for Rng<'d> {
|
pub async fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||||
fn drop(&mut self) {
|
if dest.len() == 0 {
|
||||||
self.irq.disable()
|
return; // Nothing to fill
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d> traits::rng::Rng for Rng<'d> {
|
|
||||||
type Error = Infallible;
|
|
||||||
|
|
||||||
type RngFuture<'a>
|
|
||||||
where
|
|
||||||
'd: 'a,
|
|
||||||
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
|
||||||
|
|
||||||
fn fill_bytes<'a>(&'a mut self, dest: &'a mut [u8]) -> Self::RngFuture<'a> {
|
|
||||||
async move {
|
|
||||||
if dest.len() == 0 {
|
|
||||||
return Ok(()); // Nothing to fill
|
|
||||||
}
|
|
||||||
|
|
||||||
let range = dest.as_mut_ptr_range();
|
|
||||||
// Even if we've preempted the interrupt, it can't preempt us again,
|
|
||||||
// so we don't need to worry about the order we write these in.
|
|
||||||
STATE.ptr.store(range.start, Ordering::Relaxed);
|
|
||||||
STATE.end.store(range.end, Ordering::Relaxed);
|
|
||||||
|
|
||||||
self.enable_irq();
|
|
||||||
self.start();
|
|
||||||
|
|
||||||
let on_drop = OnDrop::new(|| {
|
|
||||||
self.stop();
|
|
||||||
self.disable_irq();
|
|
||||||
|
|
||||||
// The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here.
|
|
||||||
STATE.ptr.store(ptr::null_mut(), Ordering::Relaxed);
|
|
||||||
STATE.end.store(ptr::null_mut(), Ordering::Relaxed);
|
|
||||||
});
|
|
||||||
|
|
||||||
poll_fn(|cx| {
|
|
||||||
STATE.waker.register(cx.waker());
|
|
||||||
|
|
||||||
// The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`.
|
|
||||||
let end = STATE.end.load(Ordering::Relaxed);
|
|
||||||
let ptr = STATE.ptr.load(Ordering::Relaxed);
|
|
||||||
|
|
||||||
if ptr == end {
|
|
||||||
// We're done.
|
|
||||||
Poll::Ready(())
|
|
||||||
} else {
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
// Trigger the teardown
|
|
||||||
drop(on_drop);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d> RngCore for Rng<'d> {
|
let range = dest.as_mut_ptr_range();
|
||||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
// Even if we've preempted the interrupt, it can't preempt us again,
|
||||||
|
// so we don't need to worry about the order we write these in.
|
||||||
|
STATE.ptr.store(range.start, Ordering::Relaxed);
|
||||||
|
STATE.end.store(range.end, Ordering::Relaxed);
|
||||||
|
|
||||||
|
self.enable_irq();
|
||||||
|
self.start();
|
||||||
|
|
||||||
|
let on_drop = OnDrop::new(|| {
|
||||||
|
self.stop();
|
||||||
|
self.disable_irq();
|
||||||
|
|
||||||
|
// The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here.
|
||||||
|
STATE.ptr.store(ptr::null_mut(), Ordering::Relaxed);
|
||||||
|
STATE.end.store(ptr::null_mut(), Ordering::Relaxed);
|
||||||
|
});
|
||||||
|
|
||||||
|
poll_fn(|cx| {
|
||||||
|
STATE.waker.register(cx.waker());
|
||||||
|
|
||||||
|
// The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`.
|
||||||
|
let end = STATE.end.load(Ordering::Relaxed);
|
||||||
|
let ptr = STATE.ptr.load(Ordering::Relaxed);
|
||||||
|
|
||||||
|
if ptr == end {
|
||||||
|
// We're done.
|
||||||
|
Poll::Ready(())
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// Trigger the teardown
|
||||||
|
drop(on_drop);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) {
|
||||||
self.start();
|
self.start();
|
||||||
|
|
||||||
for byte in dest.iter_mut() {
|
for byte in dest.iter_mut() {
|
||||||
|
@ -223,24 +198,36 @@ impl<'d> RngCore for Rng<'d> {
|
||||||
|
|
||||||
self.stop();
|
self.stop();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> Drop for Rng<'d> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.irq.disable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> rand_core::RngCore for Rng<'d> {
|
||||||
|
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||||
|
self.blocking_fill_bytes(dest);
|
||||||
|
}
|
||||||
|
|
||||||
fn next_u32(&mut self) -> u32 {
|
fn next_u32(&mut self) -> u32 {
|
||||||
let mut bytes = [0; 4];
|
let mut bytes = [0; 4];
|
||||||
self.fill_bytes(&mut bytes);
|
self.blocking_fill_bytes(&mut bytes);
|
||||||
// We don't care about the endianness, so just use the native one.
|
// We don't care about the endianness, so just use the native one.
|
||||||
u32::from_ne_bytes(bytes)
|
u32::from_ne_bytes(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_u64(&mut self) -> u64 {
|
fn next_u64(&mut self) -> u64 {
|
||||||
let mut bytes = [0; 8];
|
let mut bytes = [0; 8];
|
||||||
self.fill_bytes(&mut bytes);
|
self.blocking_fill_bytes(&mut bytes);
|
||||||
u64::from_ne_bytes(bytes)
|
u64::from_ne_bytes(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
|
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
|
||||||
self.fill_bytes(dest);
|
self.blocking_fill_bytes(dest);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Should `Rng` implement `CryptoRng`? It's 'suitable for cryptographic purposes' according to the specification.
|
impl<'d> rand_core::CryptoRng for Rng<'d> {}
|
||||||
|
|
|
@ -1,23 +1,21 @@
|
||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
use core::future::Future;
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
use embassy::interrupt::InterruptExt;
|
use embassy::interrupt::InterruptExt;
|
||||||
use embassy::traits;
|
|
||||||
use embassy::util::Unborrow;
|
use embassy::util::Unborrow;
|
||||||
use embassy_hal_common::unborrow;
|
use embassy_hal_common::unborrow;
|
||||||
use futures::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
use traits::spi::{FullDuplex, Read, Spi, Write};
|
|
||||||
|
|
||||||
use crate::gpio;
|
use crate::gpio;
|
||||||
use crate::gpio::sealed::Pin as _;
|
use crate::gpio::sealed::Pin as _;
|
||||||
use crate::gpio::{OptionalPin, Pin as GpioPin};
|
use crate::gpio::{OptionalPin, Pin as GpioPin};
|
||||||
use crate::interrupt::Interrupt;
|
use crate::interrupt::Interrupt;
|
||||||
|
use crate::util::{slice_ptr_parts, slice_ptr_parts_mut};
|
||||||
use crate::{pac, util::slice_in_ram_or};
|
use crate::{pac, util::slice_in_ram_or};
|
||||||
|
|
||||||
pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
|
pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
|
||||||
pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
|
pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
@ -132,9 +130,7 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||||
|
|
||||||
// Set over-read character
|
// Set over-read character
|
||||||
let orc = config.orc;
|
let orc = config.orc;
|
||||||
r.orc.write(|w|
|
r.orc.write(|w| unsafe { w.orc().bits(orc) });
|
||||||
// The ORC field is 8 bits long, so any u8 is a valid value to write.
|
|
||||||
unsafe { w.orc().bits(orc) });
|
|
||||||
|
|
||||||
// Disable all events interrupts
|
// Disable all events interrupts
|
||||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||||
|
@ -157,6 +153,97 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||||
r.intenclr.write(|w| w.end().clear());
|
r.intenclr.write(|w| w.end().clear());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
|
||||||
|
slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?;
|
||||||
|
// NOTE: RAM slice check for rx is not necessary, as a mutable
|
||||||
|
// slice can only be built from data located in RAM.
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
let r = T::regs();
|
||||||
|
|
||||||
|
// Set up the DMA write.
|
||||||
|
let (ptr, len) = slice_ptr_parts(tx);
|
||||||
|
r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
|
||||||
|
r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||||
|
|
||||||
|
// Set up the DMA read.
|
||||||
|
let (ptr, len) = slice_ptr_parts_mut(rx);
|
||||||
|
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
|
||||||
|
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||||
|
|
||||||
|
// Reset and enable the event
|
||||||
|
r.events_end.reset();
|
||||||
|
r.intenset.write(|w| w.end().set());
|
||||||
|
|
||||||
|
// Start SPI transaction.
|
||||||
|
r.tasks_start.write(|w| unsafe { w.bits(1) });
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blocking_inner(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
|
||||||
|
self.prepare(rx, tx)?;
|
||||||
|
|
||||||
|
// Wait for 'end' event.
|
||||||
|
while T::regs().events_end.read().bits() == 0 {}
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn async_inner(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
|
||||||
|
self.prepare(rx, tx)?;
|
||||||
|
|
||||||
|
// Wait for 'end' event.
|
||||||
|
poll_fn(|cx| {
|
||||||
|
T::state().end_waker.register(cx.waker());
|
||||||
|
if T::regs().events_end.read().bits() != 0 {
|
||||||
|
return Poll::Ready(());
|
||||||
|
}
|
||||||
|
|
||||||
|
Poll::Pending
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
|
||||||
|
self.blocking_inner(data, &[])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
|
||||||
|
self.blocking_inner(read, write)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
|
||||||
|
self.blocking_inner(data, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> {
|
||||||
|
self.blocking_inner(&mut [], data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn read(&mut self, data: &mut [u8]) -> Result<(), Error> {
|
||||||
|
self.async_inner(data, &[]).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
|
||||||
|
self.async_inner(read, write).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
|
||||||
|
self.async_inner(data, data).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn write(&mut self, data: &[u8]) -> Result<(), Error> {
|
||||||
|
self.async_inner(&mut [], data).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Drop for Spim<'d, T> {
|
impl<'d, T: Instance> Drop for Spim<'d, T> {
|
||||||
|
@ -177,193 +264,6 @@ impl<'d, T: Instance> Drop for Spim<'d, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Spi<u8> for Spim<'d, T> {
|
|
||||||
type Error = Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> Read<u8> for Spim<'d, T> {
|
|
||||||
type ReadFuture<'a>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
|
||||||
|
|
||||||
fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
|
||||||
self.read_write(data, &[])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> Write<u8> for Spim<'d, T> {
|
|
||||||
type WriteFuture<'a>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
|
||||||
|
|
||||||
fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> {
|
|
||||||
self.read_write(&mut [], data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> {
|
|
||||||
type WriteReadFuture<'a>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
|
||||||
|
|
||||||
fn read_write<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::WriteReadFuture<'a> {
|
|
||||||
async move {
|
|
||||||
slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?;
|
|
||||||
// NOTE: RAM slice check for rx is not necessary, as a mutable
|
|
||||||
// slice can only be built from data located in RAM.
|
|
||||||
|
|
||||||
// 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(Ordering::SeqCst);
|
|
||||||
|
|
||||||
let r = T::regs();
|
|
||||||
let s = T::state();
|
|
||||||
|
|
||||||
// Set up the DMA write.
|
|
||||||
r.txd
|
|
||||||
.ptr
|
|
||||||
.write(|w| unsafe { w.ptr().bits(tx.as_ptr() as u32) });
|
|
||||||
r.txd
|
|
||||||
.maxcnt
|
|
||||||
.write(|w| unsafe { w.maxcnt().bits(tx.len() as _) });
|
|
||||||
|
|
||||||
// Set up the DMA read.
|
|
||||||
r.rxd
|
|
||||||
.ptr
|
|
||||||
.write(|w| unsafe { w.ptr().bits(rx.as_mut_ptr() as u32) });
|
|
||||||
r.rxd
|
|
||||||
.maxcnt
|
|
||||||
.write(|w| unsafe { w.maxcnt().bits(rx.len() as _) });
|
|
||||||
|
|
||||||
// Reset and enable the event
|
|
||||||
r.events_end.reset();
|
|
||||||
r.intenset.write(|w| w.end().set());
|
|
||||||
|
|
||||||
// Start SPI transaction.
|
|
||||||
r.tasks_start.write(|w| unsafe { w.bits(1) });
|
|
||||||
|
|
||||||
// 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(Ordering::SeqCst);
|
|
||||||
|
|
||||||
// Wait for 'end' event.
|
|
||||||
poll_fn(|cx| {
|
|
||||||
s.end_waker.register(cx.waker());
|
|
||||||
if r.events_end.read().bits() != 0 {
|
|
||||||
return Poll::Ready(());
|
|
||||||
}
|
|
||||||
|
|
||||||
Poll::Pending
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blocking functions are provided by implementing `embedded_hal` traits.
|
|
||||||
//
|
|
||||||
// Code could be shared between traits to reduce code size.
|
|
||||||
impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spim<'d, T> {
|
|
||||||
type Error = Error;
|
|
||||||
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
|
|
||||||
slice_in_ram_or(words, Error::DMABufferNotInDataMemory)?;
|
|
||||||
|
|
||||||
// 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(Ordering::SeqCst);
|
|
||||||
|
|
||||||
let r = T::regs();
|
|
||||||
|
|
||||||
// Set up the DMA write.
|
|
||||||
r.txd
|
|
||||||
.ptr
|
|
||||||
.write(|w| unsafe { w.ptr().bits(words.as_ptr() as u32) });
|
|
||||||
r.txd
|
|
||||||
.maxcnt
|
|
||||||
.write(|w| unsafe { w.maxcnt().bits(words.len() as _) });
|
|
||||||
|
|
||||||
// Set up the DMA read.
|
|
||||||
r.rxd
|
|
||||||
.ptr
|
|
||||||
.write(|w| unsafe { w.ptr().bits(words.as_mut_ptr() as u32) });
|
|
||||||
r.rxd
|
|
||||||
.maxcnt
|
|
||||||
.write(|w| unsafe { w.maxcnt().bits(words.len() as _) });
|
|
||||||
|
|
||||||
// Disable the end event since we are busy-polling.
|
|
||||||
r.events_end.reset();
|
|
||||||
|
|
||||||
// Start SPI transaction.
|
|
||||||
r.tasks_start.write(|w| unsafe { w.bits(1) });
|
|
||||||
|
|
||||||
// Wait for 'end' event.
|
|
||||||
while r.events_end.read().bits() == 0 {}
|
|
||||||
|
|
||||||
// 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(Ordering::SeqCst);
|
|
||||||
|
|
||||||
Ok(words)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spim<'d, T> {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
|
|
||||||
slice_in_ram_or(words, Error::DMABufferNotInDataMemory)?;
|
|
||||||
let recv: &mut [u8] = &mut [];
|
|
||||||
|
|
||||||
// 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(Ordering::SeqCst);
|
|
||||||
|
|
||||||
let r = T::regs();
|
|
||||||
|
|
||||||
// Set up the DMA write.
|
|
||||||
r.txd
|
|
||||||
.ptr
|
|
||||||
.write(|w| unsafe { w.ptr().bits(words.as_ptr() as u32) });
|
|
||||||
r.txd
|
|
||||||
.maxcnt
|
|
||||||
.write(|w| unsafe { w.maxcnt().bits(words.len() as _) });
|
|
||||||
|
|
||||||
// Set up the DMA read.
|
|
||||||
r.rxd
|
|
||||||
.ptr
|
|
||||||
.write(|w| unsafe { w.ptr().bits(recv.as_mut_ptr() as u32) });
|
|
||||||
r.rxd
|
|
||||||
.maxcnt
|
|
||||||
.write(|w| unsafe { w.maxcnt().bits(recv.len() as _) });
|
|
||||||
|
|
||||||
// Disable the end event since we are busy-polling.
|
|
||||||
r.events_end.reset();
|
|
||||||
|
|
||||||
// Start SPI transaction.
|
|
||||||
r.tasks_start.write(|w| unsafe { w.bits(1) });
|
|
||||||
|
|
||||||
// Wait for 'end' event.
|
|
||||||
while r.events_end.read().bits() == 0 {}
|
|
||||||
|
|
||||||
// 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(Ordering::SeqCst);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
use embassy::waitqueue::AtomicWaker;
|
use embassy::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
|
@ -407,3 +307,209 @@ macro_rules! impl_spim {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====================
|
||||||
|
|
||||||
|
mod eh02 {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_02::blocking::spi::Transfer<u8> for Spim<'d, T> {
|
||||||
|
type Error = Error;
|
||||||
|
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
|
||||||
|
self.blocking_transfer_in_place(words)?;
|
||||||
|
Ok(words)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_02::blocking::spi::Write<u8> for Spim<'d, T> {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_write(words)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "unstable-traits")]
|
||||||
|
mod eh1 {
|
||||||
|
use super::*;
|
||||||
|
use core::future::Future;
|
||||||
|
|
||||||
|
impl embedded_hal_1::spi::Error for Error {
|
||||||
|
fn kind(&self) -> embedded_hal_1::spi::ErrorKind {
|
||||||
|
match *self {
|
||||||
|
Self::TxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other,
|
||||||
|
Self::RxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other,
|
||||||
|
Self::DMABufferNotInDataMemory => embedded_hal_1::spi::ErrorKind::Other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_1::spi::ErrorType for Spim<'d, T> {
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_1::spi::blocking::Read<u8> for Spim<'d, T> {
|
||||||
|
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_transfer(words, &[])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_transaction(&mut self, words: &mut [&mut [u8]]) -> Result<(), Self::Error> {
|
||||||
|
for buf in words {
|
||||||
|
self.blocking_read(buf)?
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_1::spi::blocking::Write<u8> for Spim<'d, T> {
|
||||||
|
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_write(words)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_transaction(&mut self, words: &[&[u8]]) -> Result<(), Self::Error> {
|
||||||
|
for buf in words {
|
||||||
|
self.blocking_write(buf)?
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
|
||||||
|
where
|
||||||
|
WI: IntoIterator<Item = u8>,
|
||||||
|
{
|
||||||
|
for w in words {
|
||||||
|
self.blocking_write(&[w])?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_1::spi::blocking::ReadWrite<u8> for Spim<'d, T> {
|
||||||
|
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_transfer(read, write)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_transfer_in_place(words)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transaction<'a>(
|
||||||
|
&mut self,
|
||||||
|
operations: &mut [embedded_hal_async::spi::Operation<'a, u8>],
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
use embedded_hal_1::spi::blocking::Operation;
|
||||||
|
for o in operations {
|
||||||
|
match o {
|
||||||
|
Operation::Read(b) => self.blocking_read(b)?,
|
||||||
|
Operation::Write(b) => self.blocking_write(b)?,
|
||||||
|
Operation::Transfer(r, w) => self.blocking_transfer(r, w)?,
|
||||||
|
Operation::TransferInPlace(b) => self.blocking_transfer_in_place(b)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_async::spi::Read<u8> for Spim<'d, T> {
|
||||||
|
type ReadFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn read<'a>(&'a mut self, words: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
||||||
|
self.read(words)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReadTransactionFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn read_transaction<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
words: &'a mut [&'a mut [u8]],
|
||||||
|
) -> Self::ReadTransactionFuture<'a> {
|
||||||
|
async move {
|
||||||
|
for buf in words {
|
||||||
|
self.read(buf).await?
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_async::spi::Write<u8> for Spim<'d, T> {
|
||||||
|
type WriteFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> {
|
||||||
|
self.write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WriteTransactionFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn write_transaction<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
words: &'a [&'a [u8]],
|
||||||
|
) -> Self::WriteTransactionFuture<'a> {
|
||||||
|
async move {
|
||||||
|
for buf in words {
|
||||||
|
self.write(buf).await?
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_async::spi::ReadWrite<u8> for Spim<'d, T> {
|
||||||
|
type TransferFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn transfer<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::TransferFuture<'a> {
|
||||||
|
self.transfer(rx, tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TransferInPlaceFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn transfer_in_place<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
words: &'a mut [u8],
|
||||||
|
) -> Self::TransferInPlaceFuture<'a> {
|
||||||
|
self.transfer_in_place(words)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TransactionFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn transaction<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
operations: &'a mut [embedded_hal_async::spi::Operation<'a, u8>],
|
||||||
|
) -> Self::TransactionFuture<'a> {
|
||||||
|
use embedded_hal_1::spi::blocking::Operation;
|
||||||
|
async move {
|
||||||
|
for o in operations {
|
||||||
|
match o {
|
||||||
|
Operation::Read(b) => self.read(b).await?,
|
||||||
|
Operation::Write(b) => self.write(b).await?,
|
||||||
|
Operation::Transfer(r, w) => self.transfer(r, w).await?,
|
||||||
|
Operation::TransferInPlace(b) => self.transfer_in_place(b).await?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,12 +11,10 @@ use core::marker::PhantomData;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering::SeqCst};
|
use core::sync::atomic::{compiler_fence, Ordering::SeqCst};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
use embassy::interrupt::{Interrupt, InterruptExt};
|
use embassy::interrupt::{Interrupt, InterruptExt};
|
||||||
use embassy::traits;
|
|
||||||
use embassy::util::Unborrow;
|
use embassy::util::Unborrow;
|
||||||
use embassy::waitqueue::AtomicWaker;
|
use embassy::waitqueue::AtomicWaker;
|
||||||
use embassy_hal_common::unborrow;
|
use embassy_hal_common::unborrow;
|
||||||
use futures::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
use traits::i2c::I2c;
|
|
||||||
|
|
||||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||||
use crate::gpio;
|
use crate::gpio;
|
||||||
|
@ -50,6 +48,22 @@ impl Default for Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum Error {
|
||||||
|
TxBufferTooLong,
|
||||||
|
RxBufferTooLong,
|
||||||
|
TxBufferZeroLength,
|
||||||
|
RxBufferZeroLength,
|
||||||
|
Transmit,
|
||||||
|
Receive,
|
||||||
|
DMABufferNotInDataMemory,
|
||||||
|
AddressNack,
|
||||||
|
DataNack,
|
||||||
|
Overrun,
|
||||||
|
}
|
||||||
|
|
||||||
/// Interface to a TWIM instance.
|
/// Interface to a TWIM instance.
|
||||||
pub struct Twim<'d, T: Instance> {
|
pub struct Twim<'d, T: Instance> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
|
@ -201,7 +215,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get Error instance, if any occurred.
|
/// Get Error instance, if any occurred.
|
||||||
fn read_errorsrc(&self) -> Result<(), Error> {
|
fn check_errorsrc(&self) -> Result<(), Error> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
let err = r.errorsrc.read();
|
let err = r.errorsrc.read();
|
||||||
|
@ -217,8 +231,26 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_rx(&self, len: usize) -> Result<(), Error> {
|
||||||
|
let r = T::regs();
|
||||||
|
if r.rxd.amount.read().bits() != len as u32 {
|
||||||
|
Err(Error::Receive)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_tx(&self, len: usize) -> Result<(), Error> {
|
||||||
|
let r = T::regs();
|
||||||
|
if r.txd.amount.read().bits() != len as u32 {
|
||||||
|
Err(Error::Transmit)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Wait for stop or error
|
/// Wait for stop or error
|
||||||
fn wait(&mut self) {
|
fn blocking_wait(&mut self) {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
loop {
|
loop {
|
||||||
if r.events_stopped.read().bits() != 0 {
|
if r.events_stopped.read().bits() != 0 {
|
||||||
|
@ -232,16 +264,32 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write to an I2C slave.
|
/// Wait for stop or error
|
||||||
///
|
fn async_wait(&mut self) -> impl Future<Output = ()> {
|
||||||
/// The buffer must have a length of at most 255 bytes on the nRF52832
|
poll_fn(move |cx| {
|
||||||
/// and at most 65535 bytes on the nRF52840.
|
let r = T::regs();
|
||||||
pub fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
|
let s = T::state();
|
||||||
|
|
||||||
|
s.end_waker.register(cx.waker());
|
||||||
|
if r.events_stopped.read().bits() != 0 {
|
||||||
|
r.events_stopped.reset();
|
||||||
|
|
||||||
|
return Poll::Ready(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) });
|
||||||
|
}
|
||||||
|
|
||||||
|
Poll::Pending
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_write(&mut self, address: u8, buffer: &[u8], inten: bool) -> Result<(), Error> {
|
||||||
let r = T::regs();
|
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);
|
compiler_fence(SeqCst);
|
||||||
|
|
||||||
r.address.write(|w| unsafe { w.address().bits(address) });
|
r.address.write(|w| unsafe { w.address().bits(address) });
|
||||||
|
@ -255,38 +303,21 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
r.events_lasttx.reset();
|
r.events_lasttx.reset();
|
||||||
self.clear_errorsrc();
|
self.clear_errorsrc();
|
||||||
|
|
||||||
// Start write operation.
|
if inten {
|
||||||
r.shorts.write(|w| w.lasttx_stop().enabled());
|
r.intenset.write(|w| w.stopped().set().error().set());
|
||||||
r.tasks_starttx.write(|w|
|
} else {
|
||||||
// `1` is a valid value to write to task registers.
|
r.intenclr.write(|w| w.stopped().clear().error().clear());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start write operation.
|
||||||
|
r.shorts.write(|w| w.lasttx_stop().enabled());
|
||||||
|
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read from an I2C slave.
|
fn setup_read(&mut self, address: u8, buffer: &mut [u8], inten: bool) -> Result<(), Error> {
|
||||||
///
|
|
||||||
/// 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();
|
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);
|
compiler_fence(SeqCst);
|
||||||
|
|
||||||
r.address.write(|w| unsafe { w.address().bits(address) });
|
r.address.write(|w| unsafe { w.address().bits(address) });
|
||||||
|
@ -299,44 +330,27 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
r.events_error.reset();
|
r.events_error.reset();
|
||||||
self.clear_errorsrc();
|
self.clear_errorsrc();
|
||||||
|
|
||||||
// Start read operation.
|
if inten {
|
||||||
r.shorts.write(|w| w.lastrx_stop().enabled());
|
r.intenset.write(|w| w.stopped().set().error().set());
|
||||||
r.tasks_startrx.write(|w|
|
} else {
|
||||||
// `1` is a valid value to write to task registers.
|
r.intenclr.write(|w| w.stopped().clear().error().clear());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start read operation.
|
||||||
|
r.shorts.write(|w| w.lastrx_stop().enabled());
|
||||||
|
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write data to an I2C slave, then read data from the slave without
|
fn setup_write_read(
|
||||||
/// 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,
|
&mut self,
|
||||||
address: u8,
|
address: u8,
|
||||||
wr_buffer: &[u8],
|
wr_buffer: &[u8],
|
||||||
rd_buffer: &mut [u8],
|
rd_buffer: &mut [u8],
|
||||||
|
inten: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let r = T::regs();
|
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);
|
compiler_fence(SeqCst);
|
||||||
|
|
||||||
r.address.write(|w| unsafe { w.address().bits(address) });
|
r.address.write(|w| unsafe { w.address().bits(address) });
|
||||||
|
@ -352,35 +366,65 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
r.events_error.reset();
|
r.events_error.reset();
|
||||||
self.clear_errorsrc();
|
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+read operation.
|
// Start write+read operation.
|
||||||
r.shorts.write(|w| {
|
r.shorts.write(|w| {
|
||||||
w.lasttx_startrx().enabled();
|
w.lasttx_startrx().enabled();
|
||||||
w.lastrx_stop().enabled();
|
w.lastrx_stop().enabled();
|
||||||
w
|
w
|
||||||
});
|
});
|
||||||
// `1` is a valid value to write to task registers.
|
|
||||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
self.wait();
|
/// Write to an I2C slave.
|
||||||
|
///
|
||||||
// Conservative compiler fence to prevent optimizations that do not
|
/// The buffer must have a length of at most 255 bytes on the nRF52832
|
||||||
// take in to account actions by DMA. The fence has been placed here,
|
/// and at most 65535 bytes on the nRF52840.
|
||||||
// after all possible DMA actions have completed.
|
pub fn blocking_write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
|
||||||
|
self.setup_write(address, buffer, false)?;
|
||||||
|
self.blocking_wait();
|
||||||
compiler_fence(SeqCst);
|
compiler_fence(SeqCst);
|
||||||
|
self.check_errorsrc()?;
|
||||||
|
self.check_tx(buffer.len())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
self.read_errorsrc()?;
|
/// Read from an I2C slave.
|
||||||
|
///
|
||||||
let bad_write = r.txd.amount.read().bits() != wr_buffer.len() as u32;
|
/// The buffer must have a length of at most 255 bytes on the nRF52832
|
||||||
let bad_read = r.rxd.amount.read().bits() != rd_buffer.len() as u32;
|
/// and at most 65535 bytes on the nRF52840.
|
||||||
|
pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
if bad_write {
|
self.setup_read(address, buffer, false)?;
|
||||||
return Err(Error::Transmit);
|
self.blocking_wait();
|
||||||
}
|
compiler_fence(SeqCst);
|
||||||
|
self.check_errorsrc()?;
|
||||||
if bad_read {
|
self.check_rx(buffer.len())?;
|
||||||
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 blocking_write_read(
|
||||||
|
&mut self,
|
||||||
|
address: u8,
|
||||||
|
wr_buffer: &[u8],
|
||||||
|
rd_buffer: &mut [u8],
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.setup_write_read(address, wr_buffer, rd_buffer, false)?;
|
||||||
|
self.blocking_wait();
|
||||||
|
compiler_fence(SeqCst);
|
||||||
|
self.check_errorsrc()?;
|
||||||
|
self.check_tx(wr_buffer.len())?;
|
||||||
|
self.check_rx(rd_buffer.len())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,7 +432,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
///
|
///
|
||||||
/// The write buffer must have a length of at most 255 bytes on the nRF52832
|
/// The write buffer must have a length of at most 255 bytes on the nRF52832
|
||||||
/// and at most 1024 bytes on the nRF52840.
|
/// and at most 1024 bytes on the nRF52840.
|
||||||
pub fn copy_write(&mut self, address: u8, wr_buffer: &[u8]) -> Result<(), Error> {
|
pub fn blocking_copy_write(&mut self, address: u8, wr_buffer: &[u8]) -> Result<(), Error> {
|
||||||
if wr_buffer.len() > FORCE_COPY_BUFFER_SIZE {
|
if wr_buffer.len() > FORCE_COPY_BUFFER_SIZE {
|
||||||
return Err(Error::TxBufferTooLong);
|
return Err(Error::TxBufferTooLong);
|
||||||
}
|
}
|
||||||
|
@ -397,7 +441,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
|
let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
|
||||||
wr_ram_buffer.copy_from_slice(wr_buffer);
|
wr_ram_buffer.copy_from_slice(wr_buffer);
|
||||||
|
|
||||||
self.write(address, wr_ram_buffer)
|
self.blocking_write(address, wr_ram_buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy data into RAM and write to an I2C slave, then read data from the slave without
|
/// Copy data into RAM and write to an I2C slave, then read data from the slave without
|
||||||
|
@ -408,7 +452,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
///
|
///
|
||||||
/// The read buffer must have a length of at most 255 bytes on the nRF52832
|
/// The read buffer must have a length of at most 255 bytes on the nRF52832
|
||||||
/// and at most 65535 bytes on the nRF52840.
|
/// and at most 65535 bytes on the nRF52840.
|
||||||
pub fn copy_write_then_read(
|
pub fn blocking_copy_write_read(
|
||||||
&mut self,
|
&mut self,
|
||||||
address: u8,
|
address: u8,
|
||||||
wr_buffer: &[u8],
|
wr_buffer: &[u8],
|
||||||
|
@ -422,27 +466,40 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||||
let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
|
let wr_ram_buffer = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
|
||||||
wr_ram_buffer.copy_from_slice(wr_buffer);
|
wr_ram_buffer.copy_from_slice(wr_buffer);
|
||||||
|
|
||||||
self.write_then_read(address, wr_ram_buffer, rd_buffer)
|
self.blocking_write_read(address, wr_ram_buffer, rd_buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_for_stopped_event(cx: &mut core::task::Context) -> Poll<()> {
|
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
let r = T::regs();
|
self.setup_read(address, buffer, true)?;
|
||||||
let s = T::state();
|
self.async_wait().await;
|
||||||
|
compiler_fence(SeqCst);
|
||||||
|
self.check_errorsrc()?;
|
||||||
|
self.check_rx(buffer.len())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
s.end_waker.register(cx.waker());
|
pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
|
||||||
if r.events_stopped.read().bits() != 0 {
|
self.setup_write(address, buffer, true)?;
|
||||||
r.events_stopped.reset();
|
self.async_wait().await;
|
||||||
|
compiler_fence(SeqCst);
|
||||||
|
self.check_errorsrc()?;
|
||||||
|
self.check_tx(buffer.len())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
return Poll::Ready(());
|
pub async fn write_read(
|
||||||
}
|
&mut self,
|
||||||
|
address: u8,
|
||||||
// stop if an error occured
|
wr_buffer: &[u8],
|
||||||
if r.events_error.read().bits() != 0 {
|
rd_buffer: &mut [u8],
|
||||||
r.events_error.reset();
|
) -> Result<(), Error> {
|
||||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
self.setup_write_read(address, wr_buffer, rd_buffer, true)?;
|
||||||
}
|
self.async_wait().await;
|
||||||
|
compiler_fence(SeqCst);
|
||||||
Poll::Pending
|
self.check_errorsrc()?;
|
||||||
|
self.check_tx(wr_buffer.len())?;
|
||||||
|
self.check_rx(rd_buffer.len())?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,7 +507,7 @@ impl<'a, T: Instance> Drop for Twim<'a, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
trace!("twim drop");
|
trace!("twim drop");
|
||||||
|
|
||||||
// TODO when implementing async here, check for abort
|
// TODO: check for abort
|
||||||
|
|
||||||
// disable!
|
// disable!
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
@ -463,254 +520,6 @@ impl<'a, T: Instance> Drop for Twim<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T> I2c for Twim<'d, T>
|
|
||||||
where
|
|
||||||
T: Instance,
|
|
||||||
{
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
type WriteFuture<'a>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
|
||||||
type ReadFuture<'a>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
|
||||||
type WriteReadFuture<'a>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
|
||||||
|
|
||||||
fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
|
||||||
async move {
|
|
||||||
// NOTE: RAM slice check for buffer is not necessary, as a mutable
|
|
||||||
// slice can only be built from data located in RAM.
|
|
||||||
|
|
||||||
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)? };
|
|
||||||
|
|
||||||
// Reset events
|
|
||||||
r.events_stopped.reset();
|
|
||||||
r.events_error.reset();
|
|
||||||
self.clear_errorsrc();
|
|
||||||
|
|
||||||
// Enable events
|
|
||||||
r.intenset.write(|w| w.stopped().set().error().set());
|
|
||||||
|
|
||||||
// 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) });
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Wait for 'stopped' event.
|
|
||||||
poll_fn(Self::wait_for_stopped_event).await;
|
|
||||||
|
|
||||||
self.read_errorsrc()?;
|
|
||||||
|
|
||||||
if r.rxd.amount.read().bits() != buffer.len() as u32 {
|
|
||||||
return Err(Error::Receive);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> {
|
|
||||||
async move {
|
|
||||||
slice_in_ram_or(bytes, Error::DMABufferNotInDataMemory)?;
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
let r = T::regs();
|
|
||||||
|
|
||||||
// Set up current address we're trying to talk to
|
|
||||||
r.address.write(|w| unsafe { w.address().bits(address) });
|
|
||||||
|
|
||||||
// Set up DMA write.
|
|
||||||
unsafe {
|
|
||||||
self.set_tx_buffer(bytes)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset events
|
|
||||||
r.events_stopped.reset();
|
|
||||||
r.events_error.reset();
|
|
||||||
r.events_lasttx.reset();
|
|
||||||
self.clear_errorsrc();
|
|
||||||
|
|
||||||
// Enable events
|
|
||||||
r.intenset.write(|w| w.stopped().set().error().set());
|
|
||||||
|
|
||||||
// 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) });
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Wait for 'stopped' event.
|
|
||||||
poll_fn(Self::wait_for_stopped_event).await;
|
|
||||||
|
|
||||||
self.read_errorsrc()?;
|
|
||||||
|
|
||||||
if r.txd.amount.read().bits() != bytes.len() as u32 {
|
|
||||||
return Err(Error::Transmit);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_read<'a>(
|
|
||||||
&'a mut self,
|
|
||||||
address: u8,
|
|
||||||
bytes: &'a [u8],
|
|
||||||
buffer: &'a mut [u8],
|
|
||||||
) -> Self::WriteReadFuture<'a> {
|
|
||||||
async move {
|
|
||||||
slice_in_ram_or(bytes, Error::DMABufferNotInDataMemory)?;
|
|
||||||
// NOTE: RAM slice check for buffer is not necessary, as a mutable
|
|
||||||
// slice can only be built from data located in RAM.
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
let r = T::regs();
|
|
||||||
|
|
||||||
// Set up current address we're trying to talk to
|
|
||||||
r.address.write(|w| unsafe { w.address().bits(address) });
|
|
||||||
|
|
||||||
// Set up DMA buffers.
|
|
||||||
unsafe {
|
|
||||||
self.set_tx_buffer(bytes)?;
|
|
||||||
self.set_rx_buffer(buffer)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset events
|
|
||||||
r.events_stopped.reset();
|
|
||||||
r.events_error.reset();
|
|
||||||
r.events_lasttx.reset();
|
|
||||||
self.clear_errorsrc();
|
|
||||||
|
|
||||||
// Enable events
|
|
||||||
r.intenset.write(|w| w.stopped().set().error().set());
|
|
||||||
|
|
||||||
// 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) });
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Wait for 'stopped' event.
|
|
||||||
poll_fn(Self::wait_for_stopped_event).await;
|
|
||||||
|
|
||||||
self.read_errorsrc()?;
|
|
||||||
|
|
||||||
let bad_write = r.txd.amount.read().bits() != bytes.len() as u32;
|
|
||||||
let bad_read = r.rxd.amount.read().bits() != buffer.len() as u32;
|
|
||||||
|
|
||||||
if bad_write {
|
|
||||||
return Err(Error::Transmit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if bad_read {
|
|
||||||
return Err(Error::Receive);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)]
|
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
||||||
pub enum Error {
|
|
||||||
TxBufferTooLong,
|
|
||||||
RxBufferTooLong,
|
|
||||||
TxBufferZeroLength,
|
|
||||||
RxBufferZeroLength,
|
|
||||||
Transmit,
|
|
||||||
Receive,
|
|
||||||
DMABufferNotInDataMemory,
|
|
||||||
AddressNack,
|
|
||||||
DataNack,
|
|
||||||
Overrun,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -752,3 +561,187 @@ macro_rules! impl_twim {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====================
|
||||||
|
|
||||||
|
mod eh02 {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl<'a, T: Instance> embedded_hal_02::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.blocking_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.blocking_write(addr, &buf[..chunk.len()])?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Instance> embedded_hal_02::blocking::i2c::Read for Twim<'a, T> {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn read<'w>(&mut self, addr: u8, bytes: &'w mut [u8]) -> Result<(), Error> {
|
||||||
|
self.blocking_read(addr, bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Instance> embedded_hal_02::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.blocking_write_read(addr, bytes, buffer)
|
||||||
|
} else {
|
||||||
|
self.blocking_copy_write_read(addr, bytes, buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "unstable-traits")]
|
||||||
|
mod eh1 {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl embedded_hal_1::i2c::Error for Error {
|
||||||
|
fn kind(&self) -> embedded_hal_1::i2c::ErrorKind {
|
||||||
|
match *self {
|
||||||
|
Self::TxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other,
|
||||||
|
Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other,
|
||||||
|
Self::TxBufferZeroLength => embedded_hal_1::i2c::ErrorKind::Other,
|
||||||
|
Self::RxBufferZeroLength => embedded_hal_1::i2c::ErrorKind::Other,
|
||||||
|
Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other,
|
||||||
|
Self::Receive => embedded_hal_1::i2c::ErrorKind::Other,
|
||||||
|
Self::DMABufferNotInDataMemory => embedded_hal_1::i2c::ErrorKind::Other,
|
||||||
|
Self::AddressNack => embedded_hal_1::i2c::ErrorKind::NoAcknowledge(
|
||||||
|
embedded_hal_1::i2c::NoAcknowledgeSource::Address,
|
||||||
|
),
|
||||||
|
Self::DataNack => embedded_hal_1::i2c::ErrorKind::NoAcknowledge(
|
||||||
|
embedded_hal_1::i2c::NoAcknowledgeSource::Data,
|
||||||
|
),
|
||||||
|
Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_1::i2c::ErrorType for Twim<'d, T> {
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_1::i2c::blocking::I2c for Twim<'d, T> {
|
||||||
|
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_read(address, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_write(address, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_iter<B>(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error>
|
||||||
|
where
|
||||||
|
B: IntoIterator<Item = u8>,
|
||||||
|
{
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_iter_read<B>(
|
||||||
|
&mut self,
|
||||||
|
_address: u8,
|
||||||
|
_bytes: B,
|
||||||
|
_buffer: &mut [u8],
|
||||||
|
) -> Result<(), Self::Error>
|
||||||
|
where
|
||||||
|
B: IntoIterator<Item = u8>,
|
||||||
|
{
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_read(
|
||||||
|
&mut self,
|
||||||
|
address: u8,
|
||||||
|
wr_buffer: &[u8],
|
||||||
|
rd_buffer: &mut [u8],
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_write_read(address, wr_buffer, rd_buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transaction<'a>(
|
||||||
|
&mut self,
|
||||||
|
_address: u8,
|
||||||
|
_operations: &mut [embedded_hal_async::i2c::Operation<'a>],
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transaction_iter<'a, O>(
|
||||||
|
&mut self,
|
||||||
|
_address: u8,
|
||||||
|
_operations: O,
|
||||||
|
) -> Result<(), Self::Error>
|
||||||
|
where
|
||||||
|
O: IntoIterator<Item = embedded_hal_async::i2c::Operation<'a>>,
|
||||||
|
{
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> {
|
||||||
|
type ReadFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
||||||
|
self.read(address, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WriteFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> {
|
||||||
|
self.write(address, bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WriteReadFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn write_read<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
address: u8,
|
||||||
|
wr_buffer: &'a [u8],
|
||||||
|
rd_buffer: &'a mut [u8],
|
||||||
|
) -> Self::WriteReadFuture<'a> {
|
||||||
|
self.write_read(address, wr_buffer, rd_buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TransactionFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn transaction<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
address: u8,
|
||||||
|
operations: &mut [embedded_hal_async::i2c::Operation<'a>],
|
||||||
|
) -> Self::TransactionFuture<'a> {
|
||||||
|
let _ = address;
|
||||||
|
let _ = operations;
|
||||||
|
async move { todo!() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -13,12 +13,10 @@
|
||||||
//! memory may be used given that buffers are passed in directly to its read and write
|
//! memory may be used given that buffers are passed in directly to its read and write
|
||||||
//! methods.
|
//! methods.
|
||||||
|
|
||||||
use core::future::Future;
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
use embassy::interrupt::InterruptExt;
|
use embassy::interrupt::InterruptExt;
|
||||||
use embassy::traits::uart::{Error as TraitError, Read, ReadUntilIdle, Write};
|
|
||||||
use embassy::util::Unborrow;
|
use embassy::util::Unborrow;
|
||||||
use embassy_hal_common::drop::OnDrop;
|
use embassy_hal_common::drop::OnDrop;
|
||||||
use embassy_hal_common::unborrow;
|
use embassy_hal_common::unborrow;
|
||||||
|
@ -32,6 +30,7 @@ use crate::pac;
|
||||||
use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
|
use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
|
||||||
use crate::timer::Instance as TimerInstance;
|
use crate::timer::Instance as TimerInstance;
|
||||||
use crate::timer::{Frequency, Timer};
|
use crate::timer::{Frequency, Timer};
|
||||||
|
use crate::util::slice_in_ram_or;
|
||||||
|
|
||||||
// Re-export SVD variants to allow user to directly set values.
|
// Re-export SVD variants to allow user to directly set values.
|
||||||
pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
|
pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
|
||||||
|
@ -51,6 +50,16 @@ impl Default for Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum Error {
|
||||||
|
BufferTooLong,
|
||||||
|
BufferZeroLength,
|
||||||
|
DMABufferNotInDataMemory,
|
||||||
|
// TODO: add other error variants.
|
||||||
|
}
|
||||||
|
|
||||||
/// Interface to the UARTE peripheral
|
/// Interface to the UARTE peripheral
|
||||||
pub struct Uarte<'d, T: Instance> {
|
pub struct Uarte<'d, T: Instance> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
|
@ -139,8 +148,12 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
tx: UarteTx::new(),
|
tx: UarteTx {
|
||||||
rx: UarteRx::new(),
|
phantom: PhantomData,
|
||||||
|
},
|
||||||
|
rx: UarteRx {
|
||||||
|
phantom: PhantomData,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,92 +183,110 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
||||||
r.intenclr.write(|w| w.endtx().clear());
|
r.intenclr.write(|w| w.endtx().clear());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> Read for Uarte<'d, T> {
|
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
type ReadFuture<'a>
|
self.rx.read(buffer).await
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = Result<(), TraitError>> + 'a;
|
|
||||||
|
|
||||||
fn read<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
|
||||||
self.rx.read(rx_buffer)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> Write for Uarte<'d, T> {
|
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
type WriteFuture<'a>
|
self.tx.write(buffer).await
|
||||||
where
|
}
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = Result<(), TraitError>> + 'a;
|
|
||||||
|
|
||||||
fn write<'a>(&'a mut self, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> {
|
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
self.tx.write(tx_buffer)
|
self.rx.blocking_read(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
|
self.tx.blocking_write(buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> UarteTx<'d, T> {
|
impl<'d, T: Instance> UarteTx<'d, T> {
|
||||||
pub fn new() -> Self {
|
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
Self {
|
slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?;
|
||||||
phantom: PhantomData,
|
if buffer.len() == 0 {
|
||||||
|
return Err(Error::BufferZeroLength);
|
||||||
}
|
}
|
||||||
|
if buffer.len() > EASY_DMA_SIZE {
|
||||||
|
return Err(Error::BufferTooLong);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ptr = buffer.as_ptr();
|
||||||
|
let len = buffer.len();
|
||||||
|
|
||||||
|
let r = T::regs();
|
||||||
|
let s = T::state();
|
||||||
|
|
||||||
|
let drop = OnDrop::new(move || {
|
||||||
|
trace!("write drop: stopping");
|
||||||
|
|
||||||
|
r.intenclr.write(|w| w.endtx().clear());
|
||||||
|
r.events_txstopped.reset();
|
||||||
|
r.tasks_stoptx.write(|w| unsafe { w.bits(1) });
|
||||||
|
|
||||||
|
// TX is stopped almost instantly, spinning is fine.
|
||||||
|
while r.events_endtx.read().bits() == 0 {}
|
||||||
|
trace!("write drop: stopped");
|
||||||
|
});
|
||||||
|
|
||||||
|
r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||||
|
r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||||
|
|
||||||
|
r.events_endtx.reset();
|
||||||
|
r.intenset.write(|w| w.endtx().set());
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
trace!("starttx");
|
||||||
|
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||||
|
|
||||||
|
poll_fn(|cx| {
|
||||||
|
s.endtx_waker.register(cx.waker());
|
||||||
|
if r.events_endtx.read().bits() != 0 {
|
||||||
|
return Poll::Ready(());
|
||||||
|
}
|
||||||
|
Poll::Pending
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
r.events_txstarted.reset();
|
||||||
|
drop.defuse();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> Write for UarteTx<'d, T> {
|
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
type WriteFuture<'a>
|
slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?;
|
||||||
where
|
if buffer.len() == 0 {
|
||||||
Self: 'a,
|
return Err(Error::BufferZeroLength);
|
||||||
= impl Future<Output = Result<(), TraitError>> + 'a;
|
|
||||||
|
|
||||||
fn write<'a>(&'a mut self, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> {
|
|
||||||
async move {
|
|
||||||
let ptr = tx_buffer.as_ptr();
|
|
||||||
let len = tx_buffer.len();
|
|
||||||
assert!(len <= EASY_DMA_SIZE);
|
|
||||||
// TODO: panic if buffer is not in SRAM
|
|
||||||
|
|
||||||
let r = T::regs();
|
|
||||||
let s = T::state();
|
|
||||||
|
|
||||||
let drop = OnDrop::new(move || {
|
|
||||||
trace!("write drop: stopping");
|
|
||||||
|
|
||||||
r.intenclr.write(|w| w.endtx().clear());
|
|
||||||
r.events_txstopped.reset();
|
|
||||||
r.tasks_stoptx.write(|w| unsafe { w.bits(1) });
|
|
||||||
|
|
||||||
// TX is stopped almost instantly, spinning is fine.
|
|
||||||
while r.events_endtx.read().bits() == 0 {}
|
|
||||||
trace!("write drop: stopped");
|
|
||||||
});
|
|
||||||
|
|
||||||
r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
|
||||||
r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
|
||||||
|
|
||||||
r.events_endtx.reset();
|
|
||||||
r.intenset.write(|w| w.endtx().set());
|
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
|
|
||||||
trace!("starttx");
|
|
||||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
|
||||||
|
|
||||||
poll_fn(|cx| {
|
|
||||||
s.endtx_waker.register(cx.waker());
|
|
||||||
if r.events_endtx.read().bits() != 0 {
|
|
||||||
return Poll::Ready(());
|
|
||||||
}
|
|
||||||
Poll::Pending
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
r.events_txstarted.reset();
|
|
||||||
drop.defuse();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
if buffer.len() > EASY_DMA_SIZE {
|
||||||
|
return Err(Error::BufferTooLong);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ptr = buffer.as_ptr();
|
||||||
|
let len = buffer.len();
|
||||||
|
|
||||||
|
let r = T::regs();
|
||||||
|
|
||||||
|
r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||||
|
r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||||
|
|
||||||
|
r.events_endtx.reset();
|
||||||
|
r.intenclr.write(|w| w.endtx().clear());
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
trace!("starttx");
|
||||||
|
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||||
|
|
||||||
|
while r.events_endtx.read().bits() == 0 {}
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
r.events_txstarted.reset();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,66 +309,89 @@ impl<'a, T: Instance> Drop for UarteTx<'a, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> UarteRx<'d, T> {
|
impl<'d, T: Instance> UarteRx<'d, T> {
|
||||||
pub fn new() -> Self {
|
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
Self {
|
if buffer.len() == 0 {
|
||||||
phantom: PhantomData,
|
return Err(Error::BufferZeroLength);
|
||||||
}
|
}
|
||||||
|
if buffer.len() > EASY_DMA_SIZE {
|
||||||
|
return Err(Error::BufferTooLong);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ptr = buffer.as_ptr();
|
||||||
|
let len = buffer.len();
|
||||||
|
|
||||||
|
let r = T::regs();
|
||||||
|
let s = T::state();
|
||||||
|
|
||||||
|
let drop = OnDrop::new(move || {
|
||||||
|
trace!("read drop: stopping");
|
||||||
|
|
||||||
|
r.intenclr.write(|w| w.endrx().clear());
|
||||||
|
r.events_rxto.reset();
|
||||||
|
r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
|
||||||
|
|
||||||
|
while r.events_endrx.read().bits() == 0 {}
|
||||||
|
|
||||||
|
trace!("read drop: stopped");
|
||||||
|
});
|
||||||
|
|
||||||
|
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||||
|
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||||
|
|
||||||
|
r.events_endrx.reset();
|
||||||
|
r.intenset.write(|w| w.endrx().set());
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
trace!("startrx");
|
||||||
|
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||||
|
|
||||||
|
poll_fn(|cx| {
|
||||||
|
s.endrx_waker.register(cx.waker());
|
||||||
|
if r.events_endrx.read().bits() != 0 {
|
||||||
|
return Poll::Ready(());
|
||||||
|
}
|
||||||
|
Poll::Pending
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
r.events_rxstarted.reset();
|
||||||
|
drop.defuse();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> Read for UarteRx<'d, T> {
|
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
type ReadFuture<'a>
|
if buffer.len() == 0 {
|
||||||
where
|
return Err(Error::BufferZeroLength);
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = Result<(), TraitError>> + 'a;
|
|
||||||
|
|
||||||
fn read<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
|
||||||
async move {
|
|
||||||
let ptr = rx_buffer.as_ptr();
|
|
||||||
let len = rx_buffer.len();
|
|
||||||
assert!(len <= EASY_DMA_SIZE);
|
|
||||||
|
|
||||||
let r = T::regs();
|
|
||||||
let s = T::state();
|
|
||||||
|
|
||||||
let drop = OnDrop::new(move || {
|
|
||||||
trace!("read drop: stopping");
|
|
||||||
|
|
||||||
r.intenclr.write(|w| w.endrx().clear());
|
|
||||||
r.events_rxto.reset();
|
|
||||||
r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
|
|
||||||
|
|
||||||
while r.events_endrx.read().bits() == 0 {}
|
|
||||||
|
|
||||||
trace!("read drop: stopped");
|
|
||||||
});
|
|
||||||
|
|
||||||
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
|
||||||
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
|
||||||
|
|
||||||
r.events_endrx.reset();
|
|
||||||
r.intenset.write(|w| w.endrx().set());
|
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
|
|
||||||
trace!("startrx");
|
|
||||||
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
|
||||||
|
|
||||||
poll_fn(|cx| {
|
|
||||||
s.endrx_waker.register(cx.waker());
|
|
||||||
if r.events_endrx.read().bits() != 0 {
|
|
||||||
return Poll::Ready(());
|
|
||||||
}
|
|
||||||
Poll::Pending
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
r.events_rxstarted.reset();
|
|
||||||
drop.defuse();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
if buffer.len() > EASY_DMA_SIZE {
|
||||||
|
return Err(Error::BufferTooLong);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ptr = buffer.as_ptr();
|
||||||
|
let len = buffer.len();
|
||||||
|
|
||||||
|
let r = T::regs();
|
||||||
|
|
||||||
|
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||||
|
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||||
|
|
||||||
|
r.events_endrx.reset();
|
||||||
|
r.intenclr.write(|w| w.endrx().clear());
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
trace!("startrx");
|
||||||
|
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||||
|
|
||||||
|
while r.events_endrx.read().bits() == 0 {}
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
r.events_rxstarted.reset();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,14 +493,7 @@ pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> {
|
||||||
impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> {
|
impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> {
|
||||||
/// Creates the interface to a UARTE instance.
|
/// Creates the interface to a UARTE instance.
|
||||||
/// Sets the baud rate, parity and assigns the pins to the UARTE peripheral.
|
/// Sets the baud rate, parity and assigns the pins to the UARTE peripheral.
|
||||||
///
|
pub fn new(
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The returned API is safe unless you use `mem::forget` (or similar safe mechanisms)
|
|
||||||
/// on stack allocated buffers which which have been passed to [`send()`](Uarte::send)
|
|
||||||
/// or [`receive`](Uarte::receive).
|
|
||||||
#[allow(unused_unsafe)]
|
|
||||||
pub unsafe fn new(
|
|
||||||
uarte: impl Unborrow<Target = U> + 'd,
|
uarte: impl Unborrow<Target = U> + 'd,
|
||||||
timer: impl Unborrow<Target = T> + 'd,
|
timer: impl Unborrow<Target = T> + 'd,
|
||||||
ppi_ch1: impl Unborrow<Target = impl ConfigurableChannel + 'd> + 'd,
|
ppi_ch1: impl Unborrow<Target = impl ConfigurableChannel + 'd> + 'd,
|
||||||
|
@ -501,93 +548,119 @@ impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> {
|
||||||
_ppi_ch2: ppi_ch2,
|
_ppi_ch2: ppi_ch2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, U: Instance, T: TimerInstance> ReadUntilIdle for UarteWithIdle<'d, U, T> {
|
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
type ReadUntilIdleFuture<'a>
|
self.ppi_ch1.disable();
|
||||||
where
|
self.uarte.read(buffer).await
|
||||||
Self: 'a,
|
}
|
||||||
= impl Future<Output = Result<usize, TraitError>> + 'a;
|
|
||||||
fn read_until_idle<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadUntilIdleFuture<'a> {
|
|
||||||
async move {
|
|
||||||
let ptr = rx_buffer.as_ptr();
|
|
||||||
let len = rx_buffer.len();
|
|
||||||
assert!(len <= EASY_DMA_SIZE);
|
|
||||||
|
|
||||||
let r = U::regs();
|
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
let s = U::state();
|
self.uarte.write(buffer).await
|
||||||
|
}
|
||||||
|
|
||||||
let drop = OnDrop::new(|| {
|
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
trace!("read drop: stopping");
|
self.ppi_ch1.disable();
|
||||||
|
self.uarte.blocking_read(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
self.timer.stop();
|
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
|
self.uarte.blocking_write(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
r.intenclr.write(|w| w.endrx().clear());
|
pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||||
r.events_rxto.reset();
|
if buffer.len() == 0 {
|
||||||
r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
|
return Err(Error::BufferZeroLength);
|
||||||
|
}
|
||||||
|
if buffer.len() > EASY_DMA_SIZE {
|
||||||
|
return Err(Error::BufferTooLong);
|
||||||
|
}
|
||||||
|
|
||||||
while r.events_endrx.read().bits() == 0 {}
|
let ptr = buffer.as_ptr();
|
||||||
|
let len = buffer.len();
|
||||||
|
|
||||||
trace!("read drop: stopped");
|
let r = U::regs();
|
||||||
});
|
let s = U::state();
|
||||||
|
|
||||||
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
self.ppi_ch1.enable();
|
||||||
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
|
||||||
|
|
||||||
r.events_endrx.reset();
|
let drop = OnDrop::new(|| {
|
||||||
r.intenset.write(|w| w.endrx().set());
|
trace!("read drop: stopping");
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
|
|
||||||
trace!("startrx");
|
|
||||||
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
|
||||||
|
|
||||||
poll_fn(|cx| {
|
|
||||||
s.endrx_waker.register(cx.waker());
|
|
||||||
if r.events_endrx.read().bits() != 0 {
|
|
||||||
return Poll::Ready(());
|
|
||||||
}
|
|
||||||
Poll::Pending
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
let n = r.rxd.amount.read().amount().bits() as usize;
|
|
||||||
|
|
||||||
// Stop timer
|
|
||||||
self.timer.stop();
|
self.timer.stop();
|
||||||
r.events_rxstarted.reset();
|
|
||||||
|
|
||||||
drop.defuse();
|
r.intenclr.write(|w| w.endrx().clear());
|
||||||
|
r.events_rxto.reset();
|
||||||
|
r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
|
||||||
|
|
||||||
Ok(n)
|
while r.events_endrx.read().bits() == 0 {}
|
||||||
}
|
|
||||||
|
trace!("read drop: stopped");
|
||||||
|
});
|
||||||
|
|
||||||
|
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||||
|
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||||
|
|
||||||
|
r.events_endrx.reset();
|
||||||
|
r.intenset.write(|w| w.endrx().set());
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||||
|
|
||||||
|
poll_fn(|cx| {
|
||||||
|
s.endrx_waker.register(cx.waker());
|
||||||
|
if r.events_endrx.read().bits() != 0 {
|
||||||
|
return Poll::Ready(());
|
||||||
|
}
|
||||||
|
Poll::Pending
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
let n = r.rxd.amount.read().amount().bits() as usize;
|
||||||
|
|
||||||
|
self.timer.stop();
|
||||||
|
r.events_rxstarted.reset();
|
||||||
|
|
||||||
|
drop.defuse();
|
||||||
|
|
||||||
|
Ok(n)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, U: Instance, T: TimerInstance> Read for UarteWithIdle<'d, U, T> {
|
pub fn blocking_read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||||
type ReadFuture<'a>
|
if buffer.len() == 0 {
|
||||||
where
|
return Err(Error::BufferZeroLength);
|
||||||
Self: 'a,
|
}
|
||||||
= impl Future<Output = Result<(), TraitError>> + 'a;
|
if buffer.len() > EASY_DMA_SIZE {
|
||||||
fn read<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
return Err(Error::BufferTooLong);
|
||||||
async move {
|
|
||||||
self.ppi_ch1.disable();
|
|
||||||
let result = self.uarte.read(rx_buffer).await;
|
|
||||||
self.ppi_ch1.enable();
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, U: Instance, T: TimerInstance> Write for UarteWithIdle<'d, U, T> {
|
let ptr = buffer.as_ptr();
|
||||||
type WriteFuture<'a>
|
let len = buffer.len();
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
= impl Future<Output = Result<(), TraitError>> + 'a;
|
|
||||||
|
|
||||||
fn write<'a>(&'a mut self, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> {
|
let r = U::regs();
|
||||||
self.uarte.write(tx_buffer)
|
|
||||||
|
self.ppi_ch1.enable();
|
||||||
|
|
||||||
|
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||||
|
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||||
|
|
||||||
|
r.events_endrx.reset();
|
||||||
|
r.intenclr.write(|w| w.endrx().clear());
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||||
|
|
||||||
|
while r.events_endrx.read().bits() == 0 {}
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
let n = r.rxd.amount.read().amount().bits() as usize;
|
||||||
|
|
||||||
|
self.timer.stop();
|
||||||
|
r.events_rxstarted.reset();
|
||||||
|
|
||||||
|
Ok(n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,3 +712,206 @@ macro_rules! impl_uarte {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====================
|
||||||
|
|
||||||
|
mod eh02 {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for Uarte<'d, T> {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_write(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bflush(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for UarteTx<'d, T> {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_write(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bflush(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, U: Instance, T: TimerInstance> embedded_hal_02::blocking::serial::Write<u8>
|
||||||
|
for UarteWithIdle<'d, U, T>
|
||||||
|
{
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_write(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bflush(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "unstable-traits")]
|
||||||
|
mod eh1 {
|
||||||
|
use super::*;
|
||||||
|
use core::future::Future;
|
||||||
|
|
||||||
|
impl embedded_hal_1::serial::Error for Error {
|
||||||
|
fn kind(&self) -> embedded_hal_1::serial::ErrorKind {
|
||||||
|
match *self {
|
||||||
|
Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other,
|
||||||
|
Self::BufferZeroLength => embedded_hal_1::serial::ErrorKind::Other,
|
||||||
|
Self::DMABufferNotInDataMemory => embedded_hal_1::serial::ErrorKind::Other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for Uarte<'d, T> {
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_1::serial::blocking::Write for Uarte<'d, T> {
|
||||||
|
fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_write(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_async::serial::Read for Uarte<'d, T> {
|
||||||
|
type ReadFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
||||||
|
self.read(buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_async::serial::Write for Uarte<'d, T> {
|
||||||
|
type WriteFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn write<'a>(&'a mut self, buffer: &'a [u8]) -> Self::WriteFuture<'a> {
|
||||||
|
self.write(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
type FlushFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
|
||||||
|
async move { Ok(()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteTx<'d, T> {
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_1::serial::blocking::Write for UarteTx<'d, T> {
|
||||||
|
fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_write(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_async::serial::Write for UarteTx<'d, T> {
|
||||||
|
type WriteFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn write<'a>(&'a mut self, buffer: &'a [u8]) -> Self::WriteFuture<'a> {
|
||||||
|
self.write(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
type FlushFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
|
||||||
|
async move { Ok(()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteRx<'d, T> {
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_async::serial::Read for UarteRx<'d, T> {
|
||||||
|
type ReadFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
||||||
|
self.read(buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================
|
||||||
|
|
||||||
|
impl<'d, U: Instance, T: TimerInstance> embedded_hal_1::serial::ErrorType
|
||||||
|
for UarteWithIdle<'d, U, T>
|
||||||
|
{
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, U: Instance, T: TimerInstance> embedded_hal_async::serial::Read
|
||||||
|
for UarteWithIdle<'d, U, T>
|
||||||
|
{
|
||||||
|
type ReadFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
||||||
|
self.read(buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, U: Instance, T: TimerInstance> embedded_hal_async::serial::Write
|
||||||
|
for UarteWithIdle<'d, U, T>
|
||||||
|
{
|
||||||
|
type WriteFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn write<'a>(&'a mut self, buffer: &'a [u8]) -> Self::WriteFuture<'a> {
|
||||||
|
self.write(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
type FlushFuture<'a>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
= impl Future<Output = Result<(), Self::Error>> + 'a;
|
||||||
|
|
||||||
|
fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
|
||||||
|
async move { Ok(()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,16 +1,28 @@
|
||||||
|
use core::mem;
|
||||||
|
|
||||||
const SRAM_LOWER: usize = 0x2000_0000;
|
const SRAM_LOWER: usize = 0x2000_0000;
|
||||||
const SRAM_UPPER: usize = 0x3000_0000;
|
const SRAM_UPPER: usize = 0x3000_0000;
|
||||||
|
|
||||||
|
// TODO: replace transmutes with core::ptr::metadata once it's stable
|
||||||
|
|
||||||
|
pub(crate) fn slice_ptr_parts<T>(slice: *const [T]) -> (usize, usize) {
|
||||||
|
unsafe { mem::transmute(slice) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn slice_ptr_parts_mut<T>(slice: *mut [T]) -> (usize, usize) {
|
||||||
|
unsafe { mem::transmute(slice) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Does this slice reside entirely within RAM?
|
/// Does this slice reside entirely within RAM?
|
||||||
pub(crate) fn slice_in_ram<T>(slice: &[T]) -> bool {
|
pub(crate) fn slice_in_ram<T>(slice: *const [T]) -> bool {
|
||||||
let ptr = slice.as_ptr() as usize;
|
let (ptr, len) = slice_ptr_parts(slice);
|
||||||
ptr >= SRAM_LOWER && (ptr + slice.len() * core::mem::size_of::<T>()) < SRAM_UPPER
|
ptr >= SRAM_LOWER && (ptr + len * core::mem::size_of::<T>()) < SRAM_UPPER
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return an error if slice is not in RAM.
|
/// Return an error if slice is not in RAM.
|
||||||
#[cfg(not(feature = "nrf51"))]
|
#[cfg(not(feature = "nrf51"))]
|
||||||
pub(crate) fn slice_in_ram_or<T, E>(slice: &[T], err: E) -> Result<(), E> {
|
pub(crate) fn slice_in_ram_or<T, E>(slice: *const [T], err: E) -> Result<(), E> {
|
||||||
if slice.is_empty() || slice_in_ram(slice) {
|
if slice_in_ram(slice) {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(err)
|
Err(err)
|
||||||
|
|
|
@ -15,7 +15,6 @@ defmt-rtt = "0.3"
|
||||||
|
|
||||||
cortex-m = "0.7.3"
|
cortex-m = "0.7.3"
|
||||||
cortex-m-rt = "0.7.0"
|
cortex-m-rt = "0.7.0"
|
||||||
embedded-hal = "0.2.6"
|
|
||||||
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
||||||
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
|
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
|
||||||
rand = { version = "0.8.4", default-features = false }
|
rand = { version = "0.8.4", default-features = false }
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
mod example_common;
|
mod example_common;
|
||||||
|
|
||||||
use embassy::executor::Spawner;
|
use embassy::executor::Spawner;
|
||||||
use embassy::traits::gpio::{WaitForHigh, WaitForLow};
|
|
||||||
use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull};
|
use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull};
|
||||||
use embassy_nrf::Peripherals;
|
use embassy_nrf::Peripherals;
|
||||||
use example_common::*;
|
use example_common::*;
|
||||||
|
|
|
@ -7,7 +7,6 @@ mod example_common;
|
||||||
|
|
||||||
use defmt::assert_eq;
|
use defmt::assert_eq;
|
||||||
use embassy::executor::Spawner;
|
use embassy::executor::Spawner;
|
||||||
use embassy::traits::flash::Flash;
|
|
||||||
use embassy_nrf::Peripherals;
|
use embassy_nrf::Peripherals;
|
||||||
use embassy_nrf::{interrupt, qspi};
|
use embassy_nrf::{interrupt, qspi};
|
||||||
use example_common::*;
|
use example_common::*;
|
||||||
|
|
|
@ -8,7 +8,6 @@ mod example_common;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use embassy::executor::Spawner;
|
use embassy::executor::Spawner;
|
||||||
use embassy::time::{Duration, Timer};
|
use embassy::time::{Duration, Timer};
|
||||||
use embassy::traits::flash::Flash;
|
|
||||||
use embassy_nrf::Peripherals;
|
use embassy_nrf::Peripherals;
|
||||||
use embassy_nrf::{interrupt, qspi};
|
use embassy_nrf::{interrupt, qspi};
|
||||||
use example_common::*;
|
use example_common::*;
|
||||||
|
|
|
@ -5,9 +5,7 @@
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
mod example_common;
|
mod example_common;
|
||||||
|
|
||||||
use defmt::unwrap;
|
|
||||||
use embassy::executor::Spawner;
|
use embassy::executor::Spawner;
|
||||||
use embassy::traits::rng::Rng as _;
|
|
||||||
use embassy_nrf::interrupt;
|
use embassy_nrf::interrupt;
|
||||||
use embassy_nrf::rng::Rng;
|
use embassy_nrf::rng::Rng;
|
||||||
use embassy_nrf::Peripherals;
|
use embassy_nrf::Peripherals;
|
||||||
|
@ -19,14 +17,14 @@ async fn main(_spawner: Spawner, p: Peripherals) {
|
||||||
|
|
||||||
// Async API
|
// Async API
|
||||||
let mut bytes = [0; 4];
|
let mut bytes = [0; 4];
|
||||||
unwrap!(rng.fill_bytes(&mut bytes).await); // nRF RNG is infallible
|
rng.fill_bytes(&mut bytes).await;
|
||||||
defmt::info!("Some random bytes: {:?}", bytes);
|
defmt::info!("Some random bytes: {:?}", bytes);
|
||||||
|
|
||||||
// Sync API with `rand`
|
// Sync API with `rand`
|
||||||
defmt::info!("A random number from 1 to 10: {:?}", rng.gen_range(1..=10));
|
defmt::info!("A random number from 1 to 10: {:?}", rng.gen_range(1..=10));
|
||||||
|
|
||||||
let mut bytes = [0; 1024];
|
let mut bytes = [0; 1024];
|
||||||
unwrap!(rng.fill_bytes(&mut bytes).await);
|
rng.fill_bytes(&mut bytes).await;
|
||||||
let zero_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_zeros());
|
let zero_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_zeros());
|
||||||
let one_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_ones());
|
let one_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_ones());
|
||||||
defmt::info!(
|
defmt::info!(
|
||||||
|
|
|
@ -9,7 +9,6 @@ use embassy::executor::Spawner;
|
||||||
use embassy_nrf::gpio::{Level, Output, OutputDrive};
|
use embassy_nrf::gpio::{Level, Output, OutputDrive};
|
||||||
use embassy_nrf::Peripherals;
|
use embassy_nrf::Peripherals;
|
||||||
use embassy_nrf::{interrupt, spim};
|
use embassy_nrf::{interrupt, spim};
|
||||||
use embassy_traits::spi::FullDuplex;
|
|
||||||
use example_common::*;
|
use example_common::*;
|
||||||
|
|
||||||
#[embassy::main]
|
#[embassy::main]
|
||||||
|
@ -31,7 +30,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
|
||||||
ncs.set_low();
|
ncs.set_low();
|
||||||
cortex_m::asm::delay(5);
|
cortex_m::asm::delay(5);
|
||||||
let tx = [0xFF];
|
let tx = [0xFF];
|
||||||
unwrap!(spim.read_write(&mut [], &tx).await);
|
unwrap!(spim.transfer(&mut [], &tx).await);
|
||||||
cortex_m::asm::delay(10);
|
cortex_m::asm::delay(10);
|
||||||
ncs.set_high();
|
ncs.set_high();
|
||||||
|
|
||||||
|
@ -44,7 +43,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
|
||||||
ncs.set_low();
|
ncs.set_low();
|
||||||
cortex_m::asm::delay(5000);
|
cortex_m::asm::delay(5000);
|
||||||
let tx = [0b000_11101, 0];
|
let tx = [0b000_11101, 0];
|
||||||
unwrap!(spim.read_write(&mut rx, &tx).await);
|
unwrap!(spim.transfer(&mut rx, &tx).await);
|
||||||
cortex_m::asm::delay(5000);
|
cortex_m::asm::delay(5000);
|
||||||
ncs.set_high();
|
ncs.set_high();
|
||||||
info!("estat: {=[?]}", rx);
|
info!("estat: {=[?]}", rx);
|
||||||
|
@ -54,7 +53,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
|
||||||
ncs.set_low();
|
ncs.set_low();
|
||||||
cortex_m::asm::delay(5);
|
cortex_m::asm::delay(5);
|
||||||
let tx = [0b100_11111, 0b11];
|
let tx = [0b100_11111, 0b11];
|
||||||
unwrap!(spim.read_write(&mut rx, &tx).await);
|
unwrap!(spim.transfer(&mut rx, &tx).await);
|
||||||
cortex_m::asm::delay(10);
|
cortex_m::asm::delay(10);
|
||||||
ncs.set_high();
|
ncs.set_high();
|
||||||
|
|
||||||
|
@ -63,7 +62,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
|
||||||
ncs.set_low();
|
ncs.set_low();
|
||||||
cortex_m::asm::delay(5);
|
cortex_m::asm::delay(5);
|
||||||
let tx = [0b000_10010, 0];
|
let tx = [0b000_10010, 0];
|
||||||
unwrap!(spim.read_write(&mut rx, &tx).await);
|
unwrap!(spim.transfer(&mut rx, &tx).await);
|
||||||
cortex_m::asm::delay(10);
|
cortex_m::asm::delay(10);
|
||||||
ncs.set_high();
|
ncs.set_high();
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
|
||||||
info!("Reading...");
|
info!("Reading...");
|
||||||
|
|
||||||
let mut buf = [0u8; 16];
|
let mut buf = [0u8; 16];
|
||||||
unwrap!(twi.write_then_read(ADDRESS, &mut [0x00], &mut buf));
|
unwrap!(twi.blocking_write_read(ADDRESS, &mut [0x00], &mut buf));
|
||||||
|
|
||||||
info!("Read: {=[u8]:x}", buf);
|
info!("Read: {=[u8]:x}", buf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ async fn main(_spawner: Spawner, mut p: Peripherals) {
|
||||||
info!("Reading...");
|
info!("Reading...");
|
||||||
|
|
||||||
let mut buf = [0u8; 16];
|
let mut buf = [0u8; 16];
|
||||||
unwrap!(twi.write_then_read(ADDRESS, &mut [0x00], &mut buf));
|
unwrap!(twi.blocking_write_read(ADDRESS, &mut [0x00], &mut buf));
|
||||||
|
|
||||||
info!("Read: {=[u8]:x}", buf);
|
info!("Read: {=[u8]:x}", buf);
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ mod example_common;
|
||||||
use example_common::*;
|
use example_common::*;
|
||||||
|
|
||||||
use embassy::executor::Spawner;
|
use embassy::executor::Spawner;
|
||||||
use embassy::traits::uart::{Read, Write};
|
|
||||||
use embassy_nrf::gpio::NoPin;
|
use embassy_nrf::gpio::NoPin;
|
||||||
use embassy_nrf::{interrupt, uarte, Peripherals};
|
use embassy_nrf::{interrupt, uarte, Peripherals};
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,9 @@
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
mod example_common;
|
mod example_common;
|
||||||
use embassy_traits::uart::ReadUntilIdle;
|
|
||||||
use example_common::*;
|
use example_common::*;
|
||||||
|
|
||||||
use embassy::executor::Spawner;
|
use embassy::executor::Spawner;
|
||||||
use embassy::traits::uart::Write;
|
|
||||||
use embassy_nrf::gpio::NoPin;
|
use embassy_nrf::gpio::NoPin;
|
||||||
use embassy_nrf::{interrupt, uarte, Peripherals};
|
use embassy_nrf::{interrupt, uarte, Peripherals};
|
||||||
|
|
||||||
|
@ -19,11 +17,9 @@ async fn main(_spawner: Spawner, p: Peripherals) {
|
||||||
config.baudrate = uarte::Baudrate::BAUD115200;
|
config.baudrate = uarte::Baudrate::BAUD115200;
|
||||||
|
|
||||||
let irq = interrupt::take!(UARTE0_UART0);
|
let irq = interrupt::take!(UARTE0_UART0);
|
||||||
let mut uart = unsafe {
|
let mut uart = uarte::UarteWithIdle::new(
|
||||||
uarte::UarteWithIdle::new(
|
p.UARTE0, p.TIMER0, p.PPI_CH0, p.PPI_CH1, irq, p.P0_08, p.P0_06, NoPin, NoPin, config,
|
||||||
p.UARTE0, p.TIMER0, p.PPI_CH0, p.PPI_CH1, irq, p.P0_08, p.P0_06, NoPin, NoPin, config,
|
);
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
info!("uarte initialized!");
|
info!("uarte initialized!");
|
||||||
|
|
||||||
|
|
|
@ -4,16 +4,15 @@
|
||||||
|
|
||||||
#[path = "../example_common.rs"]
|
#[path = "../example_common.rs"]
|
||||||
mod example_common;
|
mod example_common;
|
||||||
use embassy::blocking_mutex::kind::Noop;
|
|
||||||
use embassy::channel::mpsc::{self, Channel, Sender};
|
|
||||||
use embassy::util::Forever;
|
|
||||||
use embassy_nrf::peripherals::UARTE0;
|
|
||||||
use embassy_nrf::uarte::UarteRx;
|
|
||||||
use example_common::*;
|
use example_common::*;
|
||||||
|
|
||||||
|
use embassy::blocking_mutex::kind::Noop;
|
||||||
|
use embassy::channel::mpsc::{self, Channel, Sender};
|
||||||
use embassy::executor::Spawner;
|
use embassy::executor::Spawner;
|
||||||
use embassy::traits::uart::{Read, Write};
|
use embassy::util::Forever;
|
||||||
use embassy_nrf::gpio::NoPin;
|
use embassy_nrf::gpio::NoPin;
|
||||||
|
use embassy_nrf::peripherals::UARTE0;
|
||||||
|
use embassy_nrf::uarte::UarteRx;
|
||||||
use embassy_nrf::{interrupt, uarte, Peripherals};
|
use embassy_nrf::{interrupt, uarte, Peripherals};
|
||||||
|
|
||||||
static CHANNEL: Forever<Channel<Noop, [u8; 8], 1>> = Forever::new();
|
static CHANNEL: Forever<Channel<Noop, [u8; 8], 1>> = Forever::new();
|
||||||
|
|
|
@ -10,7 +10,6 @@ use embassy::executor::Spawner;
|
||||||
use embassy_nrf::gpio::{Input, Pull};
|
use embassy_nrf::gpio::{Input, Pull};
|
||||||
use embassy_nrf::wdt::{Config, Watchdog};
|
use embassy_nrf::wdt::{Config, Watchdog};
|
||||||
use embassy_nrf::Peripherals;
|
use embassy_nrf::Peripherals;
|
||||||
use embassy_traits::gpio::{WaitForHigh, WaitForLow};
|
|
||||||
|
|
||||||
#[embassy::main]
|
#[embassy::main]
|
||||||
async fn main(_spawner: Spawner, p: Peripherals) {
|
async fn main(_spawner: Spawner, p: Peripherals) {
|
||||||
|
|
Loading…
Reference in a new issue