aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.vscode/settings.json3
-rw-r--r--embassy-stm32/src/i2s.rs24
-rw-r--r--embassy-stm32/src/lib.rs23
-rw-r--r--embassy-stm32/src/spi/mod.rs527
-rw-r--r--embassy-stm32/src/traits.rs23
-rw-r--r--examples/stm32f4/src/bin/spi.rs3
-rw-r--r--examples/stm32f4/src/bin/ws2812_spi.rs4
-rw-r--r--examples/stm32g0/src/bin/spi_neopixel.rs3
-rw-r--r--examples/stm32h7/src/bin/spi.rs6
-rw-r--r--examples/stm32h7/src/bin/spi_dma.rs6
-rw-r--r--examples/stm32l0/src/bin/spi.rs3
-rw-r--r--examples/stm32l1/src/bin/spi.rs3
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs24
-rw-r--r--examples/stm32l4/src/bin/spi.rs3
-rw-r--r--examples/stm32l4/src/bin/spi_blocking_async.rs3
-rw-r--r--tests/stm32/src/bin/spi.rs5
16 files changed, 370 insertions, 293 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 0c195a13b..220d25914 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -15,10 +15,11 @@
15 "rust-analyzer.cargo.target": "thumbv7em-none-eabi", 15 "rust-analyzer.cargo.target": "thumbv7em-none-eabi",
16 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", 16 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
17 "rust-analyzer.cargo.features": [ 17 "rust-analyzer.cargo.features": [
18 "stm32f103c8", 18 "stm32f446re",
19 "time-driver-any", 19 "time-driver-any",
20 "unstable-pac", 20 "unstable-pac",
21 "exti", 21 "exti",
22 "rt",
22 ], 23 ],
23 "rust-analyzer.linkedProjects": [ 24 "rust-analyzer.linkedProjects": [
24 // Uncomment ONE line for the chip you want to work on. 25 // Uncomment ONE line for the chip you want to work on.
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index c5a606b21..9b80dc1d0 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -2,6 +2,7 @@
2use embassy_hal_internal::into_ref; 2use embassy_hal_internal::into_ref;
3 3
4use crate::gpio::{AFType, AnyPin, SealedPin}; 4use crate::gpio::{AFType, AnyPin, SealedPin};
5use crate::mode::Async;
5use crate::pac::spi::vals; 6use crate::pac::spi::vals;
6use crate::spi::{Config as SpiConfig, *}; 7use crate::spi::{Config as SpiConfig, *};
7use crate::time::Hertz; 8use crate::time::Hertz;
@@ -152,15 +153,15 @@ impl Default for Config {
152} 153}
153 154
154/// I2S driver. 155/// I2S driver.
155pub struct I2S<'d, T: Instance, Tx, Rx> { 156pub struct I2S<'d, T: Instance> {
156 _peri: Spi<'d, T, Tx, Rx>, 157 _peri: Spi<'d, T, Async>,
157 sd: Option<PeripheralRef<'d, AnyPin>>, 158 sd: Option<PeripheralRef<'d, AnyPin>>,
158 ws: Option<PeripheralRef<'d, AnyPin>>, 159 ws: Option<PeripheralRef<'d, AnyPin>>,
159 ck: Option<PeripheralRef<'d, AnyPin>>, 160 ck: Option<PeripheralRef<'d, AnyPin>>,
160 mck: Option<PeripheralRef<'d, AnyPin>>, 161 mck: Option<PeripheralRef<'d, AnyPin>>,
161} 162}
162 163
163impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { 164impl<'d, T: Instance> I2S<'d, T> {
164 /// Note: Full-Duplex modes are not supported at this time 165 /// Note: Full-Duplex modes are not supported at this time
165 pub fn new( 166 pub fn new(
166 peri: impl Peripheral<P = T> + 'd, 167 peri: impl Peripheral<P = T> + 'd,
@@ -168,8 +169,8 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
168 ws: impl Peripheral<P = impl WsPin<T>> + 'd, 169 ws: impl Peripheral<P = impl WsPin<T>> + 'd,
169 ck: impl Peripheral<P = impl CkPin<T>> + 'd, 170 ck: impl Peripheral<P = impl CkPin<T>> + 'd,
170 mck: impl Peripheral<P = impl MckPin<T>> + 'd, 171 mck: impl Peripheral<P = impl MckPin<T>> + 'd,
171 txdma: impl Peripheral<P = Tx> + 'd, 172 txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
172 rxdma: impl Peripheral<P = Rx> + 'd, 173 rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
173 freq: Hertz, 174 freq: Hertz,
174 config: Config, 175 config: Config,
175 ) -> Self { 176 ) -> Self {
@@ -265,24 +266,17 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
265 } 266 }
266 267
267 /// Write audio data. 268 /// Write audio data.
268 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> 269 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
269 where
270 Tx: TxDma<T>,
271 {
272 self._peri.write(data).await 270 self._peri.write(data).await
273 } 271 }
274 272
275 /// Read audio data. 273 /// Read audio data.
276 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 274 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
277 where
278 Tx: TxDma<T>,
279 Rx: RxDma<T>,
280 {
281 self._peri.read(data).await 275 self._peri.read(data).await
282 } 276 }
283} 277}
284 278
285impl<'d, T: Instance, Tx, Rx> Drop for I2S<'d, T, Tx, Rx> { 279impl<'d, T: Instance> Drop for I2S<'d, T> {
286 fn drop(&mut self) { 280 fn drop(&mut self) {
287 self.sd.as_ref().map(|x| x.set_as_disconnected()); 281 self.sd.as_ref().map(|x| x.set_as_disconnected());
288 self.ws.as_ref().map(|x| x.set_as_disconnected()); 282 self.ws.as_ref().map(|x| x.set_as_disconnected());
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index ea17f8477..1f0f85936 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -17,6 +17,29 @@ include!(concat!(env!("OUT_DIR"), "/_macros.rs"));
17// Utilities 17// Utilities
18pub mod time; 18pub mod time;
19mod traits; 19mod traits;
20/// Operating modes for peripherals.
21pub mod mode {
22 trait SealedMode {}
23
24 /// Operating mode for a peripheral.
25 #[allow(private_bounds)]
26 pub trait Mode: SealedMode {}
27
28 macro_rules! impl_mode {
29 ($name:ident) => {
30 impl SealedMode for $name {}
31 impl Mode for $name {}
32 };
33 }
34
35 /// Blocking mode.
36 pub struct Blocking;
37 /// Async mode.
38 pub struct Async;
39
40 impl_mode!(Blocking);
41 impl_mode!(Async);
42}
20 43
21// Always-present hardware 44// Always-present hardware
22pub mod dma; 45pub mod dma;
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 450975f18..a4465e289 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -1,6 +1,7 @@
1//! Serial Peripheral Interface (SPI) 1//! Serial Peripheral Interface (SPI)
2#![macro_use] 2#![macro_use]
3 3
4use core::marker::PhantomData;
4use core::ptr; 5use core::ptr;
5 6
6use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
@@ -8,8 +9,9 @@ use embassy_futures::join::join;
8use embassy_hal_internal::{into_ref, PeripheralRef}; 9use embassy_hal_internal::{into_ref, PeripheralRef};
9pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 10pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
10 11
11use crate::dma::{slice_ptr_parts, word, Transfer}; 12use crate::dma::{slice_ptr_parts, word, AnyChannel, Request, Transfer};
12use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _}; 13use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
14use crate::mode::{Async, Blocking, Mode as PeriMode};
13use crate::pac::spi::{regs, vals, Spi as Regs}; 15use crate::pac::spi::{regs, vals, Spi as Regs};
14use crate::rcc::RccPeripheral; 16use crate::rcc::RccPeripheral;
15use crate::time::Hertz; 17use crate::time::Hertz;
@@ -81,163 +83,37 @@ impl Config {
81 BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST, 83 BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST,
82 } 84 }
83 } 85 }
84}
85 86
87 fn sck_pull_mode(&self) -> Pull {
88 match self.mode.polarity {
89 Polarity::IdleLow => Pull::Down,
90 Polarity::IdleHigh => Pull::Up,
91 }
92 }
93}
86/// SPI driver. 94/// SPI driver.
87pub struct Spi<'d, T: Instance, Tx, Rx> { 95pub struct Spi<'d, T: Instance, M: PeriMode> {
88 _peri: PeripheralRef<'d, T>, 96 _peri: PeripheralRef<'d, T>,
89 sck: Option<PeripheralRef<'d, AnyPin>>, 97 sck: Option<PeripheralRef<'d, AnyPin>>,
90 mosi: Option<PeripheralRef<'d, AnyPin>>, 98 mosi: Option<PeripheralRef<'d, AnyPin>>,
91 miso: Option<PeripheralRef<'d, AnyPin>>, 99 miso: Option<PeripheralRef<'d, AnyPin>>,
92 txdma: PeripheralRef<'d, Tx>, 100 txdma: Option<(PeripheralRef<'d, AnyChannel>, Request)>,
93 rxdma: PeripheralRef<'d, Rx>, 101 rxdma: Option<(PeripheralRef<'d, AnyChannel>, Request)>,
102 _phantom: PhantomData<M>,
94 current_word_size: word_impl::Config, 103 current_word_size: word_impl::Config,
95} 104}
96 105
97impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { 106impl<'d, T: Instance, M: PeriMode> Spi<'d, T, M> {
98 /// Create a new SPI driver.
99 pub fn new(
100 peri: impl Peripheral<P = T> + 'd,
101 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
102 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
103 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
104 txdma: impl Peripheral<P = Tx> + 'd,
105 rxdma: impl Peripheral<P = Rx> + 'd,
106 config: Config,
107 ) -> Self {
108 into_ref!(peri, sck, mosi, miso);
109
110 let sck_pull_mode = match config.mode.polarity {
111 Polarity::IdleLow => Pull::Down,
112 Polarity::IdleHigh => Pull::Up,
113 };
114
115 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode);
116 sck.set_speed(crate::gpio::Speed::VeryHigh);
117 mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
118 mosi.set_speed(crate::gpio::Speed::VeryHigh);
119 miso.set_as_af(miso.af_num(), AFType::Input);
120 miso.set_speed(crate::gpio::Speed::VeryHigh);
121
122 Self::new_inner(
123 peri,
124 Some(sck.map_into()),
125 Some(mosi.map_into()),
126 Some(miso.map_into()),
127 txdma,
128 rxdma,
129 config,
130 )
131 }
132
133 /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
134 pub fn new_rxonly(
135 peri: impl Peripheral<P = T> + 'd,
136 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
137 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
138 txdma: impl Peripheral<P = Tx> + 'd, // TODO remove
139 rxdma: impl Peripheral<P = Rx> + 'd,
140 config: Config,
141 ) -> Self {
142 into_ref!(sck, miso);
143 sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
144 sck.set_speed(crate::gpio::Speed::VeryHigh);
145 miso.set_as_af(miso.af_num(), AFType::Input);
146 miso.set_speed(crate::gpio::Speed::VeryHigh);
147
148 Self::new_inner(
149 peri,
150 Some(sck.map_into()),
151 None,
152 Some(miso.map_into()),
153 txdma,
154 rxdma,
155 config,
156 )
157 }
158
159 /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
160 pub fn new_txonly(
161 peri: impl Peripheral<P = T> + 'd,
162 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
163 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
164 txdma: impl Peripheral<P = Tx> + 'd,
165 rxdma: impl Peripheral<P = Rx> + 'd, // TODO remove
166 config: Config,
167 ) -> Self {
168 into_ref!(sck, mosi);
169 sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
170 sck.set_speed(crate::gpio::Speed::VeryHigh);
171 mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
172 mosi.set_speed(crate::gpio::Speed::VeryHigh);
173
174 Self::new_inner(
175 peri,
176 Some(sck.map_into()),
177 Some(mosi.map_into()),
178 None,
179 txdma,
180 rxdma,
181 config,
182 )
183 }
184
185 /// Create a new SPI driver, in TX-only mode, without SCK pin.
186 ///
187 /// This can be useful for bit-banging non-SPI protocols.
188 pub fn new_txonly_nosck(
189 peri: impl Peripheral<P = T> + 'd,
190 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
191 txdma: impl Peripheral<P = Tx> + 'd,
192 rxdma: impl Peripheral<P = Rx> + 'd, // TODO: remove
193 config: Config,
194 ) -> Self {
195 into_ref!(mosi);
196 mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down);
197 mosi.set_speed(crate::gpio::Speed::Medium);
198
199 Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, config)
200 }
201
202 #[cfg(stm32wl)]
203 /// Useful for on chip peripherals like SUBGHZ which are hardwired.
204 pub fn new_subghz(
205 peri: impl Peripheral<P = T> + 'd,
206 txdma: impl Peripheral<P = Tx> + 'd,
207 rxdma: impl Peripheral<P = Rx> + 'd,
208 ) -> Self {
209 // see RM0453 rev 1 section 7.2.13 page 291
210 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two.
211 // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz.
212 let pclk3_freq = <peripherals::SUBGHZSPI as crate::rcc::SealedRccPeripheral>::frequency().0;
213 let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000));
214 let mut config = Config::default();
215 config.mode = MODE_0;
216 config.bit_order = BitOrder::MsbFirst;
217 config.frequency = freq;
218 Self::new_inner(peri, None, None, None, txdma, rxdma, config)
219 }
220
221 #[allow(dead_code)]
222 pub(crate) fn new_internal(
223 peri: impl Peripheral<P = T> + 'd,
224 txdma: impl Peripheral<P = Tx> + 'd,
225 rxdma: impl Peripheral<P = Rx> + 'd,
226 config: Config,
227 ) -> Self {
228 Self::new_inner(peri, None, None, None, txdma, rxdma, config)
229 }
230
231 fn new_inner( 107 fn new_inner(
232 peri: impl Peripheral<P = T> + 'd, 108 peri: impl Peripheral<P = T> + 'd,
233 sck: Option<PeripheralRef<'d, AnyPin>>, 109 sck: Option<PeripheralRef<'d, AnyPin>>,
234 mosi: Option<PeripheralRef<'d, AnyPin>>, 110 mosi: Option<PeripheralRef<'d, AnyPin>>,
235 miso: Option<PeripheralRef<'d, AnyPin>>, 111 miso: Option<PeripheralRef<'d, AnyPin>>,
236 txdma: impl Peripheral<P = Tx> + 'd, 112 txdma: Option<(PeripheralRef<'d, AnyChannel>, Request)>,
237 rxdma: impl Peripheral<P = Rx> + 'd, 113 rxdma: Option<(PeripheralRef<'d, AnyChannel>, Request)>,
238 config: Config, 114 config: Config,
239 ) -> Self { 115 ) -> Self {
240 into_ref!(peri, txdma, rxdma); 116 into_ref!(peri);
241 117
242 let pclk = T::frequency(); 118 let pclk = T::frequency();
243 let freq = config.frequency; 119 let freq = config.frequency;
@@ -336,6 +212,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
336 txdma, 212 txdma,
337 rxdma, 213 rxdma,
338 current_word_size: <u8 as SealedWord>::CONFIG, 214 current_word_size: <u8 as SealedWord>::CONFIG,
215 _phantom: PhantomData,
339 } 216 }
340 } 217 }
341 218
@@ -462,11 +339,251 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
462 self.current_word_size = word_size; 339 self.current_word_size = word_size;
463 } 340 }
464 341
342 /// Blocking write.
343 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
344 T::REGS.cr1().modify(|w| w.set_spe(true));
345 flush_rx_fifo(T::REGS);
346 self.set_word_size(W::CONFIG);
347 for word in words.iter() {
348 let _ = transfer_word(T::REGS, *word)?;
349 }
350 Ok(())
351 }
352
353 /// Blocking read.
354 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
355 T::REGS.cr1().modify(|w| w.set_spe(true));
356 flush_rx_fifo(T::REGS);
357 self.set_word_size(W::CONFIG);
358 for word in words.iter_mut() {
359 *word = transfer_word(T::REGS, W::default())?;
360 }
361 Ok(())
362 }
363
364 /// Blocking in-place bidirectional transfer.
365 ///
366 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
367 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
368 T::REGS.cr1().modify(|w| w.set_spe(true));
369 flush_rx_fifo(T::REGS);
370 self.set_word_size(W::CONFIG);
371 for word in words.iter_mut() {
372 *word = transfer_word(T::REGS, *word)?;
373 }
374 Ok(())
375 }
376
377 /// Blocking bidirectional transfer.
378 ///
379 /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
380 ///
381 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
382 /// If `write` is shorter it is padded with zero bytes.
383 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
384 T::REGS.cr1().modify(|w| w.set_spe(true));
385 flush_rx_fifo(T::REGS);
386 self.set_word_size(W::CONFIG);
387 let len = read.len().max(write.len());
388 for i in 0..len {
389 let wb = write.get(i).copied().unwrap_or_default();
390 let rb = transfer_word(T::REGS, wb)?;
391 if let Some(r) = read.get_mut(i) {
392 *r = rb;
393 }
394 }
395 Ok(())
396 }
397}
398
399impl<'d, T: Instance> Spi<'d, T, Blocking> {
400 /// Create a new blocking SPI driver.
401 pub fn new_blocking(
402 peri: impl Peripheral<P = T> + 'd,
403 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
404 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
405 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
406 config: Config,
407 ) -> Self {
408 Self::new_inner(
409 peri,
410 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
411 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
412 new_pin!(miso, AFType::Input, Speed::VeryHigh),
413 None,
414 None,
415 config,
416 )
417 }
418
419 /// Create a new blocking SPI driver, in RX-only mode (only MISO pin, no MOSI).
420 pub fn new_blocking_rxonly(
421 peri: impl Peripheral<P = T> + 'd,
422 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
423 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
424 config: Config,
425 ) -> Self {
426 Self::new_inner(
427 peri,
428 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
429 None,
430 new_pin!(miso, AFType::Input, Speed::VeryHigh),
431 None,
432 None,
433 config,
434 )
435 }
436
437 /// Create a new blocking SPI driver, in TX-only mode (only MOSI pin, no MISO).
438 pub fn new_blocking_txonly(
439 peri: impl Peripheral<P = T> + 'd,
440 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
441 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
442 config: Config,
443 ) -> Self {
444 Self::new_inner(
445 peri,
446 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
447 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
448 None,
449 None,
450 None,
451 config,
452 )
453 }
454
455 /// Create a new SPI driver, in TX-only mode, without SCK pin.
456 ///
457 /// This can be useful for bit-banging non-SPI protocols.
458 pub fn new_blocking_txonly_nosck(
459 peri: impl Peripheral<P = T> + 'd,
460 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
461 config: Config,
462 ) -> Self {
463 Self::new_inner(
464 peri,
465 None,
466 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
467 None,
468 None,
469 None,
470 config,
471 )
472 }
473}
474
475impl<'d, T: Instance> Spi<'d, T, Async> {
476 /// Create a new SPI driver.
477 pub fn new(
478 peri: impl Peripheral<P = T> + 'd,
479 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
480 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
481 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
482 txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
483 rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
484 config: Config,
485 ) -> Self {
486 Self::new_inner(
487 peri,
488 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
489 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
490 new_pin!(miso, AFType::Input, Speed::VeryHigh),
491 new_dma!(txdma),
492 new_dma!(rxdma),
493 config,
494 )
495 }
496
497 /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
498 pub fn new_rxonly(
499 peri: impl Peripheral<P = T> + 'd,
500 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
501 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
502 rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
503 config: Config,
504 ) -> Self {
505 Self::new_inner(
506 peri,
507 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
508 None,
509 new_pin!(miso, AFType::Input, Speed::VeryHigh),
510 None,
511 new_dma!(rxdma),
512 config,
513 )
514 }
515
516 /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
517 pub fn new_txonly(
518 peri: impl Peripheral<P = T> + 'd,
519 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
520 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
521 txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
522 config: Config,
523 ) -> Self {
524 Self::new_inner(
525 peri,
526 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
527 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
528 None,
529 new_dma!(txdma),
530 None,
531 config,
532 )
533 }
534
535 /// Create a new SPI driver, in TX-only mode, without SCK pin.
536 ///
537 /// This can be useful for bit-banging non-SPI protocols.
538 pub fn new_txonly_nosck(
539 peri: impl Peripheral<P = T> + 'd,
540 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
541 txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
542 config: Config,
543 ) -> Self {
544 Self::new_inner(
545 peri,
546 None,
547 new_pin!(mosi, AFType::OutputPushPull, Speed::VeryHigh),
548 None,
549 new_dma!(txdma),
550 None,
551 config,
552 )
553 }
554
555 #[cfg(stm32wl)]
556 /// Useful for on chip peripherals like SUBGHZ which are hardwired.
557 pub fn new_subghz(
558 peri: impl Peripheral<P = T> + 'd,
559 txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
560 rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
561 ) -> Self {
562 // see RM0453 rev 1 section 7.2.13 page 291
563 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two.
564 // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz.
565 let pclk3_freq = <peripherals::SUBGHZSPI as crate::rcc::SealedRccPeripheral>::frequency().0;
566 let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000));
567 let mut config = Config::default();
568 config.mode = MODE_0;
569 config.bit_order = BitOrder::MsbFirst;
570 config.frequency = freq;
571
572 Self::new_inner(peri, None, None, None, new_dma!(txdma), new_dma!(rxdma), config)
573 }
574
575 #[allow(dead_code)]
576 pub(crate) fn new_internal(
577 peri: impl Peripheral<P = T> + 'd,
578 txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
579 rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
580 config: Config,
581 ) -> Self {
582 Self::new_inner(peri, None, None, None, new_dma!(txdma), new_dma!(rxdma), config)
583 }
584
465 /// SPI write, using DMA. 585 /// SPI write, using DMA.
466 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> 586 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
467 where
468 Tx: TxDma<T>,
469 {
470 if data.is_empty() { 587 if data.is_empty() {
471 return Ok(()); 588 return Ok(());
472 } 589 }
@@ -476,9 +593,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
476 w.set_spe(false); 593 w.set_spe(false);
477 }); 594 });
478 595
479 let tx_request = self.txdma.request(); 596 let (txdma, tx_request) = self.txdma.as_mut().unwrap();
480 let tx_dst = T::REGS.tx_ptr(); 597 let tx_dst = T::REGS.tx_ptr();
481 let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) }; 598 let tx_f = unsafe { Transfer::new_write(txdma, *tx_request, data, tx_dst, Default::default()) };
482 599
483 set_txdmaen(T::REGS, true); 600 set_txdmaen(T::REGS, true);
484 T::REGS.cr1().modify(|w| { 601 T::REGS.cr1().modify(|w| {
@@ -497,11 +614,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
497 } 614 }
498 615
499 /// SPI read, using DMA. 616 /// SPI read, using DMA.
500 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 617 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
501 where
502 Tx: TxDma<T>,
503 Rx: RxDma<T>,
504 {
505 if data.is_empty() { 618 if data.is_empty() {
506 return Ok(()); 619 return Ok(());
507 } 620 }
@@ -519,17 +632,17 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
519 632
520 let clock_byte_count = data.len(); 633 let clock_byte_count = data.len();
521 634
522 let rx_request = self.rxdma.request(); 635 let (rxdma, rx_request) = self.rxdma.as_mut().unwrap();
523 let rx_src = T::REGS.rx_ptr(); 636 let rx_src = T::REGS.rx_ptr();
524 let rx_f = unsafe { Transfer::new_read(&mut self.rxdma, rx_request, rx_src, data, Default::default()) }; 637 let rx_f = unsafe { Transfer::new_read(rxdma, *rx_request, rx_src, data, Default::default()) };
525 638
526 let tx_request = self.txdma.request(); 639 let (txdma, tx_request) = self.txdma.as_mut().unwrap();
527 let tx_dst = T::REGS.tx_ptr(); 640 let tx_dst = T::REGS.tx_ptr();
528 let clock_byte = 0x00u8; 641 let clock_byte = 0x00u8;
529 let tx_f = unsafe { 642 let tx_f = unsafe {
530 Transfer::new_write_repeated( 643 Transfer::new_write_repeated(
531 &mut self.txdma, 644 txdma,
532 tx_request, 645 *tx_request,
533 &clock_byte, 646 &clock_byte,
534 clock_byte_count, 647 clock_byte_count,
535 tx_dst, 648 tx_dst,
@@ -553,11 +666,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
553 Ok(()) 666 Ok(())
554 } 667 }
555 668
556 async fn transfer_inner<W: Word>(&mut self, read: *mut [W], write: *const [W]) -> Result<(), Error> 669 async fn transfer_inner<W: Word>(&mut self, read: *mut [W], write: *const [W]) -> Result<(), Error> {
557 where
558 Tx: TxDma<T>,
559 Rx: RxDma<T>,
560 {
561 let (_, rx_len) = slice_ptr_parts(read); 670 let (_, rx_len) = slice_ptr_parts(read);
562 let (_, tx_len) = slice_ptr_parts(write); 671 let (_, tx_len) = slice_ptr_parts(write);
563 assert_eq!(rx_len, tx_len); 672 assert_eq!(rx_len, tx_len);
@@ -576,13 +685,13 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
576 685
577 set_rxdmaen(T::REGS, true); 686 set_rxdmaen(T::REGS, true);
578 687
579 let rx_request = self.rxdma.request(); 688 let (rxdma, rx_request) = self.rxdma.as_mut().unwrap();
580 let rx_src = T::REGS.rx_ptr(); 689 let rx_src = T::REGS.rx_ptr();
581 let rx_f = unsafe { Transfer::new_read_raw(&mut self.rxdma, rx_request, rx_src, read, Default::default()) }; 690 let rx_f = unsafe { Transfer::new_read_raw(rxdma, *rx_request, rx_src, read, Default::default()) };
582 691
583 let tx_request = self.txdma.request(); 692 let (txdma, tx_request) = self.txdma.as_mut().unwrap();
584 let tx_dst = T::REGS.tx_ptr(); 693 let tx_dst = T::REGS.tx_ptr();
585 let tx_f = unsafe { Transfer::new_write_raw(&mut self.txdma, tx_request, write, tx_dst, Default::default()) }; 694 let tx_f = unsafe { Transfer::new_write_raw(txdma, *tx_request, write, tx_dst, Default::default()) };
586 695
587 set_txdmaen(T::REGS, true); 696 set_txdmaen(T::REGS, true);
588 T::REGS.cr1().modify(|w| { 697 T::REGS.cr1().modify(|w| {
@@ -606,83 +715,19 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
606 /// 715 ///
607 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. 716 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
608 /// If `write` is shorter it is padded with zero bytes. 717 /// If `write` is shorter it is padded with zero bytes.
609 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> 718 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
610 where
611 Tx: TxDma<T>,
612 Rx: RxDma<T>,
613 {
614 self.transfer_inner(read, write).await 719 self.transfer_inner(read, write).await
615 } 720 }
616 721
617 /// In-place bidirectional transfer, using DMA. 722 /// In-place bidirectional transfer, using DMA.
618 /// 723 ///
619 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. 724 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
620 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 725 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
621 where
622 Tx: TxDma<T>,
623 Rx: RxDma<T>,
624 {
625 self.transfer_inner(data, data).await 726 self.transfer_inner(data, data).await
626 } 727 }
627
628 /// Blocking write.
629 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
630 T::REGS.cr1().modify(|w| w.set_spe(true));
631 flush_rx_fifo(T::REGS);
632 self.set_word_size(W::CONFIG);
633 for word in words.iter() {
634 let _ = transfer_word(T::REGS, *word)?;
635 }
636 Ok(())
637 }
638
639 /// Blocking read.
640 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
641 T::REGS.cr1().modify(|w| w.set_spe(true));
642 flush_rx_fifo(T::REGS);
643 self.set_word_size(W::CONFIG);
644 for word in words.iter_mut() {
645 *word = transfer_word(T::REGS, W::default())?;
646 }
647 Ok(())
648 }
649
650 /// Blocking in-place bidirectional transfer.
651 ///
652 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
653 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
654 T::REGS.cr1().modify(|w| w.set_spe(true));
655 flush_rx_fifo(T::REGS);
656 self.set_word_size(W::CONFIG);
657 for word in words.iter_mut() {
658 *word = transfer_word(T::REGS, *word)?;
659 }
660 Ok(())
661 }
662
663 /// Blocking bidirectional transfer.
664 ///
665 /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
666 ///
667 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
668 /// If `write` is shorter it is padded with zero bytes.
669 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
670 T::REGS.cr1().modify(|w| w.set_spe(true));
671 flush_rx_fifo(T::REGS);
672 self.set_word_size(W::CONFIG);
673 let len = read.len().max(write.len());
674 for i in 0..len {
675 let wb = write.get(i).copied().unwrap_or_default();
676 let rb = transfer_word(T::REGS, wb)?;
677 if let Some(r) = read.get_mut(i) {
678 *r = rb;
679 }
680 }
681 Ok(())
682 }
683} 728}
684 729
685impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { 730impl<'d, T: Instance, M: PeriMode> Drop for Spi<'d, T, M> {
686 fn drop(&mut self) { 731 fn drop(&mut self) {
687 self.sck.as_ref().map(|x| x.set_as_disconnected()); 732 self.sck.as_ref().map(|x| x.set_as_disconnected());
688 self.mosi.as_ref().map(|x| x.set_as_disconnected()); 733 self.mosi.as_ref().map(|x| x.set_as_disconnected());
@@ -900,7 +945,7 @@ fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {
900// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289 945// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
901macro_rules! impl_blocking { 946macro_rules! impl_blocking {
902 ($w:ident) => { 947 ($w:ident) => {
903 impl<'d, T: Instance, Tx, Rx> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, T, Tx, Rx> { 948 impl<'d, T: Instance, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, T, M> {
904 type Error = Error; 949 type Error = Error;
905 950
906 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> { 951 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
@@ -908,7 +953,7 @@ macro_rules! impl_blocking {
908 } 953 }
909 } 954 }
910 955
911 impl<'d, T: Instance, Tx, Rx> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, T, Tx, Rx> { 956 impl<'d, T: Instance, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, T, M> {
912 type Error = Error; 957 type Error = Error;
913 958
914 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> { 959 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
@@ -922,11 +967,11 @@ macro_rules! impl_blocking {
922impl_blocking!(u8); 967impl_blocking!(u8);
923impl_blocking!(u16); 968impl_blocking!(u16);
924 969
925impl<'d, T: Instance, Tx, Rx> embedded_hal_1::spi::ErrorType for Spi<'d, T, Tx, Rx> { 970impl<'d, T: Instance, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, T, M> {
926 type Error = Error; 971 type Error = Error;
927} 972}
928 973
929impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> { 974impl<'d, T: Instance, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, M> {
930 fn flush(&mut self) -> Result<(), Self::Error> { 975 fn flush(&mut self) -> Result<(), Self::Error> {
931 Ok(()) 976 Ok(())
932 } 977 }
@@ -959,7 +1004,7 @@ impl embedded_hal_1::spi::Error for Error {
959 } 1004 }
960} 1005}
961 1006
962impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> { 1007impl<'d, T: Instance, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Async> {
963 async fn flush(&mut self) -> Result<(), Self::Error> { 1008 async fn flush(&mut self) -> Result<(), Self::Error> {
964 Ok(()) 1009 Ok(())
965 } 1010 }
@@ -1094,7 +1139,7 @@ foreach_peripheral!(
1094 }; 1139 };
1095); 1140);
1096 1141
1097impl<'d, T: Instance, Tx, Rx> SetConfig for Spi<'d, T, Tx, Rx> { 1142impl<'d, T: Instance, M: PeriMode> SetConfig for Spi<'d, T, M> {
1098 type Config = Config; 1143 type Config = Config;
1099 type ConfigError = (); 1144 type ConfigError = ();
1100 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 1145 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
diff --git a/embassy-stm32/src/traits.rs b/embassy-stm32/src/traits.rs
index 13f695821..539302c49 100644
--- a/embassy-stm32/src/traits.rs
+++ b/embassy-stm32/src/traits.rs
@@ -69,3 +69,26 @@ macro_rules! dma_trait_impl {
69 } 69 }
70 }; 70 };
71} 71}
72
73macro_rules! new_dma {
74 ($name:ident) => {{
75 let dma = $name.into_ref();
76 let req = dma.request();
77 Some((dma.map_into(), req))
78 }};
79}
80
81macro_rules! new_pin {
82 ($name:ident, $aftype:expr, $speed:expr) => {{
83 let pin = $name.into_ref();
84 pin.set_as_af(pin.af_num(), $aftype);
85 pin.set_speed($speed);
86 Some(pin.map_into())
87 }};
88 ($name:ident, $aftype:expr, $speed:expr, $pull:expr) => {{
89 let pin = $name.into_ref();
90 pin.set_as_af_pull(pin.af_num(), $aftype, $pull);
91 pin.set_speed($speed);
92 Some(pin.map_into())
93 }};
94}
diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs
index dc9141c62..970d819fc 100644
--- a/examples/stm32f4/src/bin/spi.rs
+++ b/examples/stm32f4/src/bin/spi.rs
@@ -3,7 +3,6 @@
3 3
4use cortex_m_rt::entry; 4use cortex_m_rt::entry;
5use defmt::*; 5use defmt::*;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
@@ -18,7 +17,7 @@ fn main() -> ! {
18 let mut spi_config = Config::default(); 17 let mut spi_config = Config::default();
19 spi_config.frequency = Hertz(1_000_000); 18 spi_config.frequency = Hertz(1_000_000);
20 19
21 let mut spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); 20 let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
22 21
23 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); 22 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
24 23
diff --git a/examples/stm32f4/src/bin/ws2812_spi.rs b/examples/stm32f4/src/bin/ws2812_spi.rs
index 56ccb67b8..e00d14327 100644
--- a/examples/stm32f4/src/bin/ws2812_spi.rs
+++ b/examples/stm32f4/src/bin/ws2812_spi.rs
@@ -13,8 +13,8 @@
13#![no_std] 13#![no_std]
14#![no_main] 14#![no_main]
15 15
16use embassy_stm32::spi;
16use embassy_stm32::time::khz; 17use embassy_stm32::time::khz;
17use embassy_stm32::{dma, spi};
18use embassy_time::{Duration, Ticker, Timer}; 18use embassy_time::{Duration, Ticker, Timer};
19use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
20 20
@@ -78,7 +78,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
78 spi_config.frequency = khz(12_800); 78 spi_config.frequency = khz(12_800);
79 79
80 // Since we only output waveform, then the Rx and Sck and RxDma it is not considered 80 // Since we only output waveform, then the Rx and Sck and RxDma it is not considered
81 let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, dma::NoDma, spi_config); 81 let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, spi_config);
82 82
83 // flip color at 2 Hz 83 // flip color at 2 Hz
84 let mut ticker = Ticker::every(Duration::from_millis(500)); 84 let mut ticker = Ticker::every(Duration::from_millis(500));
diff --git a/examples/stm32g0/src/bin/spi_neopixel.rs b/examples/stm32g0/src/bin/spi_neopixel.rs
index c5ea51721..2deee271d 100644
--- a/examples/stm32g0/src/bin/spi_neopixel.rs
+++ b/examples/stm32g0/src/bin/spi_neopixel.rs
@@ -4,7 +4,6 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::word::U5; 6use embassy_stm32::dma::word::U5;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
10use embassy_time::Timer; 9use embassy_time::Timer;
@@ -77,7 +76,7 @@ async fn main(_spawner: Spawner) {
77 76
78 let mut config = Config::default(); 77 let mut config = Config::default();
79 config.frequency = Hertz(4_000_000); 78 config.frequency = Hertz(4_000_000);
80 let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, NoDma, config); 79 let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, config);
81 80
82 let mut neopixels = Ws2812::new(); 81 let mut neopixels = Ws2812::new();
83 82
diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs
index aed27723a..aaebdc346 100644
--- a/examples/stm32h7/src/bin/spi.rs
+++ b/examples/stm32h7/src/bin/spi.rs
@@ -7,7 +7,7 @@ use core::str::from_utf8;
7use cortex_m_rt::entry; 7use cortex_m_rt::entry;
8use defmt::*; 8use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_stm32::dma::NoDma; 10use embassy_stm32::mode::Blocking;
11use embassy_stm32::peripherals::SPI3; 11use embassy_stm32::peripherals::SPI3;
12use embassy_stm32::time::mhz; 12use embassy_stm32::time::mhz;
13use embassy_stm32::{spi, Config}; 13use embassy_stm32::{spi, Config};
@@ -16,7 +16,7 @@ use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
17 17
18#[embassy_executor::task] 18#[embassy_executor::task]
19async fn main_task(mut spi: spi::Spi<'static, SPI3, NoDma, NoDma>) { 19async fn main_task(mut spi: spi::Spi<'static, SPI3, Blocking>) {
20 for n in 0u32.. { 20 for n in 0u32.. {
21 let mut write: String<128> = String::new(); 21 let mut write: String<128> = String::new();
22 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); 22 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
@@ -62,7 +62,7 @@ fn main() -> ! {
62 let mut spi_config = spi::Config::default(); 62 let mut spi_config = spi::Config::default();
63 spi_config.frequency = mhz(1); 63 spi_config.frequency = mhz(1);
64 64
65 let spi = spi::Spi::new(p.SPI3, p.PB3, p.PB5, p.PB4, NoDma, NoDma, spi_config); 65 let spi = spi::Spi::new_blocking(p.SPI3, p.PB3, p.PB5, p.PB4, spi_config);
66 66
67 let executor = EXECUTOR.init(Executor::new()); 67 let executor = EXECUTOR.init(Executor::new());
68 68
diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs
index 54d4d7656..3d3c724eb 100644
--- a/examples/stm32h7/src/bin/spi_dma.rs
+++ b/examples/stm32h7/src/bin/spi_dma.rs
@@ -7,15 +7,15 @@ use core::str::from_utf8;
7use cortex_m_rt::entry; 7use cortex_m_rt::entry;
8use defmt::*; 8use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_stm32::peripherals::{DMA1_CH3, DMA1_CH4, SPI3}; 10use embassy_stm32::mode::Async;
11use embassy_stm32::time::mhz; 11use embassy_stm32::time::mhz;
12use embassy_stm32::{spi, Config}; 12use embassy_stm32::{peripherals, spi, Config};
13use heapless::String; 13use heapless::String;
14use static_cell::StaticCell; 14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17#[embassy_executor::task] 17#[embassy_executor::task]
18async fn main_task(mut spi: spi::Spi<'static, SPI3, DMA1_CH3, DMA1_CH4>) { 18async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI3, Async>) {
19 for n in 0u32.. { 19 for n in 0u32.. {
20 let mut write: String<128> = String::new(); 20 let mut write: String<128> = String::new();
21 let mut read = [0; 128]; 21 let mut read = [0; 128];
diff --git a/examples/stm32l0/src/bin/spi.rs b/examples/stm32l0/src/bin/spi.rs
index f23a537b8..8e0cfdedb 100644
--- a/examples/stm32l0/src/bin/spi.rs
+++ b/examples/stm32l0/src/bin/spi.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
@@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) {
17 let mut spi_config = Config::default(); 16 let mut spi_config = Config::default();
18 spi_config.frequency = Hertz(1_000_000); 17 spi_config.frequency = Hertz(1_000_000);
19 18
20 let mut spi = Spi::new(p.SPI1, p.PB3, p.PA7, p.PA6, NoDma, NoDma, spi_config); 19 let mut spi = Spi::new_blocking(p.SPI1, p.PB3, p.PA7, p.PA6, spi_config);
21 20
22 let mut cs = Output::new(p.PA15, Level::High, Speed::VeryHigh); 21 let mut cs = Output::new(p.PA15, Level::High, Speed::VeryHigh);
23 22
diff --git a/examples/stm32l1/src/bin/spi.rs b/examples/stm32l1/src/bin/spi.rs
index 8be686c5a..eabf1bac2 100644
--- a/examples/stm32l1/src/bin/spi.rs
+++ b/examples/stm32l1/src/bin/spi.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dma::NoDma;
7use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::spi::{Config, Spi}; 7use embassy_stm32::spi::{Config, Spi};
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
@@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) {
17 let mut spi_config = Config::default(); 16 let mut spi_config = Config::default();
18 spi_config.frequency = Hertz(1_000_000); 17 spi_config.frequency = Hertz(1_000_000);
19 18
20 let mut spi = Spi::new(p.SPI1, p.PA5, p.PA7, p.PA6, NoDma, NoDma, spi_config); 19 let mut spi = Spi::new_blocking(p.SPI1, p.PA5, p.PA7, p.PA6, spi_config);
21 20
22 let mut cs = Output::new(p.PA4, Level::High, Speed::VeryHigh); 21 let mut cs = Output::new(p.PA4, Level::High, Speed::VeryHigh);
23 22
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
index 77aa929ab..a99d08924 100644
--- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -23,18 +23,23 @@ use embassy_futures::select::{select, Either};
23use embassy_futures::yield_now; 23use embassy_futures::yield_now;
24use embassy_net::tcp::TcpSocket; 24use embassy_net::tcp::TcpSocket;
25use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4}; 25use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4};
26use embassy_net_adin1110::{Device, Runner, ADIN1110};
27use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
28use embassy_stm32::i2c::{self, Config as I2C_Config, I2c};
29use embassy_stm32::mode::Async;
30use embassy_stm32::rng::{self, Rng};
31use embassy_stm32::spi::{Config as SPI_Config, Spi};
32use embassy_stm32::time::Hertz;
33use embassy_stm32::{bind_interrupts, exti, pac, peripherals};
26use embassy_time::{Delay, Duration, Ticker, Timer}; 34use embassy_time::{Delay, Duration, Ticker, Timer};
27use embedded_hal_async::i2c::I2c as I2cBus; 35use embedded_hal_async::i2c::I2c as I2cBus;
36use embedded_hal_bus::spi::ExclusiveDevice;
28use embedded_io::Write as bWrite; 37use embedded_io::Write as bWrite;
29use embedded_io_async::Write; 38use embedded_io_async::Write;
30use hal::gpio::{Input, Level, Output, Speed};
31use hal::i2c::{self, I2c};
32use hal::rng::{self, Rng};
33use hal::{bind_interrupts, exti, pac, peripherals};
34use heapless::Vec; 39use heapless::Vec;
40use panic_probe as _;
35use rand::RngCore; 41use rand::RngCore;
36use static_cell::StaticCell; 42use static_cell::StaticCell;
37use {embassy_stm32 as hal, panic_probe as _};
38 43
39bind_interrupts!(struct Irqs { 44bind_interrupts!(struct Irqs {
40 I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>; 45 I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>;
@@ -42,13 +47,6 @@ bind_interrupts!(struct Irqs {
42 RNG => rng::InterruptHandler<peripherals::RNG>; 47 RNG => rng::InterruptHandler<peripherals::RNG>;
43}); 48});
44 49
45use embassy_net_adin1110::{Device, Runner, ADIN1110};
46use embedded_hal_bus::spi::ExclusiveDevice;
47use hal::gpio::Pull;
48use hal::i2c::Config as I2C_Config;
49use hal::spi::{Config as SPI_Config, Spi};
50use hal::time::Hertz;
51
52// Basic settings 50// Basic settings
53// MAC-address used by the adin1110 51// MAC-address used by the adin1110
54const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]; 52const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff];
@@ -57,7 +55,7 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24);
57// Listen port for the webserver 55// Listen port for the webserver
58const HTTP_LISTEN_PORT: u16 = 80; 56const HTTP_LISTEN_PORT: u16 = 80;
59 57
60pub type SpeSpi = Spi<'static, peripherals::SPI2, peripherals::DMA1_CH1, peripherals::DMA1_CH2>; 58pub type SpeSpi = Spi<'static, peripherals::SPI2, Async>;
61pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>; 59pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>;
62pub type SpeInt = exti::ExtiInput<'static>; 60pub type SpeInt = exti::ExtiInput<'static>;
63pub type SpeRst = Output<'static>; 61pub type SpeRst = Output<'static>;
diff --git a/examples/stm32l4/src/bin/spi.rs b/examples/stm32l4/src/bin/spi.rs
index 6653e4516..5693a3765 100644
--- a/examples/stm32l4/src/bin/spi.rs
+++ b/examples/stm32l4/src/bin/spi.rs
@@ -2,7 +2,6 @@
2#![no_main] 2#![no_main]
3 3
4use defmt::*; 4use defmt::*;
5use embassy_stm32::dma::NoDma;
6use embassy_stm32::gpio::{Level, Output, Speed}; 5use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_stm32::spi::{Config, Spi}; 6use embassy_stm32::spi::{Config, Spi};
8use embassy_stm32::time::Hertz; 7use embassy_stm32::time::Hertz;
@@ -17,7 +16,7 @@ fn main() -> ! {
17 let mut spi_config = Config::default(); 16 let mut spi_config = Config::default();
18 spi_config.frequency = Hertz(1_000_000); 17 spi_config.frequency = Hertz(1_000_000);
19 18
20 let mut spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); 19 let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
21 20
22 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); 21 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
23 22
diff --git a/examples/stm32l4/src/bin/spi_blocking_async.rs b/examples/stm32l4/src/bin/spi_blocking_async.rs
index 68dbb70ad..1f1089101 100644
--- a/examples/stm32l4/src/bin/spi_blocking_async.rs
+++ b/examples/stm32l4/src/bin/spi_blocking_async.rs
@@ -4,7 +4,6 @@
4use defmt::*; 4use defmt::*;
5use embassy_embedded_hal::adapter::BlockingAsync; 5use embassy_embedded_hal::adapter::BlockingAsync;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 7use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
9use embassy_stm32::spi::{Config, Spi}; 8use embassy_stm32::spi::{Config, Spi};
10use embassy_stm32::time::Hertz; 9use embassy_stm32::time::Hertz;
@@ -19,7 +18,7 @@ async fn main(_spawner: Spawner) {
19 let mut spi_config = Config::default(); 18 let mut spi_config = Config::default();
20 spi_config.frequency = Hertz(1_000_000); 19 spi_config.frequency = Hertz(1_000_000);
21 20
22 let spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); 21 let spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config);
23 22
24 let mut spi = BlockingAsync::new(spi); 23 let mut spi = BlockingAsync::new(spi);
25 24
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs
index b0bdd477f..59cb0cfd3 100644
--- a/tests/stm32/src/bin/spi.rs
+++ b/tests/stm32/src/bin/spi.rs
@@ -6,7 +6,6 @@ mod common;
6use common::*; 6use common::*;
7use defmt::assert_eq; 7use defmt::assert_eq;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma;
10use embassy_stm32::spi::{self, Spi}; 9use embassy_stm32::spi::{self, Spi};
11use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
12 11
@@ -23,11 +22,11 @@ async fn main(_spawner: Spawner) {
23 let mut spi_config = spi::Config::default(); 22 let mut spi_config = spi::Config::default();
24 spi_config.frequency = Hertz(1_000_000); 23 spi_config.frequency = Hertz(1_000_000);
25 24
26 let mut spi = Spi::new( 25 let mut spi = Spi::new_blocking(
27 spi, sck, // Arduino D13 26 spi, sck, // Arduino D13
28 mosi, // Arduino D11 27 mosi, // Arduino D11
29 miso, // Arduino D12 28 miso, // Arduino D12
30 NoDma, NoDma, spi_config, 29 spi_config,
31 ); 30 );
32 31
33 let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE]; 32 let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE];