mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-27 04:10:28 +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)
|
||||
- The `const CHANNEL: u8` parameter of RMT channels can now be erased via `Channel::degrade()`. (#3505)
|
||||
- ESP32-C6: GPIO6 now implements `AnalogPin` (#3668)
|
||||
- SPI master: Expose octal SPI-specific `with_sio` functions (#3702)
|
||||
|
||||
### 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]
|
||||
pub use dma::*;
|
||||
use enumset::{EnumSet, EnumSetType};
|
||||
use procmacros::enable_doc_switch;
|
||||
#[cfg(place_spi_master_driver_in_ram)]
|
||||
use procmacros::ram;
|
||||
|
||||
@ -59,7 +60,7 @@ use crate::{
|
||||
OutputConfig,
|
||||
OutputSignal,
|
||||
PinGuard,
|
||||
interconnect::{PeripheralInput, PeripheralOutput},
|
||||
interconnect::{self, PeripheralInput, PeripheralOutput},
|
||||
},
|
||||
interrupt::InterruptHandler,
|
||||
pac::spi2::RegisterBlock,
|
||||
@ -611,12 +612,20 @@ impl Config {
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
struct SpiPinGuard {
|
||||
mosi_pin: PinGuard,
|
||||
sclk_pin: PinGuard,
|
||||
cs_pin: PinGuard,
|
||||
sio0_pin: PinGuard,
|
||||
sio1_pin: PinGuard,
|
||||
sio2_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.
|
||||
@ -679,42 +688,40 @@ impl<'d> Spi<'d, Blocking> {
|
||||
pub fn new(spi: impl Instance + 'd, config: Config) -> Result<Self, ConfigError> {
|
||||
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 {
|
||||
spi: spi.degrade(),
|
||||
_mode: PhantomData,
|
||||
guard,
|
||||
pins: SpiPinGuard {
|
||||
mosi_pin,
|
||||
sclk_pin,
|
||||
cs_pin,
|
||||
sio1_pin,
|
||||
sio2_pin,
|
||||
sio3_pin,
|
||||
sclk_pin: PinGuard::new_unconnected(spi.info().sclk),
|
||||
cs_pin: PinGuard::new_unconnected(spi.info().cs(0)),
|
||||
sio0_pin: PinGuard::new_unconnected(spi.info().sio_output(0)),
|
||||
sio1_pin: PinGuard::new_unconnected(spi.info().sio_output(1)),
|
||||
sio2_pin: spi.info().opt_sio_output(2).map(PinGuard::new_unconnected),
|
||||
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.apply_config(&config)?;
|
||||
|
||||
let this = this
|
||||
.with_sio0(NoPin)
|
||||
.with_sio1(NoPin)
|
||||
.with_sck(NoPin)
|
||||
.with_cs(NoPin);
|
||||
let this = this.with_sck(NoPin).with_cs(NoPin);
|
||||
|
||||
let is_qspi = this.driver().info.sio2_input.is_some();
|
||||
if is_qspi {
|
||||
unwrap!(this.driver().info.sio2_input).connect_to(&NoPin);
|
||||
unwrap!(this.driver().info.sio2_output).connect_to(&NoPin);
|
||||
unwrap!(this.driver().info.sio3_input).connect_to(&NoPin);
|
||||
unwrap!(this.driver().info.sio3_output).connect_to(&NoPin);
|
||||
for sio in 0..8 {
|
||||
if let Some(signal) = this.driver().info.opt_sio_input(sio) {
|
||||
signal.connect_to(&NoPin);
|
||||
}
|
||||
if let Some(signal) = this.driver().info.opt_sio_output(sio) {
|
||||
signal.connect_to(&NoPin);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(this)
|
||||
@ -722,7 +729,7 @@ impl<'d> Spi<'d, Blocking> {
|
||||
|
||||
/// Converts the SPI instance into async mode.
|
||||
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: self.spi,
|
||||
_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.
|
||||
///
|
||||
/// 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::dma::{DmaRxBuf, DmaTxBuf};
|
||||
/// # use esp_hal::dma_buffers;
|
||||
#[cfg_attr(any(esp32, esp32s2), doc = "let dma_channel = peripherals.DMA_SPI2;")]
|
||||
#[cfg_attr(
|
||||
not(any(esp32, esp32s2)),
|
||||
doc = "let dma_channel = peripherals.DMA_CH0;"
|
||||
#[doc_switch(
|
||||
cfg(any(esp32, esp32s2)) => "let dma_channel = peripherals.DMA_SPI2;",
|
||||
_ => "let dma_channel = peripherals.DMA_CH0;",
|
||||
)]
|
||||
/// let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) =
|
||||
/// dma_buffers!(32000);
|
||||
@ -776,13 +783,10 @@ impl<'d> Spi<'d, Blocking> {
|
||||
SpiDma::new(self.spi, self.pins, channel.degrade())
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
not(multi_core),
|
||||
doc = "Registers an interrupt handler for the peripheral."
|
||||
)]
|
||||
#[cfg_attr(
|
||||
multi_core,
|
||||
doc = "Registers an interrupt handler for the peripheral on the current core."
|
||||
#[enable_doc_switch]
|
||||
#[doc_switch(
|
||||
cfg(multi_core) => "Registers an interrupt handler for the peripheral on the current core.",
|
||||
_ => "Registers an interrupt handler for the peripheral.",
|
||||
)]
|
||||
#[doc = ""]
|
||||
/// 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>
|
||||
where
|
||||
Dm: DriverMode,
|
||||
{
|
||||
fn connect_sio_pin(
|
||||
&self,
|
||||
pin: impl PeripheralOutput<'d>,
|
||||
in_signal: InputSignal,
|
||||
out_signal: OutputSignal,
|
||||
) -> PinGuard {
|
||||
let pin = pin.into();
|
||||
fn connect_sio_pin(&self, pin: interconnect::OutputSignal<'d>, n: usize) -> PinGuard {
|
||||
let in_signal = self.spi.info().sio_input(n);
|
||||
let out_signal = self.spi.info().sio_output(n);
|
||||
|
||||
pin.apply_input_config(&InputConfig::default());
|
||||
pin.apply_output_config(&OutputConfig::default());
|
||||
@ -865,9 +880,17 @@ where
|
||||
pin.connect_with_guard(out_signal)
|
||||
}
|
||||
|
||||
fn connect_output_pin(&self, pin: impl PeripheralOutput<'d>, signal: OutputSignal) -> PinGuard {
|
||||
let pin = pin.into();
|
||||
fn connect_sio_output_pin(&self, pin: interconnect::OutputSignal<'d>, n: usize) -> PinGuard {
|
||||
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.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`.
|
||||
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
|
||||
}
|
||||
@ -895,7 +918,7 @@ where
|
||||
/// Disconnects the previous pin that was assigned with `with_mosi` or
|
||||
/// `with_sio0`.
|
||||
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
|
||||
}
|
||||
@ -913,7 +936,7 @@ where
|
||||
miso.apply_input_config(&InputConfig::default());
|
||||
miso.set_input_enable(true);
|
||||
|
||||
self.driver().info.miso.connect_to(&miso);
|
||||
self.driver().info.sio_input(1).connect_to(&miso);
|
||||
|
||||
self
|
||||
}
|
||||
@ -921,20 +944,18 @@ where
|
||||
/// Assign the SIO0 pin for the SPI instance.
|
||||
///
|
||||
/// 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
|
||||
/// `with_mosi`.
|
||||
///
|
||||
/// Use this if any of the devices on the bus use half-duplex SPI.
|
||||
///
|
||||
/// The pin is configured to open-drain mode.
|
||||
///
|
||||
/// Note: You do not need to call [Self::with_mosi] when this is used.
|
||||
/// See also [Self::with_mosi] when you only need a one-directional MOSI
|
||||
/// signal.
|
||||
#[instability::unstable]
|
||||
pub fn with_sio0(mut self, mosi: impl PeripheralOutput<'d>) -> Self {
|
||||
self.pins.mosi_pin =
|
||||
self.connect_sio_pin(mosi, self.driver().info.sio0_input, self.driver().info.mosi);
|
||||
self.pins.sio0_pin = self.connect_sio_pin(mosi.into(), 0);
|
||||
|
||||
self
|
||||
}
|
||||
@ -942,55 +963,35 @@ where
|
||||
/// Assign the SIO1/MISO pin for the SPI instance.
|
||||
///
|
||||
/// 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`.
|
||||
///
|
||||
/// Use this if any of the devices on the bus use half-duplex SPI.
|
||||
///
|
||||
/// The pin is configured to open-drain mode.
|
||||
///
|
||||
/// Note: You do not need to call [Self::with_miso] when this is used.
|
||||
/// See also [Self::with_miso] when you only need a one-directional MISO
|
||||
/// signal.
|
||||
#[instability::unstable]
|
||||
pub fn with_sio1(mut self, sio1: impl PeripheralOutput<'d>) -> Self {
|
||||
self.pins.sio1_pin = self.connect_sio_pin(
|
||||
sio1,
|
||||
self.driver().info.miso,
|
||||
self.driver().info.sio1_output,
|
||||
);
|
||||
self.pins.sio1_pin = self.connect_sio_pin(sio1.into(), 1);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Assign the SIO2 pin for the SPI instance.
|
||||
///
|
||||
/// 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),
|
||||
));
|
||||
def_with_sio_pin!(with_sio2, sio2_pin, 2);
|
||||
def_with_sio_pin!(with_sio3, sio3_pin, 3);
|
||||
|
||||
self
|
||||
}
|
||||
#[cfg(spi_master_has_octal)]
|
||||
def_with_sio_pin!(with_sio4, sio4_pin, 4);
|
||||
|
||||
/// Assign the SIO3 pin for the SPI instance.
|
||||
///
|
||||
/// 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),
|
||||
));
|
||||
#[cfg(spi_master_has_octal)]
|
||||
def_with_sio_pin!(with_sio5, sio5_pin, 5);
|
||||
|
||||
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.
|
||||
///
|
||||
@ -1005,17 +1006,20 @@ where
|
||||
/// mechanism to select which CS line to use.
|
||||
#[instability::unstable]
|
||||
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
|
||||
}
|
||||
|
||||
#[procmacros::enable_doc_switch]
|
||||
/// Change the bus configuration.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If frequency passed in config exceeds
|
||||
#[cfg_attr(not(esp32h2), doc = " 80MHz")]
|
||||
#[cfg_attr(esp32h2, doc = " 48MHz")]
|
||||
#[doc_switch(
|
||||
cfg(esp32h2) => " 48MHz",
|
||||
_ => " 80MHz",
|
||||
)]
|
||||
/// or is below 70kHz,
|
||||
/// [`ConfigError::UnsupportedFrequency`] error will be returned.
|
||||
pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
@ -1185,12 +1189,15 @@ mod dma {
|
||||
sync::atomic::{Ordering, fence},
|
||||
};
|
||||
|
||||
use procmacros::enable_doc_switch;
|
||||
|
||||
use super::*;
|
||||
use crate::{
|
||||
dma::{Channel, DmaRxBuf, DmaTxBuf, EmptyBuf, PeripheralDmaChannel, asynch::DmaRxFuture},
|
||||
spi::master::dma::asynch::DropGuard,
|
||||
};
|
||||
|
||||
#[enable_doc_switch]
|
||||
/// A DMA capable SPI instance.
|
||||
///
|
||||
/// Using `SpiDma` is not recommended unless you wish
|
||||
@ -1204,10 +1211,9 @@ mod dma {
|
||||
/// # use esp_hal::spi::master::{Config, Spi};
|
||||
/// # use esp_hal::dma::{DmaRxBuf, DmaTxBuf};
|
||||
/// # use esp_hal::dma_buffers;
|
||||
#[cfg_attr(any(esp32, esp32s2), doc = "let dma_channel = peripherals.DMA_SPI2;")]
|
||||
#[cfg_attr(
|
||||
not(any(esp32, esp32s2)),
|
||||
doc = "let dma_channel = peripherals.DMA_CH0;"
|
||||
#[doc_switch(
|
||||
cfg(any(esp32, esp32s2)) => "let dma_channel = peripherals.DMA_SPI2;",
|
||||
_ => "let dma_channel = peripherals.DMA_CH0;",
|
||||
)]
|
||||
/// let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) =
|
||||
/// dma_buffers!(32000);
|
||||
@ -1254,7 +1260,7 @@ mod dma {
|
||||
/// Converts the SPI instance into async mode.
|
||||
#[instability::unstable]
|
||||
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 {
|
||||
spi: self.spi,
|
||||
channel: self.channel.into_async(),
|
||||
@ -2649,16 +2655,30 @@ mod ehal1 {
|
||||
}
|
||||
|
||||
/// SPI peripheral instance.
|
||||
#[doc(hidden)]
|
||||
#[allow(private_bounds)]
|
||||
pub trait PeripheralInstance: private::Sealed + DmaEligible {
|
||||
/// Returns the peripheral data describing this SPI instance.
|
||||
fn info(&self) -> &'static Info;
|
||||
#[cfg_attr(not(feature = "unstable"), expect(private_bounds))] // DmaEligible
|
||||
pub trait Instance: private::Sealed + IntoAnySpi + DmaEligible {
|
||||
#[doc(hidden)]
|
||||
/// Returns the peripheral data and state describing this instance.
|
||||
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.
|
||||
#[doc(hidden)]
|
||||
pub trait QspiInstance: PeripheralInstance {}
|
||||
pub trait QspiInstance: Instance {}
|
||||
|
||||
/// Peripheral data describing a particular SPI instance.
|
||||
#[doc(hidden)]
|
||||
@ -2672,67 +2692,39 @@ pub struct Info {
|
||||
/// The system peripheral marker.
|
||||
pub peripheral: crate::system::Peripheral,
|
||||
|
||||
/// Interrupt handler for the asynchronous operations.
|
||||
pub async_handler: InterruptHandler,
|
||||
|
||||
/// SCLK signal.
|
||||
pub sclk: OutputSignal,
|
||||
|
||||
/// MOSI signal.
|
||||
pub mosi: OutputSignal,
|
||||
|
||||
/// MISO signal.
|
||||
pub miso: InputSignal,
|
||||
|
||||
/// Chip select signals.
|
||||
pub cs: &'static [OutputSignal],
|
||||
|
||||
/// SIO0 (MOSI) input signal for half-duplex mode.
|
||||
pub sio0_input: InputSignal,
|
||||
pub sio_inputs: &'static [InputSignal],
|
||||
pub sio_outputs: &'static [OutputSignal],
|
||||
}
|
||||
|
||||
/// SIO1 (MISO) output signal for half-duplex mode.
|
||||
pub sio1_output: OutputSignal,
|
||||
impl Info {
|
||||
fn cs(&self, n: usize) -> OutputSignal {
|
||||
*unwrap!(self.cs.get(n), "CS{} is not defined", n)
|
||||
}
|
||||
|
||||
/// SIO2 output signal for QSPI mode.
|
||||
pub sio2_output: Option<OutputSignal>,
|
||||
fn opt_sio_input(&self, n: usize) -> Option<InputSignal> {
|
||||
self.sio_inputs.get(n).copied()
|
||||
}
|
||||
|
||||
/// SIO2 input signal for QSPI mode.
|
||||
pub sio2_input: Option<InputSignal>,
|
||||
fn opt_sio_output(&self, n: usize) -> Option<OutputSignal> {
|
||||
self.sio_outputs.get(n).copied()
|
||||
}
|
||||
|
||||
/// SIO3 output signal for QSPI mode.
|
||||
pub sio3_output: Option<OutputSignal>,
|
||||
fn sio_input(&self, n: usize) -> InputSignal {
|
||||
unwrap!(self.opt_sio_input(n), "SIO{} is not defined", n)
|
||||
}
|
||||
|
||||
/// SIO3 input signal for QSPI mode.
|
||||
pub sio3_input: Option<InputSignal>,
|
||||
|
||||
/// 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>,
|
||||
fn sio_output(&self, n: usize) -> OutputSignal {
|
||||
unwrap!(self.opt_sio_output(n), "SIO{} is not defined", n)
|
||||
}
|
||||
}
|
||||
|
||||
struct DmaDriver {
|
||||
@ -3694,89 +3686,46 @@ impl PartialEq for Info {
|
||||
|
||||
unsafe impl Sync for Info {}
|
||||
|
||||
macro_rules! spi_instance {
|
||||
($num:literal, $sclk:ident, $mosi:ident, $miso:ident, [$($cs:ident),+] $(, $sio2:ident, $sio3:ident $(, $sio4:ident, $sio5:ident, $sio6:ident, $sio7:ident)?)?) => {
|
||||
paste::paste! {
|
||||
impl PeripheralInstance for crate::peripherals::[<SPI $num>]<'_> {
|
||||
#[inline(always)]
|
||||
fn info(&self) -> &'static Info {
|
||||
static INFO: Info = Info {
|
||||
register_block: crate::peripherals::[<SPI $num>]::regs(),
|
||||
peripheral: crate::system::Peripheral::[<Spi $num>],
|
||||
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
|
||||
crate::peripherals::for_each_spi_master! {
|
||||
($peri:ident, $sys:ident, $sclk:ident [$($cs:ident),+] [$($sio:ident),*] $(, $is_qspi:tt)?) => {
|
||||
impl Instance for crate::peripherals::$peri<'_> {
|
||||
#[inline(always)]
|
||||
fn parts(&self) -> (&'static Info, &'static State) {
|
||||
#[crate::handler]
|
||||
#[cfg_attr(place_spi_master_driver_in_ram, ram)]
|
||||
fn irq_handler() {
|
||||
handle_async(&INFO, &STATE)
|
||||
}
|
||||
|
||||
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 #[cfg(esp32)] {
|
||||
spi_instance!(2, HSPICLK, HSPID, HSPIQ, [HSPICS0, HSPICS1, HSPICS2], HSPIWP, HSPIHD);
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
$(
|
||||
// If the extra pins are set, implement QspiInstance
|
||||
$crate::ignore!($is_qspi);
|
||||
impl QspiInstance for crate::peripherals::$peri<'_> {}
|
||||
)?
|
||||
};
|
||||
}
|
||||
|
||||
impl QspiInstance for AnySpi<'_> {}
|
||||
@ -3799,10 +3748,7 @@ struct Esp32Hack {
|
||||
unsafe impl Sync for Esp32Hack {}
|
||||
|
||||
#[cfg_attr(place_spi_master_driver_in_ram, ram)]
|
||||
fn handle_async(instance: impl Instance) {
|
||||
let state = instance.state();
|
||||
let info = instance.info();
|
||||
|
||||
fn handle_async(info: &'static Info, state: &'static State) {
|
||||
let driver = Driver { info, state };
|
||||
if driver.interrupts().contains(SpiInterrupt::TransferDone) {
|
||||
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
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
@ -3860,7 +3769,7 @@ pub enum DataMode {
|
||||
Dual,
|
||||
/// 4 bit, 4 data lines. (SIO0 .. SIO3)
|
||||
Quad,
|
||||
#[cfg(spi_octal)]
|
||||
#[cfg(spi_master_has_octal)]
|
||||
/// 8 bit, 8 data lines. (SIO0 .. SIO7)
|
||||
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<'_> {
|
||||
delegate::delegate! {
|
||||
to match &self.0 {
|
||||
@ -3904,8 +3808,7 @@ impl Instance for AnySpi<'_> {
|
||||
#[cfg(spi_master_spi3)]
|
||||
AnySpiInner::Spi3(spi) => spi,
|
||||
} {
|
||||
fn state(&self) -> &'static State;
|
||||
fn handler(&self) -> InterruptHandler;
|
||||
fn parts(&self) -> (&'static Info, &'static State);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -787,23 +787,21 @@ impl PartialEq for Info {
|
||||
|
||||
unsafe impl Sync for Info {}
|
||||
|
||||
macro_rules! spi_instance {
|
||||
($num:literal, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident) => {
|
||||
paste::paste! {
|
||||
impl Instance for crate::peripherals::[<SPI $num>]<'_> {
|
||||
#[inline(always)]
|
||||
fn info(&self) -> &'static Info {
|
||||
static INFO: Info = Info {
|
||||
register_block: crate::peripherals::[<SPI $num>]::regs(),
|
||||
peripheral: crate::system::Peripheral::[<Spi $num>],
|
||||
sclk: InputSignal::$sclk,
|
||||
mosi: InputSignal::$mosi,
|
||||
miso: OutputSignal::$miso,
|
||||
cs: InputSignal::$cs,
|
||||
};
|
||||
crate::peripherals::for_each_spi_slave! {
|
||||
($peri:ident, $sys:ident, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident) => {
|
||||
impl Instance for crate::peripherals::$peri<'_> {
|
||||
#[inline(always)]
|
||||
fn info(&self) -> &'static Info {
|
||||
static INFO: Info = Info {
|
||||
register_block: crate::peripherals::$peri::regs(),
|
||||
peripheral: crate::system::Peripheral::$sys,
|
||||
sclk: InputSignal::$sclk,
|
||||
mosi: InputSignal::$mosi,
|
||||
miso: OutputSignal::$miso,
|
||||
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<'_> {
|
||||
delegate::delegate! {
|
||||
to match &self.0 {
|
||||
|
@ -575,7 +575,16 @@ channel_ram_size = 64
|
||||
|
||||
[device.spi_master]
|
||||
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]
|
||||
timg_has_timer1 = true
|
||||
@ -611,7 +620,6 @@ support_status = "not_supported"
|
||||
[device.pcnt]
|
||||
[device.sd_host]
|
||||
[device.sd_slave]
|
||||
[device.spi_slave]
|
||||
[device.touch]
|
||||
[device.twai]
|
||||
|
||||
|
@ -215,7 +215,14 @@ status_registers = 2
|
||||
|
||||
[device.spi_master]
|
||||
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]
|
||||
instances = [{ name = "timg0" }]
|
||||
@ -237,7 +244,6 @@ instances = [
|
||||
|
||||
## Interfaces
|
||||
[device.ledc]
|
||||
[device.spi_slave]
|
||||
|
||||
## Miscellaneous
|
||||
[device.assist_debug]
|
||||
|
@ -269,7 +269,14 @@ channel_ram_size = 48
|
||||
|
||||
[device.spi_master]
|
||||
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]
|
||||
instances = [{ name = "timg0" }, { name = "timg1" }]
|
||||
@ -296,7 +303,6 @@ support_status = "not_supported"
|
||||
## Interfaces
|
||||
[device.i2s]
|
||||
[device.ledc]
|
||||
[device.spi_slave]
|
||||
[device.twai]
|
||||
[device.usb_serial_jtag]
|
||||
|
||||
|
@ -394,7 +394,14 @@ channel_ram_size = 48
|
||||
|
||||
[device.spi_master]
|
||||
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]
|
||||
instances = [{ name = "timg0" }, { name = "timg1" }]
|
||||
@ -429,7 +436,6 @@ has_wifi6 = true
|
||||
[device.mcpwm]
|
||||
[device.parl_io]
|
||||
[device.pcnt]
|
||||
[device.spi_slave]
|
||||
[device.sd_slave]
|
||||
[device.twai]
|
||||
[device.usb_serial_jtag]
|
||||
|
@ -339,7 +339,14 @@ channel_ram_size = 48
|
||||
|
||||
[device.spi_master]
|
||||
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]
|
||||
instances = [{ name = "timg0" }, { name = "timg1" }]
|
||||
@ -370,7 +377,6 @@ support_status = "not_supported"
|
||||
[device.mcpwm]
|
||||
[device.parl_io]
|
||||
[device.pcnt]
|
||||
[device.spi_slave]
|
||||
[device.twai]
|
||||
[device.usb_serial_jtag]
|
||||
|
||||
|
@ -69,7 +69,6 @@ symbols = [
|
||||
"psram",
|
||||
"psram_dma",
|
||||
"ulp_riscv_core",
|
||||
"spi_octal",
|
||||
|
||||
# ROM capabilities
|
||||
"rom_crc_le",
|
||||
@ -360,7 +359,17 @@ channel_ram_size = 64
|
||||
|
||||
[device.spi_master]
|
||||
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]
|
||||
timg_has_timer1 = true
|
||||
@ -397,7 +406,6 @@ support_status = "not_supported"
|
||||
## Interfaces
|
||||
[device.i2s]
|
||||
[device.ledc]
|
||||
[device.spi_slave]
|
||||
[device.pcnt]
|
||||
[device.twai]
|
||||
[device.usb_otg]
|
||||
|
@ -82,7 +82,6 @@ symbols = [
|
||||
"psram_dma",
|
||||
"octal_psram",
|
||||
"ulp_riscv_core",
|
||||
"spi_octal",
|
||||
|
||||
# ROM capabilities
|
||||
"rom_crc_le",
|
||||
@ -512,7 +511,17 @@ channel_ram_size = 48
|
||||
|
||||
[device.spi_master]
|
||||
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]
|
||||
timg_has_timer1 = true
|
||||
@ -549,7 +558,6 @@ support_status = "not_supported"
|
||||
[device.mcpwm]
|
||||
[device.pcnt]
|
||||
[device.sd_host]
|
||||
[device.spi_slave]
|
||||
[device.twai]
|
||||
[device.usb_otg]
|
||||
[device.usb_serial_jtag]
|
||||
|
@ -1,9 +1,13 @@
|
||||
pub(crate) mod gpio;
|
||||
pub(crate) mod i2c_master;
|
||||
pub(crate) mod spi_master;
|
||||
pub(crate) mod spi_slave;
|
||||
pub(crate) mod uart;
|
||||
|
||||
pub(crate) use gpio::*;
|
||||
pub(crate) use i2c_master::*;
|
||||
pub(crate) use spi_master::*;
|
||||
pub(crate) use spi_slave::*;
|
||||
pub(crate) use uart::*;
|
||||
|
||||
/// Represents a value in the driver configuration.
|
||||
@ -448,13 +452,16 @@ driver_configs![
|
||||
peripherals: &["sha"],
|
||||
properties: {}
|
||||
},
|
||||
SpiMasterProperties {
|
||||
SpiMasterProperties<SpiMasterInstanceConfig> {
|
||||
driver: spi_master,
|
||||
name: "SPI master",
|
||||
peripherals: &["spi2", "spi3"],
|
||||
properties: {}
|
||||
properties: {
|
||||
#[serde(default)]
|
||||
has_octal: bool,
|
||||
}
|
||||
},
|
||||
SpiSlaveProperties {
|
||||
SpiSlaveProperties<SpiSlaveInstanceConfig> {
|
||||
driver: spi_slave,
|
||||
name: "SPI slave",
|
||||
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();
|
||||
|
||||
// TODO: repeat for all drivers that have Instance traits
|
||||
if let Some(i2c) = self.device.peri_config.i2c_master.as_ref() {
|
||||
tokens.extend(cfg::generate_i2c_master_peripherals(i2c));
|
||||
if let Some(peri) = self.device.peri_config.i2c_master.as_ref() {
|
||||
tokens.extend(cfg::generate_i2c_master_peripherals(peri));
|
||||
};
|
||||
if let Some(uart) = self.device.peri_config.uart.as_ref() {
|
||||
tokens.extend(cfg::generate_uart_peripherals(uart));
|
||||
if let Some(peri) = self.device.peri_config.uart.as_ref() {
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user