Skip to content

Commit 24aca42

Browse files
committed
Add an example of QSPI used for flash memory
This demo uses QSPI interface to interact with the flash memory available on Daisy Seed board. This simple implementation shows how to reset registries, read and write values within a single section. In the demo, a restart counter is stored in flash and its value is indicated through LED. Signed-off-by: Petr Horacek <[email protected]>
1 parent 01aa752 commit 24aca42

File tree

2 files changed

+192
-0
lines changed

2 files changed

+192
-0
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ required-features = ["fmc"]
143143
name = "qspi"
144144
required-features = ["xspi", "rm0433"]
145145

146+
[[example]]
147+
name = "qspi_flash_memory"
148+
required-features = ["xspi", "rm0433"]
149+
146150
[[example]]
147151
name = "octospi"
148152
required-features = ["xspi", "rm0468"]

examples/qspi_flash_memory.rs

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
//! Example of communication with flash memory over QSPI interface. This
2+
//! specific program is made for Daisy Seed board and its IS25LP064A flash
3+
//! memory chip. This demo provides a non-volatile restart counter. When it is
4+
//! odd, LED will light up, when even, it stays off.
5+
6+
#![deny(warnings)]
7+
#![no_main]
8+
#![no_std]
9+
10+
#[macro_use]
11+
mod utilities;
12+
13+
use core::mem::transmute;
14+
15+
use cortex_m_rt::entry;
16+
use stm32h7xx_hal::gpio::Speed;
17+
use stm32h7xx_hal::hal::digital::v2::OutputPin;
18+
use stm32h7xx_hal::{
19+
pac, prelude::*, xspi::Qspi, xspi::QspiMode, xspi::QspiWord,
20+
};
21+
22+
use log::info;
23+
24+
// SPI commands from IS25LP064 datasheet
25+
const WRITE_STATUS_REGISTRY_CMD: u8 = 0x01; // WRSR
26+
const WRITE_CMD: u8 = 0x02; // PP
27+
const NORMAL_READ_CMD: u8 = 0x03; // NORD
28+
const READ_STATUS_REGISTRY_CMD: u8 = 0x05; // RDSR
29+
const WRITE_ENABLE_CMD: u8 = 0x06; // WREN
30+
const SET_READ_PARAMETERS_CMD: u8 = 0xC0; // SRP
31+
const SECTOR_ERASE_CMD: u8 = 0xD8; // SER
32+
33+
// Address in the external memory that will be used for the counter
34+
const COUNTER_ADDRESS: u32 = 0x00;
35+
36+
#[entry]
37+
fn main() -> ! {
38+
utilities::logger::init();
39+
let dp = pac::Peripherals::take().unwrap();
40+
41+
// Constrain and Freeze power
42+
let pwr = dp.PWR.constrain();
43+
let pwrcfg = example_power!(pwr).freeze();
44+
45+
// Constrain and Freeze clock
46+
let rcc = dp.RCC.constrain();
47+
let ccdr = rcc.sys_ck(96.mhz()).freeze(pwrcfg, &dp.SYSCFG);
48+
49+
// Acquire the GPIO peripherals
50+
let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC);
51+
let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF);
52+
let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG);
53+
54+
// Even though it is not directly used, CS pin must be acquired and configured
55+
let _qspi_cs = gpiog.pg6.into_alternate_af10().set_speed(Speed::VeryHigh);
56+
57+
let sck = gpiof.pf10.into_alternate_af9().set_speed(Speed::VeryHigh);
58+
let io0 = gpiof.pf8.into_alternate_af10().set_speed(Speed::VeryHigh);
59+
let io1 = gpiof.pf9.into_alternate_af10().set_speed(Speed::VeryHigh);
60+
let io2 = gpiof.pf7.into_alternate_af9().set_speed(Speed::VeryHigh);
61+
let io3 = gpiof.pf6.into_alternate_af9().set_speed(Speed::VeryHigh);
62+
63+
let mut led = gpioc.pc7.into_push_pull_output();
64+
65+
info!("");
66+
info!("stm32h7xx-hal example - QSPI Flash Memory");
67+
info!("");
68+
69+
// Initialise the QSPI peripheral
70+
let mut qspi = dp.QUADSPI.bank1(
71+
(sck, io0, io1, io2, io3),
72+
3.mhz(),
73+
&ccdr.clocks,
74+
ccdr.peripheral.QSPI,
75+
);
76+
qspi.configure_mode(QspiMode::OneBit).unwrap();
77+
78+
// Reset configuration of the flash memory
79+
reset_status_registry(&mut qspi);
80+
reset_read_registry(&mut qspi);
81+
82+
// Read the current value and increment it
83+
let original = read_u32(&mut qspi, COUNTER_ADDRESS);
84+
write_u32(&mut qspi, COUNTER_ADDRESS, original.overflowing_add(1).0);
85+
86+
// Based on the original value, enable or disable LED on the board
87+
if original % 2 == 0 {
88+
led.set_low().unwrap();
89+
} else {
90+
led.set_high().unwrap();
91+
}
92+
93+
loop {
94+
cortex_m::asm::nop();
95+
}
96+
}
97+
98+
fn read_u32(qspi: &mut Qspi<pac::QUADSPI>, address: u32) -> u32 {
99+
let mut buffer: [u8; 4] = [0xFF; 4];
100+
qspi.read_extended(
101+
QspiWord::U8(NORMAL_READ_CMD),
102+
QspiWord::U24(address),
103+
QspiWord::None,
104+
0,
105+
&mut buffer,
106+
)
107+
.unwrap();
108+
u32::from_be_bytes(buffer)
109+
}
110+
111+
fn write_u32(qspi: &mut Qspi<pac::QUADSPI>, address: u32, value: u32) {
112+
enable_write_operation(qspi);
113+
qspi.write_extended(
114+
QspiWord::U8(SECTOR_ERASE_CMD),
115+
QspiWord::U24(address),
116+
QspiWord::None,
117+
&[],
118+
)
119+
.unwrap();
120+
wait_for_write_completition(qspi);
121+
122+
let bytes: [u8; 4] = unsafe { transmute(value.to_be()) };
123+
enable_write_operation(qspi);
124+
qspi.write_extended(
125+
QspiWord::U8(WRITE_CMD),
126+
QspiWord::U24(address),
127+
QspiWord::None,
128+
&bytes,
129+
)
130+
.unwrap();
131+
wait_for_write_completition(qspi);
132+
}
133+
134+
fn reset_status_registry(qspi: &mut Qspi<pac::QUADSPI>) {
135+
enable_write_operation(qspi);
136+
137+
qspi.write_extended(
138+
QspiWord::U8(WRITE_STATUS_REGISTRY_CMD),
139+
QspiWord::U8(0b00000000),
140+
QspiWord::None,
141+
&[],
142+
)
143+
.unwrap();
144+
145+
wait_for_write_completition(qspi);
146+
}
147+
148+
fn reset_read_registry(qspi: &mut Qspi<pac::QUADSPI>) {
149+
enable_write_operation(qspi);
150+
151+
qspi.write_extended(
152+
QspiWord::U8(SET_READ_PARAMETERS_CMD),
153+
QspiWord::U8(0b11100000),
154+
QspiWord::None,
155+
&[],
156+
)
157+
.unwrap();
158+
159+
wait_for_write_completition(qspi);
160+
}
161+
162+
fn enable_write_operation(qspi: &mut Qspi<pac::QUADSPI>) {
163+
qspi.write_extended(
164+
QspiWord::U8(WRITE_ENABLE_CMD),
165+
QspiWord::None,
166+
QspiWord::None,
167+
&[],
168+
)
169+
.unwrap();
170+
}
171+
172+
fn wait_for_write_completition(qspi: &mut Qspi<pac::QUADSPI>) {
173+
loop {
174+
let mut status: [u8; 1] = [0xFF; 1];
175+
qspi.read_extended(
176+
QspiWord::U8(READ_STATUS_REGISTRY_CMD),
177+
QspiWord::None,
178+
QspiWord::None,
179+
0,
180+
&mut status,
181+
)
182+
.unwrap();
183+
184+
if status[0] & 0x01 == 0 {
185+
break;
186+
}
187+
}
188+
}

0 commit comments

Comments
 (0)