diff --git a/rust/pm-grid/src/main.rs b/rust/pm-grid/src/main.rs index 559afb5..edcbe64 100644 --- a/rust/pm-grid/src/main.rs +++ b/rust/pm-grid/src/main.rs @@ -141,11 +141,19 @@ impl fatfs::Seek for FlashIo { } /// Write the blank PM_G-1 template over the metadata sectors (erases the leftover volume → empty). +/// One 4 KB sector per call — exactly the proven MSC write pattern (a multi-sector call is riskier). fn format_pmg1() { - let faddr = FILESYSTEM.as_ptr() as u32 & 0x00ff_ffff & !0xfff; // flash offset 0x100000 - cortex_m::interrupt::free(|_| unsafe { - rp2040_flash::flash::flash_range_erase_and_program(faddr, FAT_TEMPLATE, false); - }); + let base = FILESYSTEM.as_ptr() as u32 & 0x00ff_ffff & !0xfff; // flash offset 0x100000 + let sz = FS_BLOCK_SIZE as usize; + let sectors = FAT_TEMPLATE.len() / sz; + for s in 0..sectors { + let mut sector = [0u8; FS_BLOCK_SIZE as usize]; + sector.copy_from_slice(&FAT_TEMPLATE[s * sz..(s + 1) * sz]); + let faddr = base + (s as u32) * FS_BLOCK_SIZE; + cortex_m::interrupt::free(|_| unsafe { + rp2040_flash::flash::flash_range_erase_and_program(faddr, §or, false); + }); + } } /// Mount the drive; if it isn't a "PM_G-1"-labelled FAT, format it. Then read programs.json (if any) @@ -1538,7 +1546,7 @@ fn main() -> ! { // heap for track-format (Vec/String). The Pico has 264 KB SRAM; 24 KB is plenty for a track. { use core::mem::MaybeUninit; - const HEAP_SIZE: usize = 24 * 1024; + const HEAP_SIZE: usize = 96 * 1024; // fatfs + owned set lists + track parse (Pico has 264 KB) static mut HEAP_MEM: [MaybeUninit; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE]; unsafe { HEAP.init(core::ptr::addr_of_mut!(HEAP_MEM) as usize, HEAP_SIZE) } } @@ -1578,11 +1586,6 @@ fn main() -> ! { let mut mtx = Matrix::new(i2c, &mut delay); - // Read the drive's set lists (and (re)format it to "PM_G-1" if it isn't ours) — BEFORE USB - // setup, so the one-time format flash-write can't disrupt enumeration. - let user_setlists = read_user_setlists(); - info!("boot: {} total set list(s)", SETLISTS.len() + user_setlists.len()); - // --- USB-MIDI: the Scroll Pack has no speaker, so clicks play through the host (the editor's // "Device audio"). We send a GM note-on per lane hit on channel 10. --- let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new( @@ -1622,6 +1625,12 @@ fn main() -> ! { let mut btn_y = pins.gpio15.into_pull_up_input(); let now_us = || timer.get_counter().ticks() as i64; + // Read the drive's set lists (and (re)format it to "PM_G-1" if it isn't ours). Done AFTER the + // splash so the screen shows life first and a FAT/flash problem can't leave it black. + info!("fat: reading drive..."); + let user_setlists = read_user_setlists(); + info!("boot: {} total set list(s)", SETLISTS.len() + user_setlists.len()); + let mut app = App::new(now_us() * 1000, user_setlists); info!("groove: bpm={} lanes={}", app.tempo, app.track.lanes.len());