diff options
| author | jake-taf <[email protected]> | 2025-08-23 18:05:47 -0400 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2025-09-05 16:34:17 +0200 |
| commit | 525c7fe1eb77e3aa7440a14d6a6decfc0b0ca576 (patch) | |
| tree | 082dee06e23abeb00e7c84ffd9f9b393910ebc67 /embassy-stm32/src/ospi | |
| parent | 4ac4452c16e1b75bcf70814a9530b7724cc16e7d (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
Diffstat (limited to 'embassy-stm32/src/ospi')
| -rw-r--r-- | embassy-stm32/src/ospi/mod.rs | 109 |
1 files changed, 100 insertions, 9 deletions
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 | ||
| 123 | impl Default for TransferConfig { | 128 | impl 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 | ||
| 859 | impl<'d, T: Instance> Ospi<'d, T, Async> { | 910 | impl<'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() { |
