ariel_os_esp/spi/main/
mod.rs1#![expect(unsafe_code)]
4
5use ariel_os_embassy_common::{
6 impl_async_spibus_for_driver_enum,
7 spi::{BitOrder, Mode, main::Kilohertz},
8};
9use embassy_embedded_hal::adapter::{BlockingAsync, YieldingAsync};
10use esp_hal::{
11 gpio::{
12 self,
13 interconnect::{PeripheralInput, PeripheralOutput},
14 },
15 peripherals,
16 spi::master::Spi as InnerSpi,
17};
18
19#[cfg(any(
22 context = "esp32",
23 context = "esp32c3",
24 context = "esp32c6",
25 context = "esp32s2",
26 context = "esp32s3"
27))]
28const MAX_FREQUENCY: Kilohertz = Kilohertz::MHz(80);
29
30#[derive(Clone)]
32#[non_exhaustive]
33pub struct Config {
34 pub frequency: Frequency,
36 pub mode: Mode,
38 #[doc(hidden)]
39 pub bit_order: BitOrder,
40}
41
42impl Default for Config {
43 fn default() -> Self {
44 Self {
45 frequency: Frequency::F(Kilohertz::MHz(80)),
46 mode: Mode::Mode0,
47 bit_order: BitOrder::default(),
48 }
49 }
50}
51
52#[derive(Debug, Copy, Clone, PartialEq, Eq)]
55#[cfg_attr(feature = "defmt", derive(defmt::Format))]
56#[repr(u32)]
57pub enum Frequency {
58 F(Kilohertz),
60}
61
62ariel_os_embassy_common::impl_spi_from_frequency!();
63ariel_os_embassy_common::impl_spi_frequency_const_functions!(MAX_FREQUENCY);
64
65impl From<Frequency> for esp_hal::time::Rate {
66 fn from(freq: Frequency) -> Self {
67 match freq {
68 Frequency::F(kilohertz) => esp_hal::time::Rate::from_khz(kilohertz.raw()),
69 }
70 }
71}
72
73macro_rules! define_spi_drivers {
74 ($( $peripheral:ident ),* $(,)?) => {
75 $(
76 pub struct $peripheral {
78 spim: YieldingAsync<BlockingAsync<InnerSpi<'static, esp_hal::Blocking>>>,
79 }
80
81 impl $peripheral {
82 #[expect(clippy::new_ret_no_self)]
85 #[must_use]
86 pub fn new<
87 SCK: PeripheralOutput<'static>,
88 MISO: PeripheralInput<'static>,
89 MOSI: PeripheralOutput<'static>,
90 >(
91 sck_pin: impl $crate::IntoPeripheral<'static, SCK>,
92 miso_pin: impl $crate::IntoPeripheral<'static, MISO>,
93 mosi_pin: impl $crate::IntoPeripheral<'static, MOSI>,
94 config: Config,
95 ) -> Spi {
96 paste::paste! {
99 #[allow(dead_code)]
100 static [<PREVENT_MULTIPLE_ $peripheral>]: () = ();
101 }
102
103 let spi_config = esp_hal::spi::master::Config::default()
104 .with_frequency(config.frequency.into())
105 .with_mode(crate::spi::from_mode(config.mode))
106 .with_read_bit_order(crate::spi::from_bit_order(config.bit_order))
107 .with_write_bit_order(crate::spi::from_bit_order(config.bit_order));
108
109 let spi_peripheral = unsafe { peripherals::$peripheral::steal() };
113
114 let spi = esp_hal::spi::master::Spi::new(
115 spi_peripheral,
116 spi_config,
117 )
118 .unwrap()
119 .with_sck(sck_pin.into_hal_peripheral())
120 .with_mosi(mosi_pin.into_hal_peripheral())
121 .with_miso(miso_pin.into_hal_peripheral())
122 .with_cs(gpio::NoPin); Spi::$peripheral(Self { spim: YieldingAsync::new(BlockingAsync::new(spi)) })
125 }
126 }
127 )*
128
129 pub enum Spi {
131 $(
132 #[doc = concat!(stringify!($peripheral), " peripheral.")]
133 $peripheral($peripheral)
134 ),*
135 }
136
137 impl embedded_hal_async::spi::ErrorType for Spi {
138 type Error = esp_hal::spi::Error;
139 }
140
141 impl_async_spibus_for_driver_enum!(Spi, $( $peripheral ),*);
142 };
143}
144
145#[cfg(context = "esp32")]
148define_spi_drivers!(SPI2, SPI3);
149#[cfg(context = "esp32c3")]
150define_spi_drivers!(SPI2);
151#[cfg(context = "esp32c6")]
152define_spi_drivers!(SPI2);
153#[cfg(context = "esp32s2")]
154define_spi_drivers!(SPI2, SPI3);
155#[cfg(context = "esp32s3")]
156define_spi_drivers!(SPI2, SPI3);