1#![expect(unsafe_code)]
4
5use portable_atomic::{AtomicBool, Ordering};
6
7use ariel_os_embassy_common::{
8 impl_async_spibus_for_driver_enum,
9 spi::{BitOrder, Mode, main::Kilohertz},
10};
11use embassy_embedded_hal::adapter::{BlockingAsync, YieldingAsync};
12use embassy_stm32::{
13 gpio,
14 mode::Blocking,
15 peripherals,
16 spi::{MisoPin, MosiPin, SckPin, Spi as InnerSpi, mode::Master},
17 time::Hertz,
18};
19
20#[cfg(context = "stm32c031c6")]
24const MAX_FREQUENCY: Kilohertz = Kilohertz::MHz(24);
25#[cfg(any(context = "stm32f303cb", context = "stm32f303re"))]
26const MAX_FREQUENCY: Kilohertz = Kilohertz::MHz(18);
27#[cfg(context = "stm32f401re")]
28const MAX_FREQUENCY: Kilohertz = Kilohertz::MHz(21);
29#[cfg(context = "stm32f411re")]
30const MAX_FREQUENCY: Kilohertz = Kilohertz::MHz(25);
31#[cfg(context = "stm32g431rb")]
32const MAX_FREQUENCY: Kilohertz = Kilohertz::MHz(75);
33#[cfg(any(context = "stm32h755zi", context = "stm32h753zi"))]
34const MAX_FREQUENCY: Kilohertz = Kilohertz::MHz(150);
35#[cfg(context = "stm32l072cz")]
36const MAX_FREQUENCY: Kilohertz = Kilohertz::MHz(16);
37#[cfg(context = "stm32l475vg")]
38const MAX_FREQUENCY: Kilohertz = Kilohertz::MHz(40);
39#[cfg(any(context = "stm32u073kc", context = "stm32u083mc"))]
40const MAX_FREQUENCY: Kilohertz = Kilohertz::MHz(32);
41#[cfg(context = "stm32u585ai")]
44const MAX_FREQUENCY: Kilohertz = Kilohertz::MHz(80);
45#[cfg(context = "stm32wb55rg")]
46const MAX_FREQUENCY: Kilohertz = Kilohertz::MHz(32);
47
48#[derive(Clone)]
50#[non_exhaustive]
51pub struct Config {
52 pub frequency: Frequency,
54 pub mode: Mode,
56 #[doc(hidden)]
57 pub bit_order: BitOrder,
58}
59
60impl Default for Config {
61 fn default() -> Self {
62 Self {
63 frequency: Frequency::F(Kilohertz::MHz(1)),
64 mode: Mode::Mode0,
65 bit_order: BitOrder::default(),
66 }
67 }
68}
69
70#[derive(Debug, Copy, Clone, PartialEq, Eq)]
72#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73#[repr(u32)]
74pub enum Frequency {
75 F(Kilohertz),
77}
78
79impl From<Frequency> for Hertz {
80 fn from(freq: Frequency) -> Self {
81 match freq {
82 Frequency::F(kilohertz) => Hertz::khz(kilohertz.to_kHz()),
83 }
84 }
85}
86
87ariel_os_embassy_common::impl_spi_from_frequency!();
88ariel_os_embassy_common::impl_spi_frequency_const_functions!(MAX_FREQUENCY);
89
90macro_rules! define_spi_drivers {
91 ($( $interrupt:ident => $peripheral:ident ),* $(,)?) => {
92 $(
93 pub struct $peripheral {
95 spim: YieldingAsync<BlockingAsync<InnerSpi<'static, Blocking, Master>>>,
96 }
97
98 paste::paste! {
100 static [< ACTIVE_ $peripheral >]: AtomicBool = AtomicBool::new(false);
101 }
102
103 impl $peripheral {
104 #[expect(clippy::new_ret_no_self)]
107 #[must_use]
108 pub fn new<
109 SCK: SckPin<peripherals::$peripheral>,
110 MISO: MisoPin<peripherals::$peripheral>,
111 MOSI: MosiPin<peripherals::$peripheral>,
112 >(
113 sck_pin: impl $crate::IntoPeripheral<'static, SCK>,
114 miso_pin: impl $crate::IntoPeripheral<'static, MISO>,
115 mosi_pin: impl $crate::IntoPeripheral<'static, MOSI>,
116 config: Config,
117 ) -> Spi {
118 paste::paste! {
121 #[allow(dead_code)]
122 static [<PREVENT_MULTIPLE_ $peripheral>]: () = ();
123 }
124
125 let mut spi_config = embassy_stm32::spi::Config::default();
126 spi_config.frequency = config.frequency.into();
127 spi_config.mode = crate::spi::from_mode(config.mode);
128 spi_config.bit_order = crate::spi::from_bit_order(config.bit_order);
129 spi_config.miso_pull = gpio::Pull::None;
130
131 paste::paste! {
133 if [< ACTIVE_ $peripheral >].swap(true, Ordering::AcqRel) {
134 panic!("SPI peripheral already initialized")
135 }
136 }
137
138 let spim_peripheral = unsafe { peripherals::$peripheral::steal() };
142
143 let spim = InnerSpi::new_blocking(
145 spim_peripheral,
146 sck_pin.into_hal_peripheral(),
147 mosi_pin.into_hal_peripheral(),
148 miso_pin.into_hal_peripheral(),
149 spi_config,
150 );
151
152 Spi::$peripheral(Self { spim: YieldingAsync::new(BlockingAsync::new(spim)) })
153 }
154 }
155
156 impl Drop for $peripheral {
157 fn drop(&mut self) {
158 paste::paste! {
159 [< ACTIVE_ $peripheral >].store(false, Ordering::Release);
160 }
161 }
162 }
163 )*
164
165 pub enum Spi {
167 $(
168 #[doc = concat!(stringify!($peripheral), " peripheral.")]
169 $peripheral($peripheral)
170 ),*
171 }
172
173 impl embedded_hal_async::spi::ErrorType for Spi {
174 type Error = embassy_stm32::spi::Error;
175 }
176
177 impl_async_spibus_for_driver_enum!(Spi, $( $peripheral ),*);
178 };
179}
180
181#[cfg(context = "stm32c031c6")]
183define_spi_drivers!(
184 SPI1 => SPI1,
185);
186#[cfg(context = "stm32f303cb")]
187define_spi_drivers!(
188 SPI1 => SPI1,
189 SPI2 => SPI2,
190 SPI3 => SPI3,
191);
192#[cfg(context = "stm32f303re")]
193define_spi_drivers!(
194 SPI1 => SPI1,
195 SPI2 => SPI2,
196 SPI3 => SPI3,
197 );
199#[cfg(context = "stm32f401re")]
200define_spi_drivers!(
201 SPI1 => SPI1,
202 SPI2 => SPI2,
203 SPI3 => SPI3,
204);
205#[cfg(context = "stm32f411re")]
206define_spi_drivers!(
207 SPI1 => SPI1,
208 SPI2 => SPI2,
209 SPI3 => SPI3,
210 SPI4 => SPI4,
211 SPI5 => SPI5,
212);
213#[cfg(context = "stm32g431rb")]
214define_spi_drivers!(
215 SPI1 => SPI1,
216 SPI2 => SPI2,
217 SPI3 => SPI3,
218);
219#[cfg(any(context = "stm32h755zi", context = "stm32h753zi"))]
220define_spi_drivers!(
221 SPI1 => SPI1,
222 SPI2 => SPI2,
223 SPI3 => SPI3,
224 SPI4 => SPI4,
225 SPI5 => SPI5,
226 SPI6 => SPI6,
227);
228#[cfg(context = "stm32l072cz")]
229define_spi_drivers!(
230 SPI1 => SPI1,
231 SPI2 => SPI2,
232);
233#[cfg(context = "stm32l475vg")]
234define_spi_drivers!(
235 SPI1 => SPI1,
236 SPI2 => SPI2,
237 SPI3 => SPI3,
238);
239#[cfg(any(context = "stm32u073kc", context = "stm32u083mc"))]
240define_spi_drivers!(
241 SPI1 => SPI1,
242 );
244#[cfg(context = "stm32u585ai")]
245define_spi_drivers!(
246 SPI1 => SPI1,
247 SPI2 => SPI2,
248 SPI3 => SPI3,
249);
250#[cfg(context = "stm32wb55rg")]
251define_spi_drivers!(
252 SPI1 => SPI1,
253 SPI2 => SPI2,
254);