diff options
| author | Lutsai Aleksandr <[email protected]> | 2025-12-02 02:31:13 +0300 |
|---|---|---|
| committer | Lutsai Aleksandr <[email protected]> | 2025-12-02 02:31:13 +0300 |
| commit | 678ecd58c90d256e80cc88e7d3ab5af3d9c921e3 (patch) | |
| tree | 01a0bd6a09175f3ef707deb8ae83ba01f6c2861c /embassy-stm32 | |
| parent | ec417c70565aac291403fb5f8e2a93c773fb25e7 (diff) | |
fix: SSM and SSOE in SPI STM32 driver behavior, add nss_output_disable in 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 70c46b025..3ad25ad33 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 abb80ed26..c6cede85f 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs | |||
| @@ -72,6 +72,10 @@ pub struct Config { | |||
| 72 | /// signal rise/fall speed (slew rate) - defaults to `Medium`. | 72 | /// signal rise/fall speed (slew rate) - defaults to `Medium`. |
| 73 | /// Increase for high SPI speeds. Change to `Low` to reduce ringing. | 73 | /// Increase for high SPI speeds. Change to `Low` to reduce ringing. |
| 74 | pub gpio_speed: Speed, | 74 | pub gpio_speed: Speed, |
| 75 | /// If True sets SSOE to zero even if SPI is in Master Mode. | ||
| 76 | /// 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. | ||
| 77 | /// 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. | ||
| 78 | pub nss_output_disable: bool, | ||
| 75 | } | 79 | } |
| 76 | 80 | ||
| 77 | impl Default for Config { | 81 | impl Default for Config { |
| @@ -82,6 +86,7 @@ impl Default for Config { | |||
| 82 | frequency: Hertz(1_000_000), | 86 | frequency: Hertz(1_000_000), |
| 83 | miso_pull: Pull::None, | 87 | miso_pull: Pull::None, |
| 84 | gpio_speed: Speed::VeryHigh, | 88 | gpio_speed: Speed::VeryHigh, |
| 89 | nss_output_disable: false, | ||
| 85 | } | 90 | } |
| 86 | } | 91 | } |
| 87 | } | 92 | } |
| @@ -217,11 +222,33 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> { | |||
| 217 | 222 | ||
| 218 | self.info.rcc.enable_and_reset(); | 223 | self.info.rcc.enable_and_reset(); |
| 219 | 224 | ||
| 225 | /* | ||
| 226 | - Software NSS management (SSM = 1) | ||
| 227 | The slave select information is driven internally by the value of the SSI bit in the | ||
| 228 | SPI_CR1 register. The external NSS pin remains free for other application uses. | ||
| 229 | |||
| 230 | - Hardware NSS management (SSM = 0) | ||
| 231 | Two configurations are possible depending on the NSS output configuration (SSOE bit | ||
| 232 | in register SPI_CR1). | ||
| 233 | |||
| 234 | -- NSS output enabled (SSM = 0, SSOE = 1) | ||
| 235 | This configuration is used only when the device operates in master mode. The | ||
| 236 | NSS signal is driven low when the master starts the communication and is kept | ||
| 237 | low until the SPI is disabled. | ||
| 238 | |||
| 239 | -- NSS output disabled (SSM = 0, SSOE = 0) | ||
| 240 | This configuration allows multimaster capability for devices operating in master | ||
| 241 | mode. For devices set as slave, the NSS pin acts as a classical NSS input: the | ||
| 242 | slave is selected when NSS is low and deselected when NSS high | ||
| 243 | */ | ||
| 244 | let ssm = self.nss.is_none(); | ||
| 245 | |||
| 220 | let regs = self.info.regs; | 246 | let regs = self.info.regs; |
| 221 | #[cfg(any(spi_v1, spi_v2))] | 247 | #[cfg(any(spi_v1, spi_v2))] |
| 222 | { | 248 | { |
| 249 | let ssoe = CM::MASTER == vals::Mstr::MASTER && !config.nss_output_disable; | ||
| 223 | regs.cr2().modify(|w| { | 250 | regs.cr2().modify(|w| { |
| 224 | w.set_ssoe(false); | 251 | w.set_ssoe(ssoe); |
| 225 | }); | 252 | }); |
| 226 | regs.cr1().modify(|w| { | 253 | regs.cr1().modify(|w| { |
| 227 | w.set_cpha(cpha); | 254 | w.set_cpha(cpha); |
| @@ -232,7 +259,7 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> { | |||
| 232 | w.set_spe(true); | 259 | w.set_spe(true); |
| 233 | w.set_lsbfirst(lsbfirst); | 260 | w.set_lsbfirst(lsbfirst); |
| 234 | w.set_ssi(CM::MASTER == vals::Mstr::MASTER); | 261 | w.set_ssi(CM::MASTER == vals::Mstr::MASTER); |
| 235 | w.set_ssm(CM::MASTER == vals::Mstr::MASTER); | 262 | w.set_ssm(ssm); |
| 236 | w.set_crcen(false); | 263 | w.set_crcen(false); |
| 237 | w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); | 264 | w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); |
| 238 | // we're doing "fake rxonly", by actually writing one | 265 | // we're doing "fake rxonly", by actually writing one |
| @@ -244,11 +271,12 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> { | |||
| 244 | } | 271 | } |
| 245 | #[cfg(spi_v3)] | 272 | #[cfg(spi_v3)] |
| 246 | { | 273 | { |
| 274 | let ssoe = CM::MASTER == vals::Mstr::MASTER && !config.nss_output_disable; | ||
| 247 | regs.cr2().modify(|w| { | 275 | regs.cr2().modify(|w| { |
| 248 | let (ds, frxth) = <u8 as SealedWord>::CONFIG; | 276 | let (ds, frxth) = <u8 as SealedWord>::CONFIG; |
| 249 | w.set_frxth(frxth); | 277 | w.set_frxth(frxth); |
| 250 | w.set_ds(ds); | 278 | w.set_ds(ds); |
| 251 | w.set_ssoe(false); | 279 | w.set_ssoe(ssoe); |
| 252 | }); | 280 | }); |
| 253 | regs.cr1().modify(|w| { | 281 | regs.cr1().modify(|w| { |
| 254 | w.set_cpha(cpha); | 282 | w.set_cpha(cpha); |
| @@ -258,7 +286,7 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> { | |||
| 258 | w.set_br(br); | 286 | w.set_br(br); |
| 259 | w.set_lsbfirst(lsbfirst); | 287 | w.set_lsbfirst(lsbfirst); |
| 260 | w.set_ssi(CM::MASTER == vals::Mstr::MASTER); | 288 | w.set_ssi(CM::MASTER == vals::Mstr::MASTER); |
| 261 | w.set_ssm(CM::MASTER == vals::Mstr::MASTER); | 289 | w.set_ssm(ssm); |
| 262 | w.set_crcen(false); | 290 | w.set_crcen(false); |
| 263 | w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); | 291 | w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); |
| 264 | w.set_spe(true); | 292 | w.set_spe(true); |
| @@ -266,14 +294,14 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> { | |||
| 266 | } | 294 | } |
| 267 | #[cfg(any(spi_v4, spi_v5, spi_v6))] | 295 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 268 | { | 296 | { |
| 297 | let ssoe = CM::MASTER == vals::Master::MASTER && !config.nss_output_disable; | ||
| 269 | regs.ifcr().write(|w| w.0 = 0xffff_ffff); | 298 | regs.ifcr().write(|w| w.0 = 0xffff_ffff); |
| 270 | regs.cfg2().modify(|w| { | 299 | regs.cfg2().modify(|w| { |
| 271 | //w.set_ssoe(true); | 300 | w.set_ssoe(ssoe); |
| 272 | w.set_ssoe(false); | ||
| 273 | w.set_cpha(cpha); | 301 | w.set_cpha(cpha); |
| 274 | w.set_cpol(cpol); | 302 | w.set_cpol(cpol); |
| 275 | w.set_lsbfirst(lsbfirst); | 303 | w.set_lsbfirst(lsbfirst); |
| 276 | w.set_ssm(CM::MASTER == vals::Master::MASTER); | 304 | w.set_ssm(ssm); |
| 277 | w.set_master(CM::MASTER); | 305 | w.set_master(CM::MASTER); |
| 278 | w.set_comm(vals::Comm::FULL_DUPLEX); | 306 | w.set_comm(vals::Comm::FULL_DUPLEX); |
| 279 | w.set_ssom(vals::Ssom::ASSERTED); | 307 | w.set_ssom(vals::Ssom::ASSERTED); |
| @@ -357,6 +385,11 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> { | |||
| 357 | #[cfg(any(spi_v4, spi_v5, spi_v6))] | 385 | #[cfg(any(spi_v4, spi_v5, spi_v6))] |
| 358 | let cfg1 = self.info.regs.cfg1().read(); | 386 | let cfg1 = self.info.regs.cfg1().read(); |
| 359 | 387 | ||
| 388 | #[cfg(any(spi_v1, spi_v2, spi_v3))] | ||
| 389 | let ssoe = self.info.regs.cr2().read().ssoe(); | ||
| 390 | #[cfg(any(spi_v4, spi_v5, spi_v6))] | ||
| 391 | let ssoe = cfg.ssoe(); | ||
| 392 | |||
| 360 | let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW { | 393 | let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW { |
| 361 | Polarity::IdleLow | 394 | Polarity::IdleLow |
| 362 | } else { | 395 | } else { |
| @@ -386,12 +419,16 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> { | |||
| 386 | 419 | ||
| 387 | let frequency = compute_frequency(self.kernel_clock, br); | 420 | let frequency = compute_frequency(self.kernel_clock, br); |
| 388 | 421 | ||
| 422 | // NSS output disabled if SSOE=0 or if SSM=1 software slave management enabled | ||
| 423 | let nss_output_disable = !ssoe || cfg.ssm(); | ||
| 424 | |||
| 389 | Config { | 425 | Config { |
| 390 | mode: Mode { polarity, phase }, | 426 | mode: Mode { polarity, phase }, |
| 391 | bit_order, | 427 | bit_order, |
| 392 | frequency, | 428 | frequency, |
| 393 | miso_pull, | 429 | miso_pull, |
| 394 | gpio_speed: self.gpio_speed, | 430 | gpio_speed: self.gpio_speed, |
| 431 | nss_output_disable, | ||
| 395 | } | 432 | } |
| 396 | } | 433 | } |
| 397 | 434 | ||
