diff options
| author | xoviat <[email protected]> | 2025-12-01 23:58:58 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-12-01 23:58:58 +0000 |
| commit | c46a6c2dcf86bd0840ce4ba6034011fdd9f669a8 (patch) | |
| tree | 3bb2eff99c18e4bdcd97e2b3de0394a4b5230011 /embassy-stm32 | |
| parent | ac57c9f667adff094627aac07164da2f220c12ed (diff) | |
| parent | 678ecd58c90d256e80cc88e7d3ab5af3d9c921e3 (diff) | |
Merge pull request #4971 from SL-RU/main
Fix SPI: SSM and SSOE in STM32 driver behavior, add nss_output_disable to SPI Config
Diffstat (limited to 'embassy-stm32')
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/mod.rs | 51 |
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 | ||
| 87 | impl Default for Config { | 91 | impl 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 | ||
