mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-27 12:20:56 +00:00
Extract SPI metadata (#3702)
* Extract SPI M/S metadata * Clean up additional instance trait * Further SPI cleanups, add OSPI pin setters * Re-generate semver baseline * Fix typo
This commit is contained in:
parent
9eadaa147f
commit
175f4a16b6
@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- `i2c::master::BusTimeout::Disabled` for ESP32-S2 (#3591)
|
- `i2c::master::BusTimeout::Disabled` for ESP32-S2 (#3591)
|
||||||
- The `const CHANNEL: u8` parameter of RMT channels can now be erased via `Channel::degrade()`. (#3505)
|
- The `const CHANNEL: u8` parameter of RMT channels can now be erased via `Channel::degrade()`. (#3505)
|
||||||
- ESP32-C6: GPIO6 now implements `AnalogPin` (#3668)
|
- ESP32-C6: GPIO6 now implements `AnalogPin` (#3668)
|
||||||
|
- SPI master: Expose octal SPI-specific `with_sio` functions (#3702)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -41,6 +41,7 @@ use core::marker::PhantomData;
|
|||||||
#[instability::unstable]
|
#[instability::unstable]
|
||||||
pub use dma::*;
|
pub use dma::*;
|
||||||
use enumset::{EnumSet, EnumSetType};
|
use enumset::{EnumSet, EnumSetType};
|
||||||
|
use procmacros::enable_doc_switch;
|
||||||
#[cfg(place_spi_master_driver_in_ram)]
|
#[cfg(place_spi_master_driver_in_ram)]
|
||||||
use procmacros::ram;
|
use procmacros::ram;
|
||||||
|
|
||||||
@ -59,7 +60,7 @@ use crate::{
|
|||||||
OutputConfig,
|
OutputConfig,
|
||||||
OutputSignal,
|
OutputSignal,
|
||||||
PinGuard,
|
PinGuard,
|
||||||
interconnect::{PeripheralInput, PeripheralOutput},
|
interconnect::{self, PeripheralInput, PeripheralOutput},
|
||||||
},
|
},
|
||||||
interrupt::InterruptHandler,
|
interrupt::InterruptHandler,
|
||||||
pac::spi2::RegisterBlock,
|
pac::spi2::RegisterBlock,
|
||||||
@ -611,12 +612,20 @@ impl Config {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
struct SpiPinGuard {
|
struct SpiPinGuard {
|
||||||
mosi_pin: PinGuard,
|
|
||||||
sclk_pin: PinGuard,
|
sclk_pin: PinGuard,
|
||||||
cs_pin: PinGuard,
|
cs_pin: PinGuard,
|
||||||
|
sio0_pin: PinGuard,
|
||||||
sio1_pin: PinGuard,
|
sio1_pin: PinGuard,
|
||||||
sio2_pin: Option<PinGuard>,
|
sio2_pin: Option<PinGuard>,
|
||||||
sio3_pin: Option<PinGuard>,
|
sio3_pin: Option<PinGuard>,
|
||||||
|
#[cfg(spi_master_has_octal)]
|
||||||
|
sio4_pin: Option<PinGuard>,
|
||||||
|
#[cfg(spi_master_has_octal)]
|
||||||
|
sio5_pin: Option<PinGuard>,
|
||||||
|
#[cfg(spi_master_has_octal)]
|
||||||
|
sio6_pin: Option<PinGuard>,
|
||||||
|
#[cfg(spi_master_has_octal)]
|
||||||
|
sio7_pin: Option<PinGuard>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration errors.
|
/// Configuration errors.
|
||||||
@ -679,42 +688,40 @@ impl<'d> Spi<'d, Blocking> {
|
|||||||
pub fn new(spi: impl Instance + 'd, config: Config) -> Result<Self, ConfigError> {
|
pub fn new(spi: impl Instance + 'd, config: Config) -> Result<Self, ConfigError> {
|
||||||
let guard = PeripheralGuard::new(spi.info().peripheral);
|
let guard = PeripheralGuard::new(spi.info().peripheral);
|
||||||
|
|
||||||
let mosi_pin = PinGuard::new_unconnected(spi.info().mosi);
|
|
||||||
let sclk_pin = PinGuard::new_unconnected(spi.info().sclk);
|
|
||||||
let cs_pin = PinGuard::new_unconnected(spi.info().cs[0]);
|
|
||||||
let sio1_pin = PinGuard::new_unconnected(spi.info().sio1_output);
|
|
||||||
let sio2_pin = spi.info().sio2_output.map(PinGuard::new_unconnected);
|
|
||||||
let sio3_pin = spi.info().sio3_output.map(PinGuard::new_unconnected);
|
|
||||||
|
|
||||||
let mut this = Spi {
|
let mut this = Spi {
|
||||||
spi: spi.degrade(),
|
|
||||||
_mode: PhantomData,
|
_mode: PhantomData,
|
||||||
guard,
|
guard,
|
||||||
pins: SpiPinGuard {
|
pins: SpiPinGuard {
|
||||||
mosi_pin,
|
sclk_pin: PinGuard::new_unconnected(spi.info().sclk),
|
||||||
sclk_pin,
|
cs_pin: PinGuard::new_unconnected(spi.info().cs(0)),
|
||||||
cs_pin,
|
sio0_pin: PinGuard::new_unconnected(spi.info().sio_output(0)),
|
||||||
sio1_pin,
|
sio1_pin: PinGuard::new_unconnected(spi.info().sio_output(1)),
|
||||||
sio2_pin,
|
sio2_pin: spi.info().opt_sio_output(2).map(PinGuard::new_unconnected),
|
||||||
sio3_pin,
|
sio3_pin: spi.info().opt_sio_output(3).map(PinGuard::new_unconnected),
|
||||||
|
#[cfg(spi_master_has_octal)]
|
||||||
|
sio4_pin: spi.info().opt_sio_output(4).map(PinGuard::new_unconnected),
|
||||||
|
#[cfg(spi_master_has_octal)]
|
||||||
|
sio5_pin: spi.info().opt_sio_output(5).map(PinGuard::new_unconnected),
|
||||||
|
#[cfg(spi_master_has_octal)]
|
||||||
|
sio6_pin: spi.info().opt_sio_output(6).map(PinGuard::new_unconnected),
|
||||||
|
#[cfg(spi_master_has_octal)]
|
||||||
|
sio7_pin: spi.info().opt_sio_output(7).map(PinGuard::new_unconnected),
|
||||||
},
|
},
|
||||||
|
spi: spi.degrade(),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.driver().init();
|
this.driver().init();
|
||||||
this.apply_config(&config)?;
|
this.apply_config(&config)?;
|
||||||
|
|
||||||
let this = this
|
let this = this.with_sck(NoPin).with_cs(NoPin);
|
||||||
.with_sio0(NoPin)
|
|
||||||
.with_sio1(NoPin)
|
|
||||||
.with_sck(NoPin)
|
|
||||||
.with_cs(NoPin);
|
|
||||||
|
|
||||||
let is_qspi = this.driver().info.sio2_input.is_some();
|
for sio in 0..8 {
|
||||||
if is_qspi {
|
if let Some(signal) = this.driver().info.opt_sio_input(sio) {
|
||||||
unwrap!(this.driver().info.sio2_input).connect_to(&NoPin);
|
signal.connect_to(&NoPin);
|
||||||
unwrap!(this.driver().info.sio2_output).connect_to(&NoPin);
|
}
|
||||||
unwrap!(this.driver().info.sio3_input).connect_to(&NoPin);
|
if let Some(signal) = this.driver().info.opt_sio_output(sio) {
|
||||||
unwrap!(this.driver().info.sio3_output).connect_to(&NoPin);
|
signal.connect_to(&NoPin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(this)
|
Ok(this)
|
||||||
@ -722,7 +729,7 @@ impl<'d> Spi<'d, Blocking> {
|
|||||||
|
|
||||||
/// Converts the SPI instance into async mode.
|
/// Converts the SPI instance into async mode.
|
||||||
pub fn into_async(mut self) -> Spi<'d, Async> {
|
pub fn into_async(mut self) -> Spi<'d, Async> {
|
||||||
self.set_interrupt_handler(self.spi.handler());
|
self.set_interrupt_handler(self.spi.info().async_handler);
|
||||||
Spi {
|
Spi {
|
||||||
spi: self.spi,
|
spi: self.spi,
|
||||||
_mode: PhantomData,
|
_mode: PhantomData,
|
||||||
@ -731,6 +738,7 @@ impl<'d> Spi<'d, Blocking> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[enable_doc_switch]
|
||||||
/// Configures the SPI instance to use DMA with the specified channel.
|
/// Configures the SPI instance to use DMA with the specified channel.
|
||||||
///
|
///
|
||||||
/// This method prepares the SPI instance for DMA transfers using SPI
|
/// This method prepares the SPI instance for DMA transfers using SPI
|
||||||
@ -742,10 +750,9 @@ impl<'d> Spi<'d, Blocking> {
|
|||||||
/// # use esp_hal::spi::master::{Config, Spi};
|
/// # use esp_hal::spi::master::{Config, Spi};
|
||||||
/// # use esp_hal::dma::{DmaRxBuf, DmaTxBuf};
|
/// # use esp_hal::dma::{DmaRxBuf, DmaTxBuf};
|
||||||
/// # use esp_hal::dma_buffers;
|
/// # use esp_hal::dma_buffers;
|
||||||
#[cfg_attr(any(esp32, esp32s2), doc = "let dma_channel = peripherals.DMA_SPI2;")]
|
#[doc_switch(
|
||||||
#[cfg_attr(
|
cfg(any(esp32, esp32s2)) => "let dma_channel = peripherals.DMA_SPI2;",
|
||||||
not(any(esp32, esp32s2)),
|
_ => "let dma_channel = peripherals.DMA_CH0;",
|
||||||
doc = "let dma_channel = peripherals.DMA_CH0;"
|
|
||||||
)]
|
)]
|
||||||
/// let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) =
|
/// let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) =
|
||||||
/// dma_buffers!(32000);
|
/// dma_buffers!(32000);
|
||||||
@ -776,13 +783,10 @@ impl<'d> Spi<'d, Blocking> {
|
|||||||
SpiDma::new(self.spi, self.pins, channel.degrade())
|
SpiDma::new(self.spi, self.pins, channel.degrade())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(
|
#[enable_doc_switch]
|
||||||
not(multi_core),
|
#[doc_switch(
|
||||||
doc = "Registers an interrupt handler for the peripheral."
|
cfg(multi_core) => "Registers an interrupt handler for the peripheral on the current core.",
|
||||||
)]
|
_ => "Registers an interrupt handler for the peripheral.",
|
||||||
#[cfg_attr(
|
|
||||||
multi_core,
|
|
||||||
doc = "Registers an interrupt handler for the peripheral on the current core."
|
|
||||||
)]
|
)]
|
||||||
#[doc = ""]
|
#[doc = ""]
|
||||||
/// Note that this will replace any previously registered interrupt
|
/// Note that this will replace any previously registered interrupt
|
||||||
@ -843,17 +847,28 @@ impl<'d> Spi<'d, Async> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! def_with_sio_pin {
|
||||||
|
($fn:ident, $field:ident, $n:literal) => {
|
||||||
|
#[doc = concat!(" Assign the SIO", stringify!($n), " pin for the SPI instance.")]
|
||||||
|
#[doc = " "]
|
||||||
|
#[doc = " Enables both input and output functionality for the pin, and connects it"]
|
||||||
|
#[doc = concat!(" to the SIO", stringify!($n), " output and input signals.")]
|
||||||
|
#[instability::unstable]
|
||||||
|
pub fn $fn(mut self, sio: impl PeripheralOutput<'d>) -> Self {
|
||||||
|
self.pins.$field = Some(self.connect_sio_pin(sio.into(), $n));
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
impl<'d, Dm> Spi<'d, Dm>
|
impl<'d, Dm> Spi<'d, Dm>
|
||||||
where
|
where
|
||||||
Dm: DriverMode,
|
Dm: DriverMode,
|
||||||
{
|
{
|
||||||
fn connect_sio_pin(
|
fn connect_sio_pin(&self, pin: interconnect::OutputSignal<'d>, n: usize) -> PinGuard {
|
||||||
&self,
|
let in_signal = self.spi.info().sio_input(n);
|
||||||
pin: impl PeripheralOutput<'d>,
|
let out_signal = self.spi.info().sio_output(n);
|
||||||
in_signal: InputSignal,
|
|
||||||
out_signal: OutputSignal,
|
|
||||||
) -> PinGuard {
|
|
||||||
let pin = pin.into();
|
|
||||||
|
|
||||||
pin.apply_input_config(&InputConfig::default());
|
pin.apply_input_config(&InputConfig::default());
|
||||||
pin.apply_output_config(&OutputConfig::default());
|
pin.apply_output_config(&OutputConfig::default());
|
||||||
@ -865,9 +880,17 @@ where
|
|||||||
pin.connect_with_guard(out_signal)
|
pin.connect_with_guard(out_signal)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connect_output_pin(&self, pin: impl PeripheralOutput<'d>, signal: OutputSignal) -> PinGuard {
|
fn connect_sio_output_pin(&self, pin: interconnect::OutputSignal<'d>, n: usize) -> PinGuard {
|
||||||
let pin = pin.into();
|
let out_signal = self.spi.info().sio_output(n);
|
||||||
|
|
||||||
|
self.connect_output_pin(pin, out_signal)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connect_output_pin(
|
||||||
|
&self,
|
||||||
|
pin: interconnect::OutputSignal<'d>,
|
||||||
|
signal: OutputSignal,
|
||||||
|
) -> PinGuard {
|
||||||
pin.apply_output_config(&OutputConfig::default());
|
pin.apply_output_config(&OutputConfig::default());
|
||||||
pin.set_output_enable(true); // TODO turn this bool into a Yes/No/PeripheralControl trio
|
pin.set_output_enable(true); // TODO turn this bool into a Yes/No/PeripheralControl trio
|
||||||
|
|
||||||
@ -881,7 +904,7 @@ where
|
|||||||
///
|
///
|
||||||
/// Disconnects the previous pin that was assigned with `with_sck`.
|
/// Disconnects the previous pin that was assigned with `with_sck`.
|
||||||
pub fn with_sck(mut self, sclk: impl PeripheralOutput<'d>) -> Self {
|
pub fn with_sck(mut self, sclk: impl PeripheralOutput<'d>) -> Self {
|
||||||
self.pins.sclk_pin = self.connect_output_pin(sclk, self.driver().info.sclk);
|
self.pins.sclk_pin = self.connect_output_pin(sclk.into(), self.driver().info.sclk);
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -895,7 +918,7 @@ where
|
|||||||
/// Disconnects the previous pin that was assigned with `with_mosi` or
|
/// Disconnects the previous pin that was assigned with `with_mosi` or
|
||||||
/// `with_sio0`.
|
/// `with_sio0`.
|
||||||
pub fn with_mosi(mut self, mosi: impl PeripheralOutput<'d>) -> Self {
|
pub fn with_mosi(mut self, mosi: impl PeripheralOutput<'d>) -> Self {
|
||||||
self.pins.mosi_pin = self.connect_output_pin(mosi, self.driver().info.mosi);
|
self.pins.sio0_pin = self.connect_sio_output_pin(mosi.into(), 0);
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -913,7 +936,7 @@ where
|
|||||||
miso.apply_input_config(&InputConfig::default());
|
miso.apply_input_config(&InputConfig::default());
|
||||||
miso.set_input_enable(true);
|
miso.set_input_enable(true);
|
||||||
|
|
||||||
self.driver().info.miso.connect_to(&miso);
|
self.driver().info.sio_input(1).connect_to(&miso);
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -921,20 +944,18 @@ where
|
|||||||
/// Assign the SIO0 pin for the SPI instance.
|
/// Assign the SIO0 pin for the SPI instance.
|
||||||
///
|
///
|
||||||
/// Enables both input and output functionality for the pin, and connects it
|
/// Enables both input and output functionality for the pin, and connects it
|
||||||
/// to the MOSI signal and SIO0 input signal.
|
/// to the MOSI output signal and SIO0 input signal.
|
||||||
///
|
///
|
||||||
/// Disconnects the previous pin that was assigned with `with_sio0` or
|
/// Disconnects the previous pin that was assigned with `with_sio0` or
|
||||||
/// `with_mosi`.
|
/// `with_mosi`.
|
||||||
///
|
///
|
||||||
/// Use this if any of the devices on the bus use half-duplex SPI.
|
/// Use this if any of the devices on the bus use half-duplex SPI.
|
||||||
///
|
///
|
||||||
/// The pin is configured to open-drain mode.
|
/// See also [Self::with_mosi] when you only need a one-directional MOSI
|
||||||
///
|
/// signal.
|
||||||
/// Note: You do not need to call [Self::with_mosi] when this is used.
|
|
||||||
#[instability::unstable]
|
#[instability::unstable]
|
||||||
pub fn with_sio0(mut self, mosi: impl PeripheralOutput<'d>) -> Self {
|
pub fn with_sio0(mut self, mosi: impl PeripheralOutput<'d>) -> Self {
|
||||||
self.pins.mosi_pin =
|
self.pins.sio0_pin = self.connect_sio_pin(mosi.into(), 0);
|
||||||
self.connect_sio_pin(mosi, self.driver().info.sio0_input, self.driver().info.mosi);
|
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -942,55 +963,35 @@ where
|
|||||||
/// Assign the SIO1/MISO pin for the SPI instance.
|
/// Assign the SIO1/MISO pin for the SPI instance.
|
||||||
///
|
///
|
||||||
/// Enables both input and output functionality for the pin, and connects it
|
/// Enables both input and output functionality for the pin, and connects it
|
||||||
/// to the MISO signal and SIO1 input signal.
|
/// to the MISO input signal and SIO1 output signal.
|
||||||
///
|
///
|
||||||
/// Disconnects the previous pin that was assigned with `with_sio1`.
|
/// Disconnects the previous pin that was assigned with `with_sio1`.
|
||||||
///
|
///
|
||||||
/// Use this if any of the devices on the bus use half-duplex SPI.
|
/// Use this if any of the devices on the bus use half-duplex SPI.
|
||||||
///
|
///
|
||||||
/// The pin is configured to open-drain mode.
|
/// See also [Self::with_miso] when you only need a one-directional MISO
|
||||||
///
|
/// signal.
|
||||||
/// Note: You do not need to call [Self::with_miso] when this is used.
|
|
||||||
#[instability::unstable]
|
#[instability::unstable]
|
||||||
pub fn with_sio1(mut self, sio1: impl PeripheralOutput<'d>) -> Self {
|
pub fn with_sio1(mut self, sio1: impl PeripheralOutput<'d>) -> Self {
|
||||||
self.pins.sio1_pin = self.connect_sio_pin(
|
self.pins.sio1_pin = self.connect_sio_pin(sio1.into(), 1);
|
||||||
sio1,
|
|
||||||
self.driver().info.miso,
|
|
||||||
self.driver().info.sio1_output,
|
|
||||||
);
|
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assign the SIO2 pin for the SPI instance.
|
def_with_sio_pin!(with_sio2, sio2_pin, 2);
|
||||||
///
|
def_with_sio_pin!(with_sio3, sio3_pin, 3);
|
||||||
/// Enables both input and output functionality for the pin, and connects it
|
|
||||||
/// to the SIO2 output and input signals.
|
|
||||||
#[instability::unstable]
|
|
||||||
pub fn with_sio2(mut self, sio2: impl PeripheralOutput<'d>) -> Self {
|
|
||||||
self.pins.sio2_pin = Some(self.connect_sio_pin(
|
|
||||||
sio2,
|
|
||||||
unwrap!(self.driver().info.sio2_input),
|
|
||||||
unwrap!(self.driver().info.sio2_output),
|
|
||||||
));
|
|
||||||
|
|
||||||
self
|
#[cfg(spi_master_has_octal)]
|
||||||
}
|
def_with_sio_pin!(with_sio4, sio4_pin, 4);
|
||||||
|
|
||||||
/// Assign the SIO3 pin for the SPI instance.
|
#[cfg(spi_master_has_octal)]
|
||||||
///
|
def_with_sio_pin!(with_sio5, sio5_pin, 5);
|
||||||
/// Enables both input and output functionality for the pin, and connects it
|
|
||||||
/// to the SIO3 output and input signals.
|
|
||||||
#[instability::unstable]
|
|
||||||
pub fn with_sio3(mut self, sio3: impl PeripheralOutput<'d>) -> Self {
|
|
||||||
self.pins.sio3_pin = Some(self.connect_sio_pin(
|
|
||||||
sio3,
|
|
||||||
unwrap!(self.driver().info.sio3_input),
|
|
||||||
unwrap!(self.driver().info.sio3_output),
|
|
||||||
));
|
|
||||||
|
|
||||||
self
|
#[cfg(spi_master_has_octal)]
|
||||||
}
|
def_with_sio_pin!(with_sio6, sio6_pin, 6);
|
||||||
|
|
||||||
|
#[cfg(spi_master_has_octal)]
|
||||||
|
def_with_sio_pin!(with_sio7, sio7_pin, 7);
|
||||||
|
|
||||||
/// Assign the CS (Chip Select) pin for the SPI instance.
|
/// Assign the CS (Chip Select) pin for the SPI instance.
|
||||||
///
|
///
|
||||||
@ -1005,17 +1006,20 @@ where
|
|||||||
/// mechanism to select which CS line to use.
|
/// mechanism to select which CS line to use.
|
||||||
#[instability::unstable]
|
#[instability::unstable]
|
||||||
pub fn with_cs(mut self, cs: impl PeripheralOutput<'d>) -> Self {
|
pub fn with_cs(mut self, cs: impl PeripheralOutput<'d>) -> Self {
|
||||||
self.pins.cs_pin = self.connect_output_pin(cs, self.driver().info.cs[0]);
|
self.pins.cs_pin = self.connect_output_pin(cs.into(), self.driver().info.cs(0));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[procmacros::enable_doc_switch]
|
||||||
/// Change the bus configuration.
|
/// Change the bus configuration.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// If frequency passed in config exceeds
|
/// If frequency passed in config exceeds
|
||||||
#[cfg_attr(not(esp32h2), doc = " 80MHz")]
|
#[doc_switch(
|
||||||
#[cfg_attr(esp32h2, doc = " 48MHz")]
|
cfg(esp32h2) => " 48MHz",
|
||||||
|
_ => " 80MHz",
|
||||||
|
)]
|
||||||
/// or is below 70kHz,
|
/// or is below 70kHz,
|
||||||
/// [`ConfigError::UnsupportedFrequency`] error will be returned.
|
/// [`ConfigError::UnsupportedFrequency`] error will be returned.
|
||||||
pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||||
@ -1185,12 +1189,15 @@ mod dma {
|
|||||||
sync::atomic::{Ordering, fence},
|
sync::atomic::{Ordering, fence},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use procmacros::enable_doc_switch;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
dma::{Channel, DmaRxBuf, DmaTxBuf, EmptyBuf, PeripheralDmaChannel, asynch::DmaRxFuture},
|
dma::{Channel, DmaRxBuf, DmaTxBuf, EmptyBuf, PeripheralDmaChannel, asynch::DmaRxFuture},
|
||||||
spi::master::dma::asynch::DropGuard,
|
spi::master::dma::asynch::DropGuard,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[enable_doc_switch]
|
||||||
/// A DMA capable SPI instance.
|
/// A DMA capable SPI instance.
|
||||||
///
|
///
|
||||||
/// Using `SpiDma` is not recommended unless you wish
|
/// Using `SpiDma` is not recommended unless you wish
|
||||||
@ -1204,10 +1211,9 @@ mod dma {
|
|||||||
/// # use esp_hal::spi::master::{Config, Spi};
|
/// # use esp_hal::spi::master::{Config, Spi};
|
||||||
/// # use esp_hal::dma::{DmaRxBuf, DmaTxBuf};
|
/// # use esp_hal::dma::{DmaRxBuf, DmaTxBuf};
|
||||||
/// # use esp_hal::dma_buffers;
|
/// # use esp_hal::dma_buffers;
|
||||||
#[cfg_attr(any(esp32, esp32s2), doc = "let dma_channel = peripherals.DMA_SPI2;")]
|
#[doc_switch(
|
||||||
#[cfg_attr(
|
cfg(any(esp32, esp32s2)) => "let dma_channel = peripherals.DMA_SPI2;",
|
||||||
not(any(esp32, esp32s2)),
|
_ => "let dma_channel = peripherals.DMA_CH0;",
|
||||||
doc = "let dma_channel = peripherals.DMA_CH0;"
|
|
||||||
)]
|
)]
|
||||||
/// let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) =
|
/// let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) =
|
||||||
/// dma_buffers!(32000);
|
/// dma_buffers!(32000);
|
||||||
@ -1254,7 +1260,7 @@ mod dma {
|
|||||||
/// Converts the SPI instance into async mode.
|
/// Converts the SPI instance into async mode.
|
||||||
#[instability::unstable]
|
#[instability::unstable]
|
||||||
pub fn into_async(mut self) -> SpiDma<'d, Async> {
|
pub fn into_async(mut self) -> SpiDma<'d, Async> {
|
||||||
self.set_interrupt_handler(self.spi.handler());
|
self.set_interrupt_handler(self.spi.info().async_handler);
|
||||||
SpiDma {
|
SpiDma {
|
||||||
spi: self.spi,
|
spi: self.spi,
|
||||||
channel: self.channel.into_async(),
|
channel: self.channel.into_async(),
|
||||||
@ -2649,16 +2655,30 @@ mod ehal1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// SPI peripheral instance.
|
/// SPI peripheral instance.
|
||||||
#[doc(hidden)]
|
#[cfg_attr(not(feature = "unstable"), expect(private_bounds))] // DmaEligible
|
||||||
#[allow(private_bounds)]
|
pub trait Instance: private::Sealed + IntoAnySpi + DmaEligible {
|
||||||
pub trait PeripheralInstance: private::Sealed + DmaEligible {
|
#[doc(hidden)]
|
||||||
/// Returns the peripheral data describing this SPI instance.
|
/// Returns the peripheral data and state describing this instance.
|
||||||
fn info(&self) -> &'static Info;
|
fn parts(&self) -> (&'static Info, &'static State);
|
||||||
|
|
||||||
|
/// Returns the peripheral data describing this instance.
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[inline(always)]
|
||||||
|
fn info(&self) -> &'static Info {
|
||||||
|
self.parts().0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the peripheral state for this instance.
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[inline(always)]
|
||||||
|
fn state(&self) -> &'static State {
|
||||||
|
self.parts().1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marker trait for QSPI-capable SPI peripherals.
|
/// Marker trait for QSPI-capable SPI peripherals.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub trait QspiInstance: PeripheralInstance {}
|
pub trait QspiInstance: Instance {}
|
||||||
|
|
||||||
/// Peripheral data describing a particular SPI instance.
|
/// Peripheral data describing a particular SPI instance.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -2672,67 +2692,39 @@ pub struct Info {
|
|||||||
/// The system peripheral marker.
|
/// The system peripheral marker.
|
||||||
pub peripheral: crate::system::Peripheral,
|
pub peripheral: crate::system::Peripheral,
|
||||||
|
|
||||||
|
/// Interrupt handler for the asynchronous operations.
|
||||||
|
pub async_handler: InterruptHandler,
|
||||||
|
|
||||||
/// SCLK signal.
|
/// SCLK signal.
|
||||||
pub sclk: OutputSignal,
|
pub sclk: OutputSignal,
|
||||||
|
|
||||||
/// MOSI signal.
|
|
||||||
pub mosi: OutputSignal,
|
|
||||||
|
|
||||||
/// MISO signal.
|
|
||||||
pub miso: InputSignal,
|
|
||||||
|
|
||||||
/// Chip select signals.
|
/// Chip select signals.
|
||||||
pub cs: &'static [OutputSignal],
|
pub cs: &'static [OutputSignal],
|
||||||
|
|
||||||
/// SIO0 (MOSI) input signal for half-duplex mode.
|
pub sio_inputs: &'static [InputSignal],
|
||||||
pub sio0_input: InputSignal,
|
pub sio_outputs: &'static [OutputSignal],
|
||||||
|
}
|
||||||
|
|
||||||
/// SIO1 (MISO) output signal for half-duplex mode.
|
impl Info {
|
||||||
pub sio1_output: OutputSignal,
|
fn cs(&self, n: usize) -> OutputSignal {
|
||||||
|
*unwrap!(self.cs.get(n), "CS{} is not defined", n)
|
||||||
|
}
|
||||||
|
|
||||||
/// SIO2 output signal for QSPI mode.
|
fn opt_sio_input(&self, n: usize) -> Option<InputSignal> {
|
||||||
pub sio2_output: Option<OutputSignal>,
|
self.sio_inputs.get(n).copied()
|
||||||
|
}
|
||||||
|
|
||||||
/// SIO2 input signal for QSPI mode.
|
fn opt_sio_output(&self, n: usize) -> Option<OutputSignal> {
|
||||||
pub sio2_input: Option<InputSignal>,
|
self.sio_outputs.get(n).copied()
|
||||||
|
}
|
||||||
|
|
||||||
/// SIO3 output signal for QSPI mode.
|
fn sio_input(&self, n: usize) -> InputSignal {
|
||||||
pub sio3_output: Option<OutputSignal>,
|
unwrap!(self.opt_sio_input(n), "SIO{} is not defined", n)
|
||||||
|
}
|
||||||
|
|
||||||
/// SIO3 input signal for QSPI mode.
|
fn sio_output(&self, n: usize) -> OutputSignal {
|
||||||
pub sio3_input: Option<InputSignal>,
|
unwrap!(self.opt_sio_output(n), "SIO{} is not defined", n)
|
||||||
|
}
|
||||||
/// SIO4 output signal for OPI mode.
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
pub sio4_output: Option<OutputSignal>,
|
|
||||||
|
|
||||||
/// SIO4 input signal for OPI mode.
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
pub sio4_input: Option<InputSignal>,
|
|
||||||
|
|
||||||
/// SIO5 output signal for OPI mode.
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
pub sio5_output: Option<OutputSignal>,
|
|
||||||
|
|
||||||
/// SIO5 input signal for OPI mode.
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
pub sio5_input: Option<InputSignal>,
|
|
||||||
|
|
||||||
/// SIO6 output signal for OPI mode.
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
pub sio6_output: Option<OutputSignal>,
|
|
||||||
|
|
||||||
/// SIO6 input signal for OPI mode.
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
pub sio6_input: Option<InputSignal>,
|
|
||||||
|
|
||||||
/// SIO7 output signal for OPI mode.
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
pub sio7_output: Option<OutputSignal>,
|
|
||||||
|
|
||||||
/// SIO7 input signal for OPI mode.
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
pub sio7_input: Option<InputSignal>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DmaDriver {
|
struct DmaDriver {
|
||||||
@ -3694,89 +3686,46 @@ impl PartialEq for Info {
|
|||||||
|
|
||||||
unsafe impl Sync for Info {}
|
unsafe impl Sync for Info {}
|
||||||
|
|
||||||
macro_rules! spi_instance {
|
crate::peripherals::for_each_spi_master! {
|
||||||
($num:literal, $sclk:ident, $mosi:ident, $miso:ident, [$($cs:ident),+] $(, $sio2:ident, $sio3:ident $(, $sio4:ident, $sio5:ident, $sio6:ident, $sio7:ident)?)?) => {
|
($peri:ident, $sys:ident, $sclk:ident [$($cs:ident),+] [$($sio:ident),*] $(, $is_qspi:tt)?) => {
|
||||||
paste::paste! {
|
impl Instance for crate::peripherals::$peri<'_> {
|
||||||
impl PeripheralInstance for crate::peripherals::[<SPI $num>]<'_> {
|
#[inline(always)]
|
||||||
#[inline(always)]
|
fn parts(&self) -> (&'static Info, &'static State) {
|
||||||
fn info(&self) -> &'static Info {
|
#[crate::handler]
|
||||||
static INFO: Info = Info {
|
#[cfg_attr(place_spi_master_driver_in_ram, ram)]
|
||||||
register_block: crate::peripherals::[<SPI $num>]::regs(),
|
fn irq_handler() {
|
||||||
peripheral: crate::system::Peripheral::[<Spi $num>],
|
handle_async(&INFO, &STATE)
|
||||||
sclk: OutputSignal::$sclk,
|
|
||||||
mosi: OutputSignal::$mosi,
|
|
||||||
miso: InputSignal::$miso,
|
|
||||||
cs: &[$(OutputSignal::$cs),+],
|
|
||||||
sio0_input: InputSignal::$mosi,
|
|
||||||
sio1_output: OutputSignal::$miso,
|
|
||||||
sio2_output: $crate::if_set!($(Some(OutputSignal::$sio2))?, None),
|
|
||||||
sio2_input: $crate::if_set!($(Some(InputSignal::$sio2))?, None),
|
|
||||||
sio3_output: $crate::if_set!($(Some(OutputSignal::$sio3))?, None),
|
|
||||||
sio3_input: $crate::if_set!($(Some(InputSignal::$sio3))?, None),
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
sio4_output: $crate::if_set!($($(Some(OutputSignal::$sio4))?)?, None),
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
sio4_input: $crate::if_set!($($(Some(InputSignal::$sio4))?)?, None),
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
sio5_output: $crate::if_set!($($(Some(OutputSignal::$sio5))?)?, None),
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
sio5_input: $crate::if_set!($($(Some(InputSignal::$sio5))?)?, None),
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
sio6_output: $crate::if_set!($($(Some(OutputSignal::$sio6))?)?, None),
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
sio6_input: $crate::if_set!($($(Some(InputSignal::$sio6))?)?, None),
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
sio7_output: $crate::if_set!($($(Some(OutputSignal::$sio7))?)?, None),
|
|
||||||
#[cfg(spi_octal)]
|
|
||||||
sio7_input: $crate::if_set!($($(Some(InputSignal::$sio7))?)?, None),
|
|
||||||
};
|
|
||||||
|
|
||||||
&INFO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static INFO: Info = Info {
|
||||||
|
register_block: crate::peripherals::$peri::regs(),
|
||||||
|
peripheral: crate::system::Peripheral::$sys,
|
||||||
|
async_handler: irq_handler,
|
||||||
|
sclk: OutputSignal::$sclk,
|
||||||
|
cs: &[$(OutputSignal::$cs),+],
|
||||||
|
sio_inputs: &[$(InputSignal::$sio),*],
|
||||||
|
sio_outputs: &[$(OutputSignal::$sio),*],
|
||||||
|
};
|
||||||
|
|
||||||
|
static STATE: State = State {
|
||||||
|
waker: AtomicWaker::new(),
|
||||||
|
#[cfg(esp32)]
|
||||||
|
esp32_hack: Esp32Hack {
|
||||||
|
timing_miso_delay: Cell::new(None),
|
||||||
|
extra_dummy: Cell::new(0),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
(&INFO, &STATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
$(
|
|
||||||
// If the extra pins are set, implement QspiInstance
|
|
||||||
$crate::ignore!($sio2);
|
|
||||||
impl QspiInstance for crate::peripherals::[<SPI $num>]<'_> {}
|
|
||||||
)?
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(spi_master_spi2)]
|
$(
|
||||||
cfg_if::cfg_if! {
|
// If the extra pins are set, implement QspiInstance
|
||||||
if #[cfg(esp32)] {
|
$crate::ignore!($is_qspi);
|
||||||
spi_instance!(2, HSPICLK, HSPID, HSPIQ, [HSPICS0, HSPICS1, HSPICS2], HSPIWP, HSPIHD);
|
impl QspiInstance for crate::peripherals::$peri<'_> {}
|
||||||
} else if #[cfg(any(esp32s2, esp32s3))] {
|
)?
|
||||||
spi_instance!(2, FSPICLK, FSPID, FSPIQ, [FSPICS0, FSPICS1, FSPICS2, FSPICS3, FSPICS4, FSPICS5], FSPIWP, FSPIHD, FSPIIO4, FSPIIO5, FSPIIO6, FSPIIO7);
|
};
|
||||||
} else {
|
|
||||||
spi_instance!(2, FSPICLK, FSPID, FSPIQ, [FSPICS0, FSPICS1, FSPICS2, FSPICS3, FSPICS4, FSPICS5], FSPIWP, FSPIHD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(spi_master_spi3)]
|
|
||||||
cfg_if::cfg_if! {
|
|
||||||
if #[cfg(esp32)] {
|
|
||||||
spi_instance!(3, VSPICLK, VSPID, VSPIQ, [VSPICS0, VSPICS1, VSPICS2], VSPIWP, VSPIHD);
|
|
||||||
} else if #[cfg(esp32s3)] {
|
|
||||||
spi_instance!(3, SPI3_CLK, SPI3_D, SPI3_Q, [SPI3_CS0, SPI3_CS1, SPI3_CS2], SPI3_WP, SPI3_HD);
|
|
||||||
} else {
|
|
||||||
spi_instance!(3, SPI3_CLK, SPI3_D, SPI3_Q, [SPI3_CS0, SPI3_CS1, SPI3_CS2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PeripheralInstance for AnySpi<'_> {
|
|
||||||
delegate::delegate! {
|
|
||||||
to match &self.0 {
|
|
||||||
#[cfg(spi_master_spi2)]
|
|
||||||
AnySpiInner::Spi2(spi) => spi,
|
|
||||||
#[cfg(spi_master_spi3)]
|
|
||||||
AnySpiInner::Spi3(spi) => spi,
|
|
||||||
} {
|
|
||||||
fn info(&self) -> &'static Info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QspiInstance for AnySpi<'_> {}
|
impl QspiInstance for AnySpi<'_> {}
|
||||||
@ -3799,10 +3748,7 @@ struct Esp32Hack {
|
|||||||
unsafe impl Sync for Esp32Hack {}
|
unsafe impl Sync for Esp32Hack {}
|
||||||
|
|
||||||
#[cfg_attr(place_spi_master_driver_in_ram, ram)]
|
#[cfg_attr(place_spi_master_driver_in_ram, ram)]
|
||||||
fn handle_async(instance: impl Instance) {
|
fn handle_async(info: &'static Info, state: &'static State) {
|
||||||
let state = instance.state();
|
|
||||||
let info = instance.info();
|
|
||||||
|
|
||||||
let driver = Driver { info, state };
|
let driver = Driver { info, state };
|
||||||
if driver.interrupts().contains(SpiInterrupt::TransferDone) {
|
if driver.interrupts().contains(SpiInterrupt::TransferDone) {
|
||||||
driver.enable_listen(SpiInterrupt::TransferDone.into(), false);
|
driver.enable_listen(SpiInterrupt::TransferDone.into(), false);
|
||||||
@ -3810,43 +3756,6 @@ fn handle_async(instance: impl Instance) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A peripheral singleton compatible with the SPI master driver.
|
|
||||||
pub trait Instance: PeripheralInstance + IntoAnySpi {
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn state(&self) -> &'static State;
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn handler(&self) -> InterruptHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! master_instance {
|
|
||||||
($peri:ident) => {
|
|
||||||
impl Instance for $crate::peripherals::$peri<'_> {
|
|
||||||
fn state(&self) -> &'static State {
|
|
||||||
static STATE: State = State {
|
|
||||||
waker: AtomicWaker::new(),
|
|
||||||
#[cfg(esp32)]
|
|
||||||
esp32_hack: Esp32Hack {
|
|
||||||
timing_miso_delay: Cell::new(None),
|
|
||||||
extra_dummy: Cell::new(0),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
&STATE
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handler(&self) -> InterruptHandler {
|
|
||||||
#[$crate::handler]
|
|
||||||
#[cfg_attr(place_spi_master_driver_in_ram, ram)]
|
|
||||||
fn handle() {
|
|
||||||
handle_async(unsafe { $crate::peripherals::$peri::steal() })
|
|
||||||
}
|
|
||||||
|
|
||||||
handle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// SPI data mode
|
/// SPI data mode
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
@ -3860,7 +3769,7 @@ pub enum DataMode {
|
|||||||
Dual,
|
Dual,
|
||||||
/// 4 bit, 4 data lines. (SIO0 .. SIO3)
|
/// 4 bit, 4 data lines. (SIO0 .. SIO3)
|
||||||
Quad,
|
Quad,
|
||||||
#[cfg(spi_octal)]
|
#[cfg(spi_master_has_octal)]
|
||||||
/// 8 bit, 8 data lines. (SIO0 .. SIO7)
|
/// 8 bit, 8 data lines. (SIO0 .. SIO7)
|
||||||
Octal,
|
Octal,
|
||||||
}
|
}
|
||||||
@ -3891,11 +3800,6 @@ impl<'d> DmaEligible for AnySpi<'d> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(spi_master_spi2)]
|
|
||||||
master_instance!(SPI2);
|
|
||||||
#[cfg(spi_master_spi3)]
|
|
||||||
master_instance!(SPI3);
|
|
||||||
|
|
||||||
impl Instance for AnySpi<'_> {
|
impl Instance for AnySpi<'_> {
|
||||||
delegate::delegate! {
|
delegate::delegate! {
|
||||||
to match &self.0 {
|
to match &self.0 {
|
||||||
@ -3904,8 +3808,7 @@ impl Instance for AnySpi<'_> {
|
|||||||
#[cfg(spi_master_spi3)]
|
#[cfg(spi_master_spi3)]
|
||||||
AnySpiInner::Spi3(spi) => spi,
|
AnySpiInner::Spi3(spi) => spi,
|
||||||
} {
|
} {
|
||||||
fn state(&self) -> &'static State;
|
fn parts(&self) -> (&'static Info, &'static State);
|
||||||
fn handler(&self) -> InterruptHandler;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -787,23 +787,21 @@ impl PartialEq for Info {
|
|||||||
|
|
||||||
unsafe impl Sync for Info {}
|
unsafe impl Sync for Info {}
|
||||||
|
|
||||||
macro_rules! spi_instance {
|
crate::peripherals::for_each_spi_slave! {
|
||||||
($num:literal, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident) => {
|
($peri:ident, $sys:ident, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident) => {
|
||||||
paste::paste! {
|
impl Instance for crate::peripherals::$peri<'_> {
|
||||||
impl Instance for crate::peripherals::[<SPI $num>]<'_> {
|
#[inline(always)]
|
||||||
#[inline(always)]
|
fn info(&self) -> &'static Info {
|
||||||
fn info(&self) -> &'static Info {
|
static INFO: Info = Info {
|
||||||
static INFO: Info = Info {
|
register_block: crate::peripherals::$peri::regs(),
|
||||||
register_block: crate::peripherals::[<SPI $num>]::regs(),
|
peripheral: crate::system::Peripheral::$sys,
|
||||||
peripheral: crate::system::Peripheral::[<Spi $num>],
|
sclk: InputSignal::$sclk,
|
||||||
sclk: InputSignal::$sclk,
|
mosi: InputSignal::$mosi,
|
||||||
mosi: InputSignal::$mosi,
|
miso: OutputSignal::$miso,
|
||||||
miso: OutputSignal::$miso,
|
cs: InputSignal::$cs,
|
||||||
cs: InputSignal::$cs,
|
};
|
||||||
};
|
|
||||||
|
|
||||||
&INFO
|
&INFO
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -834,21 +832,6 @@ impl<'d> DmaEligible for AnySpi<'d> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
|
||||||
if #[cfg(esp32)] {
|
|
||||||
#[cfg(spi_master_spi2)]
|
|
||||||
spi_instance!(2, HSPICLK, HSPID, HSPIQ, HSPICS0);
|
|
||||||
#[cfg(spi_master_spi3)]
|
|
||||||
spi_instance!(3, VSPICLK, VSPID, VSPIQ, VSPICS0);
|
|
||||||
} else {
|
|
||||||
#[cfg(spi_master_spi2)]
|
|
||||||
spi_instance!(2, FSPICLK, FSPID, FSPIQ, FSPICS0);
|
|
||||||
#[cfg(spi_master_spi3)]
|
|
||||||
spi_instance!(3, SPI3_CLK, SPI3_D, SPI3_Q, SPI3_CS0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Instance for AnySpi<'_> {
|
impl Instance for AnySpi<'_> {
|
||||||
delegate::delegate! {
|
delegate::delegate! {
|
||||||
to match &self.0 {
|
to match &self.0 {
|
||||||
|
@ -575,7 +575,16 @@ channel_ram_size = 64
|
|||||||
|
|
||||||
[device.spi_master]
|
[device.spi_master]
|
||||||
support_status = "supported"
|
support_status = "supported"
|
||||||
instances = [{ name = "spi2" }, { name = "spi3" }]
|
instances = [
|
||||||
|
{ name = "spi2", sys_instance = "Spi2", sclk = "HSPICLK", sio = ["HSPID", "HSPIQ", "HSPIWP", "HSPIHD"], cs = ["HSPICS0", "HSPICS1", "HSPICS2"] },
|
||||||
|
{ name = "spi3", sys_instance = "Spi3", sclk = "VSPICLK", sio = ["VSPID", "VSPIQ", "VSPIWP", "VSPIHD"], cs = ["VSPICS0", "VSPICS1", "VSPICS2"] },
|
||||||
|
]
|
||||||
|
|
||||||
|
[device.spi_slave]
|
||||||
|
instances = [
|
||||||
|
{ name = "spi2", sys_instance = "Spi2", sclk = "HSPICLK", mosi = "HSPID", miso = "HSPIQ", cs = "HSPICS0" },
|
||||||
|
{ name = "spi3", sys_instance = "Spi3", sclk = "VSPICLK", mosi = "VSPID", miso = "VSPIQ", cs = "VSPICS0" },
|
||||||
|
]
|
||||||
|
|
||||||
[device.timergroup]
|
[device.timergroup]
|
||||||
timg_has_timer1 = true
|
timg_has_timer1 = true
|
||||||
@ -611,7 +620,6 @@ support_status = "not_supported"
|
|||||||
[device.pcnt]
|
[device.pcnt]
|
||||||
[device.sd_host]
|
[device.sd_host]
|
||||||
[device.sd_slave]
|
[device.sd_slave]
|
||||||
[device.spi_slave]
|
|
||||||
[device.touch]
|
[device.touch]
|
||||||
[device.twai]
|
[device.twai]
|
||||||
|
|
||||||
|
@ -215,7 +215,14 @@ status_registers = 2
|
|||||||
|
|
||||||
[device.spi_master]
|
[device.spi_master]
|
||||||
support_status = "supported"
|
support_status = "supported"
|
||||||
instances = [{ name = "spi2" }]
|
instances = [
|
||||||
|
{ name = "spi2", sys_instance = "Spi2", sclk = "FSPICLK", sio = ["FSPID", "FSPIQ", "FSPIWP", "FSPIHD"], cs = ["FSPICS0", "FSPICS1", "FSPICS2", "FSPICS3", "FSPICS4", "FSPICS5"] },
|
||||||
|
]
|
||||||
|
|
||||||
|
[device.spi_slave]
|
||||||
|
instances = [
|
||||||
|
{ name = "spi2", sys_instance = "Spi2", sclk = "FSPICLK", mosi = "FSPID", miso = "FSPIQ", cs = "FSPICS0" },
|
||||||
|
]
|
||||||
|
|
||||||
[device.timergroup]
|
[device.timergroup]
|
||||||
instances = [{ name = "timg0" }]
|
instances = [{ name = "timg0" }]
|
||||||
@ -237,7 +244,6 @@ instances = [
|
|||||||
|
|
||||||
## Interfaces
|
## Interfaces
|
||||||
[device.ledc]
|
[device.ledc]
|
||||||
[device.spi_slave]
|
|
||||||
|
|
||||||
## Miscellaneous
|
## Miscellaneous
|
||||||
[device.assist_debug]
|
[device.assist_debug]
|
||||||
|
@ -269,7 +269,14 @@ channel_ram_size = 48
|
|||||||
|
|
||||||
[device.spi_master]
|
[device.spi_master]
|
||||||
support_status = "supported"
|
support_status = "supported"
|
||||||
instances = [{ name = "spi2" }]
|
instances = [
|
||||||
|
{ name = "spi2", sys_instance = "Spi2", sclk = "FSPICLK", sio = ["FSPID", "FSPIQ", "FSPIWP", "FSPIHD"], cs = ["FSPICS0", "FSPICS1", "FSPICS2", "FSPICS3", "FSPICS4", "FSPICS5"] },
|
||||||
|
]
|
||||||
|
|
||||||
|
[device.spi_slave]
|
||||||
|
instances = [
|
||||||
|
{ name = "spi2", sys_instance = "Spi2", sclk = "FSPICLK", mosi = "FSPID", miso = "FSPIQ", cs = "FSPICS0" },
|
||||||
|
]
|
||||||
|
|
||||||
[device.timergroup]
|
[device.timergroup]
|
||||||
instances = [{ name = "timg0" }, { name = "timg1" }]
|
instances = [{ name = "timg0" }, { name = "timg1" }]
|
||||||
@ -296,7 +303,6 @@ support_status = "not_supported"
|
|||||||
## Interfaces
|
## Interfaces
|
||||||
[device.i2s]
|
[device.i2s]
|
||||||
[device.ledc]
|
[device.ledc]
|
||||||
[device.spi_slave]
|
|
||||||
[device.twai]
|
[device.twai]
|
||||||
[device.usb_serial_jtag]
|
[device.usb_serial_jtag]
|
||||||
|
|
||||||
|
@ -394,7 +394,14 @@ channel_ram_size = 48
|
|||||||
|
|
||||||
[device.spi_master]
|
[device.spi_master]
|
||||||
support_status = "supported"
|
support_status = "supported"
|
||||||
instances = [{ name = "spi2" }]
|
instances = [
|
||||||
|
{ name = "spi2", sys_instance = "Spi2", sclk = "FSPICLK", sio = ["FSPID", "FSPIQ", "FSPIWP", "FSPIHD"], cs = ["FSPICS0", "FSPICS1", "FSPICS2", "FSPICS3", "FSPICS4", "FSPICS5"] },
|
||||||
|
]
|
||||||
|
|
||||||
|
[device.spi_slave]
|
||||||
|
instances = [
|
||||||
|
{ name = "spi2", sys_instance = "Spi2", sclk = "FSPICLK", mosi = "FSPID", miso = "FSPIQ", cs = "FSPICS0" },
|
||||||
|
]
|
||||||
|
|
||||||
[device.timergroup]
|
[device.timergroup]
|
||||||
instances = [{ name = "timg0" }, { name = "timg1" }]
|
instances = [{ name = "timg0" }, { name = "timg1" }]
|
||||||
@ -429,7 +436,6 @@ has_wifi6 = true
|
|||||||
[device.mcpwm]
|
[device.mcpwm]
|
||||||
[device.parl_io]
|
[device.parl_io]
|
||||||
[device.pcnt]
|
[device.pcnt]
|
||||||
[device.spi_slave]
|
|
||||||
[device.sd_slave]
|
[device.sd_slave]
|
||||||
[device.twai]
|
[device.twai]
|
||||||
[device.usb_serial_jtag]
|
[device.usb_serial_jtag]
|
||||||
|
@ -339,7 +339,14 @@ channel_ram_size = 48
|
|||||||
|
|
||||||
[device.spi_master]
|
[device.spi_master]
|
||||||
support_status = "supported"
|
support_status = "supported"
|
||||||
instances = [{ name = "spi2" }]
|
instances = [
|
||||||
|
{ name = "spi2", sys_instance = "Spi2", sclk = "FSPICLK", sio = ["FSPID", "FSPIQ", "FSPIWP", "FSPIHD"], cs = ["FSPICS0", "FSPICS1", "FSPICS2", "FSPICS3", "FSPICS4", "FSPICS5"] },
|
||||||
|
]
|
||||||
|
|
||||||
|
[device.spi_slave]
|
||||||
|
instances = [
|
||||||
|
{ name = "spi2", sys_instance = "Spi2", sclk = "FSPICLK", mosi = "FSPID", miso = "FSPIQ", cs = "FSPICS0" },
|
||||||
|
]
|
||||||
|
|
||||||
[device.timergroup]
|
[device.timergroup]
|
||||||
instances = [{ name = "timg0" }, { name = "timg1" }]
|
instances = [{ name = "timg0" }, { name = "timg1" }]
|
||||||
@ -370,7 +377,6 @@ support_status = "not_supported"
|
|||||||
[device.mcpwm]
|
[device.mcpwm]
|
||||||
[device.parl_io]
|
[device.parl_io]
|
||||||
[device.pcnt]
|
[device.pcnt]
|
||||||
[device.spi_slave]
|
|
||||||
[device.twai]
|
[device.twai]
|
||||||
[device.usb_serial_jtag]
|
[device.usb_serial_jtag]
|
||||||
|
|
||||||
|
@ -69,7 +69,6 @@ symbols = [
|
|||||||
"psram",
|
"psram",
|
||||||
"psram_dma",
|
"psram_dma",
|
||||||
"ulp_riscv_core",
|
"ulp_riscv_core",
|
||||||
"spi_octal",
|
|
||||||
|
|
||||||
# ROM capabilities
|
# ROM capabilities
|
||||||
"rom_crc_le",
|
"rom_crc_le",
|
||||||
@ -360,7 +359,17 @@ channel_ram_size = 64
|
|||||||
|
|
||||||
[device.spi_master]
|
[device.spi_master]
|
||||||
support_status = "supported"
|
support_status = "supported"
|
||||||
instances = [{ name = "spi2" }, { name = "spi3" }]
|
has_octal = true
|
||||||
|
instances = [
|
||||||
|
{ name = "spi2", sys_instance = "Spi2", sclk = "FSPICLK", sio = ["FSPID", "FSPIQ", "FSPIWP", "FSPIHD", "FSPIIO4", "FSPIIO5", "FSPIIO6", "FSPIIO7"], cs = ["FSPICS0", "FSPICS1", "FSPICS2", "FSPICS3", "FSPICS4", "FSPICS5"] },
|
||||||
|
{ name = "spi3", sys_instance = "Spi3", sclk = "SPI3_CLK", sio = ["SPI3_D", "SPI3_Q"], cs = ["SPI3_CS0", "SPI3_CS1", "SPI3_CS2"] },
|
||||||
|
]
|
||||||
|
|
||||||
|
[device.spi_slave]
|
||||||
|
instances = [
|
||||||
|
{ name = "spi2", sys_instance = "Spi2", sclk = "FSPICLK", mosi = "FSPID", miso = "FSPIQ", cs = "FSPICS0" },
|
||||||
|
{ name = "spi3", sys_instance = "Spi3", sclk = "SPI3_CLK", mosi = "SPI3_D", miso = "SPI3_Q", cs = "SPI3_CS0" },
|
||||||
|
]
|
||||||
|
|
||||||
[device.timergroup]
|
[device.timergroup]
|
||||||
timg_has_timer1 = true
|
timg_has_timer1 = true
|
||||||
@ -397,7 +406,6 @@ support_status = "not_supported"
|
|||||||
## Interfaces
|
## Interfaces
|
||||||
[device.i2s]
|
[device.i2s]
|
||||||
[device.ledc]
|
[device.ledc]
|
||||||
[device.spi_slave]
|
|
||||||
[device.pcnt]
|
[device.pcnt]
|
||||||
[device.twai]
|
[device.twai]
|
||||||
[device.usb_otg]
|
[device.usb_otg]
|
||||||
|
@ -82,7 +82,6 @@ symbols = [
|
|||||||
"psram_dma",
|
"psram_dma",
|
||||||
"octal_psram",
|
"octal_psram",
|
||||||
"ulp_riscv_core",
|
"ulp_riscv_core",
|
||||||
"spi_octal",
|
|
||||||
|
|
||||||
# ROM capabilities
|
# ROM capabilities
|
||||||
"rom_crc_le",
|
"rom_crc_le",
|
||||||
@ -512,7 +511,17 @@ channel_ram_size = 48
|
|||||||
|
|
||||||
[device.spi_master]
|
[device.spi_master]
|
||||||
support_status = "supported"
|
support_status = "supported"
|
||||||
instances = [{ name = "spi2" }, { name = "spi3" }]
|
has_octal = true
|
||||||
|
instances = [
|
||||||
|
{ name = "spi2", sys_instance = "Spi2", sclk = "FSPICLK", sio = ["FSPID", "FSPIQ", "FSPIWP", "FSPIHD", "FSPIIO4", "FSPIIO5", "FSPIIO6", "FSPIIO7"], cs = ["FSPICS0", "FSPICS1", "FSPICS2", "FSPICS3", "FSPICS4", "FSPICS5"] },
|
||||||
|
{ name = "spi3", sys_instance = "Spi3", sclk = "SPI3_CLK", sio = ["SPI3_D", "SPI3_Q", "SPI3_WP", "SPI3_HD"], cs = ["SPI3_CS0", "SPI3_CS1", "SPI3_CS2"] },
|
||||||
|
]
|
||||||
|
|
||||||
|
[device.spi_slave]
|
||||||
|
instances = [
|
||||||
|
{ name = "spi2", sys_instance = "Spi2", sclk = "FSPICLK", mosi = "FSPID", miso = "FSPIQ", cs = "FSPICS0" },
|
||||||
|
{ name = "spi3", sys_instance = "Spi3", sclk = "SPI3_CLK", mosi = "SPI3_D", miso = "SPI3_Q", cs = "SPI3_CS0" },
|
||||||
|
]
|
||||||
|
|
||||||
[device.timergroup]
|
[device.timergroup]
|
||||||
timg_has_timer1 = true
|
timg_has_timer1 = true
|
||||||
@ -549,7 +558,6 @@ support_status = "not_supported"
|
|||||||
[device.mcpwm]
|
[device.mcpwm]
|
||||||
[device.pcnt]
|
[device.pcnt]
|
||||||
[device.sd_host]
|
[device.sd_host]
|
||||||
[device.spi_slave]
|
|
||||||
[device.twai]
|
[device.twai]
|
||||||
[device.usb_otg]
|
[device.usb_otg]
|
||||||
[device.usb_serial_jtag]
|
[device.usb_serial_jtag]
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
pub(crate) mod gpio;
|
pub(crate) mod gpio;
|
||||||
pub(crate) mod i2c_master;
|
pub(crate) mod i2c_master;
|
||||||
|
pub(crate) mod spi_master;
|
||||||
|
pub(crate) mod spi_slave;
|
||||||
pub(crate) mod uart;
|
pub(crate) mod uart;
|
||||||
|
|
||||||
pub(crate) use gpio::*;
|
pub(crate) use gpio::*;
|
||||||
pub(crate) use i2c_master::*;
|
pub(crate) use i2c_master::*;
|
||||||
|
pub(crate) use spi_master::*;
|
||||||
|
pub(crate) use spi_slave::*;
|
||||||
pub(crate) use uart::*;
|
pub(crate) use uart::*;
|
||||||
|
|
||||||
/// Represents a value in the driver configuration.
|
/// Represents a value in the driver configuration.
|
||||||
@ -448,13 +452,16 @@ driver_configs![
|
|||||||
peripherals: &["sha"],
|
peripherals: &["sha"],
|
||||||
properties: {}
|
properties: {}
|
||||||
},
|
},
|
||||||
SpiMasterProperties {
|
SpiMasterProperties<SpiMasterInstanceConfig> {
|
||||||
driver: spi_master,
|
driver: spi_master,
|
||||||
name: "SPI master",
|
name: "SPI master",
|
||||||
peripherals: &["spi2", "spi3"],
|
peripherals: &["spi2", "spi3"],
|
||||||
properties: {}
|
properties: {
|
||||||
|
#[serde(default)]
|
||||||
|
has_octal: bool,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SpiSlaveProperties {
|
SpiSlaveProperties<SpiSlaveInstanceConfig> {
|
||||||
driver: spi_slave,
|
driver: spi_slave,
|
||||||
name: "SPI slave",
|
name: "SPI slave",
|
||||||
peripherals: &["spi2", "spi3"],
|
peripherals: &["spi2", "spi3"],
|
||||||
|
49
esp-metadata/src/cfg/spi_master.rs
Normal file
49
esp-metadata/src/cfg/spi_master.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::format_ident;
|
||||||
|
|
||||||
|
use crate::{cfg::SpiMasterProperties, generate_for_each_macro};
|
||||||
|
|
||||||
|
/// Instance configuration, used in [device.spi_slave.instances]
|
||||||
|
#[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)]
|
||||||
|
pub(crate) struct SpiMasterInstanceConfig {
|
||||||
|
/// The name of the instance in the `esp_hal::system::Peripheral` enum
|
||||||
|
pub sys_instance: String,
|
||||||
|
// IOMUX signal names of the instance's signals:
|
||||||
|
pub sclk: String,
|
||||||
|
pub sio: Vec<String>,
|
||||||
|
pub cs: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates `for_each_spi_slave!` which can be used to implement the SPI
|
||||||
|
/// master Instance trait for the relevant peripherals. The macro generates code
|
||||||
|
/// for each [device.spi_master.instances[X]] instance.
|
||||||
|
pub(crate) fn generate_spi_master_peripherals(spi_slave: &SpiMasterProperties) -> TokenStream {
|
||||||
|
let instance_cfgs = spi_slave
|
||||||
|
.instances
|
||||||
|
.iter()
|
||||||
|
.map(|instance| {
|
||||||
|
let instance_config = &instance.instance_config;
|
||||||
|
|
||||||
|
let instance = format_ident!("{}", instance.name.to_uppercase());
|
||||||
|
|
||||||
|
let sys = format_ident!("{}", instance_config.sys_instance);
|
||||||
|
let sclk = format_ident!("{}", instance_config.sclk);
|
||||||
|
let cs = instance_config.cs.iter().map(|cs| format_ident!("{cs}"));
|
||||||
|
let sio = instance_config.sio.iter().map(|cs| format_ident!("{cs}"));
|
||||||
|
|
||||||
|
let is_qspi = if instance_config.sio.len() > 2 {
|
||||||
|
quote::quote! { , true }
|
||||||
|
} else {
|
||||||
|
quote::quote! {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// The order and meaning of these tokens must match their use in the
|
||||||
|
// `for_each_i2c_master!` call.
|
||||||
|
quote::quote! {
|
||||||
|
#instance, #sys, #sclk [#(#cs),*] [#(#sio),*] #is_qspi
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
generate_for_each_macro("spi_master", &instance_cfgs)
|
||||||
|
}
|
45
esp-metadata/src/cfg/spi_slave.rs
Normal file
45
esp-metadata/src/cfg/spi_slave.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::format_ident;
|
||||||
|
|
||||||
|
use crate::{cfg::SpiSlaveProperties, generate_for_each_macro};
|
||||||
|
|
||||||
|
/// Instance configuration, used in [device.spi_slave.instances]
|
||||||
|
#[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)]
|
||||||
|
pub(crate) struct SpiSlaveInstanceConfig {
|
||||||
|
/// The name of the instance in the `esp_hal::system::Peripheral` enum
|
||||||
|
pub sys_instance: String,
|
||||||
|
// IOMUX signal names of the instance's signals:
|
||||||
|
pub sclk: String,
|
||||||
|
pub mosi: String,
|
||||||
|
pub miso: String,
|
||||||
|
pub cs: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates `for_each_spi_slave!` which can be used to implement the SPI
|
||||||
|
/// slave Instance trait for the relevant peripherals. The macro generates code
|
||||||
|
/// for each [device.spi_slave.instances[X]] instance.
|
||||||
|
pub(crate) fn generate_spi_slave_peripherals(spi_slave: &SpiSlaveProperties) -> TokenStream {
|
||||||
|
let instance_cfgs = spi_slave
|
||||||
|
.instances
|
||||||
|
.iter()
|
||||||
|
.map(|instance| {
|
||||||
|
let instance_config = &instance.instance_config;
|
||||||
|
|
||||||
|
let instance = format_ident!("{}", instance.name.to_uppercase());
|
||||||
|
|
||||||
|
let sys = format_ident!("{}", instance_config.sys_instance);
|
||||||
|
let sclk = format_ident!("{}", instance_config.sclk);
|
||||||
|
let mosi = format_ident!("{}", instance_config.mosi);
|
||||||
|
let miso = format_ident!("{}", instance_config.miso);
|
||||||
|
let cs = format_ident!("{}", instance_config.cs);
|
||||||
|
|
||||||
|
// The order and meaning of these tokens must match their use in the
|
||||||
|
// `for_each_i2c_master!` call.
|
||||||
|
quote::quote! {
|
||||||
|
#instance, #sys, #sclk, #mosi, #miso, #cs
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
generate_for_each_macro("spi_slave", &instance_cfgs)
|
||||||
|
}
|
@ -479,11 +479,17 @@ impl Config {
|
|||||||
let mut tokens = TokenStream::new();
|
let mut tokens = TokenStream::new();
|
||||||
|
|
||||||
// TODO: repeat for all drivers that have Instance traits
|
// TODO: repeat for all drivers that have Instance traits
|
||||||
if let Some(i2c) = self.device.peri_config.i2c_master.as_ref() {
|
if let Some(peri) = self.device.peri_config.i2c_master.as_ref() {
|
||||||
tokens.extend(cfg::generate_i2c_master_peripherals(i2c));
|
tokens.extend(cfg::generate_i2c_master_peripherals(peri));
|
||||||
};
|
};
|
||||||
if let Some(uart) = self.device.peri_config.uart.as_ref() {
|
if let Some(peri) = self.device.peri_config.uart.as_ref() {
|
||||||
tokens.extend(cfg::generate_uart_peripherals(uart));
|
tokens.extend(cfg::generate_uart_peripherals(peri));
|
||||||
|
}
|
||||||
|
if let Some(peri) = self.device.peri_config.spi_master.as_ref() {
|
||||||
|
tokens.extend(cfg::generate_spi_master_peripherals(peri));
|
||||||
|
};
|
||||||
|
if let Some(peri) = self.device.peri_config.spi_slave.as_ref() {
|
||||||
|
tokens.extend(cfg::generate_spi_slave_peripherals(peri));
|
||||||
};
|
};
|
||||||
|
|
||||||
save(out_dir.join(file_name), tokens);
|
save(out_dir.join(file_name), tokens);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user