Skip to content

Commit 391aca7

Browse files
committed
Add OCTOSPI Hyperbus support and an example for HyperRAM usage
1 parent 76f626d commit 391aca7

File tree

4 files changed

+570
-23
lines changed

4 files changed

+570
-23
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ required-features = ["xspi", "rm0433"]
159159
name = "octospi"
160160
required-features = ["xspi", "rm0468"]
161161

162+
[[example]]
163+
name = "octospi_hyperram"
164+
required-features = ["xspi", "rm0468"]
165+
162166
[[example]]
163167
name = "sdmmc"
164168
required-features = ["sdmmc", "rm0433"]

examples/octospi_hyperram.rs

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
//! Example using a OCTOSPI HyperRAM in memory-mapped mode
2+
//!
3+
//! Tested on a STM32H735G-DK with a Cypress S70KL1281DABHI023
4+
5+
#![deny(warnings)]
6+
#![no_main]
7+
#![no_std]
8+
9+
use core::mem;
10+
use core::slice;
11+
12+
#[macro_use]
13+
mod utilities;
14+
15+
use cortex_m_rt::entry;
16+
use stm32h7xx_hal::rcc::rec::{OctospiClkSel, OctospiClkSelGetter};
17+
use stm32h7xx_hal::{gpio::Speed::High, pac, prelude::*, xspi::HyperbusConfig};
18+
19+
use log::info;
20+
21+
#[entry]
22+
fn main() -> ! {
23+
utilities::logger::init();
24+
let dp = pac::Peripherals::take().unwrap();
25+
26+
// Constrain and Freeze power
27+
let pwr = dp.PWR.constrain();
28+
let pwrcfg = example_power!(pwr).freeze();
29+
30+
// Constrain and Freeze clock
31+
let rcc = dp.RCC.constrain();
32+
let ccdr = rcc.sys_ck(320.mhz()).freeze(pwrcfg, &dp.SYSCFG);
33+
34+
// Octospi from HCLK at 160MHz
35+
assert_eq!(ccdr.clocks.hclk().0, 160_000_000);
36+
assert_eq!(
37+
ccdr.peripheral.OCTOSPI1.get_kernel_clk_mux(),
38+
OctospiClkSel::RCC_HCLK3
39+
);
40+
41+
// Acquire the GPIO peripherals. This also enables the clock for
42+
// the GPIOs in the RCC register.
43+
let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG);
44+
let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
45+
let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF);
46+
47+
let _tracweswo = gpiob.pb3.into_alternate_af0();
48+
49+
let _ncs = gpiog
50+
.pg12
51+
.into_alternate_af3()
52+
.set_speed(High)
53+
.internal_pull_up(true);
54+
let _dqs = gpiof
55+
.pf12
56+
.into_alternate_af9()
57+
.set_speed(High)
58+
.internal_pull_up(true);
59+
let _clk = gpiof
60+
.pf4
61+
.into_alternate_af9()
62+
.set_speed(High)
63+
.internal_pull_up(true);
64+
let _io0 = gpiof
65+
.pf0
66+
.into_alternate_af9()
67+
.set_speed(High)
68+
.internal_pull_up(true);
69+
let _io1 = gpiof
70+
.pf1
71+
.into_alternate_af9()
72+
.set_speed(High)
73+
.internal_pull_up(true);
74+
let _io2 = gpiof
75+
.pf2
76+
.into_alternate_af9()
77+
.set_speed(High)
78+
.internal_pull_up(true);
79+
let _io3 = gpiof
80+
.pf3
81+
.into_alternate_af9()
82+
.set_speed(High)
83+
.internal_pull_up(true);
84+
let _io4 = gpiog
85+
.pg0
86+
.into_alternate_af9()
87+
.set_speed(High)
88+
.internal_pull_up(true);
89+
let _io5 = gpiog
90+
.pg1
91+
.into_alternate_af9()
92+
.set_speed(High)
93+
.internal_pull_up(true);
94+
let _io6 = gpiog
95+
.pg10
96+
.into_alternate_af3()
97+
.set_speed(High)
98+
.internal_pull_up(true);
99+
let _io7 = gpiog
100+
.pg11
101+
.into_alternate_af9()
102+
.set_speed(High)
103+
.internal_pull_up(true);
104+
105+
info!("");
106+
info!("stm32h7xx-hal example - OCTOSPI HyperRAM");
107+
info!("");
108+
109+
// Initialise a HyperRAM on the OCTOSPI2 peripheral
110+
let ram_slice = unsafe {
111+
let hyperram_size = 16 * 1024 * 1024; // 16 MByte
112+
let config = HyperbusConfig::new(80.mhz())
113+
.device_size_bytes(24) // 16 Mbyte
114+
.refresh_interval(4.us())
115+
.read_write_recovery(4) // 50ns
116+
.access_initial_latency(6);
117+
118+
let hyperram = dp.OCTOSPI2.octospi_hyperbus_unchecked(
119+
config,
120+
&ccdr.clocks,
121+
ccdr.peripheral.OCTOSPI2,
122+
);
123+
124+
info!("Created HyperRAM..");
125+
info!("{}", hyperram);
126+
info!("");
127+
128+
// Initialise and convert raw pointer to slice
129+
let ram_ptr: *mut u32 = hyperram.init();
130+
slice::from_raw_parts_mut(
131+
ram_ptr,
132+
hyperram_size / mem::size_of::<u32>(),
133+
)
134+
};
135+
136+
info!("Writing checkerboard pattern...");
137+
for x in ram_slice.iter_mut() {
138+
*x = 0xAA55AA55;
139+
}
140+
info!("Reading checkerboard pattern...");
141+
for (i, x) in ram_slice.iter().enumerate() {
142+
assert_eq!(
143+
*x,
144+
0xAA55AA55,
145+
"Mismatch at address 0x{:x} (0x{:x} != 0xaa55aa55)",
146+
i * 4,
147+
*x
148+
);
149+
}
150+
151+
info!("Writing reverse checkerboard pattern...");
152+
for x in ram_slice.iter_mut() {
153+
*x = 0x55AA55AA;
154+
}
155+
info!("Reading reverse checkerboard pattern...");
156+
for (i, x) in ram_slice.iter().enumerate() {
157+
assert_eq!(
158+
*x,
159+
0x55AA55AA,
160+
"Mismatch at address 0x{:x} (0x{:x} != 0x55aa55aa)",
161+
i * 4,
162+
*x
163+
);
164+
}
165+
166+
info!("Success!");
167+
info!("");
168+
169+
loop {
170+
cortex_m::asm::nop();
171+
}
172+
}

src/xspi/mod.rs

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,28 @@
6262
//! ```
6363
//! use stm32h7xx_hal::xspi;
6464
//! let config = xspi::Config::new(12.mhz()).fifo_threshold(16);
65+
//!
66+
//! # Hyperbus
67+
//!
68+
//! This driver supports a memory-mapped Hyperbus mode for the OCTOSPI
69+
//! peripheral.
70+
//!
71+
//! ```
72+
//! let config = HyperbusConfig::new(80.mhz())
73+
//! .device_size_bytes(24) // 16 Mbyte
74+
//! .refresh_interval(4.us())
75+
//! .read_write_recovery(4) // 50ns
76+
//! .access_initial_latency(6);
77+
//!
78+
//! let hyperram = dp.OCTOSPI1.octospi_hyperbus_unchecked(
79+
//! config,
80+
//! &ccdr.clocks,
81+
//! ccdr.peripheral.OCTOSPI1,
82+
//! );
83+
//!
84+
//! // Initialise and convert raw pointer to slice
85+
//! let ram_ptr: *mut u32 = hyperram.init();
86+
//! let ram = unsafe { slice::from_raw_parts_mut(ram_ptr, size_u32) };
6587
//! ```
6688
//!
6789
//! # Examples
@@ -74,7 +96,8 @@
7496
//! # Limitations
7597
//!
7698
//! This driver currently only supports indirect operation mode of the xSPI
77-
//! interface. Automatic polling or memory-mapped modes are not supported.
99+
//! interface. Automatic polling or memory-mapped modes are not supported,
100+
//! except for the OCTOSPI Hyperbus mode.
78101
//!
79102
//! Using different operational modes (1-bit/2-bit/4-bit etc.) for different
80103
//! phases of a single transaction is not supported. It is possible to change
@@ -106,7 +129,7 @@ pub use common::{
106129
XspiWord as OctospiWord,
107130
};
108131
#[cfg(any(feature = "rm0455", feature = "rm0468"))]
109-
pub use octospi::OctospiExt as XspiExt;
132+
pub use octospi::{Hyperbus, HyperbusConfig, OctospiExt as XspiExt};
110133

111134
// Both
112135
pub use common::{Config, Event, SamplingEdge};
@@ -280,7 +303,7 @@ mod common {
280303
/// With zero dummy cycles, the QUADSPI peripheral will erroneously drive the
281304
/// output pins for an extra half clock cycle before IO is swapped from
282305
/// output to input. Refer to
283-
/// https://github.com/quartiq/stabilizer/issues/101 for more information.
306+
/// <https://github.com/quartiq/stabilizer/issues/101> for more information.
284307
pub fn dummy_cycles(mut self, cycles: u8) -> Self {
285308
debug_assert!(
286309
cycles < 32,
@@ -298,7 +321,7 @@ mod common {
298321
/// If zero dummy cycles are used, during read operations the QUADSPI
299322
/// peripheral will erroneously drive the output pins for an extra half
300323
/// clock cycle before IO is swapped from output to input. Refer to
301-
/// https://github.com/quartiq/stabilizer/issues/101 for more information.
324+
/// <https://github.com/quartiq/stabilizer/issues/101> for more information.
302325
///
303326
/// In this case it is recommended to sample on the falling edge. Although
304327
/// this doesn't stop the possible bus contention, delaying the sampling
@@ -461,22 +484,6 @@ mod common {
461484
.dmode() // data phase
462485
.bits(self.mode.reg_value())
463486
});
464-
465-
// if mode == XspiMode::EightBit {
466-
// // TODO
467-
// self.rb.ccr.modify(|_, w| unsafe {
468-
// w.admode()
469-
// .bits(mode.reg_value())
470-
// .adsize()
471-
// .bits(3) // 32-bit
472-
// .isize()
473-
// .bits(1) // 16-bit
474-
// .imode()
475-
// .bits(mode.reg_value())
476-
// .dmode()
477-
// .bits(mode.reg_value())
478-
// });
479-
// self.rb.tcr.write(|w| unsafe { w.dcyc().bits(4) });
480487
}
481488

482489
/// Sets the interface in extended mode

0 commit comments

Comments
 (0)