ESP32 spi slave mode (#2278)
* Enable test on ESP32 * Enable module on ESP32 * Add ESP32 signal map * Change pins * Remove unknown signals * Return to low level in test * Fix bitlength * Merge enable and reset * Impl debug traits on DMA flags * Disallow mods 0 and 2 * Docs tweaks * Changelog * Undo wait change
This commit is contained in:
parent
ba96bac776
commit
af3f892381
@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Introduce `DmaRxStreamBuf` (#2242)
|
- Introduce `DmaRxStreamBuf` (#2242)
|
||||||
- Implement `embedded_hal_async::delay::DelayNs` for `TIMGx` timers (#2084)
|
- Implement `embedded_hal_async::delay::DelayNs` for `TIMGx` timers (#2084)
|
||||||
- Added `Efuse::read_bit` (#2259)
|
- Added `Efuse::read_bit` (#2259)
|
||||||
|
- Limited SPI slave support for ESP32 (Modes 1 and 3 only) (#2278)
|
||||||
- Added `Rtc::disable_rom_message_printing` (S3 and H2 only) (#2280)
|
- Added `Rtc::disable_rom_message_printing` (S3 and H2 only) (#2280)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
@ -364,7 +364,8 @@ mod gdma;
|
|||||||
mod pdma;
|
mod pdma;
|
||||||
|
|
||||||
/// Kinds of interrupt to listen to.
|
/// Kinds of interrupt to listen to.
|
||||||
#[derive(EnumSetType)]
|
#[derive(Debug, EnumSetType)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum DmaInterrupt {
|
pub enum DmaInterrupt {
|
||||||
/// RX is done
|
/// RX is done
|
||||||
RxDone,
|
RxDone,
|
||||||
@ -373,7 +374,8 @@ pub enum DmaInterrupt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Types of interrupts emitted by the TX channel.
|
/// Types of interrupts emitted by the TX channel.
|
||||||
#[derive(EnumSetType)]
|
#[derive(Debug, EnumSetType)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum DmaTxInterrupt {
|
pub enum DmaTxInterrupt {
|
||||||
/// Triggered when all data corresponding to a linked list (including
|
/// Triggered when all data corresponding to a linked list (including
|
||||||
/// multiple descriptors) have been sent via transmit channel.
|
/// multiple descriptors) have been sent via transmit channel.
|
||||||
@ -394,7 +396,8 @@ pub enum DmaTxInterrupt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Types of interrupts emitted by the RX channel.
|
/// Types of interrupts emitted by the RX channel.
|
||||||
#[derive(EnumSetType)]
|
#[derive(Debug, EnumSetType)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum DmaRxInterrupt {
|
pub enum DmaRxInterrupt {
|
||||||
/// Triggered when the size of the buffer pointed by receive descriptors
|
/// Triggered when the size of the buffer pointed by receive descriptors
|
||||||
/// is smaller than the length of data to be received via receive channel.
|
/// is smaller than the length of data to be received via receive channel.
|
||||||
|
|||||||
@ -141,8 +141,6 @@ pub enum InputSignal {
|
|||||||
U0DSR = 16,
|
U0DSR = 16,
|
||||||
U1RXD = 17,
|
U1RXD = 17,
|
||||||
U1CTS = 18,
|
U1CTS = 18,
|
||||||
I2CM_SDA = 20,
|
|
||||||
EXT_I2C_SDA = 22,
|
|
||||||
I2S0O_BCK = 23,
|
I2S0O_BCK = 23,
|
||||||
I2S1O_BCK = 24,
|
I2S1O_BCK = 24,
|
||||||
I2S0O_WS = 25,
|
I2S0O_WS = 25,
|
||||||
@ -157,8 +155,6 @@ pub enum InputSignal {
|
|||||||
PWM0_F0 = 34,
|
PWM0_F0 = 34,
|
||||||
PWM0_F1 = 35,
|
PWM0_F1 = 35,
|
||||||
PWM0_F2 = 36,
|
PWM0_F2 = 36,
|
||||||
GPIO_BT_ACTIVE = 37,
|
|
||||||
GPIO_BT_PRIORITY = 38,
|
|
||||||
PCNT0_SIG_CH0 = 39,
|
PCNT0_SIG_CH0 = 39,
|
||||||
PCNT0_SIG_CH1 = 40,
|
PCNT0_SIG_CH1 = 40,
|
||||||
PCNT0_CTRL_CH0 = 41,
|
PCNT0_CTRL_CH0 = 41,
|
||||||
@ -209,7 +205,6 @@ pub enum InputSignal {
|
|||||||
RMT_SIG_5 = 88,
|
RMT_SIG_5 = 88,
|
||||||
RMT_SIG_6 = 89,
|
RMT_SIG_6 = 89,
|
||||||
RMT_SIG_7 = 90,
|
RMT_SIG_7 = 90,
|
||||||
EXT_ADC_START = 93,
|
|
||||||
TWAI_RX = 94,
|
TWAI_RX = 94,
|
||||||
I2CEXT1_SCL = 95,
|
I2CEXT1_SCL = 95,
|
||||||
I2CEXT1_SDA = 96,
|
I2CEXT1_SDA = 96,
|
||||||
@ -231,29 +226,6 @@ pub enum InputSignal {
|
|||||||
PWM1_CAP0 = 112,
|
PWM1_CAP0 = 112,
|
||||||
PWM1_CAP1 = 113,
|
PWM1_CAP1 = 113,
|
||||||
PWM1_CAP2 = 114,
|
PWM1_CAP2 = 114,
|
||||||
PWM2_FLTA = 115,
|
|
||||||
PWM2_FLTB = 116,
|
|
||||||
PWM2_CAP1 = 117,
|
|
||||||
PWM2_CAP2 = 118,
|
|
||||||
PWM2_CAP3 = 119,
|
|
||||||
PWM3_FLTA = 120,
|
|
||||||
PWM3_FLTB = 121,
|
|
||||||
PWM3_CAP1 = 122,
|
|
||||||
PWM3_CAP2 = 123,
|
|
||||||
PWM3_CAP3 = 124,
|
|
||||||
CAN_CLKOUT = 125,
|
|
||||||
SPID4 = 128,
|
|
||||||
SPID5 = 129,
|
|
||||||
SPID6 = 130,
|
|
||||||
SPID7 = 131,
|
|
||||||
HSPID4 = 132,
|
|
||||||
HSPID5 = 133,
|
|
||||||
HSPID6 = 134,
|
|
||||||
HSPID7 = 135,
|
|
||||||
VSPID4 = 136,
|
|
||||||
VSPID5 = 137,
|
|
||||||
VSPID6 = 138,
|
|
||||||
VSPID7 = 139,
|
|
||||||
I2S0I_DATA_0 = 140,
|
I2S0I_DATA_0 = 140,
|
||||||
I2S0I_DATA_1 = 141,
|
I2S0I_DATA_1 = 141,
|
||||||
I2S0I_DATA_2 = 142,
|
I2S0I_DATA_2 = 142,
|
||||||
@ -303,11 +275,6 @@ pub enum InputSignal {
|
|||||||
PCMFSYNC = 204,
|
PCMFSYNC = 204,
|
||||||
PCMCLK = 205,
|
PCMCLK = 205,
|
||||||
PCMDIN = 206,
|
PCMDIN = 206,
|
||||||
SIG_IN_FUNC224 = 224,
|
|
||||||
SIG_IN_FUNC225 = 225,
|
|
||||||
SIG_IN_FUNC226 = 226,
|
|
||||||
SIG_IN_FUNC227 = 227,
|
|
||||||
SIG_IN_FUNC228 = 228,
|
|
||||||
|
|
||||||
SD_DATA0 = 512,
|
SD_DATA0 = 512,
|
||||||
SD_DATA1,
|
SD_DATA1,
|
||||||
@ -365,10 +332,6 @@ pub enum OutputSignal {
|
|||||||
U0DTR = 16,
|
U0DTR = 16,
|
||||||
U1TXD = 17,
|
U1TXD = 17,
|
||||||
U1RTS = 18,
|
U1RTS = 18,
|
||||||
I2CM_SCL = 19,
|
|
||||||
I2CM_SDA = 20,
|
|
||||||
EXT2C_SCL = 21,
|
|
||||||
EXT2C_SDA = 22,
|
|
||||||
I2S0O_BCK = 23,
|
I2S0O_BCK = 23,
|
||||||
I2S1O_BCK = 24,
|
I2S1O_BCK = 24,
|
||||||
I2S0O_WS = 25,
|
I2S0O_WS = 25,
|
||||||
@ -384,27 +347,6 @@ pub enum OutputSignal {
|
|||||||
PWM0_1B = 35,
|
PWM0_1B = 35,
|
||||||
PWM0_2A = 36,
|
PWM0_2A = 36,
|
||||||
PWM0_2B = 37,
|
PWM0_2B = 37,
|
||||||
GPIO_WLAN_ACTIVE = 40,
|
|
||||||
BB_DIAG0 = 41,
|
|
||||||
BB_DIAG1 = 42,
|
|
||||||
BB_DIAG2 = 43,
|
|
||||||
BB_DIAG3 = 44,
|
|
||||||
BB_DIAG4 = 45,
|
|
||||||
BB_DIAG5 = 46,
|
|
||||||
BB_DIAG6 = 47,
|
|
||||||
BB_DIAG7 = 48,
|
|
||||||
BB_DIAG8 = 49,
|
|
||||||
BB_DIAG9 = 50,
|
|
||||||
BB_DIAG10 = 51,
|
|
||||||
BB_DIAG11 = 52,
|
|
||||||
BB_DIAG12 = 53,
|
|
||||||
BB_DIAG13 = 54,
|
|
||||||
BB_DIAG14 = 55,
|
|
||||||
BB_DIAG15 = 56,
|
|
||||||
BB_DIAG16 = 57,
|
|
||||||
BB_DIAG17 = 58,
|
|
||||||
BB_DIAG18 = 59,
|
|
||||||
BB_DIAG19 = 60,
|
|
||||||
HSPICS1 = 61,
|
HSPICS1 = 61,
|
||||||
HSPICS2 = 62,
|
HSPICS2 = 62,
|
||||||
VSPICLK = 63,
|
VSPICLK = 63,
|
||||||
@ -458,29 +400,9 @@ pub enum OutputSignal {
|
|||||||
PWM1_1B = 111,
|
PWM1_1B = 111,
|
||||||
PWM1_2A = 112,
|
PWM1_2A = 112,
|
||||||
PWM1_2B = 113,
|
PWM1_2B = 113,
|
||||||
PWM2_1H = 114,
|
|
||||||
PWM2_1L = 115,
|
|
||||||
PWM2_2H = 116,
|
|
||||||
PWM2_2L = 117,
|
|
||||||
PWM2_3H = 118,
|
|
||||||
PWM2_3L = 119,
|
|
||||||
PWM2_4H = 120,
|
|
||||||
PWM2_4L = 121,
|
|
||||||
TWAI_TX = 123,
|
TWAI_TX = 123,
|
||||||
TWAI_BUS_OFF_ON = 124,
|
TWAI_BUS_OFF_ON = 124,
|
||||||
TWAI_CLKOUT = 125,
|
TWAI_CLKOUT = 125,
|
||||||
SPID4 = 128,
|
|
||||||
SPID5 = 129,
|
|
||||||
SPID6 = 130,
|
|
||||||
SPID7 = 131,
|
|
||||||
HSPID4 = 132,
|
|
||||||
HSPID5 = 133,
|
|
||||||
HSPID6 = 134,
|
|
||||||
HSPID7 = 135,
|
|
||||||
VSPID4 = 136,
|
|
||||||
VSPID5 = 137,
|
|
||||||
VSPID6 = 138,
|
|
||||||
VSPID7 = 139,
|
|
||||||
I2S0O_DATA_0 = 140,
|
I2S0O_DATA_0 = 140,
|
||||||
I2S0O_DATA_1 = 141,
|
I2S0O_DATA_1 = 141,
|
||||||
I2S0O_DATA_2 = 142,
|
I2S0O_DATA_2 = 142,
|
||||||
@ -531,14 +453,6 @@ pub enum OutputSignal {
|
|||||||
I2S1O_DATA_21 = 187,
|
I2S1O_DATA_21 = 187,
|
||||||
I2S1O_DATA_22 = 188,
|
I2S1O_DATA_22 = 188,
|
||||||
I2S1O_DATA_23 = 189,
|
I2S1O_DATA_23 = 189,
|
||||||
PWM3_1H = 190,
|
|
||||||
PWM3_1L = 191,
|
|
||||||
PWM3_2H = 192,
|
|
||||||
PWM3_2L = 193,
|
|
||||||
PWM3_3H = 194,
|
|
||||||
PWM3_3L = 195,
|
|
||||||
PWM3_4H = 196,
|
|
||||||
PWM3_4L = 197,
|
|
||||||
U2TXD = 198,
|
U2TXD = 198,
|
||||||
U2RTS = 199,
|
U2RTS = 199,
|
||||||
EMAC_MDC = 200,
|
EMAC_MDC = 200,
|
||||||
|
|||||||
@ -12,7 +12,6 @@
|
|||||||
use crate::dma::DmaError;
|
use crate::dma::DmaError;
|
||||||
|
|
||||||
pub mod master;
|
pub mod master;
|
||||||
#[cfg(not(esp32))]
|
|
||||||
pub mod slave;
|
pub mod slave;
|
||||||
|
|
||||||
/// SPI errors
|
/// SPI errors
|
||||||
|
|||||||
@ -22,8 +22,8 @@
|
|||||||
//! # use esp_hal::dma::Dma;
|
//! # use esp_hal::dma::Dma;
|
||||||
//! # use esp_hal::gpio::Io;
|
//! # use esp_hal::gpio::Io;
|
||||||
//! let dma = Dma::new(peripherals.DMA);
|
//! let dma = Dma::new(peripherals.DMA);
|
||||||
#![cfg_attr(esp32s2, doc = "let dma_channel = dma.spi2channel;")]
|
#![cfg_attr(pdma, doc = "let dma_channel = dma.spi2channel;")]
|
||||||
#![cfg_attr(not(esp32s2), doc = "let dma_channel = dma.channel0;")]
|
#![cfg_attr(gdma, doc = "let dma_channel = dma.channel0;")]
|
||||||
//! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
//! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||||
//! let sclk = io.pins.gpio0;
|
//! let sclk = io.pins.gpio0;
|
||||||
//! let miso = io.pins.gpio1;
|
//! let miso = io.pins.gpio1;
|
||||||
@ -58,16 +58,17 @@
|
|||||||
//! ## Implementation State
|
//! ## Implementation State
|
||||||
//!
|
//!
|
||||||
//! There are several options for working with the SPI peripheral in slave mode,
|
//! There are several options for working with the SPI peripheral in slave mode,
|
||||||
//! but the code currently only supports single transfers (not segmented
|
//! but the code currently only supports:
|
||||||
//! transfers), full duplex, single bit (not dual or quad SPI), and DMA mode
|
//! - Single transfers (not segmented transfers)
|
||||||
//! (not CPU mode). It also does not support blocking operations, as the actual
|
//! - Full duplex, single bit (not dual or quad SPI)
|
||||||
|
//! - DMA mode (not CPU mode).
|
||||||
|
#![cfg_attr(esp32, doc = "- ESP32 only supports SPI mode 1 and 3.\n\n")]
|
||||||
|
//! It also does not support blocking operations, as the actual
|
||||||
//! transfer is controlled by the SPI master; if these are necessary,
|
//! transfer is controlled by the SPI master; if these are necessary,
|
||||||
//! then the DmaTransfer trait instance can be wait()ed on or polled for
|
//! then the `DmaTransfer` object can be `wait()`ed on or polled for
|
||||||
//! is_done().
|
//! `is_done()`.
|
||||||
//! - ESP32 does not support SPI Slave. See [tracking issue].
|
|
||||||
//!
|
//!
|
||||||
//! [tracking issue]: https://github.com/esp-rs/esp-hal/issues/469
|
//! See [tracking issue](https://github.com/esp-rs/esp-hal/issues/469) for more information.
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use super::{Error, FullDuplexMode, SpiMode};
|
use super::{Error, FullDuplexMode, SpiMode};
|
||||||
@ -82,7 +83,9 @@ use crate::{
|
|||||||
|
|
||||||
const MAX_DMA_SIZE: usize = 32768 - 32;
|
const MAX_DMA_SIZE: usize = 32768 - 32;
|
||||||
|
|
||||||
/// SPI peripheral driver
|
/// SPI peripheral driver.
|
||||||
|
///
|
||||||
|
/// See the [module-level documentation][self] for more details.
|
||||||
pub struct Spi<'d, T, M> {
|
pub struct Spi<'d, T, M> {
|
||||||
spi: PeripheralRef<'d, T>,
|
spi: PeripheralRef<'d, T>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -138,7 +141,7 @@ where
|
|||||||
_mode: PhantomData,
|
_mode: PhantomData,
|
||||||
};
|
};
|
||||||
spi.spi.init();
|
spi.spi.init();
|
||||||
spi.spi.set_data_mode(mode);
|
spi.spi.set_data_mode(mode, false);
|
||||||
|
|
||||||
spi
|
spi
|
||||||
}
|
}
|
||||||
@ -174,8 +177,9 @@ pub mod dma {
|
|||||||
impl<'d> Spi<'d, crate::peripherals::SPI2, FullDuplexMode> {
|
impl<'d> Spi<'d, crate::peripherals::SPI2, FullDuplexMode> {
|
||||||
/// Configures the SPI3 peripheral with the provided DMA channel and
|
/// Configures the SPI3 peripheral with the provided DMA channel and
|
||||||
/// descriptors.
|
/// descriptors.
|
||||||
|
#[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")]
|
||||||
pub fn with_dma<C, DmaMode>(
|
pub fn with_dma<C, DmaMode>(
|
||||||
self,
|
mut self,
|
||||||
channel: Channel<'d, C, DmaMode>,
|
channel: Channel<'d, C, DmaMode>,
|
||||||
rx_descriptors: &'static mut [DmaDescriptor],
|
rx_descriptors: &'static mut [DmaDescriptor],
|
||||||
tx_descriptors: &'static mut [DmaDescriptor],
|
tx_descriptors: &'static mut [DmaDescriptor],
|
||||||
@ -185,6 +189,7 @@ pub mod dma {
|
|||||||
C::P: SpiPeripheral + Spi2Peripheral,
|
C::P: SpiPeripheral + Spi2Peripheral,
|
||||||
DmaMode: Mode,
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
|
self.spi.set_data_mode(self.data_mode, true);
|
||||||
SpiDma {
|
SpiDma {
|
||||||
spi: self.spi,
|
spi: self.spi,
|
||||||
channel,
|
channel,
|
||||||
@ -198,8 +203,9 @@ pub mod dma {
|
|||||||
impl<'d> Spi<'d, crate::peripherals::SPI3, FullDuplexMode> {
|
impl<'d> Spi<'d, crate::peripherals::SPI3, FullDuplexMode> {
|
||||||
/// Configures the SPI3 peripheral with the provided DMA channel and
|
/// Configures the SPI3 peripheral with the provided DMA channel and
|
||||||
/// descriptors.
|
/// descriptors.
|
||||||
|
#[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")]
|
||||||
pub fn with_dma<C, DmaMode>(
|
pub fn with_dma<C, DmaMode>(
|
||||||
self,
|
mut self,
|
||||||
channel: Channel<'d, C, DmaMode>,
|
channel: Channel<'d, C, DmaMode>,
|
||||||
rx_descriptors: &'static mut [DmaDescriptor],
|
rx_descriptors: &'static mut [DmaDescriptor],
|
||||||
tx_descriptors: &'static mut [DmaDescriptor],
|
tx_descriptors: &'static mut [DmaDescriptor],
|
||||||
@ -209,6 +215,7 @@ pub mod dma {
|
|||||||
C::P: SpiPeripheral + Spi3Peripheral,
|
C::P: SpiPeripheral + Spi3Peripheral,
|
||||||
DmaMode: Mode,
|
DmaMode: Mode,
|
||||||
{
|
{
|
||||||
|
self.spi.set_data_mode(self.data_mode, true);
|
||||||
SpiDma {
|
SpiDma {
|
||||||
spi: self.spi,
|
spi: self.spi,
|
||||||
channel,
|
channel,
|
||||||
@ -327,7 +334,16 @@ pub mod dma {
|
|||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.spi
|
self.spi
|
||||||
.start_write_bytes_dma(&mut self.tx_chain, ptr, len, &mut self.channel.tx)
|
.start_transfer_dma(
|
||||||
|
&mut self.rx_chain,
|
||||||
|
&mut self.tx_chain,
|
||||||
|
core::ptr::null_mut(),
|
||||||
|
0,
|
||||||
|
ptr,
|
||||||
|
len,
|
||||||
|
&mut self.channel.rx,
|
||||||
|
&mut self.channel.tx,
|
||||||
|
)
|
||||||
.map(move |_| DmaTransferTx::new(self))
|
.map(move |_| DmaTransferTx::new(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -353,7 +369,16 @@ pub mod dma {
|
|||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.spi
|
self.spi
|
||||||
.start_read_bytes_dma(&mut self.rx_chain, ptr, len, &mut self.channel.rx)
|
.start_transfer_dma(
|
||||||
|
&mut self.rx_chain,
|
||||||
|
&mut self.tx_chain,
|
||||||
|
ptr,
|
||||||
|
len,
|
||||||
|
core::ptr::null(),
|
||||||
|
0,
|
||||||
|
&mut self.channel.rx,
|
||||||
|
&mut self.channel.tx,
|
||||||
|
)
|
||||||
.map(move |_| DmaTransferRx::new(self))
|
.map(move |_| DmaTransferRx::new(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -421,21 +446,26 @@ pub trait InstanceDma: Instance {
|
|||||||
{
|
{
|
||||||
let reg_block = self.register_block();
|
let reg_block = self.register_block();
|
||||||
|
|
||||||
rx.is_done();
|
|
||||||
tx.is_done();
|
|
||||||
|
|
||||||
self.enable_dma();
|
self.enable_dma();
|
||||||
|
|
||||||
reset_dma_before_load_dma_dscr(reg_block);
|
reset_spi(reg_block);
|
||||||
|
|
||||||
|
if read_buffer_len > 0 {
|
||||||
rx_chain.fill_for_rx(false, read_buffer_ptr, read_buffer_len)?;
|
rx_chain.fill_for_rx(false, read_buffer_ptr, read_buffer_len)?;
|
||||||
rx.prepare_transfer_without_start(self.dma_peripheral(), rx_chain)?;
|
rx.prepare_transfer_without_start(self.dma_peripheral(), rx_chain)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if write_buffer_len > 0 {
|
||||||
tx_chain.fill_for_tx(false, write_buffer_ptr, write_buffer_len)?;
|
tx_chain.fill_for_tx(false, write_buffer_ptr, write_buffer_len)?;
|
||||||
tx.prepare_transfer_without_start(self.dma_peripheral(), tx_chain)?;
|
tx.prepare_transfer_without_start(self.dma_peripheral(), tx_chain)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(esp32)]
|
||||||
|
self.prepare_length_and_lines(read_buffer_len, write_buffer_len);
|
||||||
|
|
||||||
reset_dma_before_usr_cmd(reg_block);
|
reset_dma_before_usr_cmd(reg_block);
|
||||||
|
|
||||||
|
#[cfg(not(esp32))]
|
||||||
reg_block
|
reg_block
|
||||||
.dma_conf()
|
.dma_conf()
|
||||||
.modify(|_, w| w.dma_slv_seg_trans_en().clear_bit());
|
.modify(|_, w| w.dma_slv_seg_trans_en().clear_bit());
|
||||||
@ -444,86 +474,21 @@ pub trait InstanceDma: Instance {
|
|||||||
self.setup_for_flush();
|
self.setup_for_flush();
|
||||||
reg_block.cmd().modify(|_, w| w.usr().set_bit());
|
reg_block.cmd().modify(|_, w| w.usr().set_bit());
|
||||||
|
|
||||||
|
if read_buffer_len > 0 {
|
||||||
rx.start_transfer()?;
|
rx.start_transfer()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if write_buffer_len > 0 {
|
||||||
tx.start_transfer()?;
|
tx.start_transfer()?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn start_write_bytes_dma<TX>(
|
|
||||||
&mut self,
|
|
||||||
tx_chain: &mut DescriptorChain,
|
|
||||||
ptr: *const u8,
|
|
||||||
len: usize,
|
|
||||||
tx: &mut TX,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
TX: Tx,
|
|
||||||
{
|
|
||||||
let reg_block = self.register_block();
|
|
||||||
|
|
||||||
tx.is_done();
|
|
||||||
|
|
||||||
self.enable_dma();
|
|
||||||
|
|
||||||
reset_dma_before_load_dma_dscr(reg_block);
|
|
||||||
|
|
||||||
tx_chain.fill_for_tx(false, ptr, len)?;
|
|
||||||
tx.prepare_transfer_without_start(self.dma_peripheral(), tx_chain)?;
|
|
||||||
|
|
||||||
reset_dma_before_usr_cmd(reg_block);
|
|
||||||
|
|
||||||
reg_block
|
|
||||||
.dma_conf()
|
|
||||||
.modify(|_, w| w.dma_slv_seg_trans_en().clear_bit());
|
|
||||||
|
|
||||||
self.clear_dma_interrupts();
|
|
||||||
self.setup_for_flush();
|
|
||||||
reg_block.cmd().modify(|_, w| w.usr().set_bit());
|
|
||||||
|
|
||||||
tx.start_transfer()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn start_read_bytes_dma<RX>(
|
|
||||||
&mut self,
|
|
||||||
rx_chain: &mut DescriptorChain,
|
|
||||||
ptr: *mut u8,
|
|
||||||
len: usize,
|
|
||||||
rx: &mut RX,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
RX: Rx,
|
|
||||||
{
|
|
||||||
let reg_block = self.register_block();
|
|
||||||
|
|
||||||
rx.is_done();
|
|
||||||
|
|
||||||
self.enable_dma();
|
|
||||||
|
|
||||||
reset_dma_before_load_dma_dscr(reg_block);
|
|
||||||
rx_chain.fill_for_rx(false, ptr, len)?;
|
|
||||||
rx.prepare_transfer_without_start(self.dma_peripheral(), rx_chain)?;
|
|
||||||
|
|
||||||
reset_dma_before_usr_cmd(reg_block);
|
|
||||||
|
|
||||||
reg_block
|
|
||||||
.dma_conf()
|
|
||||||
.modify(|_, w| w.dma_slv_seg_trans_en().clear_bit());
|
|
||||||
|
|
||||||
self.clear_dma_interrupts();
|
|
||||||
self.setup_for_flush();
|
|
||||||
reg_block.cmd().modify(|_, w| w.usr().set_bit());
|
|
||||||
|
|
||||||
rx.start_transfer()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
|
|
||||||
fn enable_dma(&self) {
|
fn enable_dma(&self) {
|
||||||
let reg_block = self.register_block();
|
let reg_block = self.register_block();
|
||||||
|
#[cfg(gdma)]
|
||||||
|
{
|
||||||
reg_block.dma_conf().modify(|_, w| {
|
reg_block.dma_conf().modify(|_, w| {
|
||||||
w.dma_tx_ena().set_bit();
|
w.dma_tx_ena().set_bit();
|
||||||
w.dma_rx_ena().set_bit();
|
w.dma_rx_ena().set_bit();
|
||||||
@ -531,14 +496,30 @@ pub trait InstanceDma: Instance {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(pdma)]
|
||||||
|
{
|
||||||
|
fn set_rst_bit(reg_block: &RegisterBlock, bit: bool) {
|
||||||
|
reg_block.dma_conf().modify(|_, w| {
|
||||||
|
w.in_rst().bit(bit);
|
||||||
|
w.out_rst().bit(bit);
|
||||||
|
w.ahbm_fifo_rst().bit(bit);
|
||||||
|
w.ahbm_rst().bit(bit)
|
||||||
|
});
|
||||||
|
|
||||||
#[cfg(esp32s2)]
|
#[cfg(esp32s2)]
|
||||||
fn enable_dma(&self) {
|
reg_block
|
||||||
// for non GDMA this is done in `assign_tx_device` / `assign_rx_device`
|
.dma_conf()
|
||||||
|
.modify(|_, w| w.dma_infifo_full_clr().bit(bit));
|
||||||
|
}
|
||||||
|
set_rst_bit(reg_block, true);
|
||||||
|
set_rst_bit(reg_block, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))]
|
|
||||||
fn clear_dma_interrupts(&self) {
|
fn clear_dma_interrupts(&self) {
|
||||||
let reg_block = self.register_block();
|
let reg_block = self.register_block();
|
||||||
|
|
||||||
|
#[cfg(gdma)]
|
||||||
reg_block.dma_int_clr().write(|w| {
|
reg_block.dma_int_clr().write(|w| {
|
||||||
w.dma_infifo_full_err().clear_bit_by_one();
|
w.dma_infifo_full_err().clear_bit_by_one();
|
||||||
w.dma_outfifo_empty_err().clear_bit_by_one();
|
w.dma_outfifo_empty_err().clear_bit_by_one();
|
||||||
@ -546,11 +527,8 @@ pub trait InstanceDma: Instance {
|
|||||||
w.mst_rx_afifo_wfull_err().clear_bit_by_one();
|
w.mst_rx_afifo_wfull_err().clear_bit_by_one();
|
||||||
w.mst_tx_afifo_rempty_err().clear_bit_by_one()
|
w.mst_tx_afifo_rempty_err().clear_bit_by_one()
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(esp32s2)]
|
#[cfg(pdma)]
|
||||||
fn clear_dma_interrupts(&self) {
|
|
||||||
let reg_block = self.register_block();
|
|
||||||
reg_block.dma_int_clr().write(|w| {
|
reg_block.dma_int_clr().write(|w| {
|
||||||
w.inlink_dscr_empty().clear_bit_by_one();
|
w.inlink_dscr_empty().clear_bit_by_one();
|
||||||
w.outlink_dscr_error().clear_bit_by_one();
|
w.outlink_dscr_error().clear_bit_by_one();
|
||||||
@ -565,49 +543,30 @@ pub trait InstanceDma: Instance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(esp32s2))]
|
fn reset_spi(reg_block: &RegisterBlock) {
|
||||||
|
#[cfg(esp32)]
|
||||||
|
{
|
||||||
|
reg_block.slave().modify(|_, w| w.sync_reset().set_bit());
|
||||||
|
reg_block.slave().modify(|_, w| w.sync_reset().clear_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(esp32))]
|
||||||
|
{
|
||||||
|
reg_block.slave().modify(|_, w| w.soft_reset().set_bit());
|
||||||
|
reg_block.slave().modify(|_, w| w.soft_reset().clear_bit());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn reset_dma_before_usr_cmd(reg_block: &RegisterBlock) {
|
fn reset_dma_before_usr_cmd(reg_block: &RegisterBlock) {
|
||||||
|
#[cfg(gdma)]
|
||||||
reg_block.dma_conf().modify(|_, w| {
|
reg_block.dma_conf().modify(|_, w| {
|
||||||
w.rx_afifo_rst().set_bit();
|
w.rx_afifo_rst().set_bit();
|
||||||
w.buf_afifo_rst().set_bit();
|
w.buf_afifo_rst().set_bit();
|
||||||
w.dma_afifo_rst().set_bit()
|
w.dma_afifo_rst().set_bit()
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(esp32s2)]
|
#[cfg(pdma)]
|
||||||
fn reset_dma_before_usr_cmd(reg_block: &RegisterBlock) {
|
let _ = reg_block;
|
||||||
reg_block.slave().modify(|_, w| w.soft_reset().set_bit());
|
|
||||||
reg_block.slave().modify(|_, w| w.soft_reset().clear_bit());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(esp32s2))]
|
|
||||||
fn reset_dma_before_load_dma_dscr(_reg_block: &RegisterBlock) {}
|
|
||||||
|
|
||||||
#[cfg(esp32s2)]
|
|
||||||
fn reset_dma_before_load_dma_dscr(reg_block: &RegisterBlock) {
|
|
||||||
reg_block.dma_conf().modify(|_, w| {
|
|
||||||
w.out_rst().set_bit();
|
|
||||||
w.in_rst().set_bit();
|
|
||||||
w.ahbm_fifo_rst().set_bit();
|
|
||||||
w.ahbm_rst().set_bit()
|
|
||||||
});
|
|
||||||
|
|
||||||
#[cfg(esp32s2)]
|
|
||||||
reg_block
|
|
||||||
.dma_conf()
|
|
||||||
.modify(|_, w| w.dma_infifo_full_clr().set_bit());
|
|
||||||
|
|
||||||
reg_block.dma_conf().modify(|_, w| {
|
|
||||||
w.out_rst().clear_bit();
|
|
||||||
w.in_rst().clear_bit();
|
|
||||||
w.ahbm_fifo_rst().clear_bit();
|
|
||||||
w.ahbm_rst().clear_bit()
|
|
||||||
});
|
|
||||||
|
|
||||||
#[cfg(esp32s2)]
|
|
||||||
reg_block
|
|
||||||
.dma_conf()
|
|
||||||
.modify(|_, w| w.dma_infifo_full_clr().clear_bit());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstanceDma for crate::peripherals::SPI2 {
|
impl InstanceDma for crate::peripherals::SPI2 {
|
||||||
@ -626,6 +585,8 @@ impl InstanceDma for crate::peripherals::SPI3 {
|
|||||||
pub trait Instance: private::Sealed {
|
pub trait Instance: private::Sealed {
|
||||||
fn register_block(&self) -> &RegisterBlock;
|
fn register_block(&self) -> &RegisterBlock;
|
||||||
|
|
||||||
|
fn peripheral(&self) -> crate::system::Peripheral;
|
||||||
|
|
||||||
fn sclk_signal(&self) -> InputSignal;
|
fn sclk_signal(&self) -> InputSignal;
|
||||||
|
|
||||||
fn mosi_signal(&self) -> InputSignal;
|
fn mosi_signal(&self) -> InputSignal;
|
||||||
@ -634,8 +595,6 @@ pub trait Instance: private::Sealed {
|
|||||||
|
|
||||||
fn cs_signal(&self) -> InputSignal;
|
fn cs_signal(&self) -> InputSignal;
|
||||||
|
|
||||||
fn peripheral(&self) -> crate::system::Peripheral;
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn reset_peripheral(&self) {
|
fn reset_peripheral(&self) {
|
||||||
PeripheralClockControl::reset(self.peripheral());
|
PeripheralClockControl::reset(self.peripheral());
|
||||||
@ -648,6 +607,24 @@ pub trait Instance: private::Sealed {
|
|||||||
|
|
||||||
fn spi_num(&self) -> u8;
|
fn spi_num(&self) -> u8;
|
||||||
|
|
||||||
|
#[cfg(esp32)]
|
||||||
|
fn prepare_length_and_lines(&self, rx_len: usize, tx_len: usize) {
|
||||||
|
let reg_block = self.register_block();
|
||||||
|
|
||||||
|
reg_block
|
||||||
|
.slv_rdbuf_dlen()
|
||||||
|
.write(|w| unsafe { w.bits((rx_len as u32 * 8).saturating_sub(1)) });
|
||||||
|
reg_block
|
||||||
|
.slv_wrbuf_dlen()
|
||||||
|
.write(|w| unsafe { w.bits((tx_len as u32 * 8).saturating_sub(1)) });
|
||||||
|
|
||||||
|
// SPI Slave mode on ESP32 requires MOSI/MISO enable
|
||||||
|
reg_block.user().modify(|_, w| {
|
||||||
|
w.usr_mosi().bit(rx_len > 0);
|
||||||
|
w.usr_miso().bit(tx_len > 0)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Initialize for full-duplex 1 bit mode
|
/// Initialize for full-duplex 1 bit mode
|
||||||
fn init(&mut self) {
|
fn init(&mut self) {
|
||||||
let reg_block = self.register_block();
|
let reg_block = self.register_block();
|
||||||
@ -656,48 +633,76 @@ pub trait Instance: private::Sealed {
|
|||||||
reg_block.user().write(|w| unsafe { w.bits(0) });
|
reg_block.user().write(|w| unsafe { w.bits(0) });
|
||||||
reg_block.ctrl().write(|w| unsafe { w.bits(0) });
|
reg_block.ctrl().write(|w| unsafe { w.bits(0) });
|
||||||
|
|
||||||
reg_block.slave().write(|w| w.mode().set_bit());
|
reg_block.slave().write(|w| {
|
||||||
|
#[cfg(esp32)]
|
||||||
|
w.slv_wr_rd_buf_en().set_bit();
|
||||||
|
|
||||||
|
w.mode().set_bit()
|
||||||
|
});
|
||||||
|
reset_spi(reg_block);
|
||||||
|
|
||||||
reg_block.user().modify(|_, w| {
|
reg_block.user().modify(|_, w| {
|
||||||
w.usr_miso_highpart().clear_bit();
|
|
||||||
w.doutdin().set_bit();
|
w.doutdin().set_bit();
|
||||||
w.usr_miso().clear_bit();
|
|
||||||
w.usr_mosi().clear_bit();
|
|
||||||
w.usr_dummy_idle().clear_bit();
|
|
||||||
w.usr_addr().clear_bit();
|
|
||||||
w.usr_command().clear_bit();
|
|
||||||
w.sio().clear_bit()
|
w.sio().clear_bit()
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(not(esp32s2))]
|
#[cfg(not(esp32))]
|
||||||
reg_block.clk_gate().modify(|_, w| {
|
|
||||||
w.clk_en().clear_bit();
|
|
||||||
w.mst_clk_active().clear_bit();
|
|
||||||
w.mst_clk_sel().clear_bit()
|
|
||||||
});
|
|
||||||
|
|
||||||
reg_block.ctrl().modify(|_, w| {
|
|
||||||
w.q_pol().clear_bit();
|
|
||||||
w.d_pol().clear_bit();
|
|
||||||
#[cfg(not(esp32s2))]
|
|
||||||
w.hold_pol().clear_bit();
|
|
||||||
#[cfg(esp32s2)]
|
|
||||||
w.wp().clear_bit();
|
|
||||||
w
|
|
||||||
});
|
|
||||||
|
|
||||||
reg_block.misc().write(|w| unsafe { w.bits(0) });
|
reg_block.misc().write(|w| unsafe { w.bits(0) });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_data_mode(&mut self, data_mode: SpiMode) -> &mut Self {
|
fn set_data_mode(&mut self, data_mode: SpiMode, dma: bool) -> &mut Self {
|
||||||
let reg_block = self.register_block();
|
let reg_block = self.register_block();
|
||||||
|
#[cfg(esp32)]
|
||||||
|
{
|
||||||
|
reg_block.pin().modify(|_, w| {
|
||||||
|
w.ck_idle_edge()
|
||||||
|
.bit(matches!(data_mode, SpiMode::Mode0 | SpiMode::Mode1))
|
||||||
|
});
|
||||||
reg_block.user().modify(|_, w| {
|
reg_block.user().modify(|_, w| {
|
||||||
w.tsck_i_edge()
|
w.ck_i_edge()
|
||||||
.bit(matches!(data_mode, SpiMode::Mode1 | SpiMode::Mode2));
|
|
||||||
w.rsck_i_edge()
|
|
||||||
.bit(matches!(data_mode, SpiMode::Mode1 | SpiMode::Mode2))
|
.bit(matches!(data_mode, SpiMode::Mode1 | SpiMode::Mode2))
|
||||||
});
|
});
|
||||||
|
reg_block.ctrl2().modify(|_, w| unsafe {
|
||||||
|
match data_mode {
|
||||||
|
SpiMode::Mode0 => {
|
||||||
|
w.miso_delay_mode().bits(0);
|
||||||
|
w.miso_delay_num().bits(0);
|
||||||
|
w.mosi_delay_mode().bits(2);
|
||||||
|
w.mosi_delay_num().bits(2)
|
||||||
|
}
|
||||||
|
SpiMode::Mode1 => {
|
||||||
|
w.miso_delay_mode().bits(2);
|
||||||
|
w.miso_delay_num().bits(0);
|
||||||
|
w.mosi_delay_mode().bits(0);
|
||||||
|
w.mosi_delay_num().bits(0)
|
||||||
|
}
|
||||||
|
SpiMode::Mode2 => {
|
||||||
|
w.miso_delay_mode().bits(0);
|
||||||
|
w.miso_delay_num().bits(0);
|
||||||
|
w.mosi_delay_mode().bits(1);
|
||||||
|
w.mosi_delay_num().bits(2)
|
||||||
|
}
|
||||||
|
SpiMode::Mode3 => {
|
||||||
|
w.miso_delay_mode().bits(1);
|
||||||
|
w.miso_delay_num().bits(0);
|
||||||
|
w.mosi_delay_mode().bits(0);
|
||||||
|
w.mosi_delay_num().bits(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if dma {
|
||||||
|
assert!(
|
||||||
|
matches!(data_mode, SpiMode::Mode1 | SpiMode::Mode3),
|
||||||
|
"Mode {:?} is not supported with DMA",
|
||||||
|
data_mode
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(esp32))]
|
||||||
|
{
|
||||||
|
_ = dma;
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(esp32s2)] {
|
if #[cfg(esp32s2)] {
|
||||||
let ctrl1_reg = reg_block.ctrl1();
|
let ctrl1_reg = reg_block.ctrl1();
|
||||||
@ -705,10 +710,17 @@ pub trait Instance: private::Sealed {
|
|||||||
let ctrl1_reg = reg_block.slave();
|
let ctrl1_reg = reg_block.slave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
reg_block.user().modify(|_, w| {
|
||||||
|
w.tsck_i_edge()
|
||||||
|
.bit(matches!(data_mode, SpiMode::Mode1 | SpiMode::Mode2));
|
||||||
|
w.rsck_i_edge()
|
||||||
|
.bit(matches!(data_mode, SpiMode::Mode1 | SpiMode::Mode2))
|
||||||
|
});
|
||||||
ctrl1_reg.modify(|_, w| {
|
ctrl1_reg.modify(|_, w| {
|
||||||
w.clk_mode_13()
|
w.clk_mode_13()
|
||||||
.bit(matches!(data_mode, SpiMode::Mode1 | SpiMode::Mode3))
|
.bit(matches!(data_mode, SpiMode::Mode1 | SpiMode::Mode3))
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -716,11 +728,11 @@ pub trait Instance: private::Sealed {
|
|||||||
fn is_bus_busy(&self) -> bool {
|
fn is_bus_busy(&self) -> bool {
|
||||||
let reg_block = self.register_block();
|
let reg_block = self.register_block();
|
||||||
|
|
||||||
#[cfg(esp32s2)]
|
#[cfg(pdma)]
|
||||||
{
|
{
|
||||||
reg_block.slave().read().trans_done().bit_is_clear()
|
reg_block.slave().read().trans_done().bit_is_clear()
|
||||||
}
|
}
|
||||||
#[cfg(not(esp32s2))]
|
#[cfg(gdma)]
|
||||||
{
|
{
|
||||||
reg_block.dma_int_raw().read().trans_done().bit_is_clear()
|
reg_block.dma_int_raw().read().trans_done().bit_is_clear()
|
||||||
}
|
}
|
||||||
@ -737,52 +749,77 @@ pub trait Instance: private::Sealed {
|
|||||||
// Clear the transaction-done interrupt flag so flush() can work properly. Not
|
// Clear the transaction-done interrupt flag so flush() can work properly. Not
|
||||||
// used in DMA mode.
|
// used in DMA mode.
|
||||||
fn setup_for_flush(&self) {
|
fn setup_for_flush(&self) {
|
||||||
#[cfg(esp32s2)]
|
#[cfg(pdma)]
|
||||||
self.register_block()
|
self.register_block()
|
||||||
.slave()
|
.slave()
|
||||||
.modify(|_, w| w.trans_done().clear_bit());
|
.modify(|_, w| w.trans_done().clear_bit());
|
||||||
#[cfg(not(esp32s2))]
|
#[cfg(gdma)]
|
||||||
self.register_block()
|
self.register_block()
|
||||||
.dma_int_clr()
|
.dma_int_clr()
|
||||||
.write(|w| w.trans_done().clear_bit_by_one());
|
.write(|w| w.trans_done().clear_bit_by_one());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(spi2)]
|
||||||
impl Instance for crate::peripherals::SPI2 {
|
impl Instance for crate::peripherals::SPI2 {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn register_block(&self) -> &RegisterBlock {
|
fn register_block(&self) -> &RegisterBlock {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn peripheral(&self) -> crate::system::Peripheral {
|
|
||||||
crate::system::Peripheral::Spi2
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn spi_num(&self) -> u8 {
|
fn spi_num(&self) -> u8 {
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn peripheral(&self) -> crate::system::Peripheral {
|
||||||
|
crate::system::Peripheral::Spi2
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn sclk_signal(&self) -> InputSignal {
|
fn sclk_signal(&self) -> InputSignal {
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(esp32)] {
|
||||||
|
InputSignal::HSPICLK
|
||||||
|
} else {
|
||||||
InputSignal::FSPICLK
|
InputSignal::FSPICLK
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn mosi_signal(&self) -> InputSignal {
|
fn mosi_signal(&self) -> InputSignal {
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(esp32)] {
|
||||||
|
InputSignal::HSPID
|
||||||
|
} else {
|
||||||
InputSignal::FSPID
|
InputSignal::FSPID
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn miso_signal(&self) -> OutputSignal {
|
fn miso_signal(&self) -> OutputSignal {
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(esp32)] {
|
||||||
|
OutputSignal::HSPIQ
|
||||||
|
} else {
|
||||||
OutputSignal::FSPIQ
|
OutputSignal::FSPIQ
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn cs_signal(&self) -> InputSignal {
|
fn cs_signal(&self) -> InputSignal {
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(esp32)] {
|
||||||
|
InputSignal::HSPICS0
|
||||||
|
} else {
|
||||||
InputSignal::FSPICS0
|
InputSignal::FSPICS0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(spi3)]
|
#[cfg(spi3)]
|
||||||
@ -792,33 +829,57 @@ impl Instance for crate::peripherals::SPI3 {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn peripheral(&self) -> crate::system::Peripheral {
|
|
||||||
crate::system::Peripheral::Spi3
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn spi_num(&self) -> u8 {
|
fn spi_num(&self) -> u8 {
|
||||||
3
|
3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn peripheral(&self) -> crate::system::Peripheral {
|
||||||
|
crate::system::Peripheral::Spi3
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn sclk_signal(&self) -> InputSignal {
|
fn sclk_signal(&self) -> InputSignal {
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(esp32)] {
|
||||||
|
InputSignal::VSPICLK
|
||||||
|
} else {
|
||||||
InputSignal::SPI3_CLK
|
InputSignal::SPI3_CLK
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn mosi_signal(&self) -> InputSignal {
|
fn mosi_signal(&self) -> InputSignal {
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(esp32)] {
|
||||||
|
InputSignal::VSPID
|
||||||
|
} else {
|
||||||
InputSignal::SPI3_D
|
InputSignal::SPI3_D
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn miso_signal(&self) -> OutputSignal {
|
fn miso_signal(&self) -> OutputSignal {
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(esp32)] {
|
||||||
|
OutputSignal::VSPIQ
|
||||||
|
} else {
|
||||||
OutputSignal::SPI3_Q
|
OutputSignal::SPI3_Q
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn cs_signal(&self) -> InputSignal {
|
fn cs_signal(&self) -> InputSignal {
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(esp32)] {
|
||||||
|
InputSignal::VSPICS0
|
||||||
|
} else {
|
||||||
InputSignal::SPI3_CS0
|
InputSignal::SPI3_CS0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
//! SPI slave mode test suite.
|
//! SPI slave mode test suite.
|
||||||
|
//!
|
||||||
|
//! ESP32 does not support Modes 0 and 2 (properly, at least), so here we're
|
||||||
|
//! testing Mode 1.
|
||||||
|
|
||||||
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
|
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
@ -51,20 +54,22 @@ impl BitbangSpi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn assert_cs(&mut self) {
|
fn assert_cs(&mut self) {
|
||||||
|
self.sclk.set_level(Level::Low);
|
||||||
self.cs.set_level(Level::Low);
|
self.cs.set_level(Level::Low);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deassert_cs(&mut self) {
|
fn deassert_cs(&mut self) {
|
||||||
|
self.sclk.set_level(Level::Low);
|
||||||
self.cs.set_level(Level::High);
|
self.cs.set_level(Level::High);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mode 0, so sampled on the rising edge and set on the falling edge.
|
// Mode 1, so sampled on the rising edge and set on the falling edge.
|
||||||
fn shift_bit(&mut self, bit: bool) -> bool {
|
fn shift_bit(&mut self, bit: bool) -> bool {
|
||||||
self.mosi.set_level(Level::from(bit));
|
self.mosi.set_level(Level::from(bit));
|
||||||
self.sclk.set_level(Level::Low);
|
self.sclk.set_level(Level::High);
|
||||||
|
|
||||||
let miso = self.miso.get_level().into();
|
let miso = self.miso.get_level().into();
|
||||||
self.sclk.set_level(Level::High);
|
self.sclk.set_level(Level::Low);
|
||||||
|
|
||||||
miso
|
miso
|
||||||
}
|
}
|
||||||
@ -98,6 +103,7 @@ mod tests {
|
|||||||
let peripherals = esp_hal::init(esp_hal::Config::default());
|
let peripherals = esp_hal::init(esp_hal::Config::default());
|
||||||
|
|
||||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||||
|
|
||||||
let (mosi_pin, miso_pin) = hil_test::i2c_pins!(io);
|
let (mosi_pin, miso_pin) = hil_test::i2c_pins!(io);
|
||||||
let (sclk_pin, sclk_gpio) = hil_test::common_test_pins!(io);
|
let (sclk_pin, sclk_gpio) = hil_test::common_test_pins!(io);
|
||||||
let cs_pin = hil_test::unconnected_pin!(io);
|
let cs_pin = hil_test::unconnected_pin!(io);
|
||||||
@ -115,6 +121,7 @@ mod tests {
|
|||||||
let cs = cs_pin.peripheral_input();
|
let cs = cs_pin.peripheral_input();
|
||||||
let mosi = mosi_pin.peripheral_input();
|
let mosi = mosi_pin.peripheral_input();
|
||||||
let mut miso = miso_pin.peripheral_input();
|
let mut miso = miso_pin.peripheral_input();
|
||||||
|
let sclk_signal = sclk_pin.peripheral_input();
|
||||||
|
|
||||||
let mosi_gpio = Output::new(mosi_pin, Level::Low);
|
let mosi_gpio = Output::new(mosi_pin, Level::Low);
|
||||||
let cs_gpio = Output::new(cs_pin, Level::High);
|
let cs_gpio = Output::new(cs_pin, Level::High);
|
||||||
@ -122,11 +129,11 @@ mod tests {
|
|||||||
|
|
||||||
let spi = Spi::new(
|
let spi = Spi::new(
|
||||||
peripherals.SPI2,
|
peripherals.SPI2,
|
||||||
sclk_pin,
|
sclk_signal,
|
||||||
mosi,
|
mosi,
|
||||||
miso_pin,
|
miso_pin,
|
||||||
cs,
|
cs,
|
||||||
SpiMode::Mode0,
|
SpiMode::Mode1,
|
||||||
);
|
);
|
||||||
|
|
||||||
miso.enable_input(true, unsafe { esp_hal::Internal::conjure() });
|
miso.enable_input(true, unsafe { esp_hal::Internal::conjure() });
|
||||||
@ -145,8 +152,8 @@ mod tests {
|
|||||||
let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(DMA_SIZE);
|
let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(DMA_SIZE);
|
||||||
let mut spi = ctx.spi.with_dma(
|
let mut spi = ctx.spi.with_dma(
|
||||||
ctx.dma_channel.configure(false, DmaPriority::Priority0),
|
ctx.dma_channel.configure(false, DmaPriority::Priority0),
|
||||||
tx_descriptors,
|
|
||||||
rx_descriptors,
|
rx_descriptors,
|
||||||
|
tx_descriptors,
|
||||||
);
|
);
|
||||||
let slave_send = tx_buffer;
|
let slave_send = tx_buffer;
|
||||||
let slave_receive = rx_buffer;
|
let slave_receive = rx_buffer;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user