ariel_os_nrf/spi/main/
mod.rs1#![expect(unsafe_code)]
4
5use ariel_os_embassy_common::{
6 impl_async_spibus_for_driver_enum,
7 spi::{BitOrder, Mode},
8};
9
10use embassy_nrf::{
11 Peripheral, bind_interrupts,
12 gpio::Pin as GpioPin,
13 peripherals,
14 spim::{InterruptHandler, Spim},
15};
16
17#[derive(Clone)]
19#[non_exhaustive]
20pub struct Config {
21 pub frequency: Frequency,
23 pub mode: Mode,
25 #[doc(hidden)]
26 pub bit_order: BitOrder,
27}
28
29impl Default for Config {
30 fn default() -> Self {
31 Self {
32 frequency: Frequency::_1M,
33 mode: Mode::Mode0,
34 bit_order: BitOrder::default(),
35 }
36 }
37}
38
39#[derive(Debug, Copy, Clone, PartialEq, Eq)]
42#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43#[repr(u32)]
44pub enum Frequency {
45 _125k,
47 _250k,
49 _500k,
51 _1M,
53 _2M,
55 _4M,
57 _8M,
59 }
66
67#[doc(hidden)]
68impl Frequency {
69 #[must_use]
70 pub const fn first() -> Self {
71 Self::_125k
72 }
73
74 #[must_use]
75 pub const fn last() -> Self {
76 Self::_8M
77 }
78
79 #[must_use]
80 pub const fn next(self) -> Option<Self> {
81 match self {
82 Self::_125k => Some(Self::_250k),
83 Self::_250k => Some(Self::_500k),
84 Self::_500k => Some(Self::_1M),
85 Self::_1M => Some(Self::_2M),
86 Self::_2M => Some(Self::_4M),
87 Self::_4M => Some(Self::_8M),
88 Self::_8M => None,
89 }
90 }
91
92 #[must_use]
93 pub const fn prev(self) -> Option<Self> {
94 match self {
95 Self::_125k => None,
96 Self::_250k => Some(Self::_125k),
97 Self::_500k => Some(Self::_250k),
98 Self::_1M => Some(Self::_500k),
99 Self::_2M => Some(Self::_1M),
100 Self::_4M => Some(Self::_2M),
101 Self::_8M => Some(Self::_4M),
102 }
103 }
104
105 #[must_use]
106 pub const fn khz(self) -> u32 {
107 match self {
108 Self::_125k => 125,
109 Self::_250k => 250,
110 Self::_500k => 500,
111 Self::_1M => 1000,
112 Self::_2M => 2000,
113 Self::_4M => 4000,
114 Self::_8M => 8000,
115 }
116 }
117}
118
119impl From<ariel_os_embassy_common::spi::main::Frequency> for Frequency {
120 fn from(freq: ariel_os_embassy_common::spi::main::Frequency) -> Self {
121 match freq {
122 ariel_os_embassy_common::spi::main::Frequency::_125k => Self::_125k,
123 ariel_os_embassy_common::spi::main::Frequency::_250k => Self::_250k,
124 ariel_os_embassy_common::spi::main::Frequency::_500k => Self::_500k,
125 ariel_os_embassy_common::spi::main::Frequency::_1M => Self::_1M,
126 ariel_os_embassy_common::spi::main::Frequency::_2M => Self::_2M,
127 ariel_os_embassy_common::spi::main::Frequency::_4M => Self::_4M,
128 ariel_os_embassy_common::spi::main::Frequency::_8M => Self::_8M,
129 }
130 }
131}
132
133impl From<Frequency> for embassy_nrf::spim::Frequency {
134 fn from(freq: Frequency) -> Self {
135 match freq {
136 Frequency::_125k => embassy_nrf::spim::Frequency::K125,
137 Frequency::_250k => embassy_nrf::spim::Frequency::K250,
138 Frequency::_500k => embassy_nrf::spim::Frequency::K500,
139 Frequency::_1M => embassy_nrf::spim::Frequency::M1,
140 Frequency::_2M => embassy_nrf::spim::Frequency::M2,
141 Frequency::_4M => embassy_nrf::spim::Frequency::M4,
142 Frequency::_8M => embassy_nrf::spim::Frequency::M8,
143 }
144 }
145}
146
147macro_rules! define_spi_drivers {
148 ($( $interrupt:ident => $peripheral:ident ),* $(,)?) => {
149 $(
150 pub struct $peripheral {
152 spim: Spim<'static, peripherals::$peripheral>,
153 }
154
155 impl $peripheral {
156 #[expect(clippy::new_ret_no_self)]
159 #[must_use]
160 pub fn new(
161 sck_pin: impl Peripheral<P: GpioPin> + 'static,
162 miso_pin: impl Peripheral<P: GpioPin> + 'static,
163 mosi_pin: impl Peripheral<P: GpioPin> + 'static,
164 config: Config,
165 ) -> Spi {
166 let mut spi_config = embassy_nrf::spim::Config::default();
167 spi_config.frequency = config.frequency.into();
168 spi_config.mode = crate::spi::from_mode(config.mode);
169 spi_config.bit_order = crate::spi::from_bit_order(config.bit_order);
170
171 bind_interrupts!(
172 struct Irqs {
173 $interrupt => InterruptHandler<peripherals::$peripheral>;
174 }
175 );
176
177 paste::paste! {
180 #[allow(dead_code)]
181 static [<PREVENT_MULTIPLE_ $peripheral>]: () = ();
182 }
183
184 let spim_peripheral = unsafe { peripherals::$peripheral::steal() };
188
189 let spim = Spim::new(
190 spim_peripheral,
191 Irqs,
192 sck_pin,
193 miso_pin,
194 mosi_pin,
195 spi_config,
196 );
197
198 Spi::$peripheral(Self { spim })
199 }
200 }
201 )*
202
203 pub enum Spi {
205 $(
206 #[doc = concat!(stringify!($peripheral), " peripheral.")]
207 $peripheral($peripheral)
208 ),*
209 }
210
211 impl embedded_hal_async::spi::ErrorType for Spi {
212 type Error = embassy_nrf::spim::Error;
213 }
214
215 impl_async_spibus_for_driver_enum!(Spi, $( $peripheral ),*);
216 };
217}
218
219#[cfg(context = "nrf52833")]
221define_spi_drivers!(
222 SPIM3 => SPI3,
227);
228#[cfg(context = "nrf52840")]
229define_spi_drivers!(
230 SPIM3 => SPI3,
235);
236#[cfg(context = "nrf5340")]
238define_spi_drivers!(
239 SERIAL2 => SERIAL2,
240 );
243#[cfg(context = "nrf91")]
245define_spi_drivers!(
246 SERIAL2 => SERIAL2,
247 );