diff options
| author | Karun <[email protected]> | 2024-02-21 10:43:49 -0500 |
|---|---|---|
| committer | Karun <[email protected]> | 2024-03-07 14:41:04 -0500 |
| commit | b86a1f07009dfac8849cdc1beeb621fea348ccd5 (patch) | |
| tree | 766a38b273e26d502d7460db7f81505ce14bede3 /embassy-stm32/src | |
| parent | a0b70672054784276d6c370b87fd4635314656ae (diff) | |
Add constructors
Add transfer configuration
Update command configuration
Add peripheral width consideration
Add drop impl
Diffstat (limited to 'embassy-stm32/src')
| -rw-r--r-- | embassy-stm32/src/ospi/enums.rs | 23 | ||||
| -rw-r--r-- | embassy-stm32/src/ospi/mod.rs | 700 |
2 files changed, 664 insertions, 59 deletions
diff --git a/embassy-stm32/src/ospi/enums.rs b/embassy-stm32/src/ospi/enums.rs index 2209d7b94..e52f1f54d 100644 --- a/embassy-stm32/src/ospi/enums.rs +++ b/embassy-stm32/src/ospi/enums.rs | |||
| @@ -67,6 +67,29 @@ impl Into<bool> for FlashSelection { | |||
| 67 | } | 67 | } |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | /// Wrap Size | ||
| 71 | #[allow(dead_code)] | ||
| 72 | #[derive(Copy, Clone)] | ||
| 73 | pub enum WrapSize { | ||
| 74 | None, | ||
| 75 | _16Bytes, | ||
| 76 | _32Bytes, | ||
| 77 | _64Bytes, | ||
| 78 | _128Bytes, | ||
| 79 | } | ||
| 80 | |||
| 81 | impl Into<u8> for WrapSize { | ||
| 82 | fn into(self) -> u8 { | ||
| 83 | match self { | ||
| 84 | WrapSize::None => 0x00, | ||
| 85 | WrapSize::_16Bytes => 0x02, | ||
| 86 | WrapSize::_32Bytes => 0x03, | ||
| 87 | WrapSize::_64Bytes => 0x04, | ||
| 88 | WrapSize::_128Bytes => 0x05, | ||
| 89 | } | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 70 | /// Ospi memory size. | 93 | /// Ospi memory size. |
| 71 | #[allow(missing_docs)] | 94 | #[allow(missing_docs)] |
| 72 | #[derive(Copy, Clone)] | 95 | #[derive(Copy, Clone)] |
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index 547de65d9..48b1ef789 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs | |||
| @@ -11,20 +11,79 @@ use core::ptr; | |||
| 11 | use embassy_embedded_hal::SetConfig; | 11 | use embassy_embedded_hal::SetConfig; |
| 12 | use embassy_futures::join::join; | 12 | use embassy_futures::join::join; |
| 13 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 13 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 14 | use embedded_hal_02::blocking::i2c::Operation; | 14 | // use embedded_hal_02::spi; |
| 15 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | 15 | pub use enums::*; |
| 16 | use enums::*; | 16 | use stm32_metapac::octospi::vals::{MemType, PhaseMode, SizeInBits}; |
| 17 | 17 | ||
| 18 | use crate::dma::{slice_ptr_parts, word, Transfer}; | 18 | use crate::dma::{slice_ptr_parts, word, Transfer}; |
| 19 | use crate::gpio::sealed::{AFType, Pin as _}; | 19 | use crate::gpio::sealed::{AFType, Pin as _}; |
| 20 | use crate::gpio::{AnyPin, Pull}; | 20 | use crate::gpio::{AnyPin, Pull}; |
| 21 | use crate::pac::octospi::{regs, vals, Octospi as Regs}; | 21 | use crate::pac::octospi::{regs, vals, Octospi as Regs}; |
| 22 | use crate::rcc::RccPeripheral; | 22 | use crate::rcc::RccPeripheral; |
| 23 | use crate::time::Hertz; | ||
| 24 | use crate::{peripherals, Peripheral}; | 23 | use crate::{peripherals, Peripheral}; |
| 25 | 24 | ||
| 26 | /// OPSI driver config. | 25 | /// OPSI driver config. |
| 27 | pub struct Config; | 26 | pub struct Config { |
| 27 | /// Fifo threshold used by the peripheral to generate the interrupt indicating data | ||
| 28 | /// or space is available in the FIFO | ||
| 29 | pub fifo_threshold: FIFOThresholdLevel, | ||
| 30 | /// Enables dual-quad mode which allows access to two devices simultaneously to | ||
| 31 | /// increase throughput | ||
| 32 | pub dual_quad: bool, | ||
| 33 | /// Indicates the type of external device connected | ||
| 34 | pub memory_type: MemType, // Need to add an additional enum to provide this public interface | ||
| 35 | /// Defines the size of the external device connected to the OSPI corresponding | ||
| 36 | /// to the number of address bits required to access the device | ||
| 37 | pub device_size: MemorySize, | ||
| 38 | /// Sets the minimum number of clock cycles that the chip select signal must be held high | ||
| 39 | /// between commands | ||
| 40 | pub chip_select_high_time: ChipSelectHighTime, | ||
| 41 | /// Enables the free running clock | ||
| 42 | pub free_running_clock: bool, | ||
| 43 | /// Sets the clock level when the device is not selected | ||
| 44 | pub clock_mode: bool, | ||
| 45 | /// Indicates the wrap size corresponding to the external device configuration | ||
| 46 | pub wrap_size: WrapSize, | ||
| 47 | /// Specified the prescaler factor used for generating the external clock based | ||
| 48 | /// on the AHB clock | ||
| 49 | pub clock_prescaler: u8, | ||
| 50 | /// Allows the delay of 1/2 cycle the data sampling to account for external | ||
| 51 | /// signal delays | ||
| 52 | pub sample_shifting: bool, | ||
| 53 | /// Allows hold to 1/4 cycle the data | ||
| 54 | pub delay_hold_quarter_cycle: bool, | ||
| 55 | /// Enables the transaction boundary feature and defines the boundary to release | ||
| 56 | /// the chip select | ||
| 57 | pub chip_select_boundary: u8, | ||
| 58 | /// Enbales the delay block bypass so the sampling is not affected by the delay block | ||
| 59 | pub delay_block_bypass: bool, | ||
| 60 | /// Enables communication regulation feature. Chip select is released when the other | ||
| 61 | /// OctoSpi requests access to the bus | ||
| 62 | pub max_transfer: u8, | ||
| 63 | /// Enables the refresh feature, chip select is released every refresh + 1 clock cycles | ||
| 64 | pub refresh: u32, | ||
| 65 | } | ||
| 66 | impl Default for Config { | ||
| 67 | fn default() -> Self { | ||
| 68 | Self { | ||
| 69 | fifo_threshold: FIFOThresholdLevel::_16Bytes, // 32 bytes FIFO, half capacity | ||
| 70 | dual_quad: false, | ||
| 71 | memory_type: MemType::B_STANDARD, | ||
| 72 | device_size: MemorySize::Other(0), | ||
| 73 | chip_select_high_time: ChipSelectHighTime::_5Cycle, | ||
| 74 | free_running_clock: false, | ||
| 75 | clock_mode: false, | ||
| 76 | wrap_size: WrapSize::None, | ||
| 77 | clock_prescaler: 0, | ||
| 78 | sample_shifting: false, | ||
| 79 | delay_hold_quarter_cycle: false, | ||
| 80 | chip_select_boundary: 0, // Acceptable range 0 to 31 | ||
| 81 | delay_block_bypass: true, | ||
| 82 | max_transfer: 0, | ||
| 83 | refresh: 0, | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | ||
| 28 | 87 | ||
| 29 | /// OSPI transfer configuration. | 88 | /// OSPI transfer configuration. |
| 30 | pub struct TransferConfig { | 89 | pub struct TransferConfig { |
| @@ -94,7 +153,8 @@ impl Default for TransferConfig { | |||
| 94 | } | 153 | } |
| 95 | 154 | ||
| 96 | pub enum OspiError { | 155 | pub enum OspiError { |
| 97 | Test, | 156 | InvalidConfiguration, |
| 157 | InvalidCommand, | ||
| 98 | } | 158 | } |
| 99 | 159 | ||
| 100 | pub trait Error {} | 160 | pub trait Error {} |
| @@ -122,7 +182,7 @@ pub trait MultiSpi: ErrorType { | |||
| 122 | 182 | ||
| 123 | /// Write function used to send data to the target device following the supplied transaction | 183 | /// Write function used to send data to the target device following the supplied transaction |
| 124 | /// configuration. | 184 | /// configuration. |
| 125 | async fn write(&mut self, data: &mut [u8], config: Self::Config) -> Result<(), Self::Error>; | 185 | async fn write(&mut self, data: &[u8], config: Self::Config) -> Result<(), Self::Error>; |
| 126 | } | 186 | } |
| 127 | 187 | ||
| 128 | /// OSPI driver. | 188 | /// OSPI driver. |
| @@ -141,6 +201,7 @@ pub struct Ospi<'d, T: Instance, Dma> { | |||
| 141 | dqs: Option<PeripheralRef<'d, AnyPin>>, | 201 | dqs: Option<PeripheralRef<'d, AnyPin>>, |
| 142 | dma: PeripheralRef<'d, Dma>, | 202 | dma: PeripheralRef<'d, Dma>, |
| 143 | config: Config, | 203 | config: Config, |
| 204 | width: OspiWidth, | ||
| 144 | } | 205 | } |
| 145 | 206 | ||
| 146 | impl Error for OspiError {} | 207 | impl Error for OspiError {} |
| @@ -153,20 +214,60 @@ impl<'d, T: Instance, Dma: OctoDma<T>> MultiSpi for Ospi<'d, T, Dma> { | |||
| 153 | type Config = TransferConfig; | 214 | type Config = TransferConfig; |
| 154 | 215 | ||
| 155 | async fn command(&mut self, config: Self::Config) -> Result<(), Self::Error> { | 216 | async fn command(&mut self, config: Self::Config) -> Result<(), Self::Error> { |
| 156 | Ok(()) | 217 | self.command(&config).await |
| 157 | } | 218 | } |
| 158 | 219 | ||
| 159 | async fn read(&mut self, data: &mut [u8], config: Self::Config) -> Result<(), Self::Error> { | 220 | async fn read(&mut self, data: &mut [u8], config: Self::Config) -> Result<(), Self::Error> { |
| 160 | Ok(()) | 221 | self.read(data, config).await |
| 161 | } | 222 | } |
| 162 | 223 | ||
| 163 | async fn write(&mut self, data: &mut [u8], config: Self::Config) -> Result<(), Self::Error> { | 224 | async fn write(&mut self, data: &[u8], config: Self::Config) -> Result<(), Self::Error> { |
| 164 | Ok(()) | 225 | self.write(data, config).await |
| 165 | } | 226 | } |
| 166 | } | 227 | } |
| 167 | 228 | ||
| 168 | impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { | 229 | impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { |
| 169 | /// Create new OSPI driver for a dualspi external chip | 230 | /// Create new OSPI driver for a dualspi external chip |
| 231 | pub fn new_spi( | ||
| 232 | peri: impl Peripheral<P = T> + 'd, | ||
| 233 | sck: impl Peripheral<P = impl SckPin<T>> + 'd, | ||
| 234 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, | ||
| 235 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, | ||
| 236 | nss: impl Peripheral<P = impl NSSPin<T>> + 'd, | ||
| 237 | dma: impl Peripheral<P = Dma> + 'd, | ||
| 238 | config: Config, | ||
| 239 | ) -> Self { | ||
| 240 | into_ref!(peri, sck, d0, d1, nss); | ||
| 241 | |||
| 242 | sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 243 | sck.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 244 | nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up); | ||
| 245 | nss.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 246 | d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 247 | d0.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 248 | d1.set_as_af_pull(d1.af_num(), AFType::Input, Pull::None); | ||
| 249 | d1.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 250 | |||
| 251 | Self::new_inner( | ||
| 252 | peri, | ||
| 253 | Some(d0.map_into()), | ||
| 254 | Some(d1.map_into()), | ||
| 255 | None, | ||
| 256 | None, | ||
| 257 | None, | ||
| 258 | None, | ||
| 259 | None, | ||
| 260 | None, | ||
| 261 | Some(sck.map_into()), | ||
| 262 | Some(nss.map_into()), | ||
| 263 | None, | ||
| 264 | dma, | ||
| 265 | config, | ||
| 266 | OspiWidth::SING, | ||
| 267 | ) | ||
| 268 | } | ||
| 269 | |||
| 270 | /// Create new OSPI driver for a dualspi external chip | ||
| 170 | pub fn new_dualspi( | 271 | pub fn new_dualspi( |
| 171 | peri: impl Peripheral<P = T> + 'd, | 272 | peri: impl Peripheral<P = T> + 'd, |
| 172 | sck: impl Peripheral<P = impl SckPin<T>> + 'd, | 273 | sck: impl Peripheral<P = impl SckPin<T>> + 'd, |
| @@ -182,44 +283,189 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { | |||
| 182 | sck.set_speed(crate::gpio::Speed::VeryHigh); | 283 | sck.set_speed(crate::gpio::Speed::VeryHigh); |
| 183 | nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up); | 284 | nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up); |
| 184 | nss.set_speed(crate::gpio::Speed::VeryHigh); | 285 | nss.set_speed(crate::gpio::Speed::VeryHigh); |
| 185 | // nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Down); | ||
| 186 | // nss.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 187 | d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None); | 286 | d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None); |
| 188 | d0.set_speed(crate::gpio::Speed::VeryHigh); | 287 | d0.set_speed(crate::gpio::Speed::VeryHigh); |
| 189 | d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None); | 288 | d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None); |
| 190 | d1.set_speed(crate::gpio::Speed::VeryHigh); | 289 | d1.set_speed(crate::gpio::Speed::VeryHigh); |
| 191 | 290 | ||
| 192 | #[cfg(octospi_v1)] | 291 | Self::new_inner( |
| 193 | { | 292 | peri, |
| 194 | T::REGS.ccr().modify(|w| { | 293 | Some(d0.map_into()), |
| 195 | w.set_imode(vals::PhaseMode::TWOLINES); | 294 | Some(d1.map_into()), |
| 196 | w.set_admode(vals::PhaseMode::TWOLINES); | 295 | None, |
| 197 | w.set_abmode(vals::PhaseMode::TWOLINES); | 296 | None, |
| 198 | w.set_dmode(vals::PhaseMode::TWOLINES); | 297 | None, |
| 199 | }); | 298 | None, |
| 200 | T::REGS.wccr().modify(|w| { | 299 | None, |
| 201 | w.set_imode(vals::PhaseMode::TWOLINES); | 300 | None, |
| 202 | w.set_admode(vals::PhaseMode::TWOLINES); | 301 | Some(sck.map_into()), |
| 203 | w.set_abmode(vals::PhaseMode::TWOLINES); | 302 | Some(nss.map_into()), |
| 204 | w.set_dmode(vals::PhaseMode::TWOLINES); | 303 | None, |
| 205 | }); | 304 | dma, |
| 206 | } | 305 | config, |
| 306 | OspiWidth::DUAL, | ||
| 307 | ) | ||
| 308 | } | ||
| 309 | |||
| 310 | /// Create new OSPI driver for a quadspi external chip | ||
| 311 | pub fn new_quadspi( | ||
| 312 | peri: impl Peripheral<P = T> + 'd, | ||
| 313 | sck: impl Peripheral<P = impl SckPin<T>> + 'd, | ||
| 314 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, | ||
| 315 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, | ||
| 316 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, | ||
| 317 | d3: impl Peripheral<P = impl D3Pin<T>> + 'd, | ||
| 318 | nss: impl Peripheral<P = impl NSSPin<T>> + 'd, | ||
| 319 | dma: impl Peripheral<P = Dma> + 'd, | ||
| 320 | config: Config, | ||
| 321 | ) -> Self { | ||
| 322 | into_ref!(peri, sck, d0, d1, d2, d3, nss); | ||
| 323 | |||
| 324 | sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 325 | sck.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 326 | nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up); | ||
| 327 | nss.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 328 | d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 329 | d0.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 330 | d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 331 | d1.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 332 | d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 333 | d2.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 334 | d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 335 | d3.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 207 | 336 | ||
| 208 | Self::new_inner( | 337 | Self::new_inner( |
| 209 | peri, | 338 | peri, |
| 210 | Some(d0.map_into()), | 339 | Some(d0.map_into()), |
| 211 | Some(d1.map_into()), | 340 | Some(d1.map_into()), |
| 341 | Some(d2.map_into()), | ||
| 342 | Some(d3.map_into()), | ||
| 212 | None, | 343 | None, |
| 213 | None, | 344 | None, |
| 214 | None, | 345 | None, |
| 215 | None, | 346 | None, |
| 347 | Some(sck.map_into()), | ||
| 348 | Some(nss.map_into()), | ||
| 216 | None, | 349 | None, |
| 350 | dma, | ||
| 351 | config, | ||
| 352 | OspiWidth::QUAD, | ||
| 353 | ) | ||
| 354 | } | ||
| 355 | |||
| 356 | /// Create new OSPI driver for two quadspi external chips | ||
| 357 | pub fn new_dualquadspi( | ||
| 358 | peri: impl Peripheral<P = T> + 'd, | ||
| 359 | sck: impl Peripheral<P = impl SckPin<T>> + 'd, | ||
| 360 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, | ||
| 361 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, | ||
| 362 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, | ||
| 363 | d3: impl Peripheral<P = impl D3Pin<T>> + 'd, | ||
| 364 | d4: impl Peripheral<P = impl D4Pin<T>> + 'd, | ||
| 365 | d5: impl Peripheral<P = impl D5Pin<T>> + 'd, | ||
| 366 | d6: impl Peripheral<P = impl D6Pin<T>> + 'd, | ||
| 367 | d7: impl Peripheral<P = impl D7Pin<T>> + 'd, | ||
| 368 | nss: impl Peripheral<P = impl NSSPin<T>> + 'd, | ||
| 369 | dma: impl Peripheral<P = Dma> + 'd, | ||
| 370 | config: Config, | ||
| 371 | ) -> Self { | ||
| 372 | into_ref!(peri, sck, d0, d1, d2, d3, d4, d5, d6, d7, nss); | ||
| 373 | |||
| 374 | sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 375 | sck.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 376 | nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up); | ||
| 377 | nss.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 378 | d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 379 | d0.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 380 | d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 381 | d1.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 382 | d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 383 | d2.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 384 | d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 385 | d3.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 386 | d4.set_as_af_pull(d4.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 387 | d4.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 388 | d5.set_as_af_pull(d5.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 389 | d5.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 390 | d6.set_as_af_pull(d6.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 391 | d6.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 392 | d7.set_as_af_pull(d7.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 393 | d7.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 394 | |||
| 395 | Self::new_inner( | ||
| 396 | peri, | ||
| 397 | Some(d0.map_into()), | ||
| 398 | Some(d1.map_into()), | ||
| 399 | Some(d2.map_into()), | ||
| 400 | Some(d3.map_into()), | ||
| 401 | Some(d4.map_into()), | ||
| 402 | Some(d5.map_into()), | ||
| 403 | Some(d6.map_into()), | ||
| 404 | Some(d7.map_into()), | ||
| 405 | Some(sck.map_into()), | ||
| 406 | Some(nss.map_into()), | ||
| 217 | None, | 407 | None, |
| 408 | dma, | ||
| 409 | config, | ||
| 410 | OspiWidth::QUAD, | ||
| 411 | ) | ||
| 412 | } | ||
| 413 | |||
| 414 | /// Create new OSPI driver for two quadspi external chips | ||
| 415 | pub fn new_octospi( | ||
| 416 | peri: impl Peripheral<P = T> + 'd, | ||
| 417 | sck: impl Peripheral<P = impl SckPin<T>> + 'd, | ||
| 418 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, | ||
| 419 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, | ||
| 420 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, | ||
| 421 | d3: impl Peripheral<P = impl D3Pin<T>> + 'd, | ||
| 422 | d4: impl Peripheral<P = impl D4Pin<T>> + 'd, | ||
| 423 | d5: impl Peripheral<P = impl D5Pin<T>> + 'd, | ||
| 424 | d6: impl Peripheral<P = impl D6Pin<T>> + 'd, | ||
| 425 | d7: impl Peripheral<P = impl D7Pin<T>> + 'd, | ||
| 426 | nss: impl Peripheral<P = impl NSSPin<T>> + 'd, | ||
| 427 | dma: impl Peripheral<P = Dma> + 'd, | ||
| 428 | config: Config, | ||
| 429 | ) -> Self { | ||
| 430 | into_ref!(peri, sck, d0, d1, d2, d3, d4, d5, d6, d7, nss); | ||
| 431 | |||
| 432 | sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 433 | sck.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 434 | nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up); | ||
| 435 | nss.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 436 | d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 437 | d0.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 438 | d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 439 | d1.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 440 | d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 441 | d2.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 442 | d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 443 | d3.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 444 | d4.set_as_af_pull(d4.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 445 | d4.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 446 | d5.set_as_af_pull(d5.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 447 | d5.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 448 | d6.set_as_af_pull(d6.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 449 | d6.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 450 | d7.set_as_af_pull(d7.af_num(), AFType::OutputPushPull, Pull::None); | ||
| 451 | d7.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 452 | |||
| 453 | Self::new_inner( | ||
| 454 | peri, | ||
| 455 | Some(d0.map_into()), | ||
| 456 | Some(d1.map_into()), | ||
| 457 | Some(d2.map_into()), | ||
| 458 | Some(d3.map_into()), | ||
| 459 | Some(d4.map_into()), | ||
| 460 | Some(d5.map_into()), | ||
| 461 | Some(d6.map_into()), | ||
| 462 | Some(d7.map_into()), | ||
| 218 | Some(sck.map_into()), | 463 | Some(sck.map_into()), |
| 219 | Some(nss.map_into()), | 464 | Some(nss.map_into()), |
| 220 | None, | 465 | None, |
| 221 | dma, | 466 | dma, |
| 222 | config, | 467 | config, |
| 468 | OspiWidth::OCTO, | ||
| 223 | ) | 469 | ) |
| 224 | } | 470 | } |
| 225 | 471 | ||
| @@ -238,23 +484,72 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { | |||
| 238 | dqs: Option<PeripheralRef<'d, AnyPin>>, | 484 | dqs: Option<PeripheralRef<'d, AnyPin>>, |
| 239 | dma: impl Peripheral<P = Dma> + 'd, | 485 | dma: impl Peripheral<P = Dma> + 'd, |
| 240 | config: Config, | 486 | config: Config, |
| 487 | width: OspiWidth, | ||
| 241 | ) -> Self { | 488 | ) -> Self { |
| 242 | into_ref!(peri, dma); | 489 | into_ref!(peri, dma); |
| 243 | 490 | ||
| 491 | // System configuration | ||
| 244 | T::enable_and_reset(); | 492 | T::enable_and_reset(); |
| 245 | while T::REGS.sr().read().busy() {} | 493 | while T::REGS.sr().read().busy() {} |
| 246 | 494 | ||
| 495 | // Device configuration | ||
| 496 | T::REGS.dcr1().modify(|w| { | ||
| 497 | w.set_devsize(config.device_size.into()); | ||
| 498 | w.set_mtyp(config.memory_type); | ||
| 499 | w.set_csht(config.chip_select_high_time.into()); | ||
| 500 | w.set_dlybyp(config.delay_block_bypass); | ||
| 501 | w.set_frck(false); | ||
| 502 | w.set_ckmode(config.clock_mode); | ||
| 503 | }); | ||
| 504 | |||
| 505 | T::REGS.dcr2().modify(|w| { | ||
| 506 | w.set_wrapsize(config.wrap_size.into()); | ||
| 507 | }); | ||
| 508 | |||
| 509 | T::REGS.dcr3().modify(|w| { | ||
| 510 | w.set_csbound(config.chip_select_boundary); | ||
| 511 | w.set_maxtran(config.max_transfer); | ||
| 512 | }); | ||
| 513 | |||
| 514 | T::REGS.dcr4().modify(|w| { | ||
| 515 | w.set_refresh(config.refresh); | ||
| 516 | }); | ||
| 517 | |||
| 247 | T::REGS.cr().modify(|w| { | 518 | T::REGS.cr().modify(|w| { |
| 248 | w.set_en(true); | 519 | w.set_fthres(vals::Threshold(config.fifo_threshold.into())); |
| 249 | }); | 520 | }); |
| 250 | 521 | ||
| 251 | T::REGS.dcr1().modify(|w| { | 522 | // Wait for busy flag to clear |
| 252 | w.set_devsize(23); | 523 | while T::REGS.sr().read().busy() {} |
| 253 | w.set_mtyp(vals::MemType::MACRONIX); | 524 | |
| 254 | w.set_ckmode(false); | 525 | T::REGS.dcr2().modify(|w| { |
| 255 | // w.se | 526 | w.set_prescaler(config.clock_prescaler); |
| 527 | }); | ||
| 528 | |||
| 529 | T::REGS.cr().modify(|w| { | ||
| 530 | w.set_dmm(config.dual_quad); | ||
| 531 | }); | ||
| 532 | |||
| 533 | T::REGS.tcr().modify(|w| { | ||
| 534 | w.set_sshift(match config.sample_shifting { | ||
| 535 | true => vals::SampleShift::HALFCYCLE, | ||
| 536 | false => vals::SampleShift::NONE, | ||
| 537 | }); | ||
| 538 | w.set_dhqc(config.delay_hold_quarter_cycle); | ||
| 539 | }); | ||
| 540 | |||
| 541 | // Enable peripheral | ||
| 542 | T::REGS.cr().modify(|w| { | ||
| 543 | w.set_en(true); | ||
| 256 | }); | 544 | }); |
| 257 | 545 | ||
| 546 | // Free running clock needs to be set after peripheral enable | ||
| 547 | if config.free_running_clock { | ||
| 548 | T::REGS.dcr1().modify(|w| { | ||
| 549 | w.set_frck(config.free_running_clock); | ||
| 550 | }); | ||
| 551 | } | ||
| 552 | |||
| 258 | Self { | 553 | Self { |
| 259 | _peri: peri, | 554 | _peri: peri, |
| 260 | sck, | 555 | sck, |
| @@ -270,55 +565,343 @@ impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { | |||
| 270 | dqs, | 565 | dqs, |
| 271 | dma, | 566 | dma, |
| 272 | config, | 567 | config, |
| 568 | width, | ||
| 273 | } | 569 | } |
| 274 | } | 570 | } |
| 275 | 571 | ||
| 276 | pub fn blocking_read(&mut self, transaction: TransferConfig) -> Result<(), ()> { | 572 | // Function to configure the peripheral for the requested command |
| 573 | fn configure_command(&mut self, command: &TransferConfig) -> Result<(), OspiError> { | ||
| 574 | // Check that transaction doesn't use more than hardware initialized pins | ||
| 575 | if <enums::OspiWidth as Into<u8>>::into(command.iwidth) > <enums::OspiWidth as Into<u8>>::into(self.width) | ||
| 576 | || <enums::OspiWidth as Into<u8>>::into(command.adwidth) > <enums::OspiWidth as Into<u8>>::into(self.width) | ||
| 577 | || <enums::OspiWidth as Into<u8>>::into(command.abwidth) > <enums::OspiWidth as Into<u8>>::into(self.width) | ||
| 578 | || <enums::OspiWidth as Into<u8>>::into(command.dwidth) > <enums::OspiWidth as Into<u8>>::into(self.width) | ||
| 579 | { | ||
| 580 | return Err(OspiError::InvalidCommand); | ||
| 581 | } | ||
| 582 | |||
| 583 | T::REGS.cr().modify(|w| { | ||
| 584 | w.set_fmode(0.into()); | ||
| 585 | }); | ||
| 586 | |||
| 587 | // Configure alternate bytes | ||
| 588 | if let Some(ab) = command.alternate_bytes { | ||
| 589 | T::REGS.abr().write(|v| v.set_alternate(ab)); | ||
| 590 | T::REGS.ccr().modify(|w| { | ||
| 591 | w.set_abmode(PhaseMode::from_bits(command.abwidth.into())); | ||
| 592 | w.set_abdtr(command.abdtr); | ||
| 593 | w.set_absize(SizeInBits::from_bits(command.absize.into())); | ||
| 594 | }) | ||
| 595 | } | ||
| 596 | |||
| 597 | // Configure dummy cycles | ||
| 598 | T::REGS.tcr().modify(|w| { | ||
| 599 | w.set_dcyc(command.dummy.into()); | ||
| 600 | }); | ||
| 601 | |||
| 602 | // Configure data | ||
| 603 | if let Some(data_length) = command.data_len { | ||
| 604 | T::REGS.dlr().write(|v| { | ||
| 605 | v.set_dl((data_length - 1) as u32); | ||
| 606 | }) | ||
| 607 | } | ||
| 608 | |||
| 609 | // Configure instruction/address/data modes | ||
| 610 | T::REGS.ccr().modify(|w| { | ||
| 611 | w.set_imode(PhaseMode::from_bits(command.iwidth.into())); | ||
| 612 | w.set_idtr(command.idtr); | ||
| 613 | w.set_isize(SizeInBits::from_bits(command.isize.into())); | ||
| 614 | |||
| 615 | w.set_admode(PhaseMode::from_bits(command.adwidth.into())); | ||
| 616 | w.set_addtr(command.idtr); | ||
| 617 | w.set_adsize(SizeInBits::from_bits(command.adsize.into())); | ||
| 618 | |||
| 619 | w.set_dmode(PhaseMode::from_bits(command.dwidth.into())); | ||
| 620 | w.set_ddtr(command.ddtr); | ||
| 621 | }); | ||
| 622 | |||
| 623 | // Set informationrequired to initiate transaction | ||
| 624 | if let Some(instruction) = command.instruction { | ||
| 625 | if let Some(address) = command.address { | ||
| 626 | T::REGS.ir().write(|v| { | ||
| 627 | v.set_instruction(instruction); | ||
| 628 | }); | ||
| 629 | |||
| 630 | T::REGS.ar().write(|v| { | ||
| 631 | v.set_address(address); | ||
| 632 | }); | ||
| 633 | } else { | ||
| 634 | // Double check requirements for delay hold and sample shifting | ||
| 635 | // if let None = command.data_len { | ||
| 636 | // if self.config.delay_hold_quarter_cycle && command.idtr { | ||
| 637 | // T::REGS.ccr().modify(|w| { | ||
| 638 | // w.set_ddtr(true); | ||
| 639 | // }); | ||
| 640 | // } | ||
| 641 | // } | ||
| 642 | |||
| 643 | T::REGS.ir().write(|v| { | ||
| 644 | v.set_instruction(instruction); | ||
| 645 | }); | ||
| 646 | } | ||
| 647 | } else { | ||
| 648 | if let Some(address) = command.address { | ||
| 649 | T::REGS.ar().write(|v| { | ||
| 650 | v.set_address(address); | ||
| 651 | }); | ||
| 652 | } else { | ||
| 653 | // The only single phase transaction supported is instruction only | ||
| 654 | return Err(OspiError::InvalidCommand); | ||
| 655 | } | ||
| 656 | } | ||
| 657 | |||
| 277 | Ok(()) | 658 | Ok(()) |
| 278 | } | 659 | } |
| 279 | 660 | ||
| 280 | fn configure_command(&mut self, command: &TransferConfig) -> Result<(), ()> { | 661 | /// Function used to control or configure the target device without data transfer |
| 662 | pub async fn command(&mut self, command: &TransferConfig) -> Result<(), OspiError> { | ||
| 663 | // Prevent a transaction from being set with expected data transmission or reception | ||
| 664 | if let Some(_) = command.data_len { | ||
| 665 | return Err(OspiError::InvalidCommand); | ||
| 666 | }; | ||
| 667 | while T::REGS.sr().read().busy() {} | ||
| 668 | |||
| 669 | // Need additional validation that command configuration doesn't have data set | ||
| 670 | self.configure_command(command)?; | ||
| 671 | |||
| 672 | // Transaction initiated by setting final configuration, i.e the instruction register | ||
| 673 | while !T::REGS.sr().read().tcf() {} | ||
| 674 | T::REGS.fcr().write(|w| { | ||
| 675 | w.set_ctcf(true); | ||
| 676 | }); | ||
| 677 | |||
| 281 | Ok(()) | 678 | Ok(()) |
| 282 | } | 679 | } |
| 283 | 680 | ||
| 284 | /// Poor attempt to read data from memory | 681 | /// Blocking read with byte by byte data transfer |
| 285 | pub fn receive(&mut self, buf: &mut [u8], intruction: u8, data_len: usize) -> Result<(), ()> { | 682 | pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) -> Result<(), OspiError> { |
| 683 | // Wait for peripheral to be free | ||
| 684 | while T::REGS.sr().read().busy() {} | ||
| 685 | |||
| 686 | // Ensure DMA is not enabled for this transaction | ||
| 286 | T::REGS.cr().modify(|w| { | 687 | T::REGS.cr().modify(|w| { |
| 287 | w.set_fmode(vals::FunctionalMode::INDIRECTREAD); | 688 | w.set_dmaen(false); |
| 288 | }); | 689 | }); |
| 289 | 690 | ||
| 290 | T::REGS.ccr().modify(|w| { | 691 | self.configure_command(&transaction)?; |
| 291 | w.set_imode(vals::PhaseMode::ONELINE); | ||
| 292 | w.set_admode(vals::PhaseMode::NONE); | ||
| 293 | w.set_abmode(vals::PhaseMode::NONE); | ||
| 294 | 692 | ||
| 295 | w.set_dmode(vals::PhaseMode::ONELINE); | 693 | if let Some(len) = transaction.data_len { |
| 296 | }); | 694 | let current_address = T::REGS.ar().read().address(); |
| 695 | let current_instruction = T::REGS.ir().read().instruction(); | ||
| 696 | |||
| 697 | // For a indirect read transaction, the transaction begins when the instruction/address is set | ||
| 698 | T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD)); | ||
| 699 | if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE { | ||
| 700 | T::REGS.ir().write(|v| v.set_instruction(current_instruction)); | ||
| 701 | } else { | ||
| 702 | T::REGS.ar().write(|v| v.set_address(current_address)); | ||
| 703 | } | ||
| 704 | |||
| 705 | for idx in 0..len { | ||
| 706 | while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} | ||
| 707 | buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() }; | ||
| 708 | } | ||
| 709 | } | ||
| 710 | |||
| 711 | while !T::REGS.sr().read().tcf() {} | ||
| 712 | T::REGS.fcr().write(|v| v.set_ctcf(true)); | ||
| 297 | 713 | ||
| 298 | T::REGS.dlr().modify(|w| { | 714 | Ok(()) |
| 299 | w.set_dl((data_len - 1) as u32); | 715 | } |
| 716 | |||
| 717 | /// Blocking write with byte by byte data transfer | ||
| 718 | pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) -> Result<(), OspiError> { | ||
| 719 | T::REGS.cr().modify(|w| { | ||
| 720 | w.set_dmaen(false); | ||
| 300 | }); | 721 | }); |
| 722 | self.configure_command(&transaction)?; | ||
| 301 | 723 | ||
| 302 | // set instruction | 724 | if let Some(len) = transaction.data_len { |
| 303 | T::REGS.ir().modify(|w| w.set_instruction(intruction as u32)); | 725 | T::REGS |
| 726 | .cr() | ||
| 727 | .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE)); | ||
| 728 | |||
| 729 | for idx in 0..len { | ||
| 730 | while !T::REGS.sr().read().ftf() {} | ||
| 731 | unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) }; | ||
| 732 | } | ||
| 733 | } | ||
| 304 | 734 | ||
| 305 | // read bytes | ||
| 306 | // for idx in 0..data_len { | ||
| 307 | // while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} | ||
| 308 | // buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() }; | ||
| 309 | // } | ||
| 310 | // wait for finish | ||
| 311 | while !T::REGS.sr().read().tcf() {} | 735 | while !T::REGS.sr().read().tcf() {} |
| 736 | T::REGS.fcr().write(|v| v.set_ctcf(true)); | ||
| 737 | |||
| 738 | Ok(()) | ||
| 739 | } | ||
| 740 | |||
| 741 | /// Blocking read with DMA transfer | ||
| 742 | pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) -> Result<(), OspiError> | ||
| 743 | where | ||
| 744 | Dma: OctoDma<T>, | ||
| 745 | { | ||
| 746 | self.configure_command(&transaction)?; | ||
| 747 | |||
| 748 | let current_address = T::REGS.ar().read().address(); | ||
| 749 | let current_instruction = T::REGS.ir().read().instruction(); | ||
| 750 | |||
| 751 | // For a indirect read transaction, the transaction begins when the instruction/address is set | ||
| 752 | T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD)); | ||
| 753 | if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE { | ||
| 754 | T::REGS.ir().write(|v| v.set_instruction(current_instruction)); | ||
| 755 | } else { | ||
| 756 | T::REGS.ar().write(|v| v.set_address(current_address)); | ||
| 757 | } | ||
| 758 | |||
| 759 | let request = self.dma.request(); | ||
| 760 | let transfer = unsafe { | ||
| 761 | Transfer::new_read( | ||
| 762 | &mut self.dma, | ||
| 763 | request, | ||
| 764 | T::REGS.dr().as_ptr() as *mut u8, | ||
| 765 | buf, | ||
| 766 | Default::default(), | ||
| 767 | ) | ||
| 768 | }; | ||
| 769 | |||
| 770 | T::REGS.cr().modify(|w| w.set_dmaen(true)); | ||
| 771 | |||
| 772 | transfer.blocking_wait(); | ||
| 773 | |||
| 774 | finish_dma(T::REGS); | ||
| 775 | |||
| 776 | Ok(()) | ||
| 777 | } | ||
| 778 | |||
| 779 | /// Blocking write with DMA transfer | ||
| 780 | pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) -> Result<(), OspiError> | ||
| 781 | where | ||
| 782 | Dma: OctoDma<T>, | ||
| 783 | { | ||
| 784 | self.configure_command(&transaction)?; | ||
| 785 | T::REGS | ||
| 786 | .cr() | ||
| 787 | .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE)); | ||
| 788 | |||
| 789 | let request = self.dma.request(); | ||
| 790 | let transfer = unsafe { | ||
| 791 | Transfer::new_write( | ||
| 792 | &mut self.dma, | ||
| 793 | request, | ||
| 794 | buf, | ||
| 795 | T::REGS.dr().as_ptr() as *mut u8, | ||
| 796 | Default::default(), | ||
| 797 | ) | ||
| 798 | }; | ||
| 799 | |||
| 800 | T::REGS.cr().modify(|w| w.set_dmaen(true)); | ||
| 801 | |||
| 802 | transfer.blocking_wait(); | ||
| 803 | |||
| 804 | finish_dma(T::REGS); | ||
| 805 | |||
| 806 | Ok(()) | ||
| 807 | } | ||
| 312 | 808 | ||
| 313 | let fifo_count = T::REGS.sr().read().flevel(); | 809 | /// Asynchronous read from external device |
| 314 | for idx in 0..(fifo_count as usize) { | 810 | pub async fn read(&mut self, buf: &mut [u8], transaction: TransferConfig) -> Result<(), OspiError> |
| 315 | buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() }; | 811 | where |
| 812 | Dma: OctoDma<T>, | ||
| 813 | { | ||
| 814 | self.configure_command(&transaction)?; | ||
| 815 | |||
| 816 | let current_address = T::REGS.ar().read().address(); | ||
| 817 | let current_instruction = T::REGS.ir().read().instruction(); | ||
| 818 | |||
| 819 | // For a indirect read transaction, the transaction begins when the instruction/address is set | ||
| 820 | T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD)); | ||
| 821 | if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE { | ||
| 822 | T::REGS.ir().write(|v| v.set_instruction(current_instruction)); | ||
| 823 | } else { | ||
| 824 | T::REGS.ar().write(|v| v.set_address(current_address)); | ||
| 316 | } | 825 | } |
| 317 | 826 | ||
| 827 | let request = self.dma.request(); | ||
| 828 | let transfer = unsafe { | ||
| 829 | Transfer::new_read( | ||
| 830 | &mut self.dma, | ||
| 831 | request, | ||
| 832 | T::REGS.dr().as_ptr() as *mut u8, | ||
| 833 | buf, | ||
| 834 | Default::default(), | ||
| 835 | ) | ||
| 836 | }; | ||
| 837 | |||
| 838 | T::REGS.cr().modify(|w| w.set_dmaen(true)); | ||
| 839 | |||
| 840 | transfer.await; | ||
| 841 | |||
| 842 | finish_dma(T::REGS); | ||
| 843 | |||
| 844 | Ok(()) | ||
| 845 | } | ||
| 846 | |||
| 847 | /// Asynchronous write to external device | ||
| 848 | pub async fn write(&mut self, buf: &[u8], transaction: TransferConfig) -> Result<(), OspiError> | ||
| 849 | where | ||
| 850 | Dma: OctoDma<T>, | ||
| 851 | { | ||
| 852 | self.configure_command(&transaction)?; | ||
| 853 | T::REGS | ||
| 854 | .cr() | ||
| 855 | .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE)); | ||
| 856 | |||
| 857 | let request = self.dma.request(); | ||
| 858 | let transfer = unsafe { | ||
| 859 | Transfer::new_write( | ||
| 860 | &mut self.dma, | ||
| 861 | request, | ||
| 862 | buf, | ||
| 863 | T::REGS.dr().as_ptr() as *mut u8, | ||
| 864 | Default::default(), | ||
| 865 | ) | ||
| 866 | }; | ||
| 867 | |||
| 868 | T::REGS.cr().modify(|w| w.set_dmaen(true)); | ||
| 869 | |||
| 870 | transfer.await; | ||
| 871 | |||
| 872 | finish_dma(T::REGS); | ||
| 873 | |||
| 318 | Ok(()) | 874 | Ok(()) |
| 319 | } | 875 | } |
| 320 | } | 876 | } |
| 321 | 877 | ||
| 878 | impl<'d, T: Instance, Dma> Drop for Ospi<'d, T, Dma> { | ||
| 879 | fn drop(&mut self) { | ||
| 880 | self.sck.as_ref().map(|x| x.set_as_disconnected()); | ||
| 881 | self.d0.as_ref().map(|x| x.set_as_disconnected()); | ||
| 882 | self.d1.as_ref().map(|x| x.set_as_disconnected()); | ||
| 883 | self.d2.as_ref().map(|x| x.set_as_disconnected()); | ||
| 884 | self.d3.as_ref().map(|x| x.set_as_disconnected()); | ||
| 885 | self.d4.as_ref().map(|x| x.set_as_disconnected()); | ||
| 886 | self.d5.as_ref().map(|x| x.set_as_disconnected()); | ||
| 887 | self.d6.as_ref().map(|x| x.set_as_disconnected()); | ||
| 888 | self.d7.as_ref().map(|x| x.set_as_disconnected()); | ||
| 889 | self.nss.as_ref().map(|x| x.set_as_disconnected()); | ||
| 890 | self.dqs.as_ref().map(|x| x.set_as_disconnected()); | ||
| 891 | |||
| 892 | T::disable(); | ||
| 893 | } | ||
| 894 | } | ||
| 895 | |||
| 896 | fn finish_dma(regs: Regs) { | ||
| 897 | while !regs.sr().read().tcf() {} | ||
| 898 | regs.fcr().write(|v| v.set_ctcf(true)); | ||
| 899 | |||
| 900 | regs.cr().modify(|w| { | ||
| 901 | w.set_dmaen(false); | ||
| 902 | }); | ||
| 903 | } | ||
| 904 | |||
| 322 | pub(crate) mod sealed { | 905 | pub(crate) mod sealed { |
| 323 | use super::*; | 906 | use super::*; |
| 324 | 907 | ||
| @@ -342,7 +925,6 @@ pin_trait!(D6Pin, Instance); | |||
| 342 | pin_trait!(D7Pin, Instance); | 925 | pin_trait!(D7Pin, Instance); |
| 343 | pin_trait!(DQSPin, Instance); | 926 | pin_trait!(DQSPin, Instance); |
| 344 | pin_trait!(NSSPin, Instance); | 927 | pin_trait!(NSSPin, Instance); |
| 345 | |||
| 346 | dma_trait!(OctoDma, Instance); | 928 | dma_trait!(OctoDma, Instance); |
| 347 | 929 | ||
| 348 | foreach_peripheral!( | 930 | foreach_peripheral!( |
