diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index cb6544028..a957af6b2 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -12,6 +12,13 @@ edition = "2018" # There are no plans to make this stable. unstable-pac = [] +# Enable nightly-only features +nightly = ["embassy/nightly", "embedded-hal-1", "embedded-hal-async"] + +# Implement embedded-hal 1.0 alpha traits. +# Implement embedded-hal-async traits if `nightly` is set as well. +unstable-traits = ["embedded-hal-1"] + [dependencies] embassy = { version = "0.1.0", path = "../embassy", features = [ "time-tick-1mhz", "nightly"] } embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } @@ -25,4 +32,7 @@ critical-section = "0.2.5" rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="9ad7223a48a065e612bc7dc7be5bf5bd0b41cfc4", features = ["rt"] } #rp2040-pac2 = { path = "../../rp/rp2040-pac2", features = ["rt"] } -embedded-hal = { version = "0.2.6", features = [ "unproven" ] } + +embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } +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} diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index f9a5eff50..598759036 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -8,7 +8,6 @@ use crate::peripherals; use embassy::util::Unborrow; use embassy_hal_common::{unborrow, unsafe_impl_unborrow}; -use embedded_hal::digital::v2 as digital; /// Represents a digital input or output level. #[derive(Debug, Eq, PartialEq)] @@ -81,18 +80,6 @@ impl<'d, T: Pin> Drop for Input<'d, T> { } } -impl<'d, T: Pin> digital::InputPin for Input<'d, T> { - type Error = Infallible; - - fn is_high(&self) -> Result { - Ok(self.is_high()) - } - - fn is_low(&self) -> Result { - Ok(self.is_low()) - } -} - pub struct Output<'d, T: Pin> { pin: T, phantom: PhantomData<&'d mut T>, @@ -151,34 +138,6 @@ impl<'d, T: Pin> Drop for Output<'d, T> { } } -impl<'d, T: Pin> digital::OutputPin for Output<'d, T> { - type Error = Infallible; - - /// Set the output as high. - fn set_high(&mut self) -> Result<(), Self::Error> { - self.set_high(); - Ok(()) - } - - /// Set the output as low. - fn set_low(&mut self) -> Result<(), Self::Error> { - self.set_low(); - Ok(()) - } -} - -impl<'d, T: Pin> digital::StatefulOutputPin for Output<'d, T> { - /// Is the output pin set as high? - fn is_set_high(&self) -> Result { - Ok(self.is_set_high()) - } - - /// Is the output pin set as low? - fn is_set_low(&self) -> Result { - Ok(self.is_set_low()) - } -} - pub(crate) mod sealed { use super::*; @@ -296,3 +255,86 @@ impl_pin!(PIN_QSPI_SD0, Bank::Qspi, 2); impl_pin!(PIN_QSPI_SD1, Bank::Qspi, 3); impl_pin!(PIN_QSPI_SD2, Bank::Qspi, 4); impl_pin!(PIN_QSPI_SD3, Bank::Qspi, 5); + +// ==================== + +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 { + Ok(self.is_high()) + } + + fn is_low(&self) -> Result { + 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 { + Ok(self.is_set_high()) + } + + fn is_set_low(&self) -> Result { + 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 { + Ok(self.is_high()) + } + + fn is_low(&self) -> Result { + 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 { + Ok(self.is_set_high()) + } + + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } + } +} diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index 3d498aff9..549e1bd06 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs @@ -2,28 +2,33 @@ use core::marker::PhantomData; use embassy::util::Unborrow; use embassy_hal_common::unborrow; -use embedded_hal::blocking::spi as eh; -use embedded_hal::spi as ehnb; use crate::gpio::sealed::Pin as _; use crate::gpio::{AnyPin, Pin as GpioPin}; use crate::{pac, peripherals}; -pub use ehnb::{Phase, Polarity}; +pub use embedded_hal_02::spi::{Phase, Polarity}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + // No errors for now +} #[non_exhaustive] pub struct Config { pub frequency: u32, - pub phase: ehnb::Phase, - pub polarity: ehnb::Polarity, + pub phase: Phase, + pub polarity: Polarity, } impl Default for Config { fn default() -> Self { Self { frequency: 1_000_000, - phase: ehnb::Phase::CaptureOnFirstTransition, - polarity: ehnb::Polarity::IdleLow, + phase: Phase::CaptureOnFirstTransition, + polarity: Polarity::IdleLow, } } } @@ -130,8 +135,8 @@ impl<'d, T: Instance> Spi<'d, T> { p.cpsr().write(|w| w.set_cpsdvsr(presc)); p.cr0().write(|w| { w.set_dss(0b0111); // 8bit - w.set_spo(config.polarity == ehnb::Polarity::IdleHigh); - w.set_sph(config.phase == ehnb::Phase::CaptureOnSecondTransition); + w.set_spo(config.polarity == Polarity::IdleHigh); + w.set_sph(config.phase == Phase::CaptureOnSecondTransition); w.set_scr(postdiv); }); p.cr1().write(|w| { @@ -157,7 +162,7 @@ impl<'d, T: Instance> Spi<'d, T> { } } - pub fn write(&mut self, data: &[u8]) { + pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> { unsafe { let p = self.inner.regs(); for &b in data { @@ -166,11 +171,12 @@ impl<'d, T: Instance> Spi<'d, T> { while !p.sr().read().rne() {} let _ = p.dr().read(); } - self.flush(); } + self.flush()?; + Ok(()) } - pub fn transfer(&mut self, data: &mut [u8]) { + pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> { unsafe { let p = self.inner.regs(); for b in data { @@ -179,15 +185,50 @@ impl<'d, T: Instance> Spi<'d, T> { while !p.sr().read().rne() {} *b = p.dr().read().data() as u8; } - self.flush(); } + self.flush()?; + Ok(()) } - pub fn flush(&mut self) { + pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> { + unsafe { + let p = self.inner.regs(); + for b in data { + while !p.sr().read().tnf() {} + p.dr().write(|w| w.set_data(0)); + while !p.sr().read().rne() {} + *b = p.dr().read().data() as u8; + } + } + self.flush()?; + Ok(()) + } + + pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { + unsafe { + let p = self.inner.regs(); + let len = read.len().max(write.len()); + for i in 0..len { + let wb = write.get(i).copied().unwrap_or(0); + while !p.sr().read().tnf() {} + p.dr().write(|w| w.set_data(wb as _)); + while !p.sr().read().rne() {} + let rb = p.dr().read().data() as u8; + if let Some(r) = read.get_mut(i) { + *r = rb; + } + } + } + self.flush()?; + Ok(()) + } + + pub fn flush(&mut self) -> Result<(), Error> { unsafe { let p = self.inner.regs(); while p.sr().read().bsy() {} } + Ok(()) } pub fn set_frequency(&mut self, freq: u32) { @@ -209,23 +250,6 @@ impl<'d, T: Instance> Spi<'d, T> { } } -impl<'d, T: Instance> eh::Write for Spi<'d, T> { - type Error = core::convert::Infallible; - - fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { - self.write(words); - Ok(()) - } -} - -impl<'d, T: Instance> eh::Transfer for Spi<'d, T> { - type Error = core::convert::Infallible; - fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { - self.transfer(words); - Ok(words) - } -} - mod sealed { use super::*; @@ -281,3 +305,102 @@ impl_pin!(PIN_16, SPI0, MisoPin); impl_pin!(PIN_17, SPI0, CsPin); impl_pin!(PIN_18, SPI0, ClkPin); impl_pin!(PIN_19, SPI0, MosiPin); + +// ==================== + +mod eh02 { + use super::*; + + impl<'d, T: Instance> embedded_hal_02::blocking::spi::Transfer for Spi<'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 for Spi<'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::*; + + impl embedded_hal_1::spi::Error for Error { + fn kind(&self) -> embedded_hal_1::spi::ErrorKind { + match *self {} + } + } + + impl<'d, T: Instance> embedded_hal_1::spi::ErrorType for Spi<'d, T> { + type Error = Error; + } + + impl<'d, T: Instance> embedded_hal_1::spi::blocking::Read for Spi<'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 for Spi<'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(&mut self, words: WI) -> Result<(), Self::Error> + where + WI: IntoIterator, + { + for w in words { + self.blocking_write(&[w])?; + } + Ok(()) + } + } + + impl<'d, T: Instance> embedded_hal_1::spi::blocking::ReadWrite for Spi<'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_1::spi::blocking::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(()) + } + } +} diff --git a/examples/rp/.cargo/config.toml b/examples/rp/.cargo/config.toml index 1ce57510b..ac54f9693 100644 --- a/examples/rp/.cargo/config.toml +++ b/examples/rp/.cargo/config.toml @@ -1,5 +1,5 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "probe-run-rp --chip RP2040" +runner = "probe-run --chip RP2040" [build] target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index b3dfb04dc..c067fbbcf 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -7,7 +7,7 @@ version = "0.1.0" [dependencies] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt"] } -embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt"] } +embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac"] } atomic-polyfill = "0.1.5" defmt = "0.3" diff --git a/examples/rp/src/bin/spi.rs b/examples/rp/src/bin/spi.rs index 71dec94f3..3348dc999 100644 --- a/examples/rp/src/bin/spi.rs +++ b/examples/rp/src/bin/spi.rs @@ -34,7 +34,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { loop { cs.set_low(); let mut buf = [0x90, 0x00, 0x00, 0xd0, 0x00, 0x00]; - spi.transfer(&mut buf); + spi.blocking_transfer_in_place(&mut buf).unwrap(); cs.set_high(); let x = (buf[1] as u32) << 5 | (buf[2] as u32) >> 3; diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs index 96f0cf378..01149c250 100644 --- a/examples/rp/src/bin/spi_display.rs +++ b/examples/rp/src/bin/spi_display.rs @@ -131,7 +131,7 @@ impl<'a> embedded_hal::blocking::spi::Write for DisplaySpi<'a> { this.display_cs.set_low(); this.last_mode = SpiMode::Display; } - this.spi.write(words); + this.spi.write(words).unwrap(); Ok(()) } } @@ -147,7 +147,7 @@ impl<'a> embedded_hal::blocking::spi::Transfer for TouchSpi<'a> { this.display_cs.set_high(); this.last_mode = SpiMode::Touch; } - this.spi.transfer(words); + this.spi.transfer(words).unwrap(); Ok(words) } }