SPI and related changes (#2681)

* Define Octal SpiDataMode

* Fix BitOrder capitalization

* Hide DmaError

* Derive more traits

* Return error for unsupported half-duplex parameter combinations

* Remove unnecessary implementation detail

* Return error instead of silently breaking transaction

* Downgrade assert to debug_assert

* Expand on the enum variants

* Remove redundant imports

* Hide some unstable functions
This commit is contained in:
Dániel Buga 2024-12-06 11:30:43 +01:00 committed by GitHub
parent d86a079ea9
commit 6b01f7993b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 141 additions and 108 deletions

View File

@ -18,6 +18,8 @@ use core::{
/// ///
/// but it is the size of `T` not the size /// but it is the size of `T` not the size
/// of a pointer. This is useful if T is a zero sized type. /// of a pointer. This is useful if T is a zero sized type.
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PeripheralRef<'a, T> { pub struct PeripheralRef<'a, T> {
inner: T, inner: T,
_lifetime: PhantomData<&'a mut T>, _lifetime: PhantomData<&'a mut T>,

View File

@ -41,7 +41,6 @@
//! let sclk = peripherals.GPIO0; //! let sclk = peripherals.GPIO0;
//! let miso = peripherals.GPIO2; //! let miso = peripherals.GPIO2;
//! let mosi = peripherals.GPIO1; //! let mosi = peripherals.GPIO1;
//! let cs = peripherals.GPIO5;
//! //!
//! let mut spi = Spi::new( //! let mut spi = Spi::new(
//! peripherals.SPI2, //! peripherals.SPI2,
@ -50,8 +49,7 @@
//! .unwrap() //! .unwrap()
//! .with_sck(sclk) //! .with_sck(sclk)
//! .with_mosi(mosi) //! .with_mosi(mosi)
//! .with_miso(miso) //! .with_miso(miso);
//! .with_cs(cs);
//! # } //! # }
//! ``` //! ```
//! //!
@ -89,7 +87,7 @@ use crate::{
/// Enumeration of possible SPI interrupt events. /// Enumeration of possible SPI interrupt events.
#[cfg(gdma)] #[cfg(gdma)]
#[derive(Debug, EnumSetType)] #[derive(Debug, Hash, EnumSetType)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
pub enum SpiInterrupt { pub enum SpiInterrupt {
@ -101,10 +99,7 @@ pub enum SpiInterrupt {
} }
/// The size of the FIFO buffer for SPI /// The size of the FIFO buffer for SPI
#[cfg(not(esp32s2))] const FIFO_SIZE: usize = if cfg!(esp32s2) { 72 } else { 64 };
const FIFO_SIZE: usize = 64;
#[cfg(esp32s2)]
const FIFO_SIZE: usize = 72;
/// Padding byte for empty write transfers /// Padding byte for empty write transfers
const EMPTY_WRITE_PAD: u8 = 0x00; const EMPTY_WRITE_PAD: u8 = 0x00;
@ -115,42 +110,43 @@ const MAX_DMA_SIZE: usize = 32736;
/// ///
/// Used to define specific commands sent over the SPI bus. /// Used to define specific commands sent over the SPI bus.
/// Can be [Command::None] if command phase should be suppressed. /// Can be [Command::None] if command phase should be suppressed.
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Command { pub enum Command {
/// No command is sent. /// No command is sent.
None, None,
/// Command1. /// A 1-bit command.
Command1(u16, SpiDataMode), Command1(u16, SpiDataMode),
/// Command2. /// A 2-bit command.
Command2(u16, SpiDataMode), Command2(u16, SpiDataMode),
/// Command3. /// A 3-bit command.
Command3(u16, SpiDataMode), Command3(u16, SpiDataMode),
/// Command4. /// A 4-bit command.
Command4(u16, SpiDataMode), Command4(u16, SpiDataMode),
/// Command5. /// A 5-bit command.
Command5(u16, SpiDataMode), Command5(u16, SpiDataMode),
/// Command6. /// A 6-bit command.
Command6(u16, SpiDataMode), Command6(u16, SpiDataMode),
/// Command7. /// A 7-bit command.
Command7(u16, SpiDataMode), Command7(u16, SpiDataMode),
/// Command8. /// A 8-bit command.
Command8(u16, SpiDataMode), Command8(u16, SpiDataMode),
/// Command9. /// A 9-bit command.
Command9(u16, SpiDataMode), Command9(u16, SpiDataMode),
/// Command10. /// A 10-bit command.
Command10(u16, SpiDataMode), Command10(u16, SpiDataMode),
/// Command11. /// A 11-bit command.
Command11(u16, SpiDataMode), Command11(u16, SpiDataMode),
/// Command12. /// A 12-bit command.
Command12(u16, SpiDataMode), Command12(u16, SpiDataMode),
/// Command13. /// A 13-bit command.
Command13(u16, SpiDataMode), Command13(u16, SpiDataMode),
/// Command14. /// A 14-bit command.
Command14(u16, SpiDataMode), Command14(u16, SpiDataMode),
/// Command15. /// A 15-bit command.
Command15(u16, SpiDataMode), Command15(u16, SpiDataMode),
/// Command16. /// A 16-bit command.
Command16(u16, SpiDataMode), Command16(u16, SpiDataMode),
} }
@ -230,74 +226,75 @@ impl Command {
/// ///
/// This can be used to specify the address phase of SPI transactions. /// This can be used to specify the address phase of SPI transactions.
/// Can be [Address::None] if address phase should be suppressed. /// Can be [Address::None] if address phase should be suppressed.
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Address { pub enum Address {
/// No address phase. /// No address phase.
None, None,
/// Address with 1-bit. /// A 1-bit address.
Address1(u32, SpiDataMode), Address1(u32, SpiDataMode),
/// Address with 2-bit. /// A 2-bit address.
Address2(u32, SpiDataMode), Address2(u32, SpiDataMode),
/// Address with 3-bit. /// A 3-bit address.
Address3(u32, SpiDataMode), Address3(u32, SpiDataMode),
/// Address with 4-bit. /// A 4-bit address.
Address4(u32, SpiDataMode), Address4(u32, SpiDataMode),
/// Address with 5-bit. /// A 5-bit address.
Address5(u32, SpiDataMode), Address5(u32, SpiDataMode),
/// Address with 6-bit. /// A 6-bit address.
Address6(u32, SpiDataMode), Address6(u32, SpiDataMode),
/// Address with 7-bit. /// A 7-bit address.
Address7(u32, SpiDataMode), Address7(u32, SpiDataMode),
/// Address with 8-bit. /// A 8-bit address.
Address8(u32, SpiDataMode), Address8(u32, SpiDataMode),
/// Address with 9-bit. /// A 9-bit address.
Address9(u32, SpiDataMode), Address9(u32, SpiDataMode),
/// Address with 10-bit. /// A 10-bit address.
Address10(u32, SpiDataMode), Address10(u32, SpiDataMode),
/// Address with 11-bit. /// A 11-bit address.
Address11(u32, SpiDataMode), Address11(u32, SpiDataMode),
/// Address with 12-bit. /// A 12-bit address.
Address12(u32, SpiDataMode), Address12(u32, SpiDataMode),
/// Address with 13-bit. /// A 13-bit address.
Address13(u32, SpiDataMode), Address13(u32, SpiDataMode),
/// Address with 14-bit. /// A 14-bit address.
Address14(u32, SpiDataMode), Address14(u32, SpiDataMode),
/// Address with 15-bit. /// A 15-bit address.
Address15(u32, SpiDataMode), Address15(u32, SpiDataMode),
/// Address with 16-bit. /// A 16-bit address.
Address16(u32, SpiDataMode), Address16(u32, SpiDataMode),
/// Address with 17-bit. /// A 17-bit address.
Address17(u32, SpiDataMode), Address17(u32, SpiDataMode),
/// Address with 18-bit. /// A 18-bit address.
Address18(u32, SpiDataMode), Address18(u32, SpiDataMode),
/// Address with 19-bit. /// A 19-bit address.
Address19(u32, SpiDataMode), Address19(u32, SpiDataMode),
/// Address with 20-bit. /// A 20-bit address.
Address20(u32, SpiDataMode), Address20(u32, SpiDataMode),
/// Address with 21-bit. /// A 21-bit address.
Address21(u32, SpiDataMode), Address21(u32, SpiDataMode),
/// Address with 22-bit. /// A 22-bit address.
Address22(u32, SpiDataMode), Address22(u32, SpiDataMode),
/// Address with 23-bit. /// A 23-bit address.
Address23(u32, SpiDataMode), Address23(u32, SpiDataMode),
/// Address with 24-bit. /// A 24-bit address.
Address24(u32, SpiDataMode), Address24(u32, SpiDataMode),
/// Address with 25-bit. /// A 25-bit address.
Address25(u32, SpiDataMode), Address25(u32, SpiDataMode),
/// Address with 26-bit. /// A 26-bit address.
Address26(u32, SpiDataMode), Address26(u32, SpiDataMode),
/// Address with 27-bit. /// A 27-bit address.
Address27(u32, SpiDataMode), Address27(u32, SpiDataMode),
/// Address with 28-bit. /// A 28-bit address.
Address28(u32, SpiDataMode), Address28(u32, SpiDataMode),
/// Address with 29-bit. /// A 29-bit address.
Address29(u32, SpiDataMode), Address29(u32, SpiDataMode),
/// Address with 30-bit. /// A 30-bit address.
Address30(u32, SpiDataMode), Address30(u32, SpiDataMode),
/// Address with 31-bit. /// A 31-bit address.
Address31(u32, SpiDataMode), Address31(u32, SpiDataMode),
/// Address with 32-bit. /// A 32-bit address.
Address32(u32, SpiDataMode), Address32(u32, SpiDataMode),
} }
@ -422,14 +419,14 @@ impl Address {
} }
/// SPI peripheral configuration /// SPI peripheral configuration
#[derive(Clone, Copy, Debug, procmacros::BuilderLite)] #[derive(Clone, Copy, Debug, PartialEq, Eq, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
pub struct Config { pub struct Config {
/// SPI clock frequency /// SPI bus clock frequency.
pub frequency: HertzU32, pub frequency: HertzU32,
/// SPI mode /// SPI sample/shift mode.
pub mode: SpiMode, pub mode: SpiMode,
/// Bit order of the read data. /// Bit order of the read data.
@ -445,18 +442,21 @@ impl Default for Config {
Config { Config {
frequency: 1_u32.MHz(), frequency: 1_u32.MHz(),
mode: SpiMode::Mode0, mode: SpiMode::Mode0,
read_bit_order: SpiBitOrder::MSBFirst, read_bit_order: SpiBitOrder::MsbFirst,
write_bit_order: SpiBitOrder::MSBFirst, write_bit_order: SpiBitOrder::MsbFirst,
} }
} }
} }
/// Configuration errors. /// Configuration errors.
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ConfigError {} pub enum ConfigError {}
/// SPI peripheral driver /// SPI peripheral driver
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Spi<'d, M, T = AnySpi> { pub struct Spi<'d, M, T = AnySpi> {
spi: PeripheralRef<'d, T>, spi: PeripheralRef<'d, T>,
_mode: PhantomData<M>, _mode: PhantomData<M>,
@ -486,10 +486,6 @@ where
} }
/// Write bytes to SPI. /// Write bytes to SPI.
///
/// Copies the content of `words` in chunks of 64 bytes into the SPI
/// transmission FIFO. If `words` is longer than 64 bytes, multiple
/// sequential transfers are performed.
pub fn write_bytes(&mut self, words: &[u8]) -> Result<(), Error> { pub fn write_bytes(&mut self, words: &[u8]) -> Result<(), Error> {
self.driver().write_bytes(words)?; self.driver().write_bytes(words)?;
self.driver().flush()?; self.driver().flush()?;
@ -531,6 +527,7 @@ where
/// This method prepares the SPI instance for DMA transfers using SPI /// This method prepares the SPI instance for DMA transfers using SPI
/// and returns an instance of `SpiDma` that supports DMA /// and returns an instance of `SpiDma` that supports DMA
/// operations. /// operations.
#[instability::unstable]
pub fn with_dma<CH>(self, channel: impl Peripheral<P = CH> + 'd) -> SpiDma<'d, Blocking, T> pub fn with_dma<CH>(self, channel: impl Peripheral<P = CH> + 'd) -> SpiDma<'d, Blocking, T>
where where
CH: DmaChannelFor<T>, CH: DmaChannelFor<T>,
@ -638,6 +635,7 @@ where
/// ///
/// Sets the specified pin to push-pull output and connects it to the SPI CS /// Sets the specified pin to push-pull output and connects it to the SPI CS
/// signal. /// signal.
#[instability::unstable]
pub fn with_cs<CS: PeripheralOutput>(self, cs: impl Peripheral<P = CS> + 'd) -> Self { pub fn with_cs<CS: PeripheralOutput>(self, cs: impl Peripheral<P = CS> + 'd) -> Self {
crate::into_mapped_ref!(cs); crate::into_mapped_ref!(cs);
cs.set_to_push_pull_output(private::Internal); cs.set_to_push_pull_output(private::Internal);
@ -713,6 +711,7 @@ where
T: Instance, T: Instance,
{ {
/// Half-duplex read. /// Half-duplex read.
#[instability::unstable]
pub fn half_duplex_read( pub fn half_duplex_read(
&mut self, &mut self,
data_mode: SpiDataMode, data_mode: SpiDataMode,
@ -737,7 +736,7 @@ where
dummy, dummy,
buffer.is_empty(), buffer.is_empty(),
data_mode, data_mode,
); )?;
self.driver().configure_datalen(buffer.len(), 0); self.driver().configure_datalen(buffer.len(), 0);
self.driver().start_operation(); self.driver().start_operation();
@ -746,6 +745,7 @@ where
} }
/// Half-duplex write. /// Half-duplex write.
#[instability::unstable]
pub fn half_duplex_write( pub fn half_duplex_write(
&mut self, &mut self,
data_mode: SpiDataMode, data_mode: SpiDataMode,
@ -775,6 +775,11 @@ where
data_mode = address.mode(); data_mode = address.mode();
address = Address::None; address = Address::None;
} }
if dummy > 0 {
// FIXME: https://github.com/esp-rs/esp-hal/issues/2240
return Err(Error::Unsupported);
}
} }
} }
@ -786,7 +791,7 @@ where
dummy, dummy,
buffer.is_empty(), buffer.is_empty(),
data_mode, data_mode,
); )?;
if !buffer.is_empty() { if !buffer.is_empty() {
// re-using the full-duplex write here // re-using the full-duplex write here
@ -812,17 +817,11 @@ mod dma {
asynch::{DmaRxFuture, DmaTxFuture}, asynch::{DmaRxFuture, DmaTxFuture},
Channel, Channel,
DmaRxBuf, DmaRxBuf,
DmaRxBuffer,
DmaTxBuf, DmaTxBuf,
DmaTxBuffer,
EmptyBuf, EmptyBuf,
PeripheralDmaChannel, PeripheralDmaChannel,
Rx,
Tx,
}, },
interrupt::InterruptConfigurable, interrupt::InterruptConfigurable,
Async,
Blocking,
}; };
/// A DMA capable SPI instance. /// A DMA capable SPI instance.
@ -1100,6 +1099,11 @@ mod dma {
address: Address, address: Address,
dummy: u8, dummy: u8,
) -> Result<(), Error> { ) -> Result<(), Error> {
if dummy > 0 {
// FIXME: https://github.com/esp-rs/esp-hal/issues/2240
return Err(Error::Unsupported);
}
let bytes_to_write = address.width().div_ceil(8); let bytes_to_write = address.width().div_ceil(8);
// The address register is read in big-endian order, // The address register is read in big-endian order,
// we have to prepare the emulated write in the same way. // we have to prepare the emulated write in the same way.
@ -1115,7 +1119,7 @@ mod dma {
dummy, dummy,
bytes_to_write == 0, bytes_to_write == 0,
address.mode(), address.mode(),
); )?;
// FIXME: we could use self.start_transfer_dma if the address buffer was part of // FIXME: we could use self.start_transfer_dma if the address buffer was part of
// the (yet-to-be-created) State struct. // the (yet-to-be-created) State struct.
@ -1411,7 +1415,7 @@ mod dma {
dummy, dummy,
bytes_to_read == 0, bytes_to_read == 0,
data_mode, data_mode,
); )?;
self.start_transfer_dma(false, bytes_to_read, 0, buffer, &mut EmptyBuf) self.start_transfer_dma(false, bytes_to_read, 0, buffer, &mut EmptyBuf)
} }
@ -1476,7 +1480,7 @@ mod dma {
dummy, dummy,
bytes_to_write == 0, bytes_to_write == 0,
data_mode, data_mode,
); )?;
self.start_transfer_dma(false, 0, bytes_to_write, &mut EmptyBuf, buffer) self.start_transfer_dma(false, 0, bytes_to_write, &mut EmptyBuf, buffer)
} }
@ -1749,7 +1753,7 @@ mod dma {
buffer: &mut [u8], buffer: &mut [u8],
) -> Result<(), Error> { ) -> Result<(), Error> {
if buffer.len() > self.rx_buf.capacity() { if buffer.len() > self.rx_buf.capacity() {
return Err(Error::DmaError(DmaError::Overflow)); return Err(Error::from(DmaError::Overflow));
} }
self.wait_for_idle(); self.wait_for_idle();
self.rx_buf.set_length(buffer.len()); self.rx_buf.set_length(buffer.len());
@ -1783,7 +1787,7 @@ mod dma {
buffer: &[u8], buffer: &[u8],
) -> Result<(), Error> { ) -> Result<(), Error> {
if buffer.len() > self.tx_buf.capacity() { if buffer.len() > self.tx_buf.capacity() {
return Err(Error::DmaError(DmaError::Overflow)); return Err(Error::from(DmaError::Overflow));
} }
self.wait_for_idle(); self.wait_for_idle();
self.tx_buf.fill(buffer); self.tx_buf.fill(buffer);
@ -1828,7 +1832,6 @@ mod dma {
}; };
use super::*; use super::*;
use crate::Async;
struct DropGuard<I, F: FnOnce(I)> { struct DropGuard<I, F: FnOnce(I)> {
inner: ManuallyDrop<I>, inner: ManuallyDrop<I>,
@ -1952,7 +1955,7 @@ mod dma {
spi.wait_for_idle_async().await; spi.wait_for_idle_async().await;
let bytes_read = self.rx_buf.read_received_data(read_chunk); let bytes_read = self.rx_buf.read_received_data(read_chunk);
assert_eq!(bytes_read, read_chunk.len()); debug_assert_eq!(bytes_read, read_chunk.len());
} }
spi.defuse(); spi.defuse();
@ -1987,7 +1990,7 @@ mod dma {
spi.wait_for_idle_async().await; spi.wait_for_idle_async().await;
let bytes_read = self.rx_buf.read_received_data(chunk); let bytes_read = self.rx_buf.read_received_data(chunk);
assert_eq!(bytes_read, chunk.len()); debug_assert_eq!(bytes_read, chunk.len());
} }
spi.defuse(); spi.defuse();
@ -2421,7 +2424,7 @@ impl Info {
cmd_mode: SpiDataMode, cmd_mode: SpiDataMode,
address_mode: SpiDataMode, address_mode: SpiDataMode,
data_mode: SpiDataMode, data_mode: SpiDataMode,
) { ) -> Result<(), Error> {
let reg_block = self.register_block(); let reg_block = self.register_block();
reg_block.ctrl().modify(|_, w| { reg_block.ctrl().modify(|_, w| {
w.fcmd_dual().bit(cmd_mode == SpiDataMode::Dual); w.fcmd_dual().bit(cmd_mode == SpiDataMode::Dual);
@ -2435,6 +2438,7 @@ impl Info {
w.fwrite_dual().bit(data_mode == SpiDataMode::Dual); w.fwrite_dual().bit(data_mode == SpiDataMode::Dual);
w.fwrite_quad().bit(data_mode == SpiDataMode::Quad) w.fwrite_quad().bit(data_mode == SpiDataMode::Quad)
}); });
Ok(())
} }
#[cfg(esp32)] #[cfg(esp32)]
@ -2443,11 +2447,12 @@ impl Info {
cmd_mode: SpiDataMode, cmd_mode: SpiDataMode,
address_mode: SpiDataMode, address_mode: SpiDataMode,
data_mode: SpiDataMode, data_mode: SpiDataMode,
) { ) -> Result<(), Error> {
let reg_block = self.register_block(); let reg_block = self.register_block();
match cmd_mode { match cmd_mode {
SpiDataMode::Single => (), SpiDataMode::Single => (),
_ => panic!("Only 1-bit command supported"), // FIXME: more detailed error - Only 1-bit commands are supported.
_ => return Err(Error::Unsupported),
} }
match address_mode { match address_mode {
@ -2482,8 +2487,11 @@ impl Info {
w.fwrite_quad().clear_bit() w.fwrite_quad().clear_bit()
}); });
} }
_ => panic!("Unsupported combination of data-modes"), // FIXME: more detailed error - Unsupported combination of data-modes,
_ => return Err(Error::Unsupported),
} }
Ok(())
} }
// taken from https://github.com/apache/incubator-nuttx/blob/8267a7618629838231256edfa666e44b5313348e/arch/risc-v/src/esp32c3/esp32c3_spi.c#L496 // taken from https://github.com/apache/incubator-nuttx/blob/8267a7618629838231256edfa666e44b5313348e/arch/risc-v/src/esp32c3/esp32c3_spi.c#L496
@ -2670,12 +2678,12 @@ impl Info {
let reg_block = self.register_block(); let reg_block = self.register_block();
let read_value = match read_order { let read_value = match read_order {
SpiBitOrder::MSBFirst => 0, SpiBitOrder::MsbFirst => 0,
SpiBitOrder::LSBFirst => 1, SpiBitOrder::LsbFirst => 1,
}; };
let write_value = match write_order { let write_value = match write_order {
SpiBitOrder::MSBFirst => 0, SpiBitOrder::MsbFirst => 0,
SpiBitOrder::LSBFirst => 1, SpiBitOrder::LsbFirst => 1,
}; };
reg_block.ctrl().modify(|_, w| unsafe { reg_block.ctrl().modify(|_, w| unsafe {
w.rd_bit_order().bits(read_value); w.rd_bit_order().bits(read_value);
@ -2689,12 +2697,12 @@ impl Info {
let reg_block = self.register_block(); let reg_block = self.register_block();
let read_value = match read_order { let read_value = match read_order {
SpiBitOrder::MSBFirst => false, SpiBitOrder::MsbFirst => false,
SpiBitOrder::LSBFirst => true, SpiBitOrder::LsbFirst => true,
}; };
let write_value = match write_order { let write_value = match write_order {
SpiBitOrder::MSBFirst => false, SpiBitOrder::MsbFirst => false,
SpiBitOrder::LSBFirst => true, SpiBitOrder::LsbFirst => true,
}; };
reg_block.ctrl().modify(|_, w| { reg_block.ctrl().modify(|_, w| {
w.rd_bit_order().bit(read_value); w.rd_bit_order().bit(read_value);
@ -2869,8 +2877,8 @@ impl Info {
dummy: u8, dummy: u8,
no_mosi_miso: bool, no_mosi_miso: bool,
data_mode: SpiDataMode, data_mode: SpiDataMode,
) { ) -> Result<(), Error> {
self.init_spi_data_mode(cmd.mode(), address.mode(), data_mode); self.init_spi_data_mode(cmd.mode(), address.mode(), data_mode)?;
let reg_block = self.register_block(); let reg_block = self.register_block();
reg_block.user().modify(|_, w| { reg_block.user().modify(|_, w| {
@ -2911,6 +2919,8 @@ impl Info {
// set cmd, address, dummy cycles // set cmd, address, dummy cycles
self.set_up_common_phases(cmd, address, dummy); self.set_up_common_phases(cmd, address, dummy);
Ok(())
} }
fn set_up_common_phases(&self, cmd: Command, address: Address, dummy: u8) { fn set_up_common_phases(&self, cmd: Command, address: Address, dummy: u8) {

View File

@ -15,11 +15,13 @@ pub mod master;
pub mod slave; pub mod slave;
/// SPI errors /// SPI errors
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
pub enum Error { pub enum Error {
/// Error occurred due to a DMA-related issue. /// Error occurred due to a DMA-related issue.
#[cfg(any(doc, feature = "unstable"))]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
DmaError(DmaError), DmaError(DmaError),
/// Error indicating that the maximum DMA transfer size was exceeded. /// Error indicating that the maximum DMA transfer size was exceeded.
MaxDmaTransferSizeExceeded, MaxDmaTransferSizeExceeded,
@ -33,12 +35,22 @@ pub enum Error {
Unknown, Unknown,
} }
#[doc(hidden)]
#[cfg(any(doc, feature = "unstable"))]
impl From<DmaError> for Error { impl From<DmaError> for Error {
fn from(value: DmaError) -> Self { fn from(value: DmaError) -> Self {
Error::DmaError(value) Error::DmaError(value)
} }
} }
#[doc(hidden)]
#[cfg(not(any(doc, feature = "unstable")))]
impl From<DmaError> for Error {
fn from(_value: DmaError) -> Self {
Error::Unknown
}
}
impl embedded_hal::spi::Error for Error { impl embedded_hal::spi::Error for Error {
fn kind(&self) -> embedded_hal::spi::ErrorKind { fn kind(&self) -> embedded_hal::spi::ErrorKind {
embedded_hal::spi::ErrorKind::Other embedded_hal::spi::ErrorKind::Other
@ -50,7 +62,7 @@ impl embedded_hal::spi::Error for Error {
/// ///
/// These modes control the clock signal's idle state and when data is sampled /// These modes control the clock signal's idle state and when data is sampled
/// and shifted. /// and shifted.
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SpiMode { pub enum SpiMode {
/// Mode 0 (CPOL = 0, CPHA = 0): Clock is low when idle, data is captured on /// Mode 0 (CPOL = 0, CPHA = 0): Clock is low when idle, data is captured on
@ -68,17 +80,17 @@ pub enum SpiMode {
} }
/// SPI Bit Order /// SPI Bit Order
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SpiBitOrder { pub enum SpiBitOrder {
/// Most Significant Bit (MSB) is transmitted first. /// Most Significant Bit (MSB) is transmitted first.
MSBFirst, MsbFirst,
/// Least Significant Bit (LSB) is transmitted first. /// Least Significant Bit (LSB) is transmitted first.
LSBFirst, LsbFirst,
} }
/// SPI data mode /// SPI data mode
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SpiDataMode { pub enum SpiDataMode {
/// `Single` Data Mode - 1 bit, 2 wires. /// `Single` Data Mode - 1 bit, 2 wires.
@ -87,6 +99,9 @@ pub enum SpiDataMode {
Dual, Dual,
/// `Quad` Data Mode - 4 bit, 4 wires /// `Quad` Data Mode - 4 bit, 4 wires
Quad, Quad,
#[cfg(spi_octal)]
/// `Octal` Data Mode - 8 bit, 8 wires
Octal,
} }
crate::any_peripheral! { crate::any_peripheral! {

View File

@ -29,7 +29,7 @@ pub(crate) const KEEP_ENABLED: &[Peripheral] = &[
// FIXME: This enum needs to be public because it's exposed via a bunch of traits, but it's not // FIXME: This enum needs to be public because it's exposed via a bunch of traits, but it's not
// useful to users. // useful to users.
#[doc(hidden)] #[doc(hidden)]
#[derive(Debug, Clone, Copy, PartialEq, EnumCount, EnumIter)] #[derive(Debug, Clone, Copy, PartialEq, Eq, EnumCount, EnumIter)]
#[repr(u8)] #[repr(u8)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Peripheral { pub enum Peripheral {
@ -162,7 +162,8 @@ pub(crate) fn disable_peripherals() {
}) })
} }
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub(crate) struct PeripheralGuard { pub(crate) struct PeripheralGuard {
peripheral: Peripheral, peripheral: Peripheral,
} }

View File

@ -96,4 +96,5 @@ symbols = [
"clic", "clic",
"very_large_intr_status", "very_large_intr_status",
"gpio_bank_1", "gpio_bank_1",
"spi_octal",
] ]

View File

@ -59,6 +59,7 @@ symbols = [
"timg_timer1", "timg_timer1",
"large_intr_status", "large_intr_status",
"gpio_bank_1", "gpio_bank_1",
"spi_octal",
# ROM capabilities # ROM capabilities
"rom_crc_le", "rom_crc_le",

View File

@ -74,6 +74,7 @@ symbols = [
"timg_timer1", "timg_timer1",
"very_large_intr_status", "very_large_intr_status",
"gpio_bank_1", "gpio_bank_1",
"spi_octal",
# ROM capabilities # ROM capabilities
"rom_crc_le", "rom_crc_le",

View File

@ -13,7 +13,7 @@
//! CS => GPIO5 //! CS => GPIO5
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% FEATURES: embassy embassy-generic-timers //% FEATURES: embassy embassy-generic-timers esp-hal/unstable
#![no_std] #![no_std]
#![no_main] #![no_main]

View File

@ -11,6 +11,7 @@
//! This example transfers data via SPI. //! This example transfers data via SPI.
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% FEATURES: esp-hal/unstable
#![no_std] #![no_std]
#![no_main] #![no_main]

View File

@ -16,7 +16,7 @@
//! If your module is quad PSRAM then you need to change the `psram` feature in the //! If your module is quad PSRAM then you need to change the `psram` feature in the
//! in the features line below to `quad-psram`. //! in the features line below to `quad-psram`.
//% FEATURES: esp-hal/log esp-hal/octal-psram //% FEATURES: esp-hal/log esp-hal/octal-psram esp-hal/unstable
//% CHIPS: esp32s3 //% CHIPS: esp32s3
#![no_std] #![no_std]

View File

@ -25,6 +25,7 @@
//! so no immediate neighbor is available. //! so no immediate neighbor is available.
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 //% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% FEATURES: esp-hal/unstable
#![no_std] #![no_std]
#![no_main] #![no_main]