1#![allow(unused)]
6
7use crate::hal;
8use crate::pins::FlashPins;
9use embassy_stm32::{
10 Peri,
11 qspi::enums::{AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize},
12};
13use hal::{
14 mode::Blocking,
15 peripherals::QUADSPI,
16 qspi::{
17 Qspi, TransferConfig,
18 enums::{DummyCycles, QspiWidth},
19 },
20};
21
22const WRITE_CMD: u8 = 0x32; const WRITE_ENABLE_CMD: u8 = 0x06; const SECTOR_ERASE_CMD: u8 = 0xD7; const FAST_READ_QUAD_IO_CMD: u8 = 0xEB; const RESET_ENABLE_CMD: u8 = 0x66;
28const RESET_MEMORY_CMD: u8 = 0x99;
29
30const WRITE_STATUS_REGISTER_CMD: u8 = 0x01; const READ_STATUS_REGISTER_CMD: u8 = 0x05; const STATUS_BIT_WIP: u8 = 1 << 0;
33const STATUS_BIT_WEL: u8 = 1 << 1;
34const STATUS_BIT_BP0: u8 = 1 << 2;
35const STATUS_BIT_BP1: u8 = 1 << 3;
36const STATUS_BIT_BP2: u8 = 1 << 4;
37const STATUS_BIT_BP3: u8 = 1 << 5;
38const STATUS_BIT_QE: u8 = 1 << 6;
39const STATUS_BIT_SRWD: u8 = 1 << 7;
40
41const SET_READ_PARAMETERS_CMD: u8 = 0xC0; const READ_PARAMS_BIT_BL0: u8 = 1 << 0;
43const READ_PARAMS_BIT_BL1: u8 = 1 << 1;
44const READ_PARAMS_BIT_WE: u8 = 1 << 2;
45const READ_PARAMS_BIT_DC0: u8 = 1 << 3;
46const READ_PARAMS_BIT_DC1: u8 = 1 << 4;
47const READ_PARAMS_BIT_ODS0: u8 = 1 << 5;
48const READ_PARAMS_BIT_ODS1: u8 = 1 << 6;
49const READ_PARAMS_BIT_ODS2: u8 = 1 << 7;
50
51const SECTOR_SIZE: u32 = 4096;
53const PAGE_SIZE: u32 = 256;
54const MAX_ADDRESS: u32 = 0x7FFFFF;
55
56pub struct FlashBuilder<'a> {
57 pub pins: FlashPins<'a>,
58 pub qspi: Peri<'a, QUADSPI>,
59}
60
61impl<'a> FlashBuilder<'a> {
62 pub fn build(self) -> Flash<'a> {
63 let mut config = hal::qspi::Config::default();
64
65 config.memory_size = MemorySize::_8MiB;
66 config.address_size = AddressSize::_24bit;
67 config.prescaler = 1;
68 config.cs_high_time = ChipSelectHighTime::_2Cycle;
69 config.fifo_threshold = FIFOThresholdLevel::_1Bytes;
70
71 let Self { pins, qspi } = self;
72 let qspi = Qspi::new_blocking_bank1(
73 qspi, pins.IO0, pins.IO1, pins.IO2, pins.IO3, pins.SCK, pins.CS, config,
74 );
75 let mut result = Flash { qspi };
76 result.reset_memory();
77 result.reset_status_register();
78 result.reset_read_register();
79 result
80 }
81}
82
83pub struct Flash<'a> {
84 qspi: Qspi<'a, QUADSPI, Blocking>,
85}
86
87impl Flash<'_> {
88 pub fn read(&mut self, address: u32, buffer: &mut [u8]) {
89 assert!(address + buffer.len() as u32 <= MAX_ADDRESS);
90
91 let transaction = TransferConfig {
92 iwidth: QspiWidth::SING,
93 awidth: QspiWidth::QUAD,
94 dwidth: QspiWidth::QUAD,
95 instruction: FAST_READ_QUAD_IO_CMD,
96 address: Some(address),
97 dummy: DummyCycles::_8,
98 };
99 self.qspi.blocking_read(buffer, transaction);
100 }
101
102 pub fn read_uuid(&mut self) -> [u8; 16] {
103 let mut buffer = [0; 16];
104 let transaction: TransferConfig = TransferConfig {
105 iwidth: QspiWidth::SING,
106 awidth: QspiWidth::SING,
107 dwidth: QspiWidth::SING,
108 instruction: 0x4B,
109 address: Some(0x00),
110 dummy: DummyCycles::_8,
111 };
112 self.qspi.blocking_read(&mut buffer, transaction);
113 buffer
114 }
115
116 pub fn write(&mut self, mut address: u32, data: &[u8]) {
117 assert!(address <= MAX_ADDRESS);
118 assert!(!data.is_empty());
119 self.erase(address, data.len() as u32);
120
121 let mut length = data.len() as u32;
122 let mut start_cursor = 0;
123
124 loop {
127 let page_remainder = PAGE_SIZE - (address & (PAGE_SIZE - 1));
129 let size = page_remainder.min(length) as usize;
130 self.enable_write();
131 let transaction = TransferConfig {
132 iwidth: QspiWidth::SING,
133 awidth: QspiWidth::SING,
134 dwidth: QspiWidth::QUAD,
135 instruction: WRITE_CMD,
136 address: Some(address),
137 dummy: DummyCycles::_0,
138 };
139
140 self.qspi
141 .blocking_write(&data[start_cursor..start_cursor + size], transaction);
142 self.wait_for_write();
143 start_cursor += size;
144
145 if length <= page_remainder {
147 break;
148 }
149 length -= page_remainder;
150
151 address += page_remainder;
153 address %= MAX_ADDRESS;
154 }
155 }
156
157 pub fn erase(&mut self, mut address: u32, mut length: u32) {
158 assert!(address <= MAX_ADDRESS);
159 assert!(length > 0);
160
161 loop {
162 self.enable_write();
164 let transaction = TransferConfig {
165 iwidth: QspiWidth::SING,
166 awidth: QspiWidth::SING,
167 dwidth: QspiWidth::NONE,
168 instruction: SECTOR_ERASE_CMD,
169 address: Some(address),
170 dummy: DummyCycles::_0,
171 };
172
173 self.qspi.blocking_command(transaction);
174 self.wait_for_write();
175
176 let sector_remainder = SECTOR_SIZE - (address & (SECTOR_SIZE - 1));
178
179 if length <= sector_remainder {
181 break;
182 }
183 length -= sector_remainder;
184
185 address += sector_remainder;
187 address %= MAX_ADDRESS;
188 }
189 }
190
191 fn enable_write(&mut self) {
192 let transaction = TransferConfig {
193 iwidth: QspiWidth::SING,
194 awidth: QspiWidth::NONE,
195 dwidth: QspiWidth::NONE,
196 instruction: WRITE_ENABLE_CMD,
197 address: None,
198 dummy: DummyCycles::_0,
199 };
200 self.qspi.blocking_command(transaction);
201 }
202
203 fn wait_for_write(&mut self) {
204 loop {
205 if self.read_status() & STATUS_BIT_WIP == 0 {
206 break;
207 }
208 }
209 }
210
211 fn read_status(&mut self) -> u8 {
212 let mut status: [u8; 1] = [0xFF; 1];
213 let transaction = TransferConfig {
214 iwidth: QspiWidth::SING,
215 awidth: QspiWidth::NONE,
216 dwidth: QspiWidth::SING,
217 instruction: READ_STATUS_REGISTER_CMD,
218 address: None,
219 dummy: DummyCycles::_0,
220 };
221 self.qspi.blocking_read(&mut status, transaction);
222 status[0]
223 }
224
225 fn reset_memory(&mut self) {
226 let transaction = TransferConfig {
227 iwidth: QspiWidth::SING,
228 awidth: QspiWidth::NONE,
229 dwidth: QspiWidth::NONE,
230 instruction: RESET_ENABLE_CMD,
231 address: None,
232 dummy: DummyCycles::_0,
233 };
234 self.qspi.blocking_command(transaction);
235
236 let transaction = TransferConfig {
237 iwidth: QspiWidth::SING,
238 awidth: QspiWidth::NONE,
239 dwidth: QspiWidth::NONE,
240 instruction: RESET_MEMORY_CMD,
241 address: None,
242 dummy: DummyCycles::_0,
243 };
244 self.qspi.blocking_command(transaction);
245 }
246
247 fn reset_status_register(&mut self) {
250 self.enable_write();
251 let value = STATUS_BIT_QE;
252 let transaction = TransferConfig {
253 iwidth: QspiWidth::SING,
254 awidth: QspiWidth::NONE,
255 dwidth: QspiWidth::SING,
256 instruction: WRITE_STATUS_REGISTER_CMD,
257 address: None,
258 dummy: DummyCycles::_0,
259 };
260 self.qspi.blocking_write(&[value], transaction);
261 self.wait_for_write();
262 }
263
264 fn reset_read_register(&mut self) {
267 let value = READ_PARAMS_BIT_ODS2
268 | READ_PARAMS_BIT_ODS1
269 | READ_PARAMS_BIT_ODS0
270 | READ_PARAMS_BIT_DC1;
271 let transaction = TransferConfig {
272 iwidth: QspiWidth::SING,
273 awidth: QspiWidth::NONE,
274 dwidth: QspiWidth::SING,
275 instruction: SET_READ_PARAMETERS_CMD,
276 address: None,
277 dummy: DummyCycles::_0,
278 };
279 self.qspi.blocking_write(&[value], transaction);
280 self.wait_for_write();
281 }
282}