aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src
diff options
context:
space:
mode:
authorLutsai Aleksandr <[email protected]>2025-12-02 02:31:13 +0300
committerLutsai Aleksandr <[email protected]>2025-12-02 02:31:13 +0300
commit678ecd58c90d256e80cc88e7d3ab5af3d9c921e3 (patch)
tree01a0bd6a09175f3ef707deb8ae83ba01f6c2861c /embassy-stm32/src
parentec417c70565aac291403fb5f8e2a93c773fb25e7 (diff)
fix: SSM and SSOE in SPI STM32 driver behavior, add nss_output_disable in SPI Config
Diffstat (limited to 'embassy-stm32/src')
-rw-r--r--embassy-stm32/src/spi/mod.rs51
1 files changed, 44 insertions, 7 deletions
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
77impl Default for Config { 81impl 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