aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCristian Milatinov <[email protected]>2025-07-09 20:35:01 -0400
committerCristian Milatinov <[email protected]>2025-11-04 22:39:33 -0500
commit141f826e10802a40ac1bca8fdcdfa3da821e0f28 (patch)
treee289966bbdb69123a3e996330a0f0741d650e7fb
parentff42c61dc6c0f870b4022aca52f3c45d992ae735 (diff)
feat: stm32 spi driver slave mode
Add SPI slave constructors Fix SPI slave constructors Fix embedded hal async trait One more constructor fix Set SSM bit in SPI driver according to CommunicationMode Fix embedded_hal_async trait to be generic for both master and slave Fix I2S driver to use async master SPI Forgot import from spi mode Fix CommunicationMode associated const conditionals Duplicate doc for CommunicationMode const Add missing nss argument Fix existing SPI tests not compiling Fix stm32h7rs examples not compiling Fix failing stm32l4 example Fix stm32h7 example Fix stm32h7 spi_bdma example Fix stm32h7 spi example Fix stm32f4 example docs: added entry in changelog.md fix: spi_v3 vals mismatch + rise_fall_speed renamed to gpio_speed fix: added spi_v6 conditional compilation feature fix: use if_afio macro in slave constructors fix: add missing trait bound fix: if_afio for cs pin trait fix: changelog message fix: broken rebase
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/src/i2s.rs3
-rw-r--r--embassy-stm32/src/spi/mod.rs147
-rw-r--r--examples/stm32f4/src/bin/eth_w5500.rs3
-rw-r--r--examples/stm32h7/src/bin/spi.rs2
-rw-r--r--examples/stm32h7/src/bin/spi_bdma.rs2
-rw-r--r--examples/stm32h7/src/bin/spi_dma.rs2
-rw-r--r--examples/stm32h7rs/src/bin/spi.rs2
-rw-r--r--examples/stm32h7rs/src/bin/spi_dma.rs2
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs3
-rw-r--r--tests/stm32/src/bin/spi.rs7
-rw-r--r--tests/stm32/src/bin/spi_dma.rs7
12 files changed, 145 insertions, 36 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index ee76a5d1b..2a7a89bc9 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
44- feat: Added RTC low-power support for STM32WLEx ([#4716](https://github.com/embassy-rs/embassy/pull/4716)) 44- feat: Added RTC low-power support for STM32WLEx ([#4716](https://github.com/embassy-rs/embassy/pull/4716))
45- fix: Correct STM32WBA VREFBUFTRIM values 45- fix: Correct STM32WBA VREFBUFTRIM values
46- low_power: remove stop_with rtc and initialize in init if low-power feature enabled. 46- low_power: remove stop_with rtc and initialize in init if low-power feature enabled.
47- feat: stm32/spi: added support for slave mode ([#4388](https://github.com/embassy-rs/embassy/pull/4388))
47 48
48## 0.4.0 - 2025-08-26 49## 0.4.0 - 2025-08-26
49 50
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index db22cfa11..df077a3ae 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -7,6 +7,7 @@ use crate::Peri;
7use crate::dma::{ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer, ringbuffer}; 7use crate::dma::{ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer, ringbuffer};
8use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; 8use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
9use crate::mode::Async; 9use crate::mode::Async;
10use crate::spi::mode::Master;
10use crate::spi::{Config as SpiConfig, RegsExt as _, *}; 11use crate::spi::{Config as SpiConfig, RegsExt as _, *};
11use crate::time::Hertz; 12use crate::time::Hertz;
12 13
@@ -225,7 +226,7 @@ impl<'s, 'd, W: Word> Reader<'s, 'd, W> {
225pub struct I2S<'d, W: Word> { 226pub struct I2S<'d, W: Word> {
226 #[allow(dead_code)] 227 #[allow(dead_code)]
227 mode: Mode, 228 mode: Mode,
228 spi: Spi<'d, Async>, 229 spi: Spi<'d, Async, Master>,
229 txsd: Option<Peri<'d, AnyPin>>, 230 txsd: Option<Peri<'d, AnyPin>>,
230 rxsd: Option<Peri<'d, AnyPin>>, 231 rxsd: Option<Peri<'d, AnyPin>>,
231 ws: Option<Peri<'d, AnyPin>>, 232 ws: Option<Peri<'d, AnyPin>>,
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index c27d09ea7..abb80ed26 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -125,26 +125,69 @@ impl Config {
125 ) 125 )
126 } 126 }
127} 127}
128
129/// SPI communication mode
130pub mod mode {
131 use stm32_metapac::spi::vals;
132
133 trait SealedMode {}
134
135 /// Trait for SPI communication mode operations.
136 #[allow(private_bounds)]
137 pub trait CommunicationMode: SealedMode {
138 /// Spi communication mode
139 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
140 const MASTER: vals::Mstr;
141 /// Spi communication mode
142 #[cfg(any(spi_v4, spi_v5, spi_v6))]
143 const MASTER: vals::Master;
144 }
145
146 /// Mode allowing for SPI master operations.
147 pub struct Master;
148 /// Mode allowing for SPI slave operations.
149 pub struct Slave;
150
151 impl SealedMode for Master {}
152 impl CommunicationMode for Master {
153 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
154 const MASTER: vals::Mstr = vals::Mstr::MASTER;
155 #[cfg(any(spi_v4, spi_v5, spi_v6))]
156 const MASTER: vals::Master = vals::Master::MASTER;
157 }
158
159 impl SealedMode for Slave {}
160 impl CommunicationMode for Slave {
161 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
162 const MASTER: vals::Mstr = vals::Mstr::SLAVE;
163 #[cfg(any(spi_v4, spi_v5, spi_v6))]
164 const MASTER: vals::Master = vals::Master::SLAVE;
165 }
166}
167use mode::{CommunicationMode, Master, Slave};
168
128/// SPI driver. 169/// SPI driver.
129pub struct Spi<'d, M: PeriMode> { 170pub struct Spi<'d, M: PeriMode, CM: CommunicationMode> {
130 pub(crate) info: &'static Info, 171 pub(crate) info: &'static Info,
131 kernel_clock: Hertz, 172 kernel_clock: Hertz,
132 sck: Option<Peri<'d, AnyPin>>, 173 sck: Option<Peri<'d, AnyPin>>,
133 mosi: Option<Peri<'d, AnyPin>>, 174 mosi: Option<Peri<'d, AnyPin>>,
134 miso: Option<Peri<'d, AnyPin>>, 175 miso: Option<Peri<'d, AnyPin>>,
176 nss: Option<Peri<'d, AnyPin>>,
135 tx_dma: Option<ChannelAndRequest<'d>>, 177 tx_dma: Option<ChannelAndRequest<'d>>,
136 rx_dma: Option<ChannelAndRequest<'d>>, 178 rx_dma: Option<ChannelAndRequest<'d>>,
137 _phantom: PhantomData<M>, 179 _phantom: PhantomData<(M, CM)>,
138 current_word_size: word_impl::Config, 180 current_word_size: word_impl::Config,
139 gpio_speed: Speed, 181 gpio_speed: Speed,
140} 182}
141 183
142impl<'d, M: PeriMode> Spi<'d, M> { 184impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
143 fn new_inner<T: Instance>( 185 fn new_inner<T: Instance>(
144 _peri: Peri<'d, T>, 186 _peri: Peri<'d, T>,
145 sck: Option<Peri<'d, AnyPin>>, 187 sck: Option<Peri<'d, AnyPin>>,
146 mosi: Option<Peri<'d, AnyPin>>, 188 mosi: Option<Peri<'d, AnyPin>>,
147 miso: Option<Peri<'d, AnyPin>>, 189 miso: Option<Peri<'d, AnyPin>>,
190 nss: Option<Peri<'d, AnyPin>>,
148 tx_dma: Option<ChannelAndRequest<'d>>, 191 tx_dma: Option<ChannelAndRequest<'d>>,
149 rx_dma: Option<ChannelAndRequest<'d>>, 192 rx_dma: Option<ChannelAndRequest<'d>>,
150 config: Config, 193 config: Config,
@@ -155,6 +198,7 @@ impl<'d, M: PeriMode> Spi<'d, M> {
155 sck, 198 sck,
156 mosi, 199 mosi,
157 miso, 200 miso,
201 nss,
158 tx_dma, 202 tx_dma,
159 rx_dma, 203 rx_dma,
160 current_word_size: <u8 as SealedWord>::CONFIG, 204 current_word_size: <u8 as SealedWord>::CONFIG,
@@ -183,12 +227,12 @@ impl<'d, M: PeriMode> Spi<'d, M> {
183 w.set_cpha(cpha); 227 w.set_cpha(cpha);
184 w.set_cpol(cpol); 228 w.set_cpol(cpol);
185 229
186 w.set_mstr(vals::Mstr::MASTER); 230 w.set_mstr(CM::MASTER);
187 w.set_br(br); 231 w.set_br(br);
188 w.set_spe(true); 232 w.set_spe(true);
189 w.set_lsbfirst(lsbfirst); 233 w.set_lsbfirst(lsbfirst);
190 w.set_ssi(true); 234 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
191 w.set_ssm(true); 235 w.set_ssm(CM::MASTER == vals::Mstr::MASTER);
192 w.set_crcen(false); 236 w.set_crcen(false);
193 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 237 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
194 // we're doing "fake rxonly", by actually writing one 238 // we're doing "fake rxonly", by actually writing one
@@ -210,11 +254,11 @@ impl<'d, M: PeriMode> Spi<'d, M> {
210 w.set_cpha(cpha); 254 w.set_cpha(cpha);
211 w.set_cpol(cpol); 255 w.set_cpol(cpol);
212 256
213 w.set_mstr(vals::Mstr::MASTER); 257 w.set_mstr(CM::MASTER);
214 w.set_br(br); 258 w.set_br(br);
215 w.set_lsbfirst(lsbfirst); 259 w.set_lsbfirst(lsbfirst);
216 w.set_ssi(true); 260 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
217 w.set_ssm(true); 261 w.set_ssm(CM::MASTER == vals::Mstr::MASTER);
218 w.set_crcen(false); 262 w.set_crcen(false);
219 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 263 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
220 w.set_spe(true); 264 w.set_spe(true);
@@ -229,8 +273,8 @@ impl<'d, M: PeriMode> Spi<'d, M> {
229 w.set_cpha(cpha); 273 w.set_cpha(cpha);
230 w.set_cpol(cpol); 274 w.set_cpol(cpol);
231 w.set_lsbfirst(lsbfirst); 275 w.set_lsbfirst(lsbfirst);
232 w.set_ssm(true); 276 w.set_ssm(CM::MASTER == vals::Master::MASTER);
233 w.set_master(vals::Master::MASTER); 277 w.set_master(CM::MASTER);
234 w.set_comm(vals::Comm::FULL_DUPLEX); 278 w.set_comm(vals::Comm::FULL_DUPLEX);
235 w.set_ssom(vals::Ssom::ASSERTED); 279 w.set_ssom(vals::Ssom::ASSERTED);
236 w.set_midi(0); 280 w.set_midi(0);
@@ -469,7 +513,30 @@ impl<'d, M: PeriMode> Spi<'d, M> {
469 } 513 }
470} 514}
471 515
472impl<'d> Spi<'d, Blocking> { 516impl<'d> Spi<'d, Blocking, Slave> {
517 /// Create a new blocking SPI slave driver.
518 pub fn new_blocking_slave<T: Instance, #[cfg(afio)] A>(
519 peri: Peri<'d, T>,
520 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
521 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
522 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
523 cs: Peri<'d, if_afio!(impl CsPin<T, A>)>,
524 config: Config,
525 ) -> Self {
526 Self::new_inner(
527 peri,
528 new_pin!(sck, config.sck_af()),
529 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
530 new_pin!(miso, AfType::input(config.miso_pull)),
531 new_pin!(cs, AfType::input(Pull::None)),
532 None,
533 None,
534 config,
535 )
536 }
537}
538
539impl<'d> Spi<'d, Blocking, Master> {
473 /// Create a new blocking SPI driver. 540 /// Create a new blocking SPI driver.
474 pub fn new_blocking<T: Instance, #[cfg(afio)] A>( 541 pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
475 peri: Peri<'d, T>, 542 peri: Peri<'d, T>,
@@ -485,6 +552,7 @@ impl<'d> Spi<'d, Blocking> {
485 new_pin!(miso, AfType::input(config.miso_pull)), 552 new_pin!(miso, AfType::input(config.miso_pull)),
486 None, 553 None,
487 None, 554 None,
555 None,
488 config, 556 config,
489 ) 557 )
490 } 558 }
@@ -503,6 +571,7 @@ impl<'d> Spi<'d, Blocking> {
503 new_pin!(miso, AfType::input(config.miso_pull)), 571 new_pin!(miso, AfType::input(config.miso_pull)),
504 None, 572 None,
505 None, 573 None,
574 None,
506 config, 575 config,
507 ) 576 )
508 } 577 }
@@ -521,6 +590,7 @@ impl<'d> Spi<'d, Blocking> {
521 None, 590 None,
522 None, 591 None,
523 None, 592 None,
593 None,
524 config, 594 config,
525 ) 595 )
526 } 596 }
@@ -540,12 +610,38 @@ impl<'d> Spi<'d, Blocking> {
540 None, 610 None,
541 None, 611 None,
542 None, 612 None,
613 None,
614 config,
615 )
616 }
617}
618
619impl<'d> Spi<'d, Async, Slave> {
620 /// Create a new SPI slave driver.
621 pub fn new_slave<T: Instance, #[cfg(afio)] A>(
622 peri: Peri<'d, T>,
623 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
624 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
625 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
626 cs: Peri<'d, if_afio!(impl CsPin<T, A>)>,
627 tx_dma: Peri<'d, impl TxDma<T>>,
628 rx_dma: Peri<'d, impl RxDma<T>>,
629 config: Config,
630 ) -> Self {
631 Self::new_inner(
632 peri,
633 new_pin!(sck, config.sck_af()),
634 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
635 new_pin!(miso, AfType::input(config.miso_pull)),
636 new_pin!(cs, AfType::input(Pull::None)),
637 new_dma!(tx_dma),
638 new_dma!(rx_dma),
543 config, 639 config,
544 ) 640 )
545 } 641 }
546} 642}
547 643
548impl<'d> Spi<'d, Async> { 644impl<'d> Spi<'d, Async, Master> {
549 /// Create a new SPI driver. 645 /// Create a new SPI driver.
550 pub fn new<T: Instance, #[cfg(afio)] A>( 646 pub fn new<T: Instance, #[cfg(afio)] A>(
551 peri: Peri<'d, T>, 647 peri: Peri<'d, T>,
@@ -561,6 +657,7 @@ impl<'d> Spi<'d, Async> {
561 new_pin!(sck, config.sck_af()), 657 new_pin!(sck, config.sck_af()),
562 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 658 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
563 new_pin!(miso, AfType::input(config.miso_pull)), 659 new_pin!(miso, AfType::input(config.miso_pull)),
660 None,
564 new_dma!(tx_dma), 661 new_dma!(tx_dma),
565 new_dma!(rx_dma), 662 new_dma!(rx_dma),
566 config, 663 config,
@@ -581,6 +678,7 @@ impl<'d> Spi<'d, Async> {
581 new_pin!(sck, config.sck_af()), 678 new_pin!(sck, config.sck_af()),
582 None, 679 None,
583 new_pin!(miso, AfType::input(config.miso_pull)), 680 new_pin!(miso, AfType::input(config.miso_pull)),
681 None,
584 #[cfg(any(spi_v1, spi_v2, spi_v3))] 682 #[cfg(any(spi_v1, spi_v2, spi_v3))]
585 new_dma!(tx_dma), 683 new_dma!(tx_dma),
586 #[cfg(any(spi_v4, spi_v5, spi_v6))] 684 #[cfg(any(spi_v4, spi_v5, spi_v6))]
@@ -603,6 +701,7 @@ impl<'d> Spi<'d, Async> {
603 new_pin!(sck, config.sck_af()), 701 new_pin!(sck, config.sck_af()),
604 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 702 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
605 None, 703 None,
704 None,
606 new_dma!(tx_dma), 705 new_dma!(tx_dma),
607 None, 706 None,
608 config, 707 config,
@@ -623,6 +722,7 @@ impl<'d> Spi<'d, Async> {
623 None, 722 None,
624 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 723 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
625 None, 724 None,
725 None,
626 new_dma!(tx_dma), 726 new_dma!(tx_dma),
627 None, 727 None,
628 config, 728 config,
@@ -646,7 +746,7 @@ impl<'d> Spi<'d, Async> {
646 config.bit_order = BitOrder::MsbFirst; 746 config.bit_order = BitOrder::MsbFirst;
647 config.frequency = freq; 747 config.frequency = freq;
648 748
649 Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config) 749 Self::new_inner(peri, None, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
650 } 750 }
651 751
652 #[allow(dead_code)] 752 #[allow(dead_code)]
@@ -656,9 +756,11 @@ impl<'d> Spi<'d, Async> {
656 rx_dma: Option<ChannelAndRequest<'d>>, 756 rx_dma: Option<ChannelAndRequest<'d>>,
657 config: Config, 757 config: Config,
658 ) -> Self { 758 ) -> Self {
659 Self::new_inner(peri, None, None, None, tx_dma, rx_dma, config) 759 Self::new_inner(peri, None, None, None, None, tx_dma, rx_dma, config)
660 } 760 }
761}
661 762
763impl<'d, CM: CommunicationMode> Spi<'d, Async, CM> {
662 /// SPI write, using DMA. 764 /// SPI write, using DMA.
663 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> { 765 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
664 if data.is_empty() { 766 if data.is_empty() {
@@ -888,11 +990,12 @@ impl<'d> Spi<'d, Async> {
888 } 990 }
889} 991}
890 992
891impl<'d, M: PeriMode> Drop for Spi<'d, M> { 993impl<'d, M: PeriMode, CM: CommunicationMode> Drop for Spi<'d, M, CM> {
892 fn drop(&mut self) { 994 fn drop(&mut self) {
893 self.sck.as_ref().map(|x| x.set_as_disconnected()); 995 self.sck.as_ref().map(|x| x.set_as_disconnected());
894 self.mosi.as_ref().map(|x| x.set_as_disconnected()); 996 self.mosi.as_ref().map(|x| x.set_as_disconnected());
895 self.miso.as_ref().map(|x| x.set_as_disconnected()); 997 self.miso.as_ref().map(|x| x.set_as_disconnected());
998 self.nss.as_ref().map(|x| x.set_as_disconnected());
896 999
897 self.info.rcc.disable(); 1000 self.info.rcc.disable();
898 } 1001 }
@@ -1127,7 +1230,7 @@ fn write_word<W: Word>(regs: Regs, tx_word: W) -> Result<(), Error> {
1127// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289 1230// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
1128macro_rules! impl_blocking { 1231macro_rules! impl_blocking {
1129 ($w:ident) => { 1232 ($w:ident) => {
1130 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M> { 1233 impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M, CM> {
1131 type Error = Error; 1234 type Error = Error;
1132 1235
1133 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> { 1236 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
@@ -1135,7 +1238,7 @@ macro_rules! impl_blocking {
1135 } 1238 }
1136 } 1239 }
1137 1240
1138 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M> { 1241 impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M, CM> {
1139 type Error = Error; 1242 type Error = Error;
1140 1243
1141 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> { 1244 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
@@ -1149,11 +1252,11 @@ macro_rules! impl_blocking {
1149impl_blocking!(u8); 1252impl_blocking!(u8);
1150impl_blocking!(u16); 1253impl_blocking!(u16);
1151 1254
1152impl<'d, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, M> { 1255impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_1::spi::ErrorType for Spi<'d, M, CM> {
1153 type Error = Error; 1256 type Error = Error;
1154} 1257}
1155 1258
1156impl<'d, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, M> { 1259impl<'d, W: Word, M: PeriMode, CM: CommunicationMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, M, CM> {
1157 fn flush(&mut self) -> Result<(), Self::Error> { 1260 fn flush(&mut self) -> Result<(), Self::Error> {
1158 Ok(()) 1261 Ok(())
1159 } 1262 }
@@ -1186,7 +1289,7 @@ impl embedded_hal_1::spi::Error for Error {
1186 } 1289 }
1187} 1290}
1188 1291
1189impl<'d, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async> { 1292impl<'d, W: Word, CM: CommunicationMode> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async, CM> {
1190 async fn flush(&mut self) -> Result<(), Self::Error> { 1293 async fn flush(&mut self) -> Result<(), Self::Error> {
1191 Ok(()) 1294 Ok(())
1192 } 1295 }
@@ -1328,7 +1431,7 @@ foreach_peripheral!(
1328 }; 1431 };
1329); 1432);
1330 1433
1331impl<'d, M: PeriMode> SetConfig for Spi<'d, M> { 1434impl<'d, M: PeriMode, CM: CommunicationMode> SetConfig for Spi<'d, M, CM> {
1332 type Config = Config; 1435 type Config = Config;
1333 type ConfigError = (); 1436 type ConfigError = ();
1334 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 1437 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
diff --git a/examples/stm32f4/src/bin/eth_w5500.rs b/examples/stm32f4/src/bin/eth_w5500.rs
index cccf20949..0adcda614 100644
--- a/examples/stm32f4/src/bin/eth_w5500.rs
+++ b/examples/stm32f4/src/bin/eth_w5500.rs
@@ -12,6 +12,7 @@ use embassy_stm32::gpio::{Level, Output, Pull, Speed};
12use embassy_stm32::mode::Async; 12use embassy_stm32::mode::Async;
13use embassy_stm32::rng::Rng; 13use embassy_stm32::rng::Rng;
14use embassy_stm32::spi::Spi; 14use embassy_stm32::spi::Spi;
15use embassy_stm32::spi::mode::Master;
15use embassy_stm32::time::Hertz; 16use embassy_stm32::time::Hertz;
16use embassy_stm32::{Config, bind_interrupts, peripherals, rng, spi}; 17use embassy_stm32::{Config, bind_interrupts, peripherals, rng, spi};
17use embassy_time::{Delay, Timer}; 18use embassy_time::{Delay, Timer};
@@ -24,7 +25,7 @@ bind_interrupts!(struct Irqs {
24 HASH_RNG => rng::InterruptHandler<peripherals::RNG>; 25 HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
25}); 26});
26 27
27type EthernetSPI = ExclusiveDevice<Spi<'static, Async>, Output<'static>, Delay>; 28type EthernetSPI = ExclusiveDevice<Spi<'static, Async, Master>, Output<'static>, Delay>;
28#[embassy_executor::task] 29#[embassy_executor::task]
29async fn ethernet_task(runner: Runner<'static, W5500, EthernetSPI, ExtiInput<'static>, Output<'static>>) -> ! { 30async fn ethernet_task(runner: Runner<'static, W5500, EthernetSPI, ExtiInput<'static>, Output<'static>>) -> ! {
30 runner.run().await 31 runner.run().await
diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs
index 61f31be24..f7ab20cdd 100644
--- a/examples/stm32h7/src/bin/spi.rs
+++ b/examples/stm32h7/src/bin/spi.rs
@@ -15,7 +15,7 @@ use 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, Blocking>) { 18async fn main_task(mut spi: spi::Spi<'static, Blocking, spi::mode::Master>) {
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 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); 21 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs
index be6a26d82..cd9d6c789 100644
--- a/examples/stm32h7/src/bin/spi_bdma.rs
+++ b/examples/stm32h7/src/bin/spi_bdma.rs
@@ -20,7 +20,7 @@ use {defmt_rtt as _, panic_probe as _};
20static mut RAM_D3: GroundedArrayCell<u8, 256> = GroundedArrayCell::uninit(); 20static mut RAM_D3: GroundedArrayCell<u8, 256> = GroundedArrayCell::uninit();
21 21
22#[embassy_executor::task] 22#[embassy_executor::task]
23async fn main_task(mut spi: spi::Spi<'static, Async>) { 23async fn main_task(mut spi: spi::Spi<'static, Async, spi::mode::Master>) {
24 let (read_buffer, write_buffer) = unsafe { 24 let (read_buffer, write_buffer) = unsafe {
25 let ram = &mut *core::ptr::addr_of_mut!(RAM_D3); 25 let ram = &mut *core::ptr::addr_of_mut!(RAM_D3);
26 ram.initialize_all_copied(0); 26 ram.initialize_all_copied(0);
diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs
index 20cb67ba0..3d3c2f43e 100644
--- a/examples/stm32h7/src/bin/spi_dma.rs
+++ b/examples/stm32h7/src/bin/spi_dma.rs
@@ -15,7 +15,7 @@ use 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, Async>) { 18async fn main_task(mut spi: spi::Spi<'static, Async, spi::mode::Master>) {
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/stm32h7rs/src/bin/spi.rs b/examples/stm32h7rs/src/bin/spi.rs
index 8c280fdae..3253304eb 100644
--- a/examples/stm32h7rs/src/bin/spi.rs
+++ b/examples/stm32h7rs/src/bin/spi.rs
@@ -15,7 +15,7 @@ use 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, Blocking>) { 18async fn main_task(mut spi: spi::Spi<'static, Blocking, spi::mode::Master>) {
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 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); 21 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
diff --git a/examples/stm32h7rs/src/bin/spi_dma.rs b/examples/stm32h7rs/src/bin/spi_dma.rs
index 3fa69fd15..ca644c6a8 100644
--- a/examples/stm32h7rs/src/bin/spi_dma.rs
+++ b/examples/stm32h7rs/src/bin/spi_dma.rs
@@ -15,7 +15,7 @@ use 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, Async>) { 18async fn main_task(mut spi: spi::Spi<'static, Async, spi::mode::Master>) {
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/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
index 8e54938d1..0dbf515cf 100644
--- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -28,6 +28,7 @@ use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
28use embassy_stm32::i2c::{self, Config as I2C_Config, I2c}; 28use embassy_stm32::i2c::{self, Config as I2C_Config, I2c};
29use embassy_stm32::mode::Async; 29use embassy_stm32::mode::Async;
30use embassy_stm32::rng::{self, Rng}; 30use embassy_stm32::rng::{self, Rng};
31use embassy_stm32::spi::mode::Master;
31use embassy_stm32::spi::{Config as SPI_Config, Spi}; 32use embassy_stm32::spi::{Config as SPI_Config, Spi};
32use embassy_stm32::time::Hertz; 33use embassy_stm32::time::Hertz;
33use embassy_stm32::{bind_interrupts, exti, pac, peripherals}; 34use embassy_stm32::{bind_interrupts, exti, pac, peripherals};
@@ -54,7 +55,7 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address::new(192, 168, 1, 5), 24)
54// Listen port for the webserver 55// Listen port for the webserver
55const HTTP_LISTEN_PORT: u16 = 80; 56const HTTP_LISTEN_PORT: u16 = 80;
56 57
57pub type SpeSpi = Spi<'static, Async>; 58pub type SpeSpi = Spi<'static, Async, Master>;
58pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>; 59pub type SpeSpiCs = ExclusiveDevice<SpeSpi, Output<'static>, Delay>;
59pub type SpeInt = exti::ExtiInput<'static>; 60pub type SpeInt = exti::ExtiInput<'static>;
60pub type SpeRst = Output<'static>; 61pub type SpeRst = Output<'static>;
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs
index e8310866a..cedff772c 100644
--- a/tests/stm32/src/bin/spi.rs
+++ b/tests/stm32/src/bin/spi.rs
@@ -8,6 +8,7 @@ use defmt::assert_eq;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::gpio::{Level, Output, Speed}; 9use embassy_stm32::gpio::{Level, Output, Speed};
10use embassy_stm32::mode::Blocking; 10use embassy_stm32::mode::Blocking;
11use embassy_stm32::spi::mode::Master;
11use embassy_stm32::spi::{self, Spi, Word}; 12use embassy_stm32::spi::{self, Spi, Word};
12use embassy_stm32::time::Hertz; 13use embassy_stm32::time::Hertz;
13 14
@@ -65,7 +66,7 @@ async fn main(_spawner: Spawner) {
65 cortex_m::asm::bkpt(); 66 cortex_m::asm::bkpt();
66} 67}
67 68
68fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>) 69fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking, Master>)
69where 70where
70 W: core::ops::Not<Output = W>, 71 W: core::ops::Not<Output = W>,
71{ 72{
@@ -109,7 +110,7 @@ where
109 spi.blocking_write::<u8>(&[]).unwrap(); 110 spi.blocking_write::<u8>(&[]).unwrap();
110} 111}
111 112
112fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>, mosi_out: &mut Output<'_>) 113fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking, Master>, mosi_out: &mut Output<'_>)
113where 114where
114 W: core::ops::Not<Output = W>, 115 W: core::ops::Not<Output = W>,
115{ 116{
@@ -125,7 +126,7 @@ where
125 spi.blocking_read::<u8>(&mut []).unwrap(); 126 spi.blocking_read::<u8>(&mut []).unwrap();
126} 127}
127 128
128fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>) 129fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking, Master>)
129where 130where
130 W: core::ops::Not<Output = W>, 131 W: core::ops::Not<Output = W>,
131{ 132{
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs
index b4fdb8faa..c8cd92401 100644
--- a/tests/stm32/src/bin/spi_dma.rs
+++ b/tests/stm32/src/bin/spi_dma.rs
@@ -8,6 +8,7 @@ use defmt::assert_eq;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::gpio::{Level, Output, Speed}; 9use embassy_stm32::gpio::{Level, Output, Speed};
10use embassy_stm32::mode::Async; 10use embassy_stm32::mode::Async;
11use embassy_stm32::spi::mode::Master;
11use embassy_stm32::spi::{self, Spi, Word}; 12use embassy_stm32::spi::{self, Spi, Word};
12use embassy_stm32::time::Hertz; 13use embassy_stm32::time::Hertz;
13 14
@@ -78,7 +79,7 @@ async fn main(_spawner: Spawner) {
78 cortex_m::asm::bkpt(); 79 cortex_m::asm::bkpt();
79} 80}
80 81
81async fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async>) 82async fn test_txrx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async, Master>)
82where 83where
83 W: core::ops::Not<Output = W>, 84 W: core::ops::Not<Output = W>,
84{ 85{
@@ -142,7 +143,7 @@ where
142 spi.write(&buf).await.unwrap(); 143 spi.write(&buf).await.unwrap();
143} 144}
144 145
145async fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async>, mosi_out: &mut Output<'_>) 146async fn test_rx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async, Master>, mosi_out: &mut Output<'_>)
146where 147where
147 W: core::ops::Not<Output = W>, 148 W: core::ops::Not<Output = W>,
148{ 149{
@@ -168,7 +169,7 @@ where
168 spi.blocking_read::<u8>(&mut []).unwrap(); 169 spi.blocking_read::<u8>(&mut []).unwrap();
169} 170}
170 171
171async fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async>) 172async fn test_tx<W: Word + From<u8> + defmt::Format + Eq>(spi: &mut Spi<'_, Async, Master>)
172where 173where
173 W: core::ops::Not<Output = W>, 174 W: core::ops::Not<Output = W>,
174{ 175{