aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/src/spi/mod.rs51
2 files changed, 45 insertions, 7 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 851c22afd..2b9e0a89a 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased - ReleaseDate 8## Unreleased - ReleaseDate
9 9
10- fix: stm32: SPI driver SSOE and SSM manegment, add `nss_output_disable` to SPI Config
10- change: stm32: use typelevel timer type to allow dma for 32 bit timers 11- change: stm32: use typelevel timer type to allow dma for 32 bit timers
11- fix: fix incorrect handling of split interrupts in timer driver 12- fix: fix incorrect handling of split interrupts in timer driver
12- feat: allow granular stop for regular usart 13- feat: allow granular stop for regular usart
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 0048d5d21..3b39fd2fb 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -82,6 +82,10 @@ pub struct Config {
82 /// signal rise/fall speed (slew rate) - defaults to `Medium`. 82 /// signal rise/fall speed (slew rate) - defaults to `Medium`.
83 /// Increase for high SPI speeds. Change to `Low` to reduce ringing. 83 /// Increase for high SPI speeds. Change to `Low` to reduce ringing.
84 pub gpio_speed: Speed, 84 pub gpio_speed: Speed,
85 /// If True sets SSOE to zero even if SPI is in Master Mode.
86 /// 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.
87 /// 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.
88 pub nss_output_disable: bool,
85} 89}
86 90
87impl Default for Config { 91impl Default for Config {
@@ -92,6 +96,7 @@ impl Default for Config {
92 frequency: Hertz(1_000_000), 96 frequency: Hertz(1_000_000),
93 miso_pull: Pull::None, 97 miso_pull: Pull::None,
94 gpio_speed: Speed::VeryHigh, 98 gpio_speed: Speed::VeryHigh,
99 nss_output_disable: false,
95 } 100 }
96 } 101 }
97} 102}
@@ -227,11 +232,33 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
227 232
228 self.info.rcc.enable_and_reset(); 233 self.info.rcc.enable_and_reset();
229 234
235 /*
236 - Software NSS management (SSM = 1)
237 The slave select information is driven internally by the value of the SSI bit in the
238 SPI_CR1 register. The external NSS pin remains free for other application uses.
239
240 - Hardware NSS management (SSM = 0)
241 Two configurations are possible depending on the NSS output configuration (SSOE bit
242 in register SPI_CR1).
243
244 -- NSS output enabled (SSM = 0, SSOE = 1)
245 This configuration is used only when the device operates in master mode. The
246 NSS signal is driven low when the master starts the communication and is kept
247 low until the SPI is disabled.
248
249 -- NSS output disabled (SSM = 0, SSOE = 0)
250 This configuration allows multimaster capability for devices operating in master
251 mode. For devices set as slave, the NSS pin acts as a classical NSS input: the
252 slave is selected when NSS is low and deselected when NSS high
253 */
254 let ssm = self.nss.is_none();
255
230 let regs = self.info.regs; 256 let regs = self.info.regs;
231 #[cfg(any(spi_v1, spi_v2))] 257 #[cfg(any(spi_v1, spi_v2))]
232 { 258 {
259 let ssoe = CM::MASTER == vals::Mstr::MASTER && !config.nss_output_disable;
233 regs.cr2().modify(|w| { 260 regs.cr2().modify(|w| {
234 w.set_ssoe(false); 261 w.set_ssoe(ssoe);
235 }); 262 });
236 regs.cr1().modify(|w| { 263 regs.cr1().modify(|w| {
237 w.set_cpha(cpha); 264 w.set_cpha(cpha);
@@ -242,7 +269,7 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
242 w.set_spe(true); 269 w.set_spe(true);
243 w.set_lsbfirst(lsbfirst); 270 w.set_lsbfirst(lsbfirst);
244 w.set_ssi(CM::MASTER == vals::Mstr::MASTER); 271 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
245 w.set_ssm(CM::MASTER == vals::Mstr::MASTER); 272 w.set_ssm(ssm);
246 w.set_crcen(false); 273 w.set_crcen(false);
247 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 274 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
248 // we're doing "fake rxonly", by actually writing one 275 // we're doing "fake rxonly", by actually writing one
@@ -254,11 +281,12 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
254 } 281 }
255 #[cfg(spi_v3)] 282 #[cfg(spi_v3)]
256 { 283 {
284 let ssoe = CM::MASTER == vals::Mstr::MASTER && !config.nss_output_disable;
257 regs.cr2().modify(|w| { 285 regs.cr2().modify(|w| {
258 let (ds, frxth) = <u8 as SealedWord>::CONFIG; 286 let (ds, frxth) = <u8 as SealedWord>::CONFIG;
259 w.set_frxth(frxth); 287 w.set_frxth(frxth);
260 w.set_ds(ds); 288 w.set_ds(ds);
261 w.set_ssoe(false); 289 w.set_ssoe(ssoe);
262 }); 290 });
263 regs.cr1().modify(|w| { 291 regs.cr1().modify(|w| {
264 w.set_cpha(cpha); 292 w.set_cpha(cpha);
@@ -268,7 +296,7 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
268 w.set_br(br); 296 w.set_br(br);
269 w.set_lsbfirst(lsbfirst); 297 w.set_lsbfirst(lsbfirst);
270 w.set_ssi(CM::MASTER == vals::Mstr::MASTER); 298 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
271 w.set_ssm(CM::MASTER == vals::Mstr::MASTER); 299 w.set_ssm(ssm);
272 w.set_crcen(false); 300 w.set_crcen(false);
273 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 301 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
274 w.set_spe(true); 302 w.set_spe(true);
@@ -276,14 +304,14 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
276 } 304 }
277 #[cfg(any(spi_v4, spi_v5, spi_v6))] 305 #[cfg(any(spi_v4, spi_v5, spi_v6))]
278 { 306 {
307 let ssoe = CM::MASTER == vals::Master::MASTER && !config.nss_output_disable;
279 regs.ifcr().write(|w| w.0 = 0xffff_ffff); 308 regs.ifcr().write(|w| w.0 = 0xffff_ffff);
280 regs.cfg2().modify(|w| { 309 regs.cfg2().modify(|w| {
281 //w.set_ssoe(true); 310 w.set_ssoe(ssoe);
282 w.set_ssoe(false);
283 w.set_cpha(cpha); 311 w.set_cpha(cpha);
284 w.set_cpol(cpol); 312 w.set_cpol(cpol);
285 w.set_lsbfirst(lsbfirst); 313 w.set_lsbfirst(lsbfirst);
286 w.set_ssm(CM::MASTER == vals::Master::MASTER); 314 w.set_ssm(ssm);
287 w.set_master(CM::MASTER); 315 w.set_master(CM::MASTER);
288 w.set_comm(vals::Comm::FULL_DUPLEX); 316 w.set_comm(vals::Comm::FULL_DUPLEX);
289 w.set_ssom(vals::Ssom::ASSERTED); 317 w.set_ssom(vals::Ssom::ASSERTED);
@@ -381,6 +409,11 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
381 #[cfg(any(spi_v4, spi_v5, spi_v6))] 409 #[cfg(any(spi_v4, spi_v5, spi_v6))]
382 let cfg1 = self.info.regs.cfg1().read(); 410 let cfg1 = self.info.regs.cfg1().read();
383 411
412 #[cfg(any(spi_v1, spi_v2, spi_v3))]
413 let ssoe = self.info.regs.cr2().read().ssoe();
414 #[cfg(any(spi_v4, spi_v5, spi_v6))]
415 let ssoe = cfg.ssoe();
416
384 let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW { 417 let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW {
385 Polarity::IdleLow 418 Polarity::IdleLow
386 } else { 419 } else {
@@ -410,12 +443,16 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
410 443
411 let frequency = compute_frequency(self.kernel_clock, br); 444 let frequency = compute_frequency(self.kernel_clock, br);
412 445
446 // NSS output disabled if SSOE=0 or if SSM=1 software slave management enabled
447 let nss_output_disable = !ssoe || cfg.ssm();
448
413 Config { 449 Config {
414 mode: Mode { polarity, phase }, 450 mode: Mode { polarity, phase },
415 bit_order, 451 bit_order,
416 frequency, 452 frequency,
417 miso_pull, 453 miso_pull,
418 gpio_speed: self.gpio_speed, 454 gpio_speed: self.gpio_speed,
455 nss_output_disable,
419 } 456 }
420 } 457 }
421 458