Skip to content

Commit 946d54b

Browse files
bors[bot]richardeoinandrewgazelka
authored
Merge #278 #282
278: Add OCTOSPI Hyperbus support and an example for HyperRAM usage r=richardeoin a=richardeoin 282: improve spi traits r=richardeoin a=andrewgazelka - rename to SPI traits to possibly better names - `SpiAll` -> `HalSpi` - `SpiEnabled` -> `HalEnabledSpi` - `SpiDisabled` -> `HalDisabledSpi` - `reset` no longer needs to take ownership of the given SPI peripheral Co-authored-by: Richard Meadows <[email protected]> Co-authored-by: Andrew Gazelka <[email protected]>
3 parents cd09880 + 391aca7 + a17425f commit 946d54b

File tree

7 files changed

+612
-48
lines changed

7 files changed

+612
-48
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ required-features = ["xspi", "rm0433"]
165165
name = "octospi"
166166
required-features = ["xspi", "rm0468"]
167167

168+
[[example]]
169+
name = "octospi_hyperram"
170+
required-features = ["xspi", "rm0468"]
171+
168172
[[example]]
169173
name = "sdmmc"
170174
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/dma/macros.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ macro_rules! peripheral_target_instance {
125125
unsafe impl TargetAddress<M2P> for spi::Spi<$peripheral, spi::Disabled, $size> {
126126
#[inline(always)]
127127
fn address(&self) -> usize {
128-
use spi::SpiAll;
128+
use spi::HalSpi;
129129
&self.inner().$txreg as *const _ as usize
130130
}
131131

@@ -137,7 +137,7 @@ macro_rules! peripheral_target_instance {
137137
unsafe impl TargetAddress<P2M> for spi::Spi<$peripheral, spi::Disabled, $size> {
138138
#[inline(always)]
139139
fn address(&self) -> usize {
140-
use spi::SpiAll;
140+
use spi::HalSpi;
141141
&self.inner().$rxreg as *const _ as usize
142142
}
143143

src/prelude.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ pub use crate::sai::SaiPdmExt as _stm32h7xx_hal_spi_SaiPdmExt;
2323
#[cfg(feature = "sdmmc")]
2424
pub use crate::sdmmc::SdmmcExt as _stm32h7xx_hal_sdmmc_SdmmcExt;
2525
pub use crate::serial::SerialExt as _stm32h7xx_hal_serial_SerialExt;
26-
pub use crate::spi::SpiAll as _stm32h7xx_hal_spi_SpiAll;
27-
pub use crate::spi::SpiDisabled as _stm32h7xx_hal_spi_SpiDisabled;
28-
pub use crate::spi::SpiEnabled as _stm32h7xx_hal_spi_SpiEnabled;
26+
pub use crate::spi::HalDisabledSpi as _stm32h7xx_hal_spi_HalDisabledSpi;
27+
pub use crate::spi::HalEnabledSpi as _stm32h7xx_hal_spi_HalEnabledSpi;
28+
pub use crate::spi::HalSpi as _stm32h7xx_hal_spi_HalSpi;
2929
pub use crate::spi::SpiExt as _stm32h7xx_hal_spi_SpiExt;
3030
pub use crate::time::U32Ext as _stm32h7xx_hal_time_U32Ext;
3131
pub use crate::timer::TimerExt as _stm32h7xx_hal_timer_TimerExt;

src/spi.rs

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -541,8 +541,10 @@ pub trait SpiExt<SPI, WORD>: Sized {
541541
CONFIG: Into<Config>;
542542
}
543543

544-
pub trait SpiEnabled: SpiAll + FullDuplex<Self::Word, Error = Error> {
545-
type Disabled: SpiDisabled<
544+
pub trait HalEnabledSpi:
545+
HalSpi + FullDuplex<Self::Word, Error = Error>
546+
{
547+
type Disabled: HalDisabledSpi<
546548
Spi = Self::Spi,
547549
Word = Self::Word,
548550
Enabled = Self,
@@ -556,11 +558,8 @@ pub trait SpiEnabled: SpiAll + FullDuplex<Self::Word, Error = Error> {
556558
/// disabled.
557559
fn disable(self) -> Self::Disabled;
558560

559-
/// Resets the SPI peripheral. This is just a call to [SpiEnabled::disable]
560-
/// and [SpiDisabled::enable]
561-
fn reset(self) -> Self {
562-
self.disable().enable()
563-
}
561+
/// Resets the SPI peripheral.
562+
fn reset(&mut self);
564563

565564
/// Sets up a frame transaction with the given amount of data words.
566565
///
@@ -585,9 +584,9 @@ pub trait SpiEnabled: SpiAll + FullDuplex<Self::Word, Error = Error> {
585584
fn end_transaction(&mut self) -> Result<(), Error>;
586585
}
587586

588-
pub trait SpiDisabled: SpiAll {
587+
pub trait HalDisabledSpi: HalSpi {
589588
type Rec;
590-
type Enabled: SpiEnabled<Spi = Self::Spi, Word = Self::Word>;
589+
type Enabled: HalEnabledSpi<Spi = Self::Spi, Word = Self::Word>;
591590

592591
/// Enables the SPI peripheral.
593592
/// Clears the MODF flag, the SSI flag, and sets the SPE bit.
@@ -611,7 +610,7 @@ pub trait SpiDisabled: SpiAll {
611610
fn free(self) -> (Self::Spi, Self::Rec);
612611
}
613612

614-
pub trait SpiAll: Sized {
613+
pub trait HalSpi: Sized {
615614
type Spi;
616615
type Word;
617616

@@ -681,7 +680,7 @@ macro_rules! spi {
681680
// For each $TY
682681
$(
683682

684-
impl Spi<$SPIX, Enabled, $TY> {
683+
impl Spi<$SPIX, Enabled, $TY> {
685684
fn $spiX<T, CONFIG>(
686685
spi: $SPIX,
687686
config: CONFIG,
@@ -805,14 +804,33 @@ macro_rules! spi {
805804
}
806805
}
807806

808-
impl SpiEnabled for Spi<$SPIX, Enabled, $TY> {
809-
type Disabled = Spi<Self::Spi, Disabled, Self::Word>;
810-
811-
fn disable(self) -> Spi<$SPIX, Disabled, $TY> {
812-
// Master communication must be suspended before the peripheral is disabled
807+
impl <Ed> Spi<$SPIX, Ed, $TY> {
808+
/// internally disable the SPI without changing its type-state
809+
fn internal_disable(&mut self) {
813810
self.spi.cr1.modify(|_, w| w.csusp().requested());
814811
while self.spi.sr.read().eot().is_completed() {}
815812
self.spi.cr1.write(|w| w.ssi().slave_not_selected().spe().disabled());
813+
}
814+
815+
/// internally enable the SPI without changing its type-state
816+
fn internal_enable(&mut self) {
817+
self.clear_modf(); // SPE cannot be set when MODF is set
818+
self.spi.cr1.write(|w| w.ssi().slave_not_selected().spe().enabled());
819+
}
820+
}
821+
822+
impl HalEnabledSpi for Spi<$SPIX, Enabled, $TY> {
823+
type Disabled = Spi<Self::Spi, Disabled, Self::Word>;
824+
825+
fn reset(&mut self) {
826+
self.internal_disable();
827+
self.internal_enable();
828+
}
829+
830+
fn disable(mut self) -> Spi<$SPIX, Disabled, $TY> {
831+
// Master communication must be suspended before the peripheral is disabled
832+
self.internal_disable();
833+
816834
Spi {
817835
spi: self.spi,
818836
hardware_cs_mode: self.hardware_cs_mode,
@@ -859,13 +877,12 @@ macro_rules! spi {
859877
}
860878
}
861879

862-
impl SpiDisabled for Spi<$SPIX, Disabled, $TY> {
880+
impl HalDisabledSpi for Spi<$SPIX, Disabled, $TY> {
863881
type Rec = rec::$Rec;
864882
type Enabled = Spi<Self::Spi, Enabled, Self::Word>;
865883

866884
fn enable(mut self) -> Self::Enabled {
867-
self.clear_modf(); // SPE cannot be set when MODF is set
868-
self.spi.cr1.write(|w| w.ssi().slave_not_selected().spe().enabled());
885+
self.internal_enable();
869886
Spi {
870887
spi: self.spi,
871888
hardware_cs_mode: self.hardware_cs_mode,
@@ -895,7 +912,7 @@ macro_rules! spi {
895912
}
896913
}
897914

898-
impl<EN> SpiAll for Spi<$SPIX, EN, $TY>
915+
impl<EN> HalSpi for Spi<$SPIX, EN, $TY>
899916
{
900917
type Word = $TY;
901918
type Spi = $SPIX;

0 commit comments

Comments
 (0)