aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32
diff options
context:
space:
mode:
authorPer Rosengren <[email protected]>2025-09-16 19:17:13 +0200
committerPer Rosengren <[email protected]>2025-09-16 19:17:13 +0200
commit42c21a24e590adbfc577ed8afea06abe3fc7b9e9 (patch)
treedc23754b42d532fcb04e7d1877e9bdd87ce5fde7 /embassy-stm32
parent4e1e4249556e20907839f09a65ae9283a8490cac (diff)
parent017064138003fa38b52f11dba872a43d4fec8b61 (diff)
Merge remote-tracking branch 'upstream/main' into adc_v3-enums
Diffstat (limited to 'embassy-stm32')
-rw-r--r--embassy-stm32/CHANGELOG.md6
-rw-r--r--embassy-stm32/src/adc/adc4.rs3
-rw-r--r--embassy-stm32/src/adc/c0.rs3
-rw-r--r--embassy-stm32/src/adc/v3.rs2
-rw-r--r--embassy-stm32/src/adc/v4.rs3
-rw-r--r--embassy-stm32/src/hspi/mod.rs19
-rw-r--r--embassy-stm32/src/ospi/enums.rs8
-rw-r--r--embassy-stm32/src/ospi/mod.rs81
-rw-r--r--embassy-stm32/src/qspi/enums.rs7
-rw-r--r--embassy-stm32/src/qspi/mod.rs54
-rw-r--r--embassy-stm32/src/usart/buffered.rs4
-rw-r--r--embassy-stm32/src/xspi/enums.rs8
-rw-r--r--embassy-stm32/src/xspi/mod.rs20
13 files changed, 143 insertions, 75 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index aa979e9b8..59328404f 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -16,6 +16,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
16- fix: STM32: Prevent dropped DacChannel from disabling Dac peripheral if another DacChannel is still in scope ([#4577](https://github.com/embassy-rs/embassy/pull/4577)) 16- fix: STM32: Prevent dropped DacChannel from disabling Dac peripheral if another DacChannel is still in scope ([#4577](https://github.com/embassy-rs/embassy/pull/4577))
17- feat: Added support for more OctoSPI configurations (e.g. APS6408 RAM) ([#4581](https://github.com/embassy-rs/embassy/pull/4581)) 17- feat: Added support for more OctoSPI configurations (e.g. APS6408 RAM) ([#4581](https://github.com/embassy-rs/embassy/pull/4581))
18- feat: More ADC enums for g0 PAC, API change for over sampling, allow separate sample times 18- feat: More ADC enums for g0 PAC, API change for over sampling, allow separate sample times
19- fix: stm32/usart: fix bug with blocking flush in buffered uart ([#4648](https://github.com/embassy-rs/embassy/pull/4648))
20- fix: stm32/(ospi/hspi/xspi): Fix the alternate bytes register config sticking around for subsequent writes
21- feat: Configurable gpio speed for QSPI
22- feat: derive Clone, Copy and defmt::Format for all *SPI-related configs
23- fix: handle address and data-length errors in OSPI
24- feat: Allow OSPI DMA writes larger than 64kB using chunking
19 25
20## 0.4.0 - 2025-08-26 26## 0.4.0 - 2025-08-26
21 27
diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs
index 31cbdc0d7..255dc7956 100644
--- a/embassy-stm32/src/adc/adc4.rs
+++ b/embassy-stm32/src/adc/adc4.rs
@@ -83,7 +83,8 @@ pub enum DacChannel {
83} 83}
84 84
85/// Number of samples used for averaging. 85/// Number of samples used for averaging.
86#[derive(Copy, Clone)] 86#[derive(Copy, Clone, Debug)]
87#[cfg_attr(feature = "defmt", derive(defmt::Format))]
87pub enum Averaging { 88pub enum Averaging {
88 Disabled, 89 Disabled,
89 Samples2, 90 Samples2,
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs
index f5870801e..f2837a8f1 100644
--- a/embassy-stm32/src/adc/c0.rs
+++ b/embassy-stm32/src/adc/c0.rs
@@ -138,7 +138,8 @@ impl<'a> defmt::Format for Prescaler {
138/// Number of samples used for averaging. 138/// Number of samples used for averaging.
139/// TODO: Implement hardware averaging setting. 139/// TODO: Implement hardware averaging setting.
140#[allow(unused)] 140#[allow(unused)]
141#[derive(Copy, Clone)] 141#[derive(Copy, Clone, Debug)]
142#[cfg_attr(feature = "defmt", derive(defmt::Format))]
142pub enum Averaging { 143pub enum Averaging {
143 Disabled, 144 Disabled,
144 Samples2, 145 Samples2,
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index d50fb9001..16063ce4d 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -107,6 +107,8 @@ cfg_if! {
107} 107}
108 108
109/// Number of samples used for averaging. 109/// Number of samples used for averaging.
110#[derive(Copy, Clone, Debug)]
111#[cfg_attr(feature = "defmt", derive(defmt::Format))]
110pub enum Averaging { 112pub enum Averaging {
111 Disabled, 113 Disabled,
112 Samples2, 114 Samples2,
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index b0871019a..b66437e6e 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -142,7 +142,8 @@ impl Prescaler {
142} 142}
143 143
144/// Number of samples used for averaging. 144/// Number of samples used for averaging.
145#[derive(Copy, Clone)] 145#[derive(Copy, Clone, Debug)]
146#[cfg_attr(feature = "defmt", derive(defmt::Format))]
146pub enum Averaging { 147pub enum Averaging {
147 Disabled, 148 Disabled,
148 Samples2, 149 Samples2,
diff --git a/embassy-stm32/src/hspi/mod.rs b/embassy-stm32/src/hspi/mod.rs
index 62bc0e979..95d9e5099 100644
--- a/embassy-stm32/src/hspi/mod.rs
+++ b/embassy-stm32/src/hspi/mod.rs
@@ -86,6 +86,8 @@ impl Default for Config {
86} 86}
87 87
88/// HSPI transfer configuration. 88/// HSPI transfer configuration.
89#[derive(Clone, Copy)]
90#[cfg_attr(feature = "defmt", derive(defmt::Format))]
89pub struct TransferConfig { 91pub struct TransferConfig {
90 /// Instruction width (IMODE) 92 /// Instruction width (IMODE)
91 pub iwidth: HspiWidth, 93 pub iwidth: HspiWidth,
@@ -116,7 +118,7 @@ pub struct TransferConfig {
116 118
117 /// Data width (DMODE) 119 /// Data width (DMODE)
118 pub dwidth: HspiWidth, 120 pub dwidth: HspiWidth,
119 /// Data buffer 121 /// Data Double Transfer rate enable
120 pub ddtr: bool, 122 pub ddtr: bool,
121 123
122 /// Number of dummy cycles (DCYC) 124 /// Number of dummy cycles (DCYC)
@@ -395,11 +397,6 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
395 // Configure alternate bytes 397 // Configure alternate bytes
396 if let Some(ab) = command.alternate_bytes { 398 if let Some(ab) = command.alternate_bytes {
397 T::REGS.abr().write(|v| v.set_alternate(ab)); 399 T::REGS.abr().write(|v| v.set_alternate(ab));
398 T::REGS.ccr().modify(|w| {
399 w.set_abmode(command.abwidth.into());
400 w.set_abdtr(command.abdtr);
401 w.set_absize(command.absize.into());
402 })
403 } 400 }
404 401
405 // Configure dummy cycles 402 // Configure dummy cycles
@@ -411,14 +408,14 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
411 if let Some(data_length) = data_len { 408 if let Some(data_length) = data_len {
412 T::REGS.dlr().write(|v| { 409 T::REGS.dlr().write(|v| {
413 v.set_dl((data_length - 1) as u32); 410 v.set_dl((data_length - 1) as u32);
414 }) 411 });
415 } else { 412 } else {
416 T::REGS.dlr().write(|v| { 413 T::REGS.dlr().write(|v| {
417 v.set_dl((0) as u32); 414 v.set_dl((0) as u32);
418 }) 415 });
419 } 416 }
420 417
421 // Configure instruction/address/data modes 418 // Configure instruction/address/alternate bytes/data modes
422 T::REGS.ccr().modify(|w| { 419 T::REGS.ccr().modify(|w| {
423 w.set_imode(command.iwidth.into()); 420 w.set_imode(command.iwidth.into());
424 w.set_idtr(command.idtr); 421 w.set_idtr(command.idtr);
@@ -428,6 +425,10 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
428 w.set_addtr(command.addtr); 425 w.set_addtr(command.addtr);
429 w.set_adsize(command.adsize.into()); 426 w.set_adsize(command.adsize.into());
430 427
428 w.set_abmode(command.abwidth.into());
429 w.set_abdtr(command.abdtr);
430 w.set_absize(command.absize.into());
431
431 w.set_dmode(command.dwidth.into()); 432 w.set_dmode(command.dwidth.into());
432 w.set_ddtr(command.ddtr); 433 w.set_ddtr(command.ddtr);
433 }); 434 });
diff --git a/embassy-stm32/src/ospi/enums.rs b/embassy-stm32/src/ospi/enums.rs
index 4021f7ce3..4db801752 100644
--- a/embassy-stm32/src/ospi/enums.rs
+++ b/embassy-stm32/src/ospi/enums.rs
@@ -23,6 +23,7 @@ impl Into<u8> for OspiMode {
23/// Ospi lane width 23/// Ospi lane width
24#[allow(dead_code)] 24#[allow(dead_code)]
25#[derive(Copy, Clone)] 25#[derive(Copy, Clone)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub enum OspiWidth { 27pub enum OspiWidth {
27 /// None 28 /// None
28 NONE, 29 NONE,
@@ -71,6 +72,7 @@ impl Into<bool> for FlashSelection {
71#[allow(dead_code)] 72#[allow(dead_code)]
72#[allow(missing_docs)] 73#[allow(missing_docs)]
73#[derive(Copy, Clone)] 74#[derive(Copy, Clone)]
75#[cfg_attr(feature = "defmt", derive(defmt::Format))]
74pub enum WrapSize { 76pub enum WrapSize {
75 None, 77 None,
76 _16Bytes, 78 _16Bytes,
@@ -95,6 +97,7 @@ impl Into<u8> for WrapSize {
95#[allow(missing_docs)] 97#[allow(missing_docs)]
96#[allow(dead_code)] 98#[allow(dead_code)]
97#[derive(Copy, Clone)] 99#[derive(Copy, Clone)]
100#[cfg_attr(feature = "defmt", derive(defmt::Format))]
98pub enum MemoryType { 101pub enum MemoryType {
99 Micron, 102 Micron,
100 Macronix, 103 Macronix,
@@ -120,6 +123,7 @@ impl Into<u8> for MemoryType {
120/// Ospi memory size. 123/// Ospi memory size.
121#[allow(missing_docs)] 124#[allow(missing_docs)]
122#[derive(Copy, Clone)] 125#[derive(Copy, Clone)]
126#[cfg_attr(feature = "defmt", derive(defmt::Format))]
123pub enum MemorySize { 127pub enum MemorySize {
124 _1KiB, 128 _1KiB,
125 _2KiB, 129 _2KiB,
@@ -180,6 +184,7 @@ impl Into<u8> for MemorySize {
180 184
181/// Ospi Address size 185/// Ospi Address size
182#[derive(Copy, Clone)] 186#[derive(Copy, Clone)]
187#[cfg_attr(feature = "defmt", derive(defmt::Format))]
183pub enum AddressSize { 188pub enum AddressSize {
184 /// 8-bit address 189 /// 8-bit address
185 _8Bit, 190 _8Bit,
@@ -205,6 +210,7 @@ impl Into<u8> for AddressSize {
205/// Time the Chip Select line stays high. 210/// Time the Chip Select line stays high.
206#[allow(missing_docs)] 211#[allow(missing_docs)]
207#[derive(Copy, Clone)] 212#[derive(Copy, Clone)]
213#[cfg_attr(feature = "defmt", derive(defmt::Format))]
208pub enum ChipSelectHighTime { 214pub enum ChipSelectHighTime {
209 _1Cycle, 215 _1Cycle,
210 _2Cycle, 216 _2Cycle,
@@ -234,6 +240,7 @@ impl Into<u8> for ChipSelectHighTime {
234/// FIFO threshold. 240/// FIFO threshold.
235#[allow(missing_docs)] 241#[allow(missing_docs)]
236#[derive(Copy, Clone)] 242#[derive(Copy, Clone)]
243#[cfg_attr(feature = "defmt", derive(defmt::Format))]
237pub enum FIFOThresholdLevel { 244pub enum FIFOThresholdLevel {
238 _1Bytes, 245 _1Bytes,
239 _2Bytes, 246 _2Bytes,
@@ -311,6 +318,7 @@ impl Into<u8> for FIFOThresholdLevel {
311/// Dummy cycle count 318/// Dummy cycle count
312#[allow(missing_docs)] 319#[allow(missing_docs)]
313#[derive(Copy, Clone)] 320#[derive(Copy, Clone)]
321#[cfg_attr(feature = "defmt", derive(defmt::Format))]
314pub enum DummyCycles { 322pub enum DummyCycles {
315 _0, 323 _0,
316 _1, 324 _1,
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs
index 8384f4fc4..d93cecb69 100644
--- a/embassy-stm32/src/ospi/mod.rs
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -23,6 +23,7 @@ use crate::{peripherals, Peri};
23 23
24/// OPSI driver config. 24/// OPSI driver config.
25#[derive(Clone, Copy)] 25#[derive(Clone, Copy)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub struct Config { 27pub struct Config {
27 /// Fifo threshold used by the peripheral to generate the interrupt indicating data 28 /// Fifo threshold used by the peripheral to generate the interrupt indicating data
28 /// or space is available in the FIFO 29 /// or space is available in the FIFO
@@ -30,7 +31,9 @@ pub struct Config {
30 /// Indicates the type of external device connected 31 /// Indicates the type of external device connected
31 pub memory_type: MemoryType, // Need to add an additional enum to provide this public interface 32 pub memory_type: MemoryType, // Need to add an additional enum to provide this public interface
32 /// Defines the size of the external device connected to the OSPI corresponding 33 /// Defines the size of the external device connected to the OSPI corresponding
33 /// to the number of address bits required to access the device 34 /// to the number of address bits required to access the device.
35 /// When using indirect mode, [`TransferConfig::address`] + the length of the data being read
36 /// or written must fit within the configured `device_size`, otherwise an error is returned.
34 pub device_size: MemorySize, 37 pub device_size: MemorySize,
35 /// Sets the minimum number of clock cycles that the chip select signal must be held high 38 /// Sets the minimum number of clock cycles that the chip select signal must be held high
36 /// between commands 39 /// between commands
@@ -83,6 +86,8 @@ impl Default for Config {
83} 86}
84 87
85/// OSPI transfer configuration. 88/// OSPI transfer configuration.
89#[derive(Clone, Copy)]
90#[cfg_attr(feature = "defmt", derive(defmt::Format))]
86pub struct TransferConfig { 91pub struct TransferConfig {
87 /// Instruction width (IMODE) 92 /// Instruction width (IMODE)
88 pub iwidth: OspiWidth, 93 pub iwidth: OspiWidth,
@@ -92,10 +97,11 @@ pub struct TransferConfig {
92 pub isize: AddressSize, 97 pub isize: AddressSize,
93 /// Instruction Double Transfer rate enable 98 /// Instruction Double Transfer rate enable
94 pub idtr: bool, 99 pub idtr: bool,
95
96 /// Address width (ADMODE) 100 /// Address width (ADMODE)
97 pub adwidth: OspiWidth, 101 pub adwidth: OspiWidth,
98 /// Device memory address 102 /// Device memory address.
103 /// In indirect mode, this value + the length of the data being read or written must be within
104 /// configured [`Config::device_size`], otherwise the transfer returns an error.
99 pub address: Option<u32>, 105 pub address: Option<u32>,
100 /// Number of Address Bytes 106 /// Number of Address Bytes
101 pub adsize: AddressSize, 107 pub adsize: AddressSize,
@@ -113,7 +119,7 @@ pub struct TransferConfig {
113 119
114 /// Data width (DMODE) 120 /// Data width (DMODE)
115 pub dwidth: OspiWidth, 121 pub dwidth: OspiWidth,
116 /// Data buffer 122 /// Data Double Transfer rate enable
117 pub ddtr: bool, 123 pub ddtr: bool,
118 124
119 /// Number of dummy cycles (DCYC) 125 /// Number of dummy cycles (DCYC)
@@ -451,11 +457,6 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
451 // Configure alternate bytes 457 // Configure alternate bytes
452 if let Some(ab) = command.alternate_bytes { 458 if let Some(ab) = command.alternate_bytes {
453 T::REGS.abr().write(|v| v.set_alternate(ab)); 459 T::REGS.abr().write(|v| v.set_alternate(ab));
454 T::REGS.ccr().modify(|w| {
455 w.set_abmode(PhaseMode::from_bits(command.abwidth.into()));
456 w.set_abdtr(command.abdtr);
457 w.set_absize(SizeInBits::from_bits(command.absize.into()));
458 })
459 } 460 }
460 461
461 // Configure dummy cycles 462 // Configure dummy cycles
@@ -467,14 +468,14 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
467 if let Some(data_length) = data_len { 468 if let Some(data_length) = data_len {
468 T::REGS.dlr().write(|v| { 469 T::REGS.dlr().write(|v| {
469 v.set_dl((data_length - 1) as u32); 470 v.set_dl((data_length - 1) as u32);
470 }) 471 });
471 } else { 472 } else {
472 T::REGS.dlr().write(|v| { 473 T::REGS.dlr().write(|v| {
473 v.set_dl((0) as u32); 474 v.set_dl((0) as u32);
474 }) 475 });
475 } 476 }
476 477
477 // Configure instruction/address/data/communication modes 478 // Configure instruction/address/alternate bytes/data/communication modes
478 T::REGS.ccr().modify(|w| { 479 T::REGS.ccr().modify(|w| {
479 w.set_imode(PhaseMode::from_bits(command.iwidth.into())); 480 w.set_imode(PhaseMode::from_bits(command.iwidth.into()));
480 w.set_idtr(command.idtr); 481 w.set_idtr(command.idtr);
@@ -484,6 +485,10 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
484 w.set_addtr(command.addtr); 485 w.set_addtr(command.addtr);
485 w.set_adsize(SizeInBits::from_bits(command.adsize.into())); 486 w.set_adsize(SizeInBits::from_bits(command.adsize.into()));
486 487
488 w.set_abmode(PhaseMode::from_bits(command.abwidth.into()));
489 w.set_abdtr(command.abdtr);
490 w.set_absize(SizeInBits::from_bits(command.absize.into()));
491
487 w.set_dmode(PhaseMode::from_bits(command.dwidth.into())); 492 w.set_dmode(PhaseMode::from_bits(command.dwidth.into()));
488 w.set_ddtr(command.ddtr); 493 w.set_ddtr(command.ddtr);
489 494
@@ -491,7 +496,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
491 w.set_sioo(command.sioo); 496 w.set_sioo(command.sioo);
492 }); 497 });
493 498
494 // Set informationrequired to initiate transaction 499 // Set information required to initiate transaction
495 if let Some(instruction) = command.instruction { 500 if let Some(instruction) = command.instruction {
496 if let Some(address) = command.address { 501 if let Some(address) = command.address {
497 T::REGS.ir().write(|v| { 502 T::REGS.ir().write(|v| {
@@ -526,6 +531,18 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
526 } 531 }
527 } 532 }
528 533
534 // The following errors set the TEF flag in OCTOSPI_SR register:
535 // - in indirect or automatic status-polling mode, when a wrong address has been programmed
536 // in OCTOSPI_AR (according to the device size defined by DEVSIZE[4:0])
537 // - in indirect mode, if the address plus the data length exceed the device size: TEF is
538 // set as soon as the access is triggered.
539 if T::REGS.sr().read().tef() {
540 // Clear the TEF register to make it ready for the next transfer.
541 T::REGS.fcr().write(|w| w.set_ctef(true));
542
543 return Err(OspiError::InvalidCommand);
544 }
545
529 Ok(()) 546 Ok(())
530 } 547 }
531 548
@@ -1181,16 +1198,19 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
1181 .cr() 1198 .cr()
1182 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE)); 1199 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE));
1183 1200
1184 let transfer = unsafe { 1201 // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU.
1185 self.dma 1202 for chunk in buf.chunks(0xFFFF) {
1186 .as_mut() 1203 let transfer = unsafe {
1187 .unwrap() 1204 self.dma
1188 .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) 1205 .as_mut()
1189 }; 1206 .unwrap()
1207 .write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default())
1208 };
1190 1209
1191 T::REGS.cr().modify(|w| w.set_dmaen(true)); 1210 T::REGS.cr().modify(|w| w.set_dmaen(true));
1192 1211
1193 transfer.blocking_wait(); 1212 transfer.blocking_wait();
1213 }
1194 1214
1195 finish_dma(T::REGS); 1215 finish_dma(T::REGS);
1196 1216
@@ -1251,16 +1271,19 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
1251 .cr() 1271 .cr()
1252 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE)); 1272 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE));
1253 1273
1254 let transfer = unsafe { 1274 // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU.
1255 self.dma 1275 for chunk in buf.chunks(0xFFFF) {
1256 .as_mut() 1276 let transfer = unsafe {
1257 .unwrap() 1277 self.dma
1258 .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) 1278 .as_mut()
1259 }; 1279 .unwrap()
1280 .write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default())
1281 };
1260 1282
1261 T::REGS.cr().modify(|w| w.set_dmaen(true)); 1283 T::REGS.cr().modify(|w| w.set_dmaen(true));
1262 1284
1263 transfer.await; 1285 transfer.await;
1286 }
1264 1287
1265 finish_dma(T::REGS); 1288 finish_dma(T::REGS);
1266 1289
diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs
index fa5e36d06..8a8420127 100644
--- a/embassy-stm32/src/qspi/enums.rs
+++ b/embassy-stm32/src/qspi/enums.rs
@@ -23,6 +23,7 @@ impl From<QspiMode> for u8 {
23/// QSPI lane width 23/// QSPI lane width
24#[allow(dead_code)] 24#[allow(dead_code)]
25#[derive(Copy, Clone)] 25#[derive(Copy, Clone)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub enum QspiWidth { 27pub enum QspiWidth {
27 /// None 28 /// None
28 NONE, 29 NONE,
@@ -67,6 +68,7 @@ impl From<FlashSelection> for bool {
67/// QSPI memory size. 68/// QSPI memory size.
68#[allow(missing_docs)] 69#[allow(missing_docs)]
69#[derive(Copy, Clone)] 70#[derive(Copy, Clone)]
71#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70pub enum MemorySize { 72pub enum MemorySize {
71 _1KiB, 73 _1KiB,
72 _2KiB, 74 _2KiB,
@@ -127,6 +129,7 @@ impl From<MemorySize> for u8 {
127 129
128/// QSPI Address size 130/// QSPI Address size
129#[derive(Copy, Clone)] 131#[derive(Copy, Clone)]
132#[cfg_attr(feature = "defmt", derive(defmt::Format))]
130pub enum AddressSize { 133pub enum AddressSize {
131 /// 8-bit address 134 /// 8-bit address
132 _8Bit, 135 _8Bit,
@@ -152,6 +155,7 @@ impl From<AddressSize> for u8 {
152/// Time the Chip Select line stays high. 155/// Time the Chip Select line stays high.
153#[allow(missing_docs)] 156#[allow(missing_docs)]
154#[derive(Copy, Clone)] 157#[derive(Copy, Clone)]
158#[cfg_attr(feature = "defmt", derive(defmt::Format))]
155pub enum ChipSelectHighTime { 159pub enum ChipSelectHighTime {
156 _1Cycle, 160 _1Cycle,
157 _2Cycle, 161 _2Cycle,
@@ -181,6 +185,7 @@ impl From<ChipSelectHighTime> for u8 {
181/// FIFO threshold. 185/// FIFO threshold.
182#[allow(missing_docs)] 186#[allow(missing_docs)]
183#[derive(Copy, Clone)] 187#[derive(Copy, Clone)]
188#[cfg_attr(feature = "defmt", derive(defmt::Format))]
184pub enum FIFOThresholdLevel { 189pub enum FIFOThresholdLevel {
185 _1Bytes, 190 _1Bytes,
186 _2Bytes, 191 _2Bytes,
@@ -258,6 +263,7 @@ impl From<FIFOThresholdLevel> for u8 {
258/// Dummy cycle count 263/// Dummy cycle count
259#[allow(missing_docs)] 264#[allow(missing_docs)]
260#[derive(Copy, Clone)] 265#[derive(Copy, Clone)]
266#[cfg_attr(feature = "defmt", derive(defmt::Format))]
261pub enum DummyCycles { 267pub enum DummyCycles {
262 _0, 268 _0,
263 _1, 269 _1,
@@ -334,6 +340,7 @@ impl From<DummyCycles> for u8 {
334 340
335#[allow(missing_docs)] 341#[allow(missing_docs)]
336#[derive(Copy, Clone)] 342#[derive(Copy, Clone)]
343#[cfg_attr(feature = "defmt", derive(defmt::Format))]
337pub enum SampleShifting { 344pub enum SampleShifting {
338 None, 345 None,
339 HalfCycle, 346 HalfCycle,
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index c0cd216f0..b03cd9009 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -18,6 +18,7 @@ use crate::{peripherals, Peri};
18 18
19/// QSPI transfer configuration. 19/// QSPI transfer configuration.
20#[derive(Clone, Copy)] 20#[derive(Clone, Copy)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21pub struct TransferConfig { 22pub struct TransferConfig {
22 /// Instruction width (IMODE) 23 /// Instruction width (IMODE)
23 pub iwidth: QspiWidth, 24 pub iwidth: QspiWidth,
@@ -48,6 +49,8 @@ impl Default for TransferConfig {
48 49
49/// QSPI driver configuration. 50/// QSPI driver configuration.
50#[derive(Clone, Copy)] 51#[derive(Clone, Copy)]
52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53#[non_exhaustive]
51pub struct Config { 54pub struct Config {
52 /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. 55 /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen.
53 /// If you need other value the whose predefined use `Other` variant. 56 /// If you need other value the whose predefined use `Other` variant.
@@ -62,6 +65,8 @@ pub struct Config {
62 pub cs_high_time: ChipSelectHighTime, 65 pub cs_high_time: ChipSelectHighTime,
63 /// Shift sampling point of input data (none, or half-cycle) 66 /// Shift sampling point of input data (none, or half-cycle)
64 pub sample_shifting: SampleShifting, 67 pub sample_shifting: SampleShifting,
68 /// GPIO Speed
69 pub gpio_speed: Speed,
65} 70}
66 71
67impl Default for Config { 72impl Default for Config {
@@ -73,6 +78,7 @@ impl Default for Config {
73 fifo_threshold: FIFOThresholdLevel::_17Bytes, 78 fifo_threshold: FIFOThresholdLevel::_17Bytes,
74 cs_high_time: ChipSelectHighTime::_5Cycle, 79 cs_high_time: ChipSelectHighTime::_5Cycle,
75 sample_shifting: SampleShifting::None, 80 sample_shifting: SampleShifting::None,
81 gpio_speed: Speed::VeryHigh,
76 } 82 }
77 } 83 }
78} 84}
@@ -286,14 +292,14 @@ impl<'d, T: Instance> Qspi<'d, T, Blocking> {
286 ) -> Self { 292 ) -> Self {
287 Self::new_inner( 293 Self::new_inner(
288 peri, 294 peri,
289 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 295 new_pin!(d0, AfType::output(OutputType::PushPull, config.gpio_speed)),
290 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 296 new_pin!(d1, AfType::output(OutputType::PushPull, config.gpio_speed)),
291 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 297 new_pin!(d2, AfType::output(OutputType::PushPull, config.gpio_speed)),
292 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 298 new_pin!(d3, AfType::output(OutputType::PushPull, config.gpio_speed)),
293 new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 299 new_pin!(sck, AfType::output(OutputType::PushPull, config.gpio_speed)),
294 new_pin!( 300 new_pin!(
295 nss, 301 nss,
296 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) 302 AfType::output_pull(OutputType::PushPull, config.gpio_speed, Pull::Up)
297 ), 303 ),
298 None, 304 None,
299 config, 305 config,
@@ -314,14 +320,14 @@ impl<'d, T: Instance> Qspi<'d, T, Blocking> {
314 ) -> Self { 320 ) -> Self {
315 Self::new_inner( 321 Self::new_inner(
316 peri, 322 peri,
317 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 323 new_pin!(d0, AfType::output(OutputType::PushPull, config.gpio_speed)),
318 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 324 new_pin!(d1, AfType::output(OutputType::PushPull, config.gpio_speed)),
319 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 325 new_pin!(d2, AfType::output(OutputType::PushPull, config.gpio_speed)),
320 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 326 new_pin!(d3, AfType::output(OutputType::PushPull, config.gpio_speed)),
321 new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 327 new_pin!(sck, AfType::output(OutputType::PushPull, config.gpio_speed)),
322 new_pin!( 328 new_pin!(
323 nss, 329 nss,
324 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) 330 AfType::output_pull(OutputType::PushPull, config.gpio_speed, Pull::Up)
325 ), 331 ),
326 None, 332 None,
327 config, 333 config,
@@ -345,14 +351,14 @@ impl<'d, T: Instance> Qspi<'d, T, Async> {
345 ) -> Self { 351 ) -> Self {
346 Self::new_inner( 352 Self::new_inner(
347 peri, 353 peri,
348 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 354 new_pin!(d0, AfType::output(OutputType::PushPull, config.gpio_speed)),
349 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 355 new_pin!(d1, AfType::output(OutputType::PushPull, config.gpio_speed)),
350 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 356 new_pin!(d2, AfType::output(OutputType::PushPull, config.gpio_speed)),
351 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 357 new_pin!(d3, AfType::output(OutputType::PushPull, config.gpio_speed)),
352 new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 358 new_pin!(sck, AfType::output(OutputType::PushPull, config.gpio_speed)),
353 new_pin!( 359 new_pin!(
354 nss, 360 nss,
355 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) 361 AfType::output_pull(OutputType::PushPull, config.gpio_speed, Pull::Up)
356 ), 362 ),
357 new_dma!(dma), 363 new_dma!(dma),
358 config, 364 config,
@@ -374,14 +380,14 @@ impl<'d, T: Instance> Qspi<'d, T, Async> {
374 ) -> Self { 380 ) -> Self {
375 Self::new_inner( 381 Self::new_inner(
376 peri, 382 peri,
377 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 383 new_pin!(d0, AfType::output(OutputType::PushPull, config.gpio_speed)),
378 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 384 new_pin!(d1, AfType::output(OutputType::PushPull, config.gpio_speed)),
379 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 385 new_pin!(d2, AfType::output(OutputType::PushPull, config.gpio_speed)),
380 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 386 new_pin!(d3, AfType::output(OutputType::PushPull, config.gpio_speed)),
381 new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 387 new_pin!(sck, AfType::output(OutputType::PushPull, config.gpio_speed)),
382 new_pin!( 388 new_pin!(
383 nss, 389 nss,
384 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) 390 AfType::output_pull(OutputType::PushPull, config.gpio_speed, Pull::Up)
385 ), 391 ),
386 new_dma!(dma), 392 new_dma!(dma),
387 config, 393 config,
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 890c8a80e..c734eed49 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -692,6 +692,8 @@ impl<'d> BufferedUartTx<'d> {
692 fn blocking_write(&self, buf: &[u8]) -> Result<usize, Error> { 692 fn blocking_write(&self, buf: &[u8]) -> Result<usize, Error> {
693 loop { 693 loop {
694 let state = self.state; 694 let state = self.state;
695 state.tx_done.store(false, Ordering::Release);
696
695 let empty = state.tx_buf.is_empty(); 697 let empty = state.tx_buf.is_empty();
696 698
697 let mut tx_writer = unsafe { state.tx_buf.writer() }; 699 let mut tx_writer = unsafe { state.tx_buf.writer() };
@@ -713,7 +715,7 @@ impl<'d> BufferedUartTx<'d> {
713 fn blocking_flush(&self) -> Result<(), Error> { 715 fn blocking_flush(&self) -> Result<(), Error> {
714 loop { 716 loop {
715 let state = self.state; 717 let state = self.state;
716 if state.tx_buf.is_empty() { 718 if state.tx_done.load(Ordering::Acquire) {
717 return Ok(()); 719 return Ok(());
718 } 720 }
719 } 721 }
diff --git a/embassy-stm32/src/xspi/enums.rs b/embassy-stm32/src/xspi/enums.rs
index c96641180..2e510fada 100644
--- a/embassy-stm32/src/xspi/enums.rs
+++ b/embassy-stm32/src/xspi/enums.rs
@@ -22,6 +22,7 @@ impl Into<u8> for XspiMode {
22 22
23/// Xspi lane width 23/// Xspi lane width
24#[derive(Copy, Clone)] 24#[derive(Copy, Clone)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25pub enum XspiWidth { 26pub enum XspiWidth {
26 /// None 27 /// None
27 NONE, 28 NONE,
@@ -50,6 +51,7 @@ impl Into<u8> for XspiWidth {
50/// Wrap Size 51/// Wrap Size
51#[allow(missing_docs)] 52#[allow(missing_docs)]
52#[derive(Copy, Clone)] 53#[derive(Copy, Clone)]
54#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53pub enum WrapSize { 55pub enum WrapSize {
54 None, 56 None,
55 _16Bytes, 57 _16Bytes,
@@ -73,6 +75,7 @@ impl Into<u8> for WrapSize {
73/// Memory Type 75/// Memory Type
74#[allow(missing_docs)] 76#[allow(missing_docs)]
75#[derive(Copy, Clone)] 77#[derive(Copy, Clone)]
78#[cfg_attr(feature = "defmt", derive(defmt::Format))]
76pub enum MemoryType { 79pub enum MemoryType {
77 Micron, 80 Micron,
78 Macronix, 81 Macronix,
@@ -98,6 +101,7 @@ impl Into<u8> for MemoryType {
98/// Xspi memory size. 101/// Xspi memory size.
99#[allow(missing_docs)] 102#[allow(missing_docs)]
100#[derive(Copy, Clone)] 103#[derive(Copy, Clone)]
104#[cfg_attr(feature = "defmt", derive(defmt::Format))]
101pub enum MemorySize { 105pub enum MemorySize {
102 _1KiB, 106 _1KiB,
103 _2KiB, 107 _2KiB,
@@ -158,6 +162,7 @@ impl Into<u8> for MemorySize {
158 162
159/// Xspi Address size 163/// Xspi Address size
160#[derive(Copy, Clone)] 164#[derive(Copy, Clone)]
165#[cfg_attr(feature = "defmt", derive(defmt::Format))]
161pub enum AddressSize { 166pub enum AddressSize {
162 /// 8-bit address 167 /// 8-bit address
163 _8bit, 168 _8bit,
@@ -183,6 +188,7 @@ impl Into<u8> for AddressSize {
183/// Time the Chip Select line stays high. 188/// Time the Chip Select line stays high.
184#[allow(missing_docs)] 189#[allow(missing_docs)]
185#[derive(Copy, Clone)] 190#[derive(Copy, Clone)]
191#[cfg_attr(feature = "defmt", derive(defmt::Format))]
186pub enum ChipSelectHighTime { 192pub enum ChipSelectHighTime {
187 _1Cycle, 193 _1Cycle,
188 _2Cycle, 194 _2Cycle,
@@ -212,6 +218,7 @@ impl Into<u8> for ChipSelectHighTime {
212/// FIFO threshold. 218/// FIFO threshold.
213#[allow(missing_docs)] 219#[allow(missing_docs)]
214#[derive(Copy, Clone)] 220#[derive(Copy, Clone)]
221#[cfg_attr(feature = "defmt", derive(defmt::Format))]
215pub enum FIFOThresholdLevel { 222pub enum FIFOThresholdLevel {
216 _1Bytes, 223 _1Bytes,
217 _2Bytes, 224 _2Bytes,
@@ -289,6 +296,7 @@ impl Into<u8> for FIFOThresholdLevel {
289/// Dummy cycle count 296/// Dummy cycle count
290#[allow(missing_docs)] 297#[allow(missing_docs)]
291#[derive(Copy, Clone)] 298#[derive(Copy, Clone)]
299#[cfg_attr(feature = "defmt", derive(defmt::Format))]
292pub enum DummyCycles { 300pub enum DummyCycles {
293 _0, 301 _0,
294 _1, 302 _1,
diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs
index 60ccf3c97..901569f64 100644
--- a/embassy-stm32/src/xspi/mod.rs
+++ b/embassy-stm32/src/xspi/mod.rs
@@ -23,6 +23,7 @@ use crate::{peripherals, Peri};
23 23
24/// XPSI driver config. 24/// XPSI driver config.
25#[derive(Clone, Copy)] 25#[derive(Clone, Copy)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub struct Config { 27pub struct Config {
27 /// Fifo threshold used by the peripheral to generate the interrupt indicating data 28 /// Fifo threshold used by the peripheral to generate the interrupt indicating data
28 /// or space is available in the FIFO 29 /// or space is available in the FIFO
@@ -80,6 +81,8 @@ impl Default for Config {
80} 81}
81 82
82/// XSPI transfer configuration. 83/// XSPI transfer configuration.
84#[derive(Clone, Copy)]
85#[cfg_attr(feature = "defmt", derive(defmt::Format))]
83pub struct TransferConfig { 86pub struct TransferConfig {
84 /// Instruction width (IMODE) 87 /// Instruction width (IMODE)
85 pub iwidth: XspiWidth, 88 pub iwidth: XspiWidth,
@@ -110,7 +113,7 @@ pub struct TransferConfig {
110 113
111 /// Data width (DMODE) 114 /// Data width (DMODE)
112 pub dwidth: XspiWidth, 115 pub dwidth: XspiWidth,
113 /// Data buffer 116 /// Data Double Transfer rate enable
114 pub ddtr: bool, 117 pub ddtr: bool,
115 118
116 /// Number of dummy cycles (DCYC) 119 /// Number of dummy cycles (DCYC)
@@ -424,11 +427,6 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
424 // Configure alternate bytes 427 // Configure alternate bytes
425 if let Some(ab) = command.alternate_bytes { 428 if let Some(ab) = command.alternate_bytes {
426 T::REGS.abr().write(|v| v.set_alternate(ab)); 429 T::REGS.abr().write(|v| v.set_alternate(ab));
427 T::REGS.ccr().modify(|w| {
428 w.set_abmode(CcrAbmode::from_bits(command.abwidth.into()));
429 w.set_abdtr(command.abdtr);
430 w.set_absize(CcrAbsize::from_bits(command.absize.into()));
431 })
432 } else { 430 } else {
433 T::REGS.ccr().modify(|w| { 431 T::REGS.ccr().modify(|w| {
434 // disable alternate bytes 432 // disable alternate bytes
@@ -445,14 +443,14 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
445 if let Some(data_length) = data_len { 443 if let Some(data_length) = data_len {
446 T::REGS.dlr().write(|v| { 444 T::REGS.dlr().write(|v| {
447 v.set_dl((data_length - 1) as u32); 445 v.set_dl((data_length - 1) as u32);
448 }) 446 });
449 } else { 447 } else {
450 T::REGS.dlr().write(|v| { 448 T::REGS.dlr().write(|v| {
451 v.set_dl((0) as u32); 449 v.set_dl((0) as u32);
452 }) 450 });
453 } 451 }
454 452
455 // Configure instruction/address/data modes 453 // Configure instruction/address/alternate bytes/data modes
456 T::REGS.ccr().modify(|w| { 454 T::REGS.ccr().modify(|w| {
457 w.set_imode(CcrImode::from_bits(command.iwidth.into())); 455 w.set_imode(CcrImode::from_bits(command.iwidth.into()));
458 w.set_idtr(command.idtr); 456 w.set_idtr(command.idtr);
@@ -462,6 +460,10 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
462 w.set_addtr(command.addtr); 460 w.set_addtr(command.addtr);
463 w.set_adsize(CcrAdsize::from_bits(command.adsize.into())); 461 w.set_adsize(CcrAdsize::from_bits(command.adsize.into()));
464 462
463 w.set_abmode(CcrAbmode::from_bits(command.abwidth.into()));
464 w.set_abdtr(command.abdtr);
465 w.set_absize(CcrAbsize::from_bits(command.absize.into()));
466
465 w.set_dmode(CcrDmode::from_bits(command.dwidth.into())); 467 w.set_dmode(CcrDmode::from_bits(command.dwidth.into()));
466 w.set_ddtr(command.ddtr); 468 w.set_ddtr(command.ddtr);
467 }); 469 });