aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/stm32h7rs/src/bin/xspi_memory_mapped.rs850
1 files changed, 677 insertions, 173 deletions
diff --git a/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs b/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs
index 88d914180..59045ca2e 100644
--- a/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs
+++ b/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs
@@ -3,7 +3,8 @@
3 3
4//! For Nucleo STM32H7S3L8 MB1737, has MX25UW25645GXDI00 4//! For Nucleo STM32H7S3L8 MB1737, has MX25UW25645GXDI00
5//! 5//!
6//! TODO: Currently this only uses single SPI, pending flash chip documentation for octo SPI. 6
7use core::cmp::min;
7 8
8use defmt::info; 9use defmt::info;
9use embassy_executor::Spawner; 10use embassy_executor::Spawner;
@@ -52,14 +53,16 @@ async fn main(_spawner: Spawner) {
52 fifo_threshold: FIFOThresholdLevel::_4Bytes, 53 fifo_threshold: FIFOThresholdLevel::_4Bytes,
53 memory_type: MemoryType::Macronix, 54 memory_type: MemoryType::Macronix,
54 delay_hold_quarter_cycle: true, 55 delay_hold_quarter_cycle: true,
55 // memory_type: MemoryType::Micron,
56 // delay_hold_quarter_cycle: false,
57 device_size: MemorySize::_32MiB, 56 device_size: MemorySize::_32MiB,
58 chip_select_high_time: ChipSelectHighTime::_2Cycle, 57 chip_select_high_time: ChipSelectHighTime::_2Cycle,
59 free_running_clock: false, 58 free_running_clock: false,
60 clock_mode: false, 59 clock_mode: false,
61 wrap_size: WrapSize::None, 60 wrap_size: WrapSize::None,
62 // 300mhz / (4+1) = 60mhz. Unsure the limit, need to find a MX25UW25645GXDI00 datasheet. 61 // 300 MHz clock / (3 + 1) = 75 MHz. This is above the max for READ instructions so the
62 // FAST READ must be used. The nucleo board's flash can run at up to 133 MHz in SPI mode
63 // and 200 MHz in OPI mode. This clock prescaler must be even otherwise the clock will not
64 // have symmetric high and low times.
65 // The clock can also be fed by one of the PLLs to allow for more flexible clock rates.
63 clock_prescaler: 3, 66 clock_prescaler: 3,
64 sample_shifting: false, 67 sample_shifting: false,
65 chip_select_boundary: 0, 68 chip_select_boundary: 0,
@@ -71,28 +74,41 @@ async fn main(_spawner: Spawner) {
71 74
72 // Not necessary, but recommended if using XIP 75 // Not necessary, but recommended if using XIP
73 cor.SCB.enable_icache(); 76 cor.SCB.enable_icache();
77 // Note: Enabling data cache can cause issues with DMA transfers.
74 cor.SCB.enable_dcache(&mut cor.CPUID); 78 cor.SCB.enable_dcache(&mut cor.CPUID);
75 79
76 let xspi = embassy_stm32::xspi::Xspi::new_blocking_xspi( 80 let xspi = embassy_stm32::xspi::Xspi::new_blocking_xspi(
77 p.XSPI2, p.PN6, p.PN2, p.PN3, p.PN4, p.PN5, p.PN8, p.PN9, p.PN10, p.PN11, p.PN1, spi_config, 81 p.XSPI2, p.PN6, p.PN2, p.PN3, p.PN4, p.PN5, p.PN8, p.PN9, p.PN10, p.PN11, p.PN1, spi_config,
78 ); 82 );
79 83
80 let mut flash = FlashMemory::new(xspi).await; 84 let mut flash = SpiFlashMemory::new(xspi);
81 85
82 let flash_id = flash.read_id(); 86 let flash_id = flash.read_id();
83 info!("FLASH ID: {=[u8]:x}", flash_id); 87 info!("FLASH ID: {=[u8]:x}", flash_id);
84 88
85 let mut wr_buf = [0u8; 8]; 89 // Erase the first sector
86 for i in 0..8 { 90 flash.erase_sector(0);
87 wr_buf[i] = 0x90 + i as u8; 91
88 } 92 // Write some data into the flash. This writes more than one page to test that functionality.
89 let mut rd_buf = [0u8; 8]; 93 let mut wr_buf = [0u8; 512];
90 flash.erase_sector(0).await; 94 let base_number: u8 = 0x90;
91 flash.write_memory(0, &wr_buf, true).await; 95 for i in 0..512 {
92 flash.read_memory(0, &mut rd_buf, true); 96 wr_buf[i] = base_number.wrapping_add(i as u8);
93 info!("WRITE BUF: {=[u8]:#X}", wr_buf); 97 }
94 info!("READ BUF: {=[u8]:#X}", rd_buf); 98 flash.write_memory(0, &wr_buf);
95 flash.enable_mm().await; 99
100 // Read the data back and verify it.
101 let mut rd_buf = [0u8; 512];
102 let start_time = embassy_time::Instant::now();
103 flash.read_memory(0, &mut rd_buf);
104 let elapsed = start_time.elapsed();
105 info!("Read 512 bytes in {} us in SPI mode", elapsed.as_micros());
106 info!("WRITE BUF: {=[u8]:#X}", wr_buf[0..32]);
107 info!("READ BUF: {=[u8]:#X}", rd_buf[0..32]);
108
109 assert_eq!(wr_buf, rd_buf, "Read buffer does not match write buffer");
110
111 flash.enable_mm();
96 info!("Enabled memory mapped mode"); 112 info!("Enabled memory mapped mode");
97 113
98 let first_u32 = unsafe { *(0x70000000 as *const u32) }; 114 let first_u32 = unsafe { *(0x70000000 as *const u32) };
@@ -103,10 +119,53 @@ async fn main(_spawner: Spawner) {
103 assert_eq!(second_u32, 0x97969594); 119 assert_eq!(second_u32, 0x97969594);
104 info!("second_u32 {:08x}", first_u32); 120 info!("second_u32 {:08x}", first_u32);
105 121
106 flash.disable_mm().await; 122 flash.disable_mm();
107 info!("Disabled memory mapped mode"); 123 info!("Disabled memory mapped mode");
108 124
125 let flash_id = flash.read_id();
126 info!("FLASH ID: {=[u8]:x}", flash_id);
127
128 let mut flash = flash.into_octo();
129
130 Timer::after_millis(100).await;
131
132 let flash_id = flash.read_id();
133 info!("FLASH ID in OPI mode: {=[u8]:x}", flash_id);
134
135 flash.erase_sector(0);
136
137 let mut rd_buf = [0u8; 512];
138 flash.read_memory(0, &mut rd_buf);
139 info!("READ BUF after erase: {=[u8]:#X}", rd_buf[0..32]);
140
141 assert_eq!(rd_buf, [0xFF; 512], "Read buffer is not all 0xFF after erase");
142
143 flash.write_memory(0, &wr_buf);
144 let start = embassy_time::Instant::now();
145 flash.read_memory(0, &mut rd_buf);
146 let elapsed = start.elapsed();
147 info!("Read 512 bytes in {} us in OPI mode", elapsed.as_micros());
148 info!("READ BUF after write: {=[u8]:#X}", rd_buf[0..32]);
149 assert_eq!(wr_buf, rd_buf, "Read buffer does not match write buffer in OPI mode");
150
151 flash.enable_mm();
152 info!("Enabled memory mapped mode in OPI mode");
153 let first_u32 = unsafe { *(0x70000000 as *const u32) };
154 assert_eq!(first_u32, 0x93929190);
155 info!("first_u32 {:08x}", first_u32);
156 let second_u32 = unsafe { *(0x70000004 as *const u32) };
157 assert_eq!(second_u32, 0x97969594);
158 info!("second_u32 {:08x}", first_u32);
159 flash.disable_mm();
160 info!("Disabled memory mapped mode in OPI mode");
161
162 // Reset back to SPI mode
163 let mut flash = flash.into_spi();
164 let flash_id = flash.read_id();
165 info!("FLASH ID back in SPI mode: {=[u8]:x}", flash_id);
166
109 info!("DONE"); 167 info!("DONE");
168
110 // Output pin PE3 169 // Output pin PE3
111 let mut led = Output::new(p.PE3, Level::Low, Speed::Low); 170 let mut led = Output::new(p.PE3, Level::Low, Speed::Low);
112 171
@@ -116,80 +175,268 @@ async fn main(_spawner: Spawner) {
116 } 175 }
117} 176}
118 177
119const MEMORY_PAGE_SIZE: usize = 8; 178const MEMORY_PAGE_SIZE: usize = 256;
120
121const CMD_READ: u8 = 0x0B;
122const _CMD_QUAD_READ: u8 = 0x6B;
123
124const CMD_WRITE_PG: u8 = 0x02;
125const _CMD_QUAD_WRITE_PG: u8 = 0x32;
126
127const CMD_READ_ID: u8 = 0x9F;
128const CMD_READ_ID_OCTO: u16 = 0x9F60;
129 179
130const CMD_ENABLE_RESET: u8 = 0x66; 180/// Implementation of access to flash chip using SPI.
131const CMD_RESET: u8 = 0x99; 181///
132 182/// Chip commands are hardcoded as it depends on used chip.
133const CMD_WRITE_ENABLE: u8 = 0x06; 183/// This targets a MX25UW25645GXDI00.
134 184pub struct SpiFlashMemory<I: Instance> {
135const CMD_CHIP_ERASE: u8 = 0xC7; 185 xspi: Xspi<'static, I, Blocking>,
136const CMD_SECTOR_ERASE: u8 = 0x20; 186}
137const CMD_BLOCK_ERASE_32K: u8 = 0x52;
138const CMD_BLOCK_ERASE_64K: u8 = 0xD8;
139
140const CMD_READ_SR: u8 = 0x05;
141const CMD_READ_CR: u8 = 0x35;
142
143const CMD_WRITE_SR: u8 = 0x01;
144const CMD_WRITE_CR: u8 = 0x31;
145 187
146/// Implementation of access to flash chip. 188/// Implementation of access to flash chip using Octo SPI.
147/// 189///
148/// Chip commands are hardcoded as it depends on used chip. 190/// Chip commands are hardcoded as it depends on used chip.
149/// This targets a MX25UW25645GXDI00. 191/// This targets a MX25UW25645GXDI00.
150pub struct FlashMemory<I: Instance> { 192pub struct OpiFlashMemory<I: Instance> {
151 xspi: Xspi<'static, I, Blocking>, 193 xspi: Xspi<'static, I, Blocking>,
152} 194}
153 195
154impl<I: Instance> FlashMemory<I> { 196/// SPI mode commands for MX25UW25645G flash memory
155 pub async fn new(xspi: Xspi<'static, I, Blocking>) -> Self { 197#[allow(dead_code)]
156 let mut memory = Self { xspi }; 198#[repr(u8)]
199enum SpiCommand {
200 // Array access commands
201 /// Read data bytes using 3-byte address (up to 50 MHz)
202 Read3B = 0x03,
203 /// Fast read data bytes using 3-byte address with 8 dummy cycles (up to 133 MHz)
204 FastRead3B = 0x0B,
205 /// Program 1-256 bytes of data using 3-byte address
206 PageProgram3B = 0x02,
207 /// Erase 4KB sector using 3-byte address
208 SectorErase3B = 0x20,
209 /// Erase 64KB block using 3-byte address
210 BlockErase3B = 0xD8,
211 /// Read data bytes using 4-byte address (up to 50 MHz)
212 Read4B = 0x13,
213 /// Fast read data bytes using 4-byte address with 8 dummy cycles (up to 133 MHz)
214 FastRead4B = 0x0C,
215 /// Program 1-256 bytes of data using 4-byte address
216 PageProgram4B = 0x12,
217 /// Erase 4KB sector using 4-byte address
218 SectorErase4B = 0x21,
219 /// Erase 64KB block using 4-byte address
220 BlockErase4B = 0xDC,
221 /// Erase entire chip (only if no blocks are protected)
222 ChipErase = 0x60,
223
224 // Write Buffer Access commands
225 /// Read data from the 256-byte page buffer
226 ReadBuffer = 0x25,
227 /// Initialize write-to-buffer sequence, clears buffer and writes initial data
228 WriteBufferInitial = 0x22,
229 /// Continue writing data to buffer (used between WRBI and WRCF)
230 WriteBufferContinue = 0x24,
231 /// Confirm write operation, programs buffer contents to flash array
232 WriteBufferConfirm = 0x31,
233
234 // Device operation commands
235 /// Set Write Enable Latch (WEL) bit, required before write/program/erase operations
236 WriteEnable = 0x06,
237 /// Clear Write Enable Latch (WEL) bit
238 WriteDisable = 0x04,
239 /// Select write protection mode (BP mode or Advanced Sector Protection)
240 WriteProtectSelection = 0x68,
241 /// Suspend ongoing program or erase operation to allow read access
242 ProgramEraseSuspend = 0xB0,
243 /// Resume suspended program or erase operation
244 ProgramEraseResume = 0x30,
245 /// Enter deep power-down mode for minimum power consumption
246 DeepPowerDown = 0xB9,
247 /// Exit deep power-down mode and return to standby
248 ReleaseFromDeepPowerDown = 0xAB,
249 /// No operation, can terminate Reset Enable command
250 NoOperation = 0x00,
251 /// Enable reset operation (must precede Reset Memory command)
252 ResetEnable = 0x66,
253 /// Reset device to power-on state (requires prior Reset Enable)
254 ResetMemory = 0x99,
255 /// Protect all sectors using Dynamic Protection Bits (DPB)
256 GangBlockLock = 0x7E,
257 /// Unprotect all sectors by clearing Dynamic Protection Bits (DPB)
258 GangBlockUnlock = 0x98,
259
260 // Register Access commands
261 /// Read 3-byte device identification (manufacturer ID + device ID)
262 ReadIdentification = 0x9F,
263 /// Read Serial Flash Discoverable Parameters (SFDP) table
264 ReadSFDP = 0x5A,
265 /// Read 8-bit Status Register (WIP, WEL, BP bits, etc.)
266 ReadStatusRegister = 0x05,
267 /// Read 8-bit Configuration Register (ODS, TB, PBE bits)
268 ReadConfigurationRegister = 0x15,
269 /// Write Status and/or Configuration Register (1-2 bytes)
270 WriteStatusConfigurationRegister = 0x01,
271 /// Read Configuration Register 2 from specified 4-byte address
272 ReadConfigurationRegister2 = 0x71,
273 /// Write Configuration Register 2 to specified 4-byte address
274 WriteConfigurationRegister2 = 0x72,
275 /// Read 8-bit Security Register (protection status, suspend bits)
276 ReadSecurityRegister = 0x2B,
277 /// Write Security Register to set customer lock-down bit
278 WriteSecurityRegister = 0x2F,
279 /// Read 32-bit Fast Boot Register (boot address and configuration)
280 ReadFastBootRegister = 0x16,
281 /// Write 32-bit Fast Boot Register
282 WriteFastBootRegister = 0x17,
283 /// Erase Fast Boot Register (disable fast boot feature)
284 EraseFastBootRegister = 0x18,
285 /// Set burst/wrap length for read operations (16/32/64 bytes)
286 SetBurstLength = 0xC0,
287 /// Enter 8K-bit secured OTP mode for programming unique identifiers
288 EnterSecuredOTP = 0xB1,
289 /// Exit secured OTP mode and return to main array access
290 ExitSecuredOTP = 0xC1,
291 /// Write Lock Register to control SPB protection mode
292 WriteLockRegister = 0x2C,
293 /// Read Lock Register status
294 ReadLockRegister = 0x2D,
295 /// Program Solid Protection Bit (SPB) for specified sector/block
296 WriteSPB = 0xE3,
297 /// Erase all Solid Protection Bits (SPB)
298 EraseSPB = 0xE4,
299 /// Read Solid Protection Bit (SPB) status for specified sector/block
300 ReadSPB = 0xE2,
301 /// Write Dynamic Protection Bit (DPB) for specified sector
302 WriteDPB = 0xE1,
303 /// Read Dynamic Protection Bit (DPB) status for specified sector
304 ReadDPB = 0xE0,
305 /// Read 64-bit password register (only in Solid Protection mode)
306 ReadPassword = 0x27,
307 /// Write 64-bit password register
308 WritePassword = 0x28,
309 /// Unlock SPB operations using 64-bit password
310 PasswordUnlock = 0x29,
311}
157 312
158 memory.reset_memory().await; 313/// OPI mode commands for MX25UW25645G flash memory
159 memory.enable_octo(); 314#[allow(dead_code)]
160 memory 315#[repr(u16)]
161 } 316enum OpiCommand {
317 // Array access commands
318 /// Read data using 8 I/O lines in STR mode with configurable dummy cycles (up to 200 MHz)
319 OctaRead = 0xEC13,
320 /// Read data using 8 I/O lines in DTR mode with configurable dummy cycles (up to 200 MHz)
321 OctaDTRRead = 0xEE11,
322 /// Program 1-256 bytes using 4-byte address and 8 I/O lines
323 PageProgram4B = 0x12ED,
324 /// Erase 4KB sector using 4-byte address
325 SectorErase4B = 0x21DE,
326 /// Erase 64KB block using 4-byte address
327 BlockErase4B = 0xDC23,
328 /// Erase entire chip (only if no blocks are protected)
329 ChipErase = 0x609F,
330
331 // Write Buffer Access commands
332 /// Read data from the 256-byte page buffer using 4-byte address
333 ReadBuffer = 0x25DA,
334 /// Initialize interruptible write-to-buffer sequence with 4-byte address
335 WriteBufferInitial = 0x22DD,
336 /// Continue writing data to buffer during interruptible sequence
337 WriteBufferContinue = 0x24DB,
338 /// Confirm and execute write operation from buffer to flash array
339 WriteBufferConfirm = 0x31CE,
340
341 // Device operation commands
342 /// Set Write Enable Latch (WEL) bit, required before write/program/erase operations
343 WriteEnable = 0x06F9,
344 /// Clear Write Enable Latch (WEL) bit, aborts write-to-buffer sequence
345 WriteDisable = 0x04FB,
346 /// Select write protection mode (BP mode or Advanced Sector Protection) - OTP bit
347 WriteProtectSelection = 0x6897,
348 /// Suspend ongoing program or erase operation to allow read from other banks
349 ProgramEraseSuspend = 0xB04F,
350 /// Resume suspended program or erase operation
351 ProgramEraseResume = 0x30CF,
352 /// Enter deep power-down mode for minimum power consumption
353 DeepPowerDown = 0xB946,
354 /// Exit deep power-down mode and return to standby
355 ReleaseFromDeepPowerDown = 0xAB54,
356 /// No operation, can terminate Reset Enable command
357 NoOperation = 0x00FF,
358 /// Enable reset operation (must precede Reset Memory command)
359 ResetEnable = 0x6699,
360 /// Reset device to power-on state, clears volatile settings
361 ResetMemory = 0x9966,
362 /// Protect all sectors using Dynamic Protection Bits (DPB)
363 GangBlockLock = 0x7E81,
364 /// Unprotect all sectors by clearing Dynamic Protection Bits (DPB)
365 GangBlockUnlock = 0x9867,
366
367 // Register Access commands
368 /// Read 3-byte device identification with 4-byte dummy address
369 ReadIdentification = 0x9F60,
370 /// Read Serial Flash Discoverable Parameters (SFDP) table with 4-byte address
371 ReadSFDP = 0x5AA5,
372 /// Read 8-bit Status Register with 4-byte dummy address
373 ReadStatusRegister = 0x05FA,
374 /// Read 8-bit Configuration Register with specific address (00000001h)
375 ReadConfigurationRegister = 0x15EA,
376 /// Write 8-bit Status Register with specific address (00000000h) or Configuration Register with address (00000001h)
377 WriteStatusConfigurationRegister = 0x01FE,
378 /// Read Configuration Register 2 from specified 4-byte address
379 ReadConfigurationRegister2 = 0x718E,
380 /// Write Configuration Register 2 to specified 4-byte address
381 WriteConfigurationRegister2 = 0x728D,
382 /// Read 8-bit Security Register with 4-byte dummy address
383 ReadSecurityRegister = 0x2BD4,
384 /// Write Security Register to set customer lock-down bit
385 WriteSecurityRegister = 0x2FD0,
386 /// Set burst/wrap length for read operations with 4-byte dummy address
387 SetBurstLength = 0xC03F,
388 /// Read 32-bit Fast Boot Register with 4-byte dummy address
389 ReadFastBootRegister = 0x16E9,
390 /// Write 32-bit Fast Boot Register with 4-byte dummy address
391 WriteFastBootRegister = 0x17E8,
392 /// Erase Fast Boot Register (disable fast boot feature)
393 EraseFastBootRegister = 0x18E7,
394 /// Enter 8K-bit secured OTP mode for programming unique identifiers
395 EnterSecuredOTP = 0xB14E,
396 /// Exit secured OTP mode and return to main array access
397 ExitSecuredOTP = 0xC13E,
398 /// Write Lock Register to control SPB protection mode with 4-byte dummy address
399 WriteLockRegister = 0x2CD3,
400 /// Read Lock Register status with 4-byte dummy address
401 ReadLockRegister = 0x2DD2,
402 /// Program Solid Protection Bit (SPB) for specified 4-byte address
403 WriteSPB = 0xE31C,
404 /// Erase all Solid Protection Bits (SPB)
405 EraseSPB = 0xE41B,
406 /// Read Solid Protection Bit (SPB) status for specified 4-byte address
407 ReadSPB = 0xE21D,
408 /// Write Dynamic Protection Bit (DPB) for specified 4-byte address
409 WriteDPB = 0xE11E,
410 /// Read Dynamic Protection Bit (DPB) status for specified 4-byte address
411 ReadDPB = 0xE01F,
412 /// Read 64-bit password register with 4-byte dummy address and 20 dummy cycles
413 ReadPassword = 0x27D8,
414 /// Write 64-bit password register with 4-byte dummy address
415 WritePassword = 0x28D7,
416 /// Unlock SPB operations using 64-bit password with 4-byte dummy address
417 PasswordUnlock = 0x29D6,
418}
162 419
163 async fn qpi_mode(&mut self) { 420impl<I: Instance> SpiFlashMemory<I> {
164 // Enter qpi mode 421 pub fn new(xspi: Xspi<'static, I, Blocking>) -> Self {
165 self.exec_command(0x38).await; 422 let mut memory = Self { xspi };
166 423
167 // Set read param 424 memory.reset_memory();
168 let transaction = TransferConfig { 425 memory
169 iwidth: XspiWidth::QUAD,
170 dwidth: XspiWidth::QUAD,
171 instruction: Some(0xC0),
172 ..Default::default()
173 };
174 self.enable_write().await;
175 self.xspi.blocking_write(&[0x30_u8], transaction).unwrap();
176 self.wait_write_finish();
177 } 426 }
178 427
179 pub async fn disable_mm(&mut self) { 428 pub fn disable_mm(&mut self) {
180 self.xspi.disable_memory_mapped_mode(); 429 self.xspi.disable_memory_mapped_mode();
181 } 430 }
182 431
183 pub async fn enable_mm(&mut self) { 432 pub fn enable_mm(&mut self) {
184 self.qpi_mode().await;
185
186 let read_config = TransferConfig { 433 let read_config = TransferConfig {
187 iwidth: XspiWidth::SING, 434 iwidth: XspiWidth::SING,
188 isize: AddressSize::_8bit, 435 isize: AddressSize::_8bit,
189 adwidth: XspiWidth::SING, 436 adwidth: XspiWidth::SING,
190 adsize: AddressSize::_24bit, 437 adsize: AddressSize::_32bit,
191 dwidth: XspiWidth::SING, 438 dwidth: XspiWidth::SING,
192 instruction: Some(CMD_READ as u32), 439 instruction: Some(SpiCommand::FastRead4B as u32),
193 dummy: DummyCycles::_8, 440 dummy: DummyCycles::_8,
194 ..Default::default() 441 ..Default::default()
195 }; 442 };
@@ -198,42 +445,28 @@ impl<I: Instance> FlashMemory<I> {
198 iwidth: XspiWidth::SING, 445 iwidth: XspiWidth::SING,
199 isize: AddressSize::_8bit, 446 isize: AddressSize::_8bit,
200 adwidth: XspiWidth::SING, 447 adwidth: XspiWidth::SING,
201 adsize: AddressSize::_24bit, 448 adsize: AddressSize::_32bit,
202 dwidth: XspiWidth::SING, 449 dwidth: XspiWidth::SING,
203 instruction: Some(CMD_WRITE_PG as u32), 450 instruction: Some(SpiCommand::PageProgram4B as u32),
204 dummy: DummyCycles::_0, 451 dummy: DummyCycles::_0,
205 ..Default::default() 452 ..Default::default()
206 }; 453 };
207 self.xspi.enable_memory_mapped_mode(read_config, write_config).unwrap(); 454 self.xspi.enable_memory_mapped_mode(read_config, write_config).unwrap();
208 } 455 }
209 456
210 fn enable_octo(&mut self) { 457 fn into_octo(mut self) -> OpiFlashMemory<I> {
211 let cr = self.read_cr(); 458 self.enable_opi_mode();
212 // info!("Read cr: {:x}", cr); 459 OpiFlashMemory { xspi: self.xspi }
213 self.write_cr(cr | 0x02);
214 // info!("Read cr after writing: {:x}", cr);
215 } 460 }
216 461
217 pub fn disable_octo(&mut self) { 462 fn enable_opi_mode(&mut self) {
218 let cr = self.read_cr(); 463 let cr2_0 = self.read_cr2(0);
219 self.write_cr(cr & (!(0x02))); 464 info!("Read CR2 at 0x0: {:x}", cr2_0);
220 } 465 self.enable_write();
221 466 self.write_cr2(0, cr2_0 | 0x01); // Set bit 0 to enable octo SPI in STR
222 async fn exec_command_4(&mut self, cmd: u8) {
223 let transaction = TransferConfig {
224 iwidth: XspiWidth::QUAD,
225 adwidth: XspiWidth::NONE,
226 // adsize: AddressSize::_24bit,
227 dwidth: XspiWidth::NONE,
228 instruction: Some(cmd as u32),
229 address: None,
230 dummy: DummyCycles::_0,
231 ..Default::default()
232 };
233 self.xspi.blocking_command(&transaction).unwrap();
234 } 467 }
235 468
236 async fn exec_command(&mut self, cmd: u8) { 469 fn exec_command(&mut self, cmd: u8) {
237 let transaction = TransferConfig { 470 let transaction = TransferConfig {
238 iwidth: XspiWidth::SING, 471 iwidth: XspiWidth::SING,
239 adwidth: XspiWidth::NONE, 472 adwidth: XspiWidth::NONE,
@@ -248,16 +481,14 @@ impl<I: Instance> FlashMemory<I> {
248 self.xspi.blocking_command(&transaction).unwrap(); 481 self.xspi.blocking_command(&transaction).unwrap();
249 } 482 }
250 483
251 pub async fn reset_memory(&mut self) { 484 pub fn reset_memory(&mut self) {
252 self.exec_command_4(CMD_ENABLE_RESET).await; 485 self.exec_command(SpiCommand::ResetEnable as u8);
253 self.exec_command_4(CMD_RESET).await; 486 self.exec_command(SpiCommand::ResetMemory as u8);
254 self.exec_command(CMD_ENABLE_RESET).await;
255 self.exec_command(CMD_RESET).await;
256 self.wait_write_finish(); 487 self.wait_write_finish();
257 } 488 }
258 489
259 pub async fn enable_write(&mut self) { 490 pub fn enable_write(&mut self) {
260 self.exec_command(CMD_WRITE_ENABLE).await; 491 self.exec_command(SpiCommand::WriteEnable as u8);
261 } 492 }
262 493
263 pub fn read_id(&mut self) -> [u8; 3] { 494 pub fn read_id(&mut self) -> [u8; 3] {
@@ -266,92 +497,64 @@ impl<I: Instance> FlashMemory<I> {
266 iwidth: XspiWidth::SING, 497 iwidth: XspiWidth::SING,
267 isize: AddressSize::_8bit, 498 isize: AddressSize::_8bit,
268 adwidth: XspiWidth::NONE, 499 adwidth: XspiWidth::NONE,
269 // adsize: AddressSize::_24bit,
270 dwidth: XspiWidth::SING, 500 dwidth: XspiWidth::SING,
271 instruction: Some(CMD_READ_ID as u32), 501 instruction: Some(SpiCommand::ReadIdentification as u32),
272 ..Default::default() 502 ..Default::default()
273 }; 503 };
274 // info!("Reading id: 0x{:X}", transaction.instruction);
275 self.xspi.blocking_read(&mut buffer, transaction).unwrap(); 504 self.xspi.blocking_read(&mut buffer, transaction).unwrap();
276 buffer 505 buffer
277 } 506 }
278 507
279 pub fn read_id_8(&mut self) -> [u8; 3] { 508 pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8]) {
280 let mut buffer = [0; 3];
281 let transaction: TransferConfig = TransferConfig {
282 iwidth: XspiWidth::OCTO,
283 isize: AddressSize::_16bit,
284 adwidth: XspiWidth::OCTO,
285 address: Some(0),
286 adsize: AddressSize::_32bit,
287 dwidth: XspiWidth::OCTO,
288 instruction: Some(CMD_READ_ID_OCTO as u32),
289 dummy: DummyCycles::_4,
290 ..Default::default()
291 };
292 info!("Reading id: {:#X}", transaction.instruction);
293 self.xspi.blocking_read(&mut buffer, transaction).unwrap();
294 buffer
295 }
296
297 pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8], use_dma: bool) {
298 let transaction = TransferConfig { 509 let transaction = TransferConfig {
299 iwidth: XspiWidth::SING, 510 iwidth: XspiWidth::SING,
300 adwidth: XspiWidth::SING, 511 adwidth: XspiWidth::SING,
301 adsize: AddressSize::_24bit, 512 adsize: AddressSize::_32bit,
302 dwidth: XspiWidth::SING, 513 dwidth: XspiWidth::SING,
303 instruction: Some(CMD_READ as u32), 514 instruction: Some(SpiCommand::FastRead4B as u32),
304 dummy: DummyCycles::_8, 515 dummy: DummyCycles::_8,
305 // dwidth: XspiWidth::QUAD,
306 // instruction: Some(CMD_QUAD_READ as u32),
307 // dummy: DummyCycles::_8,
308 address: Some(addr), 516 address: Some(addr),
309 ..Default::default() 517 ..Default::default()
310 }; 518 };
311 if use_dma { 519
312 self.xspi.blocking_read(buffer, transaction).unwrap(); 520 self.xspi.blocking_read(buffer, transaction).unwrap();
313 } else {
314 self.xspi.blocking_read(buffer, transaction).unwrap();
315 }
316 } 521 }
317 522
318 fn wait_write_finish(&mut self) { 523 fn wait_write_finish(&mut self) {
319 while (self.read_sr() & 0x01) != 0 {} 524 while (self.read_sr() & 0x01) != 0 {}
320 } 525 }
321 526
322 async fn perform_erase(&mut self, addr: u32, cmd: u8) { 527 fn perform_erase(&mut self, addr: u32, cmd: u8) {
323 let transaction = TransferConfig { 528 let transaction = TransferConfig {
324 iwidth: XspiWidth::SING, 529 iwidth: XspiWidth::SING,
325 adwidth: XspiWidth::SING, 530 adwidth: XspiWidth::SING,
326 adsize: AddressSize::_24bit, 531 adsize: AddressSize::_32bit,
327 dwidth: XspiWidth::NONE, 532 dwidth: XspiWidth::NONE,
328 instruction: Some(cmd as u32), 533 instruction: Some(cmd as u32),
329 address: Some(addr), 534 address: Some(addr),
330 dummy: DummyCycles::_0, 535 dummy: DummyCycles::_0,
331 ..Default::default() 536 ..Default::default()
332 }; 537 };
333 self.enable_write().await; 538 self.enable_write();
334 self.xspi.blocking_command(&transaction).unwrap(); 539 self.xspi.blocking_command(&transaction).unwrap();
335 self.wait_write_finish(); 540 self.wait_write_finish();
336 } 541 }
337 542
338 pub async fn erase_sector(&mut self, addr: u32) { 543 pub fn erase_sector(&mut self, addr: u32) {
339 self.perform_erase(addr, CMD_SECTOR_ERASE).await; 544 self.perform_erase(addr, SpiCommand::SectorErase4B as u8);
340 } 545 }
341 546
342 pub async fn erase_block_32k(&mut self, addr: u32) { 547 pub fn erase_block_64k(&mut self, addr: u32) {
343 self.perform_erase(addr, CMD_BLOCK_ERASE_32K).await; 548 self.perform_erase(addr, SpiCommand::BlockErase4B as u8);
344 } 549 }
345 550
346 pub async fn erase_block_64k(&mut self, addr: u32) { 551 pub fn erase_chip(&mut self) {
347 self.perform_erase(addr, CMD_BLOCK_ERASE_64K).await; 552 self.enable_write();
348 } 553 self.exec_command(SpiCommand::ChipErase as u8);
349 554 self.wait_write_finish();
350 pub async fn erase_chip(&mut self) {
351 self.exec_command(CMD_CHIP_ERASE).await;
352 } 555 }
353 556
354 async fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize, use_dma: bool) { 557 fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize) {
355 assert!( 558 assert!(
356 (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32, 559 (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32,
357 "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}", 560 "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}",
@@ -361,48 +564,43 @@ impl<I: Instance> FlashMemory<I> {
361 564
362 let transaction = TransferConfig { 565 let transaction = TransferConfig {
363 iwidth: XspiWidth::SING, 566 iwidth: XspiWidth::SING,
364 adsize: AddressSize::_24bit, 567 adsize: AddressSize::_32bit,
365 adwidth: XspiWidth::SING, 568 adwidth: XspiWidth::SING,
366 dwidth: XspiWidth::SING, 569 dwidth: XspiWidth::SING,
367 instruction: Some(CMD_WRITE_PG as u32), 570 instruction: Some(SpiCommand::PageProgram4B as u32),
368 // dwidth: XspiWidth::QUAD,
369 // instruction: Some(CMD_QUAD_WRITE_PG as u32),
370 address: Some(addr), 571 address: Some(addr),
371 dummy: DummyCycles::_0, 572 dummy: DummyCycles::_0,
372 ..Default::default() 573 ..Default::default()
373 }; 574 };
374 self.enable_write().await; 575 self.enable_write();
375 if use_dma { 576 self.xspi.blocking_write(buffer, transaction).unwrap();
376 self.xspi.blocking_write(buffer, transaction).unwrap();
377 } else {
378 self.xspi.blocking_write(buffer, transaction).unwrap();
379 }
380 self.wait_write_finish(); 577 self.wait_write_finish();
381 } 578 }
382 579
383 pub async fn write_memory(&mut self, addr: u32, buffer: &[u8], use_dma: bool) { 580 pub fn write_memory(&mut self, addr: u32, buffer: &[u8]) {
384 let mut left = buffer.len(); 581 let mut left = buffer.len();
385 let mut place = addr; 582 let mut place = addr;
386 let mut chunk_start = 0; 583 let mut chunk_start = 0;
387 584
388 while left > 0 { 585 while left > 0 {
389 let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize; 586 let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize;
390 let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left }; 587 let chunk_size = min(max_chunk_size, left);
391 let chunk = &buffer[chunk_start..(chunk_start + chunk_size)]; 588 let chunk = &buffer[chunk_start..(chunk_start + chunk_size)];
392 self.write_page(place, chunk, chunk_size, use_dma).await; 589 self.write_page(place, chunk, chunk_size);
393 place += chunk_size as u32; 590 place += chunk_size as u32;
394 left -= chunk_size; 591 left -= chunk_size;
395 chunk_start += chunk_size; 592 chunk_start += chunk_size;
396 } 593 }
397 } 594 }
398 595
596 // Note: read_register cannot be used to read the configuration register 2 since there is an
597 // address required for that read.
399 fn read_register(&mut self, cmd: u8) -> u8 { 598 fn read_register(&mut self, cmd: u8) -> u8 {
400 let mut buffer = [0; 1]; 599 let mut buffer = [0; 1];
401 let transaction: TransferConfig = TransferConfig { 600 let transaction: TransferConfig = TransferConfig {
402 iwidth: XspiWidth::SING, 601 iwidth: XspiWidth::SING,
403 isize: AddressSize::_8bit, 602 isize: AddressSize::_8bit,
404 adwidth: XspiWidth::NONE, 603 adwidth: XspiWidth::NONE,
405 adsize: AddressSize::_24bit,
406 dwidth: XspiWidth::SING, 604 dwidth: XspiWidth::SING,
407 instruction: Some(cmd as u32), 605 instruction: Some(cmd as u32),
408 address: None, 606 address: None,
@@ -410,39 +608,345 @@ impl<I: Instance> FlashMemory<I> {
410 ..Default::default() 608 ..Default::default()
411 }; 609 };
412 self.xspi.blocking_read(&mut buffer, transaction).unwrap(); 610 self.xspi.blocking_read(&mut buffer, transaction).unwrap();
413 // info!("Read w25q64 register: 0x{:x}", buffer[0]);
414 buffer[0] 611 buffer[0]
415 } 612 }
416 613
417 fn write_register(&mut self, cmd: u8, value: u8) { 614 pub fn read_sr(&mut self) -> u8 {
418 let buffer = [value; 1]; 615 self.read_register(SpiCommand::ReadStatusRegister as u8)
616 }
617
618 pub fn read_cr(&mut self) -> u8 {
619 self.read_register(SpiCommand::ReadConfigurationRegister as u8)
620 }
621
622 pub fn write_sr_cr(&mut self, sr: u8, cr: u8) {
623 let buffer = [sr, cr];
419 let transaction: TransferConfig = TransferConfig { 624 let transaction: TransferConfig = TransferConfig {
420 iwidth: XspiWidth::SING, 625 iwidth: XspiWidth::SING,
421 isize: AddressSize::_8bit, 626 isize: AddressSize::_8bit,
422 instruction: Some(cmd as u32), 627 instruction: Some(SpiCommand::WriteStatusConfigurationRegister as u32),
423 adsize: AddressSize::_24bit,
424 adwidth: XspiWidth::NONE, 628 adwidth: XspiWidth::NONE,
425 dwidth: XspiWidth::SING, 629 dwidth: XspiWidth::SING,
426 address: None, 630 address: None,
427 dummy: DummyCycles::_0, 631 dummy: DummyCycles::_0,
428 ..Default::default() 632 ..Default::default()
429 }; 633 };
634 self.enable_write();
635 self.xspi.blocking_write(&buffer, transaction).unwrap();
636 self.wait_write_finish();
637 }
638
639 pub fn read_cr2(&mut self, address: u32) -> u8 {
640 let mut buffer = [0; 1];
641 let transaction: TransferConfig = TransferConfig {
642 iwidth: XspiWidth::SING,
643 isize: AddressSize::_8bit,
644 instruction: Some(SpiCommand::ReadConfigurationRegister2 as u32),
645 adsize: AddressSize::_32bit,
646 adwidth: XspiWidth::SING,
647 dwidth: XspiWidth::SING,
648 address: Some(address),
649 dummy: DummyCycles::_0,
650 ..Default::default()
651 };
652 self.xspi.blocking_read(&mut buffer, transaction).unwrap();
653 buffer[0]
654 }
655
656 pub fn write_cr2(&mut self, address: u32, value: u8) {
657 let buffer = [value; 1];
658 let transaction: TransferConfig = TransferConfig {
659 iwidth: XspiWidth::SING,
660 isize: AddressSize::_8bit,
661 instruction: Some(SpiCommand::WriteConfigurationRegister2 as u32),
662 adsize: AddressSize::_32bit,
663 adwidth: XspiWidth::SING,
664 dwidth: XspiWidth::SING,
665 address: Some(address),
666 dummy: DummyCycles::_0,
667 ..Default::default()
668 };
430 self.xspi.blocking_write(&buffer, transaction).unwrap(); 669 self.xspi.blocking_write(&buffer, transaction).unwrap();
670 self.wait_write_finish();
671 }
672}
673
674impl<I: Instance> OpiFlashMemory<I> {
675 pub fn into_spi(mut self) -> SpiFlashMemory<I> {
676 self.disable_opi_mode();
677 SpiFlashMemory { xspi: self.xspi }
678 }
679
680 /// Disable OPI mode and return to SPI
681 pub fn disable_opi_mode(&mut self) {
682 // Clear SOPI and DOPI bits in CR2 volatile register
683 let cr2_0 = self.read_cr2(0x00000000);
684 self.write_cr2(0x00000000, cr2_0 & 0xFC); // Clear bits 0 and 1
685 }
686
687 /// Enable memory-mapped mode for OPI
688 pub fn enable_mm(&mut self) {
689 let read_config = TransferConfig {
690 iwidth: XspiWidth::OCTO,
691 isize: AddressSize::_16bit, // 2-byte command for OPI
692 adwidth: XspiWidth::OCTO,
693 adsize: AddressSize::_32bit,
694 dwidth: XspiWidth::OCTO,
695 instruction: Some(OpiCommand::OctaRead as u32),
696 dummy: DummyCycles::_20, // Default dummy cycles for OPI
697 ..Default::default()
698 };
699
700 let write_config = TransferConfig {
701 iwidth: XspiWidth::OCTO,
702 isize: AddressSize::_16bit,
703 adwidth: XspiWidth::OCTO,
704 adsize: AddressSize::_32bit,
705 dwidth: XspiWidth::OCTO,
706 instruction: Some(OpiCommand::PageProgram4B as u32),
707 dummy: DummyCycles::_0,
708 ..Default::default()
709 };
710
711 self.xspi.enable_memory_mapped_mode(read_config, write_config).unwrap();
712 }
713
714 pub fn disable_mm(&mut self) {
715 self.xspi.disable_memory_mapped_mode();
716 }
717
718 /// Execute OPI command (2-byte command)
719 fn exec_command(&mut self, cmd: OpiCommand) {
720 let transaction = TransferConfig {
721 iwidth: XspiWidth::OCTO,
722 isize: AddressSize::_16bit, // 2-byte command
723 adwidth: XspiWidth::NONE,
724 dwidth: XspiWidth::NONE,
725 instruction: Some(cmd as u32),
726 address: None,
727 dummy: DummyCycles::_0,
728 ..Default::default()
729 };
730 self.xspi.blocking_command(&transaction).unwrap();
731 }
732
733 /// Reset memory using OPI commands
734 pub fn reset_memory(&mut self) {
735 self.exec_command(OpiCommand::ResetEnable);
736 self.exec_command(OpiCommand::ResetMemory);
737 self.wait_write_finish();
431 } 738 }
432 739
740 /// Enable write using OPI command
741 pub fn enable_write(&mut self) {
742 self.exec_command(OpiCommand::WriteEnable);
743 }
744
745 /// Read device ID in OPI mode
746 pub fn read_id(&mut self) -> [u8; 3] {
747 let mut buffer = [0; 3];
748 let transaction = TransferConfig {
749 iwidth: XspiWidth::OCTO,
750 isize: AddressSize::_16bit,
751 adwidth: XspiWidth::OCTO,
752 adsize: AddressSize::_32bit,
753 dwidth: XspiWidth::OCTO,
754 instruction: Some(OpiCommand::ReadIdentification as u32),
755 address: Some(0x00000000), // Dummy address required
756 dummy: DummyCycles::_4,
757 ..Default::default()
758 };
759 self.xspi.blocking_read(&mut buffer, transaction).unwrap();
760 buffer
761 }
762
763 /// Read memory using OPI mode
764 pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8]) {
765 let transaction = TransferConfig {
766 iwidth: XspiWidth::OCTO,
767 isize: AddressSize::_16bit,
768 adwidth: XspiWidth::OCTO,
769 adsize: AddressSize::_32bit,
770 dwidth: XspiWidth::OCTO,
771 instruction: Some(OpiCommand::OctaRead as u32),
772 address: Some(addr),
773 dummy: DummyCycles::_20, // Default for 200MHz operation
774 ..Default::default()
775 };
776 self.xspi.blocking_read(buffer, transaction).unwrap();
777 }
778
779 /// Wait for write completion using OPI status read
780 fn wait_write_finish(&mut self) {
781 while (self.read_sr() & 0x01) != 0 {}
782 }
783
784 /// Perform erase operation using OPI command
785 fn perform_erase(&mut self, addr: u32, cmd: OpiCommand) {
786 let transaction = TransferConfig {
787 iwidth: XspiWidth::OCTO,
788 isize: AddressSize::_16bit,
789 adwidth: XspiWidth::OCTO,
790 adsize: AddressSize::_32bit,
791 dwidth: XspiWidth::NONE,
792 instruction: Some(cmd as u32),
793 address: Some(addr),
794 dummy: DummyCycles::_0,
795 ..Default::default()
796 };
797 self.enable_write();
798 self.xspi.blocking_command(&transaction).unwrap();
799 self.wait_write_finish();
800 }
801
802 /// Erase 4KB sector using OPI
803 pub fn erase_sector(&mut self, addr: u32) {
804 self.perform_erase(addr, OpiCommand::SectorErase4B);
805 }
806
807 /// Erase 64KB block using OPI
808 pub fn erase_block_64k(&mut self, addr: u32) {
809 self.perform_erase(addr, OpiCommand::BlockErase4B);
810 }
811
812 /// Erase entire chip using OPI
813 pub fn erase_chip(&mut self) {
814 self.enable_write();
815 self.exec_command(OpiCommand::ChipErase);
816 self.wait_write_finish();
817 }
818
819 /// Write single page using OPI
820 fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize) {
821 assert!(
822 (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32,
823 "write_page(): page write length exceeds page boundary (len = {}, addr = {:X})",
824 len,
825 addr
826 );
827
828 let transaction = TransferConfig {
829 iwidth: XspiWidth::OCTO,
830 isize: AddressSize::_16bit,
831 adwidth: XspiWidth::OCTO,
832 adsize: AddressSize::_32bit,
833 dwidth: XspiWidth::OCTO,
834 instruction: Some(OpiCommand::PageProgram4B as u32),
835 address: Some(addr),
836 dummy: DummyCycles::_0,
837 ..Default::default()
838 };
839 self.enable_write();
840 self.xspi.blocking_write(buffer, transaction).unwrap();
841 self.wait_write_finish();
842 }
843
844 /// Write memory using OPI (handles page boundaries)
845 pub fn write_memory(&mut self, addr: u32, buffer: &[u8]) {
846 let mut left = buffer.len();
847 let mut place = addr;
848 let mut chunk_start = 0;
849
850 while left > 0 {
851 let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize;
852 let chunk_size = min(max_chunk_size, left);
853 let chunk = &buffer[chunk_start..(chunk_start + chunk_size)];
854 self.write_page(place, chunk, chunk_size);
855 place += chunk_size as u32;
856 left -= chunk_size;
857 chunk_start += chunk_size;
858 }
859 }
860
861 /// Read register using OPI mode
862 fn read_register(&mut self, cmd: OpiCommand, dummy_addr: u32, dummy_cycles: DummyCycles) -> u8 {
863 let mut buffer = [0; 1];
864 let transaction = TransferConfig {
865 iwidth: XspiWidth::OCTO,
866 isize: AddressSize::_16bit,
867 adwidth: XspiWidth::OCTO,
868 adsize: AddressSize::_32bit,
869 dwidth: XspiWidth::OCTO,
870 instruction: Some(cmd as u32),
871 address: Some(dummy_addr),
872 dummy: dummy_cycles,
873 ..Default::default()
874 };
875 self.xspi.blocking_read(&mut buffer, transaction).unwrap();
876 buffer[0]
877 }
878
879 /// Read Status Register using OPI
433 pub fn read_sr(&mut self) -> u8 { 880 pub fn read_sr(&mut self) -> u8 {
434 self.read_register(CMD_READ_SR) 881 self.read_register(
882 OpiCommand::ReadStatusRegister,
883 0x00000000, // Dummy address
884 DummyCycles::_4,
885 )
435 } 886 }
436 887
888 /// Read Configuration Register using OPI
437 pub fn read_cr(&mut self) -> u8 { 889 pub fn read_cr(&mut self) -> u8 {
438 self.read_register(CMD_READ_CR) 890 self.read_register(
891 OpiCommand::ReadConfigurationRegister,
892 0x00000001, // Address for CR
893 DummyCycles::_4,
894 )
439 } 895 }
440 896
441 pub fn write_sr(&mut self, value: u8) { 897 /// Write Status/Configuration Register using OPI
442 self.write_register(CMD_WRITE_SR, value); 898 pub fn write_sr_cr(&mut self, sr: u8, cr: u8) {
899 let transaction = TransferConfig {
900 iwidth: XspiWidth::OCTO,
901 isize: AddressSize::_16bit,
902 adwidth: XspiWidth::OCTO,
903 adsize: AddressSize::_32bit,
904 dwidth: XspiWidth::OCTO,
905 instruction: Some(OpiCommand::WriteStatusConfigurationRegister as u32),
906 address: Some(0x00000000),
907 dummy: DummyCycles::_0,
908 ..Default::default()
909 };
910
911 self.enable_write();
912 self.xspi.blocking_write(&[sr, cr], transaction).unwrap();
913 self.wait_write_finish();
914 }
915
916 /// Read Configuration Register 2 using OPI
917 pub fn read_cr2(&mut self, address: u32) -> u8 {
918 let mut buffer = [0; 1];
919 let transaction = TransferConfig {
920 iwidth: XspiWidth::OCTO,
921 isize: AddressSize::_16bit,
922 adwidth: XspiWidth::OCTO,
923 adsize: AddressSize::_32bit,
924 dwidth: XspiWidth::OCTO,
925 instruction: Some(OpiCommand::ReadConfigurationRegister2 as u32),
926 address: Some(address),
927 dummy: DummyCycles::_4,
928 ..Default::default()
929 };
930 self.xspi.blocking_read(&mut buffer, transaction).unwrap();
931 buffer[0]
443 } 932 }
444 933
445 pub fn write_cr(&mut self, value: u8) { 934 /// Write Configuration Register 2 using OPI
446 self.write_register(CMD_WRITE_CR, value); 935 pub fn write_cr2(&mut self, address: u32, value: u8) {
936 let transaction = TransferConfig {
937 iwidth: XspiWidth::OCTO,
938 isize: AddressSize::_16bit,
939 adwidth: XspiWidth::OCTO,
940 adsize: AddressSize::_32bit,
941 dwidth: XspiWidth::OCTO,
942 instruction: Some(OpiCommand::WriteConfigurationRegister2 as u32),
943 address: Some(address),
944 dummy: DummyCycles::_0,
945 ..Default::default()
946 };
947
948 self.enable_write();
949 self.xspi.blocking_write(&[value], transaction).unwrap();
950 self.wait_write_finish();
447 } 951 }
448} 952}