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