aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjake-taf <[email protected]>2025-08-23 18:05:47 -0400
committerDario Nieuwenhuis <[email protected]>2025-09-05 16:34:17 +0200
commit525c7fe1eb77e3aa7440a14d6a6decfc0b0ca576 (patch)
tree082dee06e23abeb00e7c84ffd9f9b393910ebc67
parent4ac4452c16e1b75bcf70814a9530b7724cc16e7d (diff)
OSPI RAM Support
- Make DQSE / SIOO configurable - Make write instruction configurable - Fix bug where the address DTR was using the config for the instruction DTR instead of its own - Configure DQS pin
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/src/ospi/mod.rs109
2 files changed, 101 insertions, 9 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 69f15013d..a473834dd 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
16### Fixed 16### Fixed
17 17
18- STM32: Prevent dropped DacChannel from disabling Dac peripheral if another DacChannel is still in scope ([#4577](https://github.com/embassy-rs/embassy/pull/4577)) 18- STM32: Prevent dropped DacChannel from disabling Dac peripheral if another DacChannel is still in scope ([#4577](https://github.com/embassy-rs/embassy/pull/4577))
19- feat: Added support for more OctoSPI configurations (e.g. APS6408 RAM) ([#4581](https://github.com/embassy-rs/embassy/pull/4581))
19 20
20## 0.4.0 - 2025-08-26 21## 0.4.0 - 2025-08-26
21 22
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs
index 74edfd5e4..8384f4fc4 100644
--- a/embassy-stm32/src/ospi/mod.rs
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -118,6 +118,11 @@ pub struct TransferConfig {
118 118
119 /// Number of dummy cycles (DCYC) 119 /// Number of dummy cycles (DCYC)
120 pub dummy: DummyCycles, 120 pub dummy: DummyCycles,
121
122 /// Data strobe (DQS) management enable
123 pub dqse: bool,
124 /// Send instruction only once (SIOO) mode enable
125 pub sioo: bool,
121} 126}
122 127
123impl Default for TransferConfig { 128impl Default for TransferConfig {
@@ -142,6 +147,9 @@ impl Default for TransferConfig {
142 ddtr: false, 147 ddtr: false,
143 148
144 dummy: DummyCycles::_0, 149 dummy: DummyCycles::_0,
150
151 dqse: false,
152 sioo: true,
145 } 153 }
146 } 154 }
147} 155}
@@ -192,26 +200,27 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
192 let reg = T::REGS; 200 let reg = T::REGS;
193 while reg.sr().read().busy() {} 201 while reg.sr().read().busy() {}
194 202
195 reg.ccr().modify(|r| { 203 if let Some(instruction) = write_config.instruction {
196 r.set_dqse(false); 204 reg.wir().write(|r| {
197 r.set_sioo(true); 205 r.set_instruction(instruction);
198 }); 206 });
207 }
199 208
200 // Set wrting configurations, there are separate registers for write configurations in memory mapped mode 209 // Set writing configurations, there are separate registers for write configurations in memory mapped mode
201 reg.wccr().modify(|w| { 210 reg.wccr().modify(|w| {
202 w.set_imode(PhaseMode::from_bits(write_config.iwidth.into())); 211 w.set_imode(PhaseMode::from_bits(write_config.iwidth.into()));
203 w.set_idtr(write_config.idtr); 212 w.set_idtr(write_config.idtr);
204 w.set_isize(SizeInBits::from_bits(write_config.isize.into())); 213 w.set_isize(SizeInBits::from_bits(write_config.isize.into()));
205 214
206 w.set_admode(PhaseMode::from_bits(write_config.adwidth.into())); 215 w.set_admode(PhaseMode::from_bits(write_config.adwidth.into()));
207 w.set_addtr(write_config.idtr); 216 w.set_addtr(write_config.addtr);
208 w.set_adsize(SizeInBits::from_bits(write_config.adsize.into())); 217 w.set_adsize(SizeInBits::from_bits(write_config.adsize.into()));
209 218
210 w.set_dmode(PhaseMode::from_bits(write_config.dwidth.into())); 219 w.set_dmode(PhaseMode::from_bits(write_config.dwidth.into()));
211 w.set_ddtr(write_config.ddtr); 220 w.set_ddtr(write_config.ddtr);
212 221
213 w.set_abmode(PhaseMode::from_bits(write_config.abwidth.into())); 222 w.set_abmode(PhaseMode::from_bits(write_config.abwidth.into()));
214 w.set_dqse(true); 223 w.set_dqse(write_config.dqse);
215 }); 224 });
216 225
217 reg.wtcr().modify(|w| w.set_dcyc(write_config.dummy.into())); 226 reg.wtcr().modify(|w| w.set_dcyc(write_config.dummy.into()));
@@ -465,18 +474,21 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
465 }) 474 })
466 } 475 }
467 476
468 // Configure instruction/address/data modes 477 // Configure instruction/address/data/communication modes
469 T::REGS.ccr().modify(|w| { 478 T::REGS.ccr().modify(|w| {
470 w.set_imode(PhaseMode::from_bits(command.iwidth.into())); 479 w.set_imode(PhaseMode::from_bits(command.iwidth.into()));
471 w.set_idtr(command.idtr); 480 w.set_idtr(command.idtr);
472 w.set_isize(SizeInBits::from_bits(command.isize.into())); 481 w.set_isize(SizeInBits::from_bits(command.isize.into()));
473 482
474 w.set_admode(PhaseMode::from_bits(command.adwidth.into())); 483 w.set_admode(PhaseMode::from_bits(command.adwidth.into()));
475 w.set_addtr(command.idtr); 484 w.set_addtr(command.addtr);
476 w.set_adsize(SizeInBits::from_bits(command.adsize.into())); 485 w.set_adsize(SizeInBits::from_bits(command.adsize.into()));
477 486
478 w.set_dmode(PhaseMode::from_bits(command.dwidth.into())); 487 w.set_dmode(PhaseMode::from_bits(command.dwidth.into()));
479 w.set_ddtr(command.ddtr); 488 w.set_ddtr(command.ddtr);
489
490 w.set_dqse(command.dqse);
491 w.set_sioo(command.sioo);
480 }); 492 });
481 493
482 // Set informationrequired to initiate transaction 494 // Set informationrequired to initiate transaction
@@ -854,6 +866,45 @@ impl<'d, T: Instance> Ospi<'d, T, Blocking> {
854 false, 866 false,
855 ) 867 )
856 } 868 }
869
870 /// Create new blocking OSPI driver for octospi external chips with DQS support
871 pub fn new_blocking_octospi_with_dqs(
872 peri: Peri<'d, T>,
873 sck: Peri<'d, impl SckPin<T>>,
874 d0: Peri<'d, impl D0Pin<T>>,
875 d1: Peri<'d, impl D1Pin<T>>,
876 d2: Peri<'d, impl D2Pin<T>>,
877 d3: Peri<'d, impl D3Pin<T>>,
878 d4: Peri<'d, impl D4Pin<T>>,
879 d5: Peri<'d, impl D5Pin<T>>,
880 d6: Peri<'d, impl D6Pin<T>>,
881 d7: Peri<'d, impl D7Pin<T>>,
882 nss: Peri<'d, impl NSSPin<T>>,
883 dqs: Peri<'d, impl DQSPin<T>>,
884 config: Config,
885 ) -> Self {
886 Self::new_inner(
887 peri,
888 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
889 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
890 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
891 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
892 new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
893 new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
894 new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
895 new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
896 new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
897 new_pin!(
898 nss,
899 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
900 ),
901 new_pin!(dqs, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
902 None,
903 config,
904 OspiWidth::OCTO,
905 false,
906 )
907 }
857} 908}
858 909
859impl<'d, T: Instance> Ospi<'d, T, Async> { 910impl<'d, T: Instance> Ospi<'d, T, Async> {
@@ -1036,6 +1087,46 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
1036 ) 1087 )
1037 } 1088 }
1038 1089
1090 /// Create new blocking OSPI driver for octospi external chips with DQS support
1091 pub fn new_octospi_with_dqs(
1092 peri: Peri<'d, T>,
1093 sck: Peri<'d, impl SckPin<T>>,
1094 d0: Peri<'d, impl D0Pin<T>>,
1095 d1: Peri<'d, impl D1Pin<T>>,
1096 d2: Peri<'d, impl D2Pin<T>>,
1097 d3: Peri<'d, impl D3Pin<T>>,
1098 d4: Peri<'d, impl D4Pin<T>>,
1099 d5: Peri<'d, impl D5Pin<T>>,
1100 d6: Peri<'d, impl D6Pin<T>>,
1101 d7: Peri<'d, impl D7Pin<T>>,
1102 nss: Peri<'d, impl NSSPin<T>>,
1103 dqs: Peri<'d, impl DQSPin<T>>,
1104 dma: Peri<'d, impl OctoDma<T>>,
1105 config: Config,
1106 ) -> Self {
1107 Self::new_inner(
1108 peri,
1109 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1110 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1111 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1112 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1113 new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1114 new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1115 new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1116 new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1117 new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1118 new_pin!(
1119 nss,
1120 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
1121 ),
1122 new_pin!(dqs, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1123 new_dma!(dma),
1124 config,
1125 OspiWidth::OCTO,
1126 false,
1127 )
1128 }
1129
1039 /// Blocking read with DMA transfer 1130 /// Blocking read with DMA transfer
1040 pub fn blocking_read_dma<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> { 1131 pub fn blocking_read_dma<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> {
1041 if buf.is_empty() { 1132 if buf.is_empty() {