aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src
diff options
context:
space:
mode:
authorKarun <[email protected]>2024-02-21 10:43:49 -0500
committerKarun <[email protected]>2024-03-07 14:41:04 -0500
commitb86a1f07009dfac8849cdc1beeb621fea348ccd5 (patch)
tree766a38b273e26d502d7460db7f81505ce14bede3 /embassy-stm32/src
parenta0b70672054784276d6c370b87fd4635314656ae (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.rs23
-rw-r--r--embassy-stm32/src/ospi/mod.rs700
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)]
73pub enum WrapSize {
74 None,
75 _16Bytes,
76 _32Bytes,
77 _64Bytes,
78 _128Bytes,
79}
80
81impl 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;
11use embassy_embedded_hal::SetConfig; 11use embassy_embedded_hal::SetConfig;
12use embassy_futures::join::join; 12use embassy_futures::join::join;
13use embassy_hal_internal::{into_ref, PeripheralRef}; 13use embassy_hal_internal::{into_ref, PeripheralRef};
14use embedded_hal_02::blocking::i2c::Operation; 14// use embedded_hal_02::spi;
15pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 15pub use enums::*;
16use enums::*; 16use stm32_metapac::octospi::vals::{MemType, PhaseMode, SizeInBits};
17 17
18use crate::dma::{slice_ptr_parts, word, Transfer}; 18use crate::dma::{slice_ptr_parts, word, Transfer};
19use crate::gpio::sealed::{AFType, Pin as _}; 19use crate::gpio::sealed::{AFType, Pin as _};
20use crate::gpio::{AnyPin, Pull}; 20use crate::gpio::{AnyPin, Pull};
21use crate::pac::octospi::{regs, vals, Octospi as Regs}; 21use crate::pac::octospi::{regs, vals, Octospi as Regs};
22use crate::rcc::RccPeripheral; 22use crate::rcc::RccPeripheral;
23use crate::time::Hertz;
24use crate::{peripherals, Peripheral}; 23use crate::{peripherals, Peripheral};
25 24
26/// OPSI driver config. 25/// OPSI driver config.
27pub struct Config; 26pub 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}
66impl 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.
30pub struct TransferConfig { 89pub struct TransferConfig {
@@ -94,7 +153,8 @@ impl Default for TransferConfig {
94} 153}
95 154
96pub enum OspiError { 155pub enum OspiError {
97 Test, 156 InvalidConfiguration,
157 InvalidCommand,
98} 158}
99 159
100pub trait Error {} 160pub 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
146impl Error for OspiError {} 207impl 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
168impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> { 229impl<'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
878impl<'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
896fn 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
322pub(crate) mod sealed { 905pub(crate) mod sealed {
323 use super::*; 906 use super::*;
324 907
@@ -342,7 +925,6 @@ pin_trait!(D6Pin, Instance);
342pin_trait!(D7Pin, Instance); 925pin_trait!(D7Pin, Instance);
343pin_trait!(DQSPin, Instance); 926pin_trait!(DQSPin, Instance);
344pin_trait!(NSSPin, Instance); 927pin_trait!(NSSPin, Instance);
345
346dma_trait!(OctoDma, Instance); 928dma_trait!(OctoDma, Instance);
347 929
348foreach_peripheral!( 930foreach_peripheral!(