diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2addd1a..4366937 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,8 +11,8 @@ jobs: continue-on-error: ${{ matrix.experimental || false }} strategy: matrix: - # All generated code should be running on stable now, MRSV is 1.42.0 - rust: [nightly, stable, 1.42.0] + # All generated code should be running on stable now, MRSV is 1.59.0 + rust: [nightly, stable, 1.59.0] include: # Nightly is only for reference and allowed to fail diff --git a/CHANGELOG.md b/CHANGELOG.md index 9966133..fa3c7fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Updated to support `embedded-hal` version `1.0.0-alpha.7` + - Refactored `e310x-hal::spi` module, splitting the abstraction into `SpiBus` and `SpiExclusiveDevice/SpiSharedDevice` to allow multiple devices on a single SPI bus to co-exist ## [v0.9.3] - 2021-08-15 diff --git a/Cargo.toml b/Cargo.toml index e79aed9..7322a14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "e310x-hal" -version = "0.9.3" +version = "0.10.0-alpha.1" authors = ["David Craven "] repository = "https://github.com/riscv-rust/e310x-hal" categories = ["embedded", "hardware-support", "no-std"] @@ -10,10 +10,10 @@ license = "ISC" edition = "2018" [dependencies] -embedded-hal = { version = "0.2.6", features = ["unproven"] } +embedded-hal = "=1.0.0-alpha.8" nb = "1.0.0" -riscv = "0.7.0" -e310x = { version = "0.9.0", features = ["rt"] } +riscv = "0.9.0-alpha.1" +e310x = { version = "0.9.1", features = ["rt"] } [features] g002 = ["e310x/g002"] diff --git a/README.md b/README.md index 81455da..bf2f875 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ This project is developed and maintained by the [RISC-V team][team]. ## Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.42.0 and up. It *might* +This crate is guaranteed to compile on stable Rust 1.59.0 and up. It *might* compile with older versions but that may change in any new patch release. ## License diff --git a/src/delay.rs b/src/delay.rs index 4778bf1..30b42e6 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -2,7 +2,8 @@ use crate::clock::Clocks; use crate::core::clint::{MTIME, MTIMECMP}; -use embedded_hal::blocking::delay::{DelayMs, DelayUs}; +use core::convert::Infallible; +use embedded_hal::delay::blocking::DelayUs; use riscv::register::{mie, mip}; /// Machine timer (mtime) as a busyloop delay provider @@ -17,65 +18,16 @@ impl Delay { } } -impl DelayUs for Delay { - fn delay_us(&mut self, us: u32) { +impl DelayUs for Delay { + type Error = Infallible; + + fn delay_us(&mut self, us: u32) -> Result<(), Infallible> { let ticks = (us as u64) * TICKS_PER_SECOND / 1_000_000; let mtime = MTIME; let t = mtime.mtime() + ticks; while mtime.mtime() < t {} - } -} - -// This is a workaround to allow `delay_us(42)` construction without specifying a type. -impl DelayUs for Delay { - #[inline(always)] - fn delay_us(&mut self, us: i32) { - assert!(us >= 0); - self.delay_us(us as u32); - } -} - -impl DelayUs for Delay { - #[inline(always)] - fn delay_us(&mut self, us: u16) { - self.delay_us(u32::from(us)); - } -} - -impl DelayUs for Delay { - #[inline(always)] - fn delay_us(&mut self, us: u8) { - self.delay_us(u32::from(us)); - } -} - -impl DelayMs for Delay { - fn delay_ms(&mut self, ms: u32) { - self.delay_us(ms * 1000); - } -} - -// This is a workaround to allow `delay_ms(42)` construction without specifying a type. -impl DelayMs for Delay { - #[inline(always)] - fn delay_ms(&mut self, ms: i32) { - assert!(ms >= 0); - self.delay_ms(ms as u32); - } -} - -impl DelayMs for Delay { - #[inline(always)] - fn delay_ms(&mut self, ms: u16) { - self.delay_ms(u32::from(ms)); - } -} - -impl DelayMs for Delay { - #[inline(always)] - fn delay_ms(&mut self, ms: u8) { - self.delay_ms(u32::from(ms)); + Ok(()) } } @@ -95,9 +47,11 @@ impl Sleep { } } -impl DelayMs for Sleep { - fn delay_ms(&mut self, ms: u32) { - let ticks = (ms as u64) * (self.clock_freq as u64) / 1000; +impl DelayUs for Sleep { + type Error = Infallible; + + fn delay_us(&mut self, us: u32) -> Result<(), Infallible> { + let ticks = (us as u64) * (self.clock_freq as u64) / 1_000_000; let t = MTIME.mtime() + ticks; self.mtimecmp.set_mtimecmp(t); @@ -126,28 +80,7 @@ impl DelayMs for Sleep { unsafe { mie::clear_mtimer(); } - } -} - -// This is a workaround to allow `delay_ms(42)` construction without specifying a type. -impl DelayMs for Sleep { - #[inline(always)] - fn delay_ms(&mut self, ms: i32) { - assert!(ms >= 0); - self.delay_ms(ms as u32); - } -} - -impl DelayMs for Sleep { - #[inline(always)] - fn delay_ms(&mut self, ms: u16) { - self.delay_ms(u32::from(ms)); - } -} -impl DelayMs for Sleep { - #[inline(always)] - fn delay_ms(&mut self, ms: u8) { - self.delay_ms(u32::from(ms)); + Ok(()) } } diff --git a/src/gpio.rs b/src/gpio.rs index 63239f0..be0b294 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -142,7 +142,8 @@ macro_rules! gpio { use core::marker::PhantomData; use core::convert::Infallible; - use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, + use embedded_hal::digital::ErrorType; + use embedded_hal::digital::blocking::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; use e310x::$GPIOX; use super::{Unknown, IOF0, IOF1, Drive, Floating, GpioExt, Input, Invert, @@ -275,9 +276,11 @@ macro_rules! gpio { } } - impl InputPin for $PXi> { + impl ErrorType for $PXi> { type Error = Infallible; + } + impl InputPin for $PXi> { fn is_high(&self) -> Result { Ok($GPIOX::input_value(Self::INDEX)) @@ -298,9 +301,11 @@ macro_rules! gpio { } } - impl OutputPin for $PXi> { + impl ErrorType for $PXi> { type Error = Infallible; + } + impl OutputPin for $PXi> { fn set_high(&mut self) -> Result<(), Infallible> { $GPIOX::set_output_value(Self::INDEX, true); Ok(()) @@ -313,8 +318,6 @@ macro_rules! gpio { } impl ToggleableOutputPin for $PXi> { - type Error = Infallible; - /// Toggles the pin state. fn toggle(&mut self) -> Result<(), Infallible> { $GPIOX::toggle_pin(Self::INDEX); diff --git a/src/i2c.rs b/src/i2c.rs index d969add..e0e049a 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -16,7 +16,8 @@ use crate::time::Bps; use core::mem; use core::ops::Deref; use e310x::{i2c0, I2C0}; -use embedded_hal::blocking::i2c::{Read, Write, WriteRead}; +use embedded_hal::i2c::blocking::{self as i2c, Operation}; +use embedded_hal::i2c::{ErrorKind, ErrorType, NoAcknowledgeSource}; /// SDA pin - DO NOT IMPLEMENT THIS TRAIT pub unsafe trait SdaPin {} @@ -26,19 +27,6 @@ pub unsafe trait SclPin {} unsafe impl SdaPin for gpio0::Pin12> {} unsafe impl SclPin for gpio0::Pin13> {} -/// I2C error -#[derive(Debug, Eq, PartialEq)] -pub enum Error { - /// Invalid peripheral state - InvalidState, - - /// Arbitration lost - ArbitrationLost, - - /// No ACK received - NoAck, -} - /// Transmission speed pub enum Speed { /// 100Kbps @@ -121,7 +109,7 @@ impl, PINS> I2c { } fn read_sr(&self) -> i2c0::sr::R { - unsafe { mem::transmute(self.i2c.sr().read()) } + self.i2c.sr().read() } fn write_byte(&self, byte: u8) { @@ -132,7 +120,7 @@ impl, PINS> I2c { self.i2c.txr_rxr.read().data().bits() } - fn wait_for_interrupt(&self) -> Result<(), Error> { + fn wait_for_interrupt(&self) -> Result<(), ErrorKind> { loop { let sr = self.read_sr(); @@ -141,7 +129,7 @@ impl, PINS> I2c { self.write_cr(|w| w.sto().set_bit()); self.wait_for_complete(); - return Err(Error::ArbitrationLost); + return Err(ErrorKind::ArbitrationLoss); } if sr.if_().bit_is_set() { @@ -153,11 +141,11 @@ impl, PINS> I2c { } } - fn wait_for_read(&self) -> Result<(), Error> { + fn wait_for_read(&self) -> Result<(), ErrorKind> { self.wait_for_interrupt() } - fn wait_for_write(&self) -> Result<(), Error> { + fn wait_for_write(&self) -> Result<(), ErrorKind> { self.wait_for_interrupt()?; if self.read_sr().rx_ack().bit_is_set() { @@ -165,7 +153,7 @@ impl, PINS> I2c { self.write_cr(|w| w.sto().set_bit()); self.wait_for_complete(); - return Err(Error::NoAck); + return Err(ErrorKind::NoAcknowledge(NoAcknowledgeSource::Unknown)); } Ok(()) @@ -179,14 +167,16 @@ impl, PINS> I2c { const FLAG_READ: u8 = 1; const FLAG_WRITE: u8 = 0; -impl, PINS> Read for I2c { - type Error = Error; +impl ErrorType for I2c { + type Error = ErrorKind; +} +impl, PINS> i2c::I2c for I2c { fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { self.reset(); if self.read_sr().busy().bit_is_set() { - return Err(Error::InvalidState); + return Err(ErrorKind::Other); } // Write address + R @@ -212,16 +202,12 @@ impl, PINS> Read for I2c { } Ok(()) } -} - -impl, PINS> Write for I2c { - type Error = Error; fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { self.reset(); if self.read_sr().busy().bit_is_set() { - return Err(Error::InvalidState); + return Err(ErrorKind::Other); } // Write address + W @@ -244,10 +230,39 @@ impl, PINS> Write for I2c { } Ok(()) } -} -impl, PINS> WriteRead for I2c { - type Error = Error; + fn write_iter>( + &mut self, + address: u8, + bytes: B, + ) -> Result<(), Self::Error> { + self.reset(); + + if self.read_sr().busy().bit_is_set() { + return Err(ErrorKind::Other); + } + + // Write address + W + self.write_byte((address << 1) + FLAG_WRITE); + + // Generate start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + + // Write bytes + let mut bytes = bytes.into_iter().peekable(); + while let Some(byte) = bytes.next() { + self.write_byte(byte); + + if bytes.peek().is_some() { + self.write_cr(|w| w.wr().set_bit()); // all others + } else { + self.write_cr(|w| w.wr().set_bit().sto().set_bit()); // last one + } + self.wait_for_write()?; + } + Ok(()) + } fn write_read( &mut self, @@ -258,7 +273,7 @@ impl, PINS> WriteRead for I2c, PINS> WriteRead for I2c>( + &mut self, + address: u8, + bytes: B, + buffer: &mut [u8], + ) -> Result<(), Self::Error> { + self.reset(); + + if self.read_sr().busy().bit_is_set() { + return Err(ErrorKind::Other); + } + + let mut bytes = bytes.into_iter().peekable(); + if bytes.peek().is_some() && buffer.is_empty() { + self.write_iter(address, bytes) + } else if !buffer.is_empty() && bytes.peek().is_none() { + self.read(address, buffer) + } else if bytes.peek().is_none() && buffer.is_empty() { + Ok(()) + } else { + // Write address + W + self.write_byte((address << 1) + FLAG_WRITE); + + // Generate start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + + // Write bytes + for byte in bytes { + self.write_byte(byte); + + self.write_cr(|w| w.wr().set_bit()); + self.wait_for_write()?; + } + + // Write address + R + self.write_byte((address << 1) + FLAG_READ); + + // Generate repeated start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + + // Read bytes + let buffer_len = buffer.len(); + for (i, byte) in buffer.iter_mut().enumerate() { + if i != buffer_len - 1 { + // W + ACK + self.write_cr(|w| w.rd().set_bit().ack().clear_bit()); + } else { + // W + NACK + STOP + self.write_cr(|w| w.rd().set_bit().ack().set_bit().sto().set_bit()); + } + self.wait_for_read()?; + + *byte = self.read_byte(); + } + + Ok(()) + } + } + + fn transaction<'a>( + &mut self, + address: u8, + operations: &mut [Operation<'a>], + ) -> Result<(), Self::Error> { + self.reset(); + + if self.read_sr().busy().bit_is_set() { + return Err(ErrorKind::Other); + } + + let last_op = operations.len() - 1; + let mut last_flag = 0xFF; + for (i, op) in operations.iter_mut().enumerate() { + match op { + Operation::Read(bytes) => { + if last_flag != FLAG_READ { + // Write address + R + self.write_byte((address << 1) + FLAG_READ); + + // Generate repeated start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + last_flag = FLAG_READ; + } + + // Read bytes + let last_byte = bytes.len() - 1; + for (j, byte) in bytes.iter_mut().enumerate() { + if i != last_op || j != last_byte { + // W + ACK + self.write_cr(|w| w.rd().set_bit().ack().clear_bit()); + } else { + // W + NACK + STOP + self.write_cr(|w| w.rd().set_bit().ack().set_bit().sto().set_bit()); + } + self.wait_for_read()?; + + *byte = self.read_byte(); + } + } + Operation::Write(bytes) => { + if last_flag != FLAG_WRITE { + // Write address + W + self.write_byte((address << 1) + FLAG_WRITE); + + // Generate start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + last_flag = FLAG_WRITE; + } + + // Write bytes + for (j, byte) in bytes.iter().enumerate() { + self.write_byte(*byte); + + if i != last_op || j != bytes.len() - 1 { + self.write_cr(|w| w.wr().set_bit()); + } else { + self.write_cr(|w| w.wr().set_bit().sto().set_bit()); + } + self.wait_for_write()?; + } + } + } + } + + Ok(()) + } + + fn transaction_iter<'a, O: IntoIterator>>( + &mut self, + address: u8, + operations: O, + ) -> Result<(), Self::Error> { + self.reset(); + + if self.read_sr().busy().bit_is_set() { + return Err(ErrorKind::Other); + } + + let mut last_flag = 0xFF; + let mut operations = operations.into_iter().peekable(); + while let Some(op) = operations.next() { + match op { + Operation::Read(bytes) => { + if last_flag != FLAG_READ { + // Write address + R + self.write_byte((address << 1) + FLAG_READ); + + // Generate repeated start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + last_flag = FLAG_READ; + } + + // Read bytes + let last_byte = bytes.len() - 1; + for (j, byte) in bytes.iter_mut().enumerate() { + if operations.peek().is_some() || j != last_byte { + // W + ACK + self.write_cr(|w| w.rd().set_bit().ack().clear_bit()); + } else { + // W + NACK + STOP + self.write_cr(|w| w.rd().set_bit().ack().set_bit().sto().set_bit()); + } + self.wait_for_read()?; + + *byte = self.read_byte(); + } + } + Operation::Write(bytes) => { + if last_flag != FLAG_WRITE { + // Write address + W + self.write_byte((address << 1) + FLAG_WRITE); + + // Generate start condition and write command + self.write_cr(|w| w.sta().set_bit().wr().set_bit()); + self.wait_for_write()?; + last_flag = FLAG_WRITE; + } + + // Write bytes + for (j, byte) in bytes.iter().enumerate() { + self.write_byte(*byte); + + if operations.peek().is_some() || j != bytes.len() - 1 { + self.write_cr(|w| w.wr().set_bit()); + } else { + self.write_cr(|w| w.wr().set_bit().sto().set_bit()); + } + self.wait_for_write()?; + } + } + } + } + + Ok(()) + } } diff --git a/src/prelude.rs b/src/prelude.rs index c6ccd12..a26b75f 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -7,9 +7,4 @@ pub use crate::rtc::RtcExt as _e310x_hal_rtc_RtcExt; pub use crate::stdout::Write as _e310x_hal_stdout_Write; pub use crate::time::U32Ext as _e310x_hal_time_U32Ext; pub use crate::wdog::WdogExt as _e310x_hal_wdog_WdogExt; -pub use embedded_hal::digital::v2::{ - InputPin as _embedded_hal_digital_v2_InputPin, OutputPin as _embedded_hal_digital_v2_OutputPin, - StatefulOutputPin as _embedded_hal_digital_v2_StatefulOutputPin, - ToggleableOutputPin as _embedded_hal_digital_v2_ToggleableOutputPin, -}; -pub use embedded_hal::prelude::*; +pub use embedded_hal::digital::blocking::StatefulOutputPin as _embedded_hal_digital_StatefulOutputPin; diff --git a/src/serial.rs b/src/serial.rs index 0184679..c88c2ac 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -13,7 +13,6 @@ //! - RX: Pin 23 IOF0 //! - Interrupt::UART1 -use core::convert::Infallible; use core::ops::Deref; use embedded_hal::serial; @@ -114,10 +113,12 @@ impl Serial { } } -impl serial::Read for Rx { - type Error = Infallible; +impl serial::ErrorType for Rx { + type Error = serial::ErrorKind; +} - fn read(&mut self) -> nb::Result { +impl serial::nb::Read for Rx { + fn read(&mut self) -> nb::Result { let rxdata = self.uart.rxdata.read(); if rxdata.empty().bit_is_set() { @@ -128,10 +129,12 @@ impl serial::Read for Rx { } } -impl serial::Write for Tx { - type Error = Infallible; +impl serial::ErrorType for Tx { + type Error = serial::ErrorKind; +} - fn write(&mut self, byte: u8) -> nb::Result<(), Infallible> { +impl serial::nb::Write for Tx { + fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { let txdata = self.uart.txdata.read(); if txdata.full().bit_is_set() { @@ -144,7 +147,7 @@ impl serial::Write for Tx { } } - fn flush(&mut self) -> nb::Result<(), Infallible> { + fn flush(&mut self) -> nb::Result<(), Self::Error> { if self.uart.ip.read().txwm().bit_is_set() { // FIFO count is below the receive watermark (1) Ok(()) diff --git a/src/spi.rs b/src/spi.rs index d508849..5c447a2 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -24,7 +24,7 @@ //! - Interrupt::QSPI2 //! //! # Exclusive Bus usage example -//!``` +//!```ignore //! let pins = (mosi, miso, sck, cs0); //! let spi_bus = SpiBus::new(p.QSPI1, pins); //! @@ -35,7 +35,7 @@ //!``` //! //! # Shared Bus usage example -//!``` +//!```ignore //! let pins = (mosi, miso, sck); //! let spi_bus = SpiBus::shared(p.QSPI1, pins); //! diff --git a/src/spi/bus.rs b/src/spi/bus.rs index 94ea72b..e60285d 100644 --- a/src/spi/bus.rs +++ b/src/spi/bus.rs @@ -1,9 +1,7 @@ -use core::convert::Infallible; -use embedded_hal::blocking::spi::Operation; -pub use embedded_hal::blocking::spi::{Transfer, Write, WriteIter}; -pub use embedded_hal::spi::{FullDuplex, Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; - -use nb; +use embedded_hal::spi::blocking::{SpiBus as SpiBusTransfer, SpiBusFlush}; +use embedded_hal::spi::blocking::{SpiBusRead, SpiBusWrite}; +use embedded_hal::spi::ErrorType; +pub use embedded_hal::spi::{ErrorKind, Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use super::{Pins, PinsNoCS, SharedBus, SpiConfig, SpiExclusiveDevice, SpiX}; @@ -101,39 +99,20 @@ where } } - // ex-traits now only accessible via devices - - pub(crate) fn read(&mut self) -> nb::Result { - let rxdata = self.spi.rxdata.read(); - - if rxdata.empty().bit_is_set() { - Err(nb::Error::WouldBlock) - } else { - Ok(rxdata.data().bits()) - } - } - - pub(crate) fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { - let txdata = self.spi.txdata.read(); - - if txdata.full().bit_is_set() { - Err(nb::Error::WouldBlock) - } else { - self.spi.txdata.write(|w| unsafe { w.data().bits(byte) }); - Ok(()) - } - } - - pub(crate) fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Infallible> { + /// Transfer implementation out of trait for reuse in Read and Write + fn perform_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), ErrorKind> { let mut iwrite = 0; let mut iread = 0; + let bytes = core::cmp::max(read.len(), write.len()); // Ensure that RX FIFO is empty self.wait_for_rxfifo(); - while iwrite < words.len() || iread < words.len() { - if iwrite < words.len() && self.spi.txdata.read().full().bit_is_clear() { - let byte = unsafe { words.get_unchecked(iwrite) }; + // go through entire write buffer and read back (even if read buffer is empty) + // while iwrite < write.len() || iread < write.len() { + while iwrite < bytes || iread < bytes { + if iwrite < write.len() && self.spi.txdata.read().full().bit_is_clear() { + let byte = write.get(iwrite).unwrap_or(&0); iwrite += 1; self.spi.txdata.write(|w| unsafe { w.data().bits(*byte) }); } @@ -141,16 +120,59 @@ where if iread < iwrite { let data = self.spi.rxdata.read(); if data.empty().bit_is_clear() { - unsafe { *words.get_unchecked_mut(iread) = data.data().bits() }; + if let Some(d) = read.get_mut(iread) { + *d = data.data().bits() + }; iread += 1; } } } - Ok(words) + Ok(()) + } +} + +impl ErrorType for SpiBus { + type Error = ErrorKind; +} + +impl SpiBusFlush for SpiBus +where + SPI: SpiX, +{ + fn flush(&mut self) -> Result<(), Self::Error> { + // unnecessary as all Bus operations always wait for reads to finish + + Ok(()) + } +} +impl SpiBusRead for SpiBus +where + SPI: SpiX, +{ + fn read(&mut self, words: &mut [u8]) -> Result<(), ErrorKind> { + self.perform_transfer(words, &[]) + } +} + +impl SpiBusWrite for SpiBus +where + SPI: SpiX, +{ + fn write(&mut self, words: &[u8]) -> Result<(), ErrorKind> { + self.perform_transfer(&mut [], words) + } +} + +impl SpiBusTransfer for SpiBus +where + SPI: SpiX, +{ + fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), ErrorKind> { + self.perform_transfer(read, write) } - pub(crate) fn write(&mut self, words: &[u8]) -> Result<(), Infallible> { + fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), ErrorKind> { let mut iwrite = 0; let mut iread = 0; @@ -165,8 +187,9 @@ where } if iread < iwrite { - // Read and discard byte, if any - if self.spi.rxdata.read().empty().bit_is_clear() { + let data = self.spi.rxdata.read(); + if data.empty().bit_is_clear() { + unsafe { *words.get_unchecked_mut(iread) = data.data().bits() }; iread += 1; } } @@ -174,57 +197,6 @@ where Ok(()) } - - pub(crate) fn write_iter(&mut self, words: WI) -> Result<(), Infallible> - where - WI: IntoIterator, - { - let mut iter = words.into_iter(); - - let mut read_count = 0; - let mut has_data = true; - - // Ensure that RX FIFO is empty - self.wait_for_rxfifo(); - - while has_data || read_count > 0 { - if has_data && self.spi.txdata.read().full().bit_is_clear() { - if let Some(byte) = iter.next() { - self.spi.txdata.write(|w| unsafe { w.data().bits(byte) }); - read_count += 1; - } else { - has_data = false; - } - } - - if read_count > 0 { - // Read and discard byte, if any - if self.spi.rxdata.read().empty().bit_is_clear() { - read_count -= 1; - } - } - } - - Ok(()) - } - - pub(crate) fn exec<'op>( - &mut self, - operations: &mut [Operation<'op, u8>], - ) -> Result<(), Infallible> { - for op in operations { - match op { - Operation::Transfer(words) => { - self.transfer(words)?; - } - Operation::Write(words) => { - self.write(words)?; - } - } - } - - Ok(()) - } } impl SpiBus diff --git a/src/spi/exclusive_device.rs b/src/spi/exclusive_device.rs index d9e808e..1dc5c15 100644 --- a/src/spi/exclusive_device.rs +++ b/src/spi/exclusive_device.rs @@ -1,9 +1,4 @@ -use core::convert::Infallible; - -use embedded_hal::{ - blocking::spi::{Operation, Transactional, Transfer, Write, WriteIter}, - spi::FullDuplex, -}; +use embedded_hal::spi::{blocking::SpiDevice, ErrorKind, ErrorType}; use crate::spi::SpiConfig; @@ -36,85 +31,25 @@ where } } -impl FullDuplex for SpiExclusiveDevice -where - SPI: SpiX, - PINS: Pins, -{ - type Error = Infallible; - - fn read(&mut self) -> nb::Result { - self.bus.read() - } - - fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { - self.bus.send(byte) - } -} - -impl Transfer for SpiExclusiveDevice -where - SPI: SpiX, - PINS: Pins, -{ - type Error = Infallible; - - fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { - self.bus.start_frame(); - let result = self.bus.transfer(words); - self.bus.end_frame(); - - result - } -} - -impl Write for SpiExclusiveDevice -where - SPI: SpiX, - PINS: Pins, -{ - type Error = Infallible; - - fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { - self.bus.start_frame(); - let result = self.bus.write(words); - self.bus.end_frame(); - - result - } -} - -impl WriteIter for SpiExclusiveDevice -where - SPI: SpiX, - PINS: Pins, -{ - type Error = Infallible; - - fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> - where - WI: IntoIterator, - { - self.bus.start_frame(); - let result = self.bus.write_iter(words); - self.bus.end_frame(); - - result - } +impl ErrorType for SpiExclusiveDevice { + type Error = ErrorKind; } -impl Transactional for SpiExclusiveDevice +impl SpiDevice for SpiExclusiveDevice where SPI: SpiX, PINS: Pins, { - type Error = Infallible; + type Bus = SpiBus; - fn exec<'op>(&mut self, operations: &mut [Operation<'op, u8>]) -> Result<(), Infallible> { + fn transaction( + &mut self, + f: impl FnOnce(&mut Self::Bus) -> Result::Error>, + ) -> Result { self.bus.start_frame(); - let result = self.bus.exec(operations); + let result = f(&mut self.bus)?; self.bus.end_frame(); - result + Ok(result) } } diff --git a/src/spi/shared_bus.rs b/src/spi/shared_bus.rs index ab10025..60ad1ca 100644 --- a/src/spi/shared_bus.rs +++ b/src/spi/shared_bus.rs @@ -1,5 +1,6 @@ use core::cell::RefCell; use core::ops::Deref; +use embedded_hal::spi::{ErrorKind, ErrorType}; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use riscv::interrupt; use riscv::interrupt::Mutex; @@ -10,6 +11,10 @@ use super::{PinCS, PinsNoCS, SpiBus, SpiConfig, SpiSharedDevice, SpiX}; /// Used to hold the [SpiBus] instance so it can be used for multiple [SpiSharedDevice] instances. pub struct SharedBus(Mutex>>); +impl ErrorType for SharedBus { + type Error = ErrorKind; +} + impl SharedBus where SPI: SpiX, diff --git a/src/spi/shared_device.rs b/src/spi/shared_device.rs index e611273..4d0d9fe 100644 --- a/src/spi/shared_device.rs +++ b/src/spi/shared_device.rs @@ -1,12 +1,9 @@ -use core::convert::Infallible; +use core::ops::DerefMut; -use embedded_hal::{ - blocking::spi::{Operation, Transactional, Transfer, Write, WriteIter}, - spi::FullDuplex, -}; +use embedded_hal::spi::{blocking::SpiDevice, ErrorKind, ErrorType}; use riscv::interrupt; -use super::{PinCS, Pins, PinsNoCS, SharedBus, SpiConfig, SpiX}; +use super::{PinCS, PinsNoCS, SharedBus, SpiBus, SpiConfig, SpiX}; /// SPI shared device abstraction pub struct SpiSharedDevice<'bus, SPI, PINS, CS> { @@ -40,126 +37,37 @@ where } } -impl FullDuplex for SpiSharedDevice<'_, SPI, PINS, CS> -where - SPI: SpiX, - PINS: Pins, - CS: PinCS, -{ - type Error = Infallible; - - fn read(&mut self) -> nb::Result { - interrupt::free(|cs| { - let mut bus = self.bus.borrow(*cs).borrow_mut(); - - bus.configure(&self.config, Some(CS::CS_INDEX)); - - bus.read() - }) - } - - fn send(&mut self, byte: u8) -> nb::Result<(), Infallible> { - interrupt::free(|cs| { - let mut bus = self.bus.borrow(*cs).borrow_mut(); - - bus.configure(&self.config, Some(CS::CS_INDEX)); - - bus.send(byte) - }) - } -} - -impl Transfer for SpiSharedDevice<'_, SPI, PINS, CS> -where - SPI: SpiX, - PINS: Pins, - CS: PinCS, -{ - type Error = Infallible; - - fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { - interrupt::free(move |cs| { - let mut bus = self.bus.borrow(*cs).borrow_mut(); - - bus.configure(&self.config, Some(CS::CS_INDEX)); - - bus.start_frame(); - let result = bus.transfer(words); - bus.end_frame(); - - result - }) - } +impl ErrorType for SpiSharedDevice<'_, SPI, PINS, CS> { + type Error = ErrorKind; } -impl Write for SpiSharedDevice<'_, SPI, PINS, CS> +impl SpiDevice for SpiSharedDevice<'_, SPI, PINS, CS> where SPI: SpiX, - PINS: Pins, + PINS: PinsNoCS, CS: PinCS, { - type Error = Infallible; + type Bus = SpiBus; + // type Bus = RefMut<'bus, SpiBus>; - fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { - interrupt::free(|cs| { - let mut bus = self.bus.borrow(*cs).borrow_mut(); - - bus.configure(&self.config, Some(CS::CS_INDEX)); + fn transaction( + &mut self, + f: impl FnOnce(&mut Self::Bus) -> Result::Error>, + ) -> Result { + let mut result = Err(ErrorKind::Other); - bus.start_frame(); - let result = bus.write(words); - bus.end_frame(); - - result - }) - } -} - -impl WriteIter for SpiSharedDevice<'_, SPI, PINS, CS> -where - SPI: SpiX, - PINS: Pins, - CS: PinCS, -{ - type Error = Infallible; - - fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> - where - WI: IntoIterator, - { interrupt::free(|cs| { let mut bus = self.bus.borrow(*cs).borrow_mut(); bus.configure(&self.config, Some(CS::CS_INDEX)); bus.start_frame(); - let result = bus.write_iter(words); + result = f(bus.deref_mut()); bus.end_frame(); - result - }) - } -} - -impl Transactional for SpiSharedDevice<'_, SPI, PINS, CS> -where - SPI: SpiX, - PINS: Pins, - CS: PinCS, -{ - type Error = Infallible; - - fn exec<'op>(&mut self, operations: &mut [Operation<'op, u8>]) -> Result<(), Infallible> { - interrupt::free(|cs| { - let mut bus = self.bus.borrow(*cs).borrow_mut(); - - bus.configure(&self.config, Some(CS::CS_INDEX)); - - bus.start_frame(); - let result = bus.exec(operations); - bus.end_frame(); + 0 + }); - result - }) + result } } diff --git a/src/stdout.rs b/src/stdout.rs index 004bcc8..516a280 100644 --- a/src/stdout.rs +++ b/src/stdout.rs @@ -10,7 +10,7 @@ where impl<'p, T> Write for Stdout<'p, T> where - T: embedded_hal::serial::Write, + T: embedded_hal::serial::nb::Write, { fn write_str(&mut self, s: &str) -> ::core::fmt::Result { for byte in s.as_bytes() {