aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/spi
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/spi')
-rw-r--r--embassy-stm32/src/spi/mod.rs298
1 files changed, 265 insertions, 33 deletions
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index c5373a54d..13ff31a34 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -6,15 +6,15 @@ use core::ptr;
6 6
7use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
8use embassy_futures::join::join; 8use embassy_futures::join::join;
9pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 9pub use embedded_hal_02::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity};
10 10
11use crate::dma::{word, ChannelAndRequest}; 11use crate::Peri;
12use crate::dma::{ChannelAndRequest, word};
12use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 13use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
13use crate::mode::{Async, Blocking, Mode as PeriMode}; 14use crate::mode::{Async, Blocking, Mode as PeriMode};
14use crate::pac::spi::{regs, vals, Spi as Regs}; 15use crate::pac::spi::{Spi as Regs, regs, vals};
15use crate::rcc::{RccInfo, SealedRccPeripheral}; 16use crate::rcc::{RccInfo, SealedRccPeripheral};
16use crate::time::Hertz; 17use crate::time::Hertz;
17use crate::Peri;
18 18
19/// SPI error. 19/// SPI error.
20#[derive(Debug, PartialEq, Eq, Clone, Copy)] 20#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -54,6 +54,26 @@ pub enum BitOrder {
54 MsbFirst, 54 MsbFirst,
55} 55}
56 56
57/// SPI Direction.
58#[derive(Debug, PartialEq, Eq, Clone, Copy)]
59#[cfg_attr(feature = "defmt", derive(defmt::Format))]
60pub enum Direction {
61 /// Transmit
62 Transmit,
63 /// Receive
64 Receive,
65}
66
67/// Slave Select (SS) pin polarity.
68#[derive(Debug, PartialEq, Eq, Clone, Copy)]
69#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70pub enum SlaveSelectPolarity {
71 /// SS active high
72 ActiveHigh,
73 /// SS active low
74 ActiveLow,
75}
76
57/// SPI configuration. 77/// SPI configuration.
58#[non_exhaustive] 78#[non_exhaustive]
59#[derive(Copy, Clone)] 79#[derive(Copy, Clone)]
@@ -72,6 +92,13 @@ pub struct Config {
72 /// signal rise/fall speed (slew rate) - defaults to `Medium`. 92 /// signal rise/fall speed (slew rate) - defaults to `Medium`.
73 /// Increase for high SPI speeds. Change to `Low` to reduce ringing. 93 /// Increase for high SPI speeds. Change to `Low` to reduce ringing.
74 pub gpio_speed: Speed, 94 pub gpio_speed: Speed,
95 /// If True sets SSOE to zero even if SPI is in Master Mode.
96 /// NSS output enabled (SSM = 0, SSOE = 1): The NSS signal is driven low when the master starts the communication and is kept low until the SPI is disabled.
97 /// NSS output disabled (SSM = 0, SSOE = 0): For devices set as slave, the NSS pin acts as a classical NSS input: the slave is selected when NSS is low and deselected when NSS high.
98 pub nss_output_disable: bool,
99 /// Slave Select (SS) pin polarity.
100 #[cfg(any(spi_v4, spi_v5, spi_v6))]
101 pub nss_polarity: SlaveSelectPolarity,
75} 102}
76 103
77impl Default for Config { 104impl Default for Config {
@@ -82,6 +109,9 @@ impl Default for Config {
82 frequency: Hertz(1_000_000), 109 frequency: Hertz(1_000_000),
83 miso_pull: Pull::None, 110 miso_pull: Pull::None,
84 gpio_speed: Speed::VeryHigh, 111 gpio_speed: Speed::VeryHigh,
112 nss_output_disable: false,
113 #[cfg(any(spi_v4, spi_v5, spi_v6))]
114 nss_polarity: SlaveSelectPolarity::ActiveHigh,
85 } 115 }
86 } 116 }
87} 117}
@@ -108,6 +138,14 @@ impl Config {
108 } 138 }
109 } 139 }
110 140
141 #[cfg(any(spi_v4, spi_v5, spi_v6))]
142 fn raw_nss_polarity(&self) -> vals::Ssiop {
143 match self.nss_polarity {
144 SlaveSelectPolarity::ActiveHigh => vals::Ssiop::ACTIVE_HIGH,
145 SlaveSelectPolarity::ActiveLow => vals::Ssiop::ACTIVE_LOW,
146 }
147 }
148
111 #[cfg(gpio_v1)] 149 #[cfg(gpio_v1)]
112 fn sck_af(&self) -> AfType { 150 fn sck_af(&self) -> AfType {
113 AfType::output(OutputType::PushPull, self.gpio_speed) 151 AfType::output(OutputType::PushPull, self.gpio_speed)
@@ -125,26 +163,69 @@ impl Config {
125 ) 163 )
126 } 164 }
127} 165}
166
167/// SPI communication mode
168pub mod mode {
169 use stm32_metapac::spi::vals;
170
171 trait SealedMode {}
172
173 /// Trait for SPI communication mode operations.
174 #[allow(private_bounds)]
175 pub trait CommunicationMode: SealedMode {
176 /// Spi communication mode
177 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
178 const MASTER: vals::Mstr;
179 /// Spi communication mode
180 #[cfg(any(spi_v4, spi_v5, spi_v6))]
181 const MASTER: vals::Master;
182 }
183
184 /// Mode allowing for SPI master operations.
185 pub struct Master;
186 /// Mode allowing for SPI slave operations.
187 pub struct Slave;
188
189 impl SealedMode for Master {}
190 impl CommunicationMode for Master {
191 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
192 const MASTER: vals::Mstr = vals::Mstr::MASTER;
193 #[cfg(any(spi_v4, spi_v5, spi_v6))]
194 const MASTER: vals::Master = vals::Master::MASTER;
195 }
196
197 impl SealedMode for Slave {}
198 impl CommunicationMode for Slave {
199 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
200 const MASTER: vals::Mstr = vals::Mstr::SLAVE;
201 #[cfg(any(spi_v4, spi_v5, spi_v6))]
202 const MASTER: vals::Master = vals::Master::SLAVE;
203 }
204}
205use mode::{CommunicationMode, Master, Slave};
206
128/// SPI driver. 207/// SPI driver.
129pub struct Spi<'d, M: PeriMode> { 208pub struct Spi<'d, M: PeriMode, CM: CommunicationMode> {
130 pub(crate) info: &'static Info, 209 pub(crate) info: &'static Info,
131 kernel_clock: Hertz, 210 kernel_clock: Hertz,
132 sck: Option<Peri<'d, AnyPin>>, 211 sck: Option<Peri<'d, AnyPin>>,
133 mosi: Option<Peri<'d, AnyPin>>, 212 mosi: Option<Peri<'d, AnyPin>>,
134 miso: Option<Peri<'d, AnyPin>>, 213 miso: Option<Peri<'d, AnyPin>>,
214 nss: Option<Peri<'d, AnyPin>>,
135 tx_dma: Option<ChannelAndRequest<'d>>, 215 tx_dma: Option<ChannelAndRequest<'d>>,
136 rx_dma: Option<ChannelAndRequest<'d>>, 216 rx_dma: Option<ChannelAndRequest<'d>>,
137 _phantom: PhantomData<M>, 217 _phantom: PhantomData<(M, CM)>,
138 current_word_size: word_impl::Config, 218 current_word_size: word_impl::Config,
139 gpio_speed: Speed, 219 gpio_speed: Speed,
140} 220}
141 221
142impl<'d, M: PeriMode> Spi<'d, M> { 222impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
143 fn new_inner<T: Instance>( 223 fn new_inner<T: Instance>(
144 _peri: Peri<'d, T>, 224 _peri: Peri<'d, T>,
145 sck: Option<Peri<'d, AnyPin>>, 225 sck: Option<Peri<'d, AnyPin>>,
146 mosi: Option<Peri<'d, AnyPin>>, 226 mosi: Option<Peri<'d, AnyPin>>,
147 miso: Option<Peri<'d, AnyPin>>, 227 miso: Option<Peri<'d, AnyPin>>,
228 nss: Option<Peri<'d, AnyPin>>,
148 tx_dma: Option<ChannelAndRequest<'d>>, 229 tx_dma: Option<ChannelAndRequest<'d>>,
149 rx_dma: Option<ChannelAndRequest<'d>>, 230 rx_dma: Option<ChannelAndRequest<'d>>,
150 config: Config, 231 config: Config,
@@ -155,6 +236,7 @@ impl<'d, M: PeriMode> Spi<'d, M> {
155 sck, 236 sck,
156 mosi, 237 mosi,
157 miso, 238 miso,
239 nss,
158 tx_dma, 240 tx_dma,
159 rx_dma, 241 rx_dma,
160 current_word_size: <u8 as SealedWord>::CONFIG, 242 current_word_size: <u8 as SealedWord>::CONFIG,
@@ -171,24 +253,46 @@ impl<'d, M: PeriMode> Spi<'d, M> {
171 let cpol = config.raw_polarity(); 253 let cpol = config.raw_polarity();
172 let lsbfirst = config.raw_byte_order(); 254 let lsbfirst = config.raw_byte_order();
173 255
174 self.info.rcc.enable_and_reset(); 256 self.info.rcc.enable_and_reset_without_stop();
257
258 /*
259 - Software NSS management (SSM = 1)
260 The slave select information is driven internally by the value of the SSI bit in the
261 SPI_CR1 register. The external NSS pin remains free for other application uses.
262
263 - Hardware NSS management (SSM = 0)
264 Two configurations are possible depending on the NSS output configuration (SSOE bit
265 in register SPI_CR1).
266
267 -- NSS output enabled (SSM = 0, SSOE = 1)
268 This configuration is used only when the device operates in master mode. The
269 NSS signal is driven low when the master starts the communication and is kept
270 low until the SPI is disabled.
271
272 -- NSS output disabled (SSM = 0, SSOE = 0)
273 This configuration allows multimaster capability for devices operating in master
274 mode. For devices set as slave, the NSS pin acts as a classical NSS input: the
275 slave is selected when NSS is low and deselected when NSS high
276 */
277 let ssm = self.nss.is_none();
175 278
176 let regs = self.info.regs; 279 let regs = self.info.regs;
177 #[cfg(any(spi_v1, spi_v2))] 280 #[cfg(any(spi_v1, spi_v2))]
178 { 281 {
282 let ssoe = CM::MASTER == vals::Mstr::MASTER && !config.nss_output_disable;
179 regs.cr2().modify(|w| { 283 regs.cr2().modify(|w| {
180 w.set_ssoe(false); 284 w.set_ssoe(ssoe);
181 }); 285 });
182 regs.cr1().modify(|w| { 286 regs.cr1().modify(|w| {
183 w.set_cpha(cpha); 287 w.set_cpha(cpha);
184 w.set_cpol(cpol); 288 w.set_cpol(cpol);
185 289
186 w.set_mstr(vals::Mstr::MASTER); 290 w.set_mstr(CM::MASTER);
187 w.set_br(br); 291 w.set_br(br);
188 w.set_spe(true); 292 w.set_spe(true);
189 w.set_lsbfirst(lsbfirst); 293 w.set_lsbfirst(lsbfirst);
190 w.set_ssi(true); 294 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
191 w.set_ssm(true); 295 w.set_ssm(ssm);
192 w.set_crcen(false); 296 w.set_crcen(false);
193 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 297 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
194 // we're doing "fake rxonly", by actually writing one 298 // we're doing "fake rxonly", by actually writing one
@@ -200,21 +304,22 @@ impl<'d, M: PeriMode> Spi<'d, M> {
200 } 304 }
201 #[cfg(spi_v3)] 305 #[cfg(spi_v3)]
202 { 306 {
307 let ssoe = CM::MASTER == vals::Mstr::MASTER && !config.nss_output_disable;
203 regs.cr2().modify(|w| { 308 regs.cr2().modify(|w| {
204 let (ds, frxth) = <u8 as SealedWord>::CONFIG; 309 let (ds, frxth) = <u8 as SealedWord>::CONFIG;
205 w.set_frxth(frxth); 310 w.set_frxth(frxth);
206 w.set_ds(ds); 311 w.set_ds(ds);
207 w.set_ssoe(false); 312 w.set_ssoe(ssoe);
208 }); 313 });
209 regs.cr1().modify(|w| { 314 regs.cr1().modify(|w| {
210 w.set_cpha(cpha); 315 w.set_cpha(cpha);
211 w.set_cpol(cpol); 316 w.set_cpol(cpol);
212 317
213 w.set_mstr(vals::Mstr::MASTER); 318 w.set_mstr(CM::MASTER);
214 w.set_br(br); 319 w.set_br(br);
215 w.set_lsbfirst(lsbfirst); 320 w.set_lsbfirst(lsbfirst);
216 w.set_ssi(true); 321 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
217 w.set_ssm(true); 322 w.set_ssm(ssm);
218 w.set_crcen(false); 323 w.set_crcen(false);
219 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 324 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
220 w.set_spe(true); 325 w.set_spe(true);
@@ -222,21 +327,22 @@ impl<'d, M: PeriMode> Spi<'d, M> {
222 } 327 }
223 #[cfg(any(spi_v4, spi_v5, spi_v6))] 328 #[cfg(any(spi_v4, spi_v5, spi_v6))]
224 { 329 {
330 let ssoe = CM::MASTER == vals::Master::MASTER && !config.nss_output_disable;
331 let ssiop = config.raw_nss_polarity();
225 regs.ifcr().write(|w| w.0 = 0xffff_ffff); 332 regs.ifcr().write(|w| w.0 = 0xffff_ffff);
226 regs.cfg2().modify(|w| { 333 regs.cfg2().modify(|w| {
227 //w.set_ssoe(true); 334 w.set_ssoe(ssoe);
228 w.set_ssoe(false);
229 w.set_cpha(cpha); 335 w.set_cpha(cpha);
230 w.set_cpol(cpol); 336 w.set_cpol(cpol);
231 w.set_lsbfirst(lsbfirst); 337 w.set_lsbfirst(lsbfirst);
232 w.set_ssm(true); 338 w.set_ssm(ssm);
233 w.set_master(vals::Master::MASTER); 339 w.set_master(CM::MASTER);
234 w.set_comm(vals::Comm::FULL_DUPLEX); 340 w.set_comm(vals::Comm::FULL_DUPLEX);
235 w.set_ssom(vals::Ssom::ASSERTED); 341 w.set_ssom(vals::Ssom::ASSERTED);
236 w.set_midi(0); 342 w.set_midi(0);
237 w.set_mssi(0); 343 w.set_mssi(0);
238 w.set_afcntr(true); 344 w.set_afcntr(true);
239 w.set_ssiop(vals::Ssiop::ACTIVE_HIGH); 345 w.set_ssiop(ssiop);
240 }); 346 });
241 regs.cfg1().modify(|w| { 347 regs.cfg1().modify(|w| {
242 w.set_crcen(false); 348 w.set_crcen(false);
@@ -284,6 +390,8 @@ impl<'d, M: PeriMode> Spi<'d, M> {
284 390
285 #[cfg(any(spi_v4, spi_v5, spi_v6))] 391 #[cfg(any(spi_v4, spi_v5, spi_v6))]
286 { 392 {
393 let ssiop = config.raw_nss_polarity();
394
287 self.info.regs.cr1().modify(|w| { 395 self.info.regs.cr1().modify(|w| {
288 w.set_spe(false); 396 w.set_spe(false);
289 }); 397 });
@@ -292,6 +400,7 @@ impl<'d, M: PeriMode> Spi<'d, M> {
292 w.set_cpha(cpha); 400 w.set_cpha(cpha);
293 w.set_cpol(cpol); 401 w.set_cpol(cpol);
294 w.set_lsbfirst(lsbfirst); 402 w.set_lsbfirst(lsbfirst);
403 w.set_ssiop(ssiop);
295 }); 404 });
296 self.info.regs.cfg1().modify(|w| { 405 self.info.regs.cfg1().modify(|w| {
297 w.set_mbr(br); 406 w.set_mbr(br);
@@ -304,6 +413,20 @@ impl<'d, M: PeriMode> Spi<'d, M> {
304 Ok(()) 413 Ok(())
305 } 414 }
306 415
416 /// Set SPI direction
417 #[cfg(any(spi_v1, spi_v2, spi_v3))]
418 pub fn set_direction(&mut self, dir: Option<Direction>) {
419 let (bidimode, bidioe) = match dir {
420 Some(Direction::Transmit) => (vals::Bidimode::BIDIRECTIONAL, vals::Bidioe::TRANSMIT),
421 Some(Direction::Receive) => (vals::Bidimode::BIDIRECTIONAL, vals::Bidioe::RECEIVE),
422 None => (vals::Bidimode::UNIDIRECTIONAL, vals::Bidioe::TRANSMIT),
423 };
424 self.info.regs.cr1().modify(|w| {
425 w.set_bidimode(bidimode);
426 w.set_bidioe(bidioe);
427 });
428 }
429
307 /// Get current SPI configuration. 430 /// Get current SPI configuration.
308 pub fn get_current_config(&self) -> Config { 431 pub fn get_current_config(&self) -> Config {
309 #[cfg(any(spi_v1, spi_v2, spi_v3))] 432 #[cfg(any(spi_v1, spi_v2, spi_v3))]
@@ -313,6 +436,11 @@ impl<'d, M: PeriMode> Spi<'d, M> {
313 #[cfg(any(spi_v4, spi_v5, spi_v6))] 436 #[cfg(any(spi_v4, spi_v5, spi_v6))]
314 let cfg1 = self.info.regs.cfg1().read(); 437 let cfg1 = self.info.regs.cfg1().read();
315 438
439 #[cfg(any(spi_v1, spi_v2, spi_v3))]
440 let ssoe = self.info.regs.cr2().read().ssoe();
441 #[cfg(any(spi_v4, spi_v5, spi_v6))]
442 let ssoe = cfg.ssoe();
443
316 let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW { 444 let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW {
317 Polarity::IdleLow 445 Polarity::IdleLow
318 } else { 446 } else {
@@ -342,12 +470,25 @@ impl<'d, M: PeriMode> Spi<'d, M> {
342 470
343 let frequency = compute_frequency(self.kernel_clock, br); 471 let frequency = compute_frequency(self.kernel_clock, br);
344 472
473 // NSS output disabled if SSOE=0 or if SSM=1 software slave management enabled
474 let nss_output_disable = !ssoe || cfg.ssm();
475
476 #[cfg(any(spi_v4, spi_v5, spi_v6))]
477 let nss_polarity = if cfg.ssiop() == vals::Ssiop::ACTIVE_LOW {
478 SlaveSelectPolarity::ActiveLow
479 } else {
480 SlaveSelectPolarity::ActiveHigh
481 };
482
345 Config { 483 Config {
346 mode: Mode { polarity, phase }, 484 mode: Mode { polarity, phase },
347 bit_order, 485 bit_order,
348 frequency, 486 frequency,
349 miso_pull, 487 miso_pull,
350 gpio_speed: self.gpio_speed, 488 gpio_speed: self.gpio_speed,
489 nss_output_disable,
490 #[cfg(any(spi_v4, spi_v5, spi_v6))]
491 nss_polarity,
351 } 492 }
352 } 493 }
353 494
@@ -469,7 +610,30 @@ impl<'d, M: PeriMode> Spi<'d, M> {
469 } 610 }
470} 611}
471 612
472impl<'d> Spi<'d, Blocking> { 613impl<'d> Spi<'d, Blocking, Slave> {
614 /// Create a new blocking SPI slave driver.
615 pub fn new_blocking_slave<T: Instance, #[cfg(afio)] A>(
616 peri: Peri<'d, T>,
617 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
618 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
619 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
620 cs: Peri<'d, if_afio!(impl CsPin<T, A>)>,
621 config: Config,
622 ) -> Self {
623 Self::new_inner(
624 peri,
625 new_pin!(sck, config.sck_af()),
626 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
627 new_pin!(miso, AfType::input(config.miso_pull)),
628 new_pin!(cs, AfType::input(Pull::None)),
629 None,
630 None,
631 config,
632 )
633 }
634}
635
636impl<'d> Spi<'d, Blocking, Master> {
473 /// Create a new blocking SPI driver. 637 /// Create a new blocking SPI driver.
474 pub fn new_blocking<T: Instance, #[cfg(afio)] A>( 638 pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
475 peri: Peri<'d, T>, 639 peri: Peri<'d, T>,
@@ -485,6 +649,7 @@ impl<'d> Spi<'d, Blocking> {
485 new_pin!(miso, AfType::input(config.miso_pull)), 649 new_pin!(miso, AfType::input(config.miso_pull)),
486 None, 650 None,
487 None, 651 None,
652 None,
488 config, 653 config,
489 ) 654 )
490 } 655 }
@@ -503,6 +668,7 @@ impl<'d> Spi<'d, Blocking> {
503 new_pin!(miso, AfType::input(config.miso_pull)), 668 new_pin!(miso, AfType::input(config.miso_pull)),
504 None, 669 None,
505 None, 670 None,
671 None,
506 config, 672 config,
507 ) 673 )
508 } 674 }
@@ -521,6 +687,7 @@ impl<'d> Spi<'d, Blocking> {
521 None, 687 None,
522 None, 688 None,
523 None, 689 None,
690 None,
524 config, 691 config,
525 ) 692 )
526 } 693 }
@@ -540,12 +707,38 @@ impl<'d> Spi<'d, Blocking> {
540 None, 707 None,
541 None, 708 None,
542 None, 709 None,
710 None,
543 config, 711 config,
544 ) 712 )
545 } 713 }
546} 714}
547 715
548impl<'d> Spi<'d, Async> { 716impl<'d> Spi<'d, Async, Slave> {
717 /// Create a new SPI slave driver.
718 pub fn new_slave<T: Instance, #[cfg(afio)] A>(
719 peri: Peri<'d, T>,
720 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
721 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
722 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
723 cs: Peri<'d, if_afio!(impl CsPin<T, A>)>,
724 tx_dma: Peri<'d, impl TxDma<T>>,
725 rx_dma: Peri<'d, impl RxDma<T>>,
726 config: Config,
727 ) -> Self {
728 Self::new_inner(
729 peri,
730 new_pin!(sck, config.sck_af()),
731 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
732 new_pin!(miso, AfType::input(config.miso_pull)),
733 new_pin!(cs, AfType::input(Pull::None)),
734 new_dma!(tx_dma),
735 new_dma!(rx_dma),
736 config,
737 )
738 }
739}
740
741impl<'d> Spi<'d, Async, Master> {
549 /// Create a new SPI driver. 742 /// Create a new SPI driver.
550 pub fn new<T: Instance, #[cfg(afio)] A>( 743 pub fn new<T: Instance, #[cfg(afio)] A>(
551 peri: Peri<'d, T>, 744 peri: Peri<'d, T>,
@@ -561,6 +754,7 @@ impl<'d> Spi<'d, Async> {
561 new_pin!(sck, config.sck_af()), 754 new_pin!(sck, config.sck_af()),
562 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 755 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
563 new_pin!(miso, AfType::input(config.miso_pull)), 756 new_pin!(miso, AfType::input(config.miso_pull)),
757 None,
564 new_dma!(tx_dma), 758 new_dma!(tx_dma),
565 new_dma!(rx_dma), 759 new_dma!(rx_dma),
566 config, 760 config,
@@ -581,6 +775,7 @@ impl<'d> Spi<'d, Async> {
581 new_pin!(sck, config.sck_af()), 775 new_pin!(sck, config.sck_af()),
582 None, 776 None,
583 new_pin!(miso, AfType::input(config.miso_pull)), 777 new_pin!(miso, AfType::input(config.miso_pull)),
778 None,
584 #[cfg(any(spi_v1, spi_v2, spi_v3))] 779 #[cfg(any(spi_v1, spi_v2, spi_v3))]
585 new_dma!(tx_dma), 780 new_dma!(tx_dma),
586 #[cfg(any(spi_v4, spi_v5, spi_v6))] 781 #[cfg(any(spi_v4, spi_v5, spi_v6))]
@@ -603,12 +798,37 @@ impl<'d> Spi<'d, Async> {
603 new_pin!(sck, config.sck_af()), 798 new_pin!(sck, config.sck_af()),
604 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 799 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
605 None, 800 None,
801 None,
606 new_dma!(tx_dma), 802 new_dma!(tx_dma),
607 None, 803 None,
608 config, 804 config,
609 ) 805 )
610 } 806 }
611 807
808 /// Create a new SPI driver, in bidirectional mode, specifically in tranmit mode
809 #[cfg(any(spi_v1, spi_v2, spi_v3))]
810 pub fn new_bidi<T: Instance, #[cfg(afio)] A>(
811 peri: Peri<'d, T>,
812 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
813 sdio: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
814 tx_dma: Peri<'d, impl TxDma<T>>,
815 rx_dma: Peri<'d, impl RxDma<T>>,
816 config: Config,
817 ) -> Self {
818 let mut this = Self::new_inner(
819 peri,
820 new_pin!(sck, config.sck_af()),
821 new_pin!(sdio, AfType::output(OutputType::PushPull, config.gpio_speed)),
822 None,
823 None,
824 new_dma!(tx_dma),
825 new_dma!(rx_dma),
826 config,
827 );
828 this.set_direction(Some(Direction::Transmit));
829 this
830 }
831
612 /// Create a new SPI driver, in TX-only mode, without SCK pin. 832 /// Create a new SPI driver, in TX-only mode, without SCK pin.
613 /// 833 ///
614 /// This can be useful for bit-banging non-SPI protocols. 834 /// This can be useful for bit-banging non-SPI protocols.
@@ -623,6 +843,7 @@ impl<'d> Spi<'d, Async> {
623 None, 843 None,
624 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 844 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
625 None, 845 None,
846 None,
626 new_dma!(tx_dma), 847 new_dma!(tx_dma),
627 None, 848 None,
628 config, 849 config,
@@ -646,7 +867,7 @@ impl<'d> Spi<'d, Async> {
646 config.bit_order = BitOrder::MsbFirst; 867 config.bit_order = BitOrder::MsbFirst;
647 config.frequency = freq; 868 config.frequency = freq;
648 869
649 Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config) 870 Self::new_inner(peri, None, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
650 } 871 }
651 872
652 #[allow(dead_code)] 873 #[allow(dead_code)]
@@ -656,11 +877,14 @@ impl<'d> Spi<'d, Async> {
656 rx_dma: Option<ChannelAndRequest<'d>>, 877 rx_dma: Option<ChannelAndRequest<'d>>,
657 config: Config, 878 config: Config,
658 ) -> Self { 879 ) -> Self {
659 Self::new_inner(peri, None, None, None, tx_dma, rx_dma, config) 880 Self::new_inner(peri, None, None, None, None, tx_dma, rx_dma, config)
660 } 881 }
882}
661 883
884impl<'d, CM: CommunicationMode> Spi<'d, Async, CM> {
662 /// SPI write, using DMA. 885 /// SPI write, using DMA.
663 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> { 886 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
887 let _scoped_block_stop = self.info.rcc.block_stop();
664 if data.is_empty() { 888 if data.is_empty() {
665 return Ok(()); 889 return Ok(());
666 } 890 }
@@ -692,6 +916,7 @@ impl<'d> Spi<'d, Async> {
692 /// SPI read, using DMA. 916 /// SPI read, using DMA.
693 #[cfg(any(spi_v4, spi_v5, spi_v6))] 917 #[cfg(any(spi_v4, spi_v5, spi_v6))]
694 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { 918 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
919 let _scoped_block_stop = self.info.rcc.block_stop();
695 if data.is_empty() { 920 if data.is_empty() {
696 return Ok(()); 921 return Ok(());
697 } 922 }
@@ -779,6 +1004,7 @@ impl<'d> Spi<'d, Async> {
779 /// SPI read, using DMA. 1004 /// SPI read, using DMA.
780 #[cfg(any(spi_v1, spi_v2, spi_v3))] 1005 #[cfg(any(spi_v1, spi_v2, spi_v3))]
781 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { 1006 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
1007 let _scoped_block_stop = self.info.rcc.block_stop();
782 if data.is_empty() { 1008 if data.is_empty() {
783 return Ok(()); 1009 return Ok(());
784 } 1010 }
@@ -826,6 +1052,7 @@ impl<'d> Spi<'d, Async> {
826 } 1052 }
827 1053
828 async fn transfer_inner<W: Word>(&mut self, read: *mut [W], write: *const [W]) -> Result<(), Error> { 1054 async fn transfer_inner<W: Word>(&mut self, read: *mut [W], write: *const [W]) -> Result<(), Error> {
1055 let _scoped_block_stop = self.info.rcc.block_stop();
829 assert_eq!(read.len(), write.len()); 1056 assert_eq!(read.len(), write.len());
830 if read.len() == 0 { 1057 if read.len() == 0 {
831 return Ok(()); 1058 return Ok(());
@@ -877,6 +1104,8 @@ impl<'d> Spi<'d, Async> {
877 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. 1104 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
878 /// If `write` is shorter it is padded with zero bytes. 1105 /// If `write` is shorter it is padded with zero bytes.
879 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { 1106 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
1107 let _scoped_block_stop = self.info.rcc.block_stop();
1108
880 self.transfer_inner(read, write).await 1109 self.transfer_inner(read, write).await
881 } 1110 }
882 1111
@@ -884,17 +1113,20 @@ impl<'d> Spi<'d, Async> {
884 /// 1113 ///
885 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. 1114 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
886 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { 1115 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
1116 let _scoped_block_stop = self.info.rcc.block_stop();
1117
887 self.transfer_inner(data, data).await 1118 self.transfer_inner(data, data).await
888 } 1119 }
889} 1120}
890 1121
891impl<'d, M: PeriMode> Drop for Spi<'d, M> { 1122impl<'d, M: PeriMode, CM: CommunicationMode> Drop for Spi<'d, M, CM> {
892 fn drop(&mut self) { 1123 fn drop(&mut self) {
893 self.sck.as_ref().map(|x| x.set_as_disconnected()); 1124 self.sck.as_ref().map(|x| x.set_as_disconnected());
894 self.mosi.as_ref().map(|x| x.set_as_disconnected()); 1125 self.mosi.as_ref().map(|x| x.set_as_disconnected());
895 self.miso.as_ref().map(|x| x.set_as_disconnected()); 1126 self.miso.as_ref().map(|x| x.set_as_disconnected());
1127 self.nss.as_ref().map(|x| x.set_as_disconnected());
896 1128
897 self.info.rcc.disable(); 1129 self.info.rcc.disable_without_stop();
898 } 1130 }
899} 1131}
900 1132
@@ -1127,7 +1359,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 1359// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
1128macro_rules! impl_blocking { 1360macro_rules! impl_blocking {
1129 ($w:ident) => { 1361 ($w:ident) => {
1130 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M> { 1362 impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M, CM> {
1131 type Error = Error; 1363 type Error = Error;
1132 1364
1133 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> { 1365 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
@@ -1135,7 +1367,7 @@ macro_rules! impl_blocking {
1135 } 1367 }
1136 } 1368 }
1137 1369
1138 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M> { 1370 impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M, CM> {
1139 type Error = Error; 1371 type Error = Error;
1140 1372
1141 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> { 1373 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
@@ -1149,11 +1381,11 @@ macro_rules! impl_blocking {
1149impl_blocking!(u8); 1381impl_blocking!(u8);
1150impl_blocking!(u16); 1382impl_blocking!(u16);
1151 1383
1152impl<'d, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, M> { 1384impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_1::spi::ErrorType for Spi<'d, M, CM> {
1153 type Error = Error; 1385 type Error = Error;
1154} 1386}
1155 1387
1156impl<'d, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, M> { 1388impl<'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> { 1389 fn flush(&mut self) -> Result<(), Self::Error> {
1158 Ok(()) 1390 Ok(())
1159 } 1391 }
@@ -1186,7 +1418,7 @@ impl embedded_hal_1::spi::Error for Error {
1186 } 1418 }
1187} 1419}
1188 1420
1189impl<'d, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async> { 1421impl<'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> { 1422 async fn flush(&mut self) -> Result<(), Self::Error> {
1191 Ok(()) 1423 Ok(())
1192 } 1424 }
@@ -1328,7 +1560,7 @@ foreach_peripheral!(
1328 }; 1560 };
1329); 1561);
1330 1562
1331impl<'d, M: PeriMode> SetConfig for Spi<'d, M> { 1563impl<'d, M: PeriMode, CM: CommunicationMode> SetConfig for Spi<'d, M, CM> {
1332 type Config = Config; 1564 type Config = Config;
1333 type ConfigError = (); 1565 type ConfigError = ();
1334 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 1566 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {