Open ryankurte opened 2 years ago
extract / add example for use with nrf52, perhaps other platforms?
flash Control wrapper provides DynamicFile over NVMC:
DynamicFile
NVMC
use core::cell::UnsafeCell; use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; use nrf52840_hal::nvmc::Nvmc; use nrf52840_pac::NVMC; const FILE_START: usize = 0x00080000; const FILE_LEN: usize = 256 * 1024; pub struct FlashControl { nvm: UnsafeCell<Nvmc<NVMC>>, len: usize, } unsafe impl Sync for FlashControl {} impl FlashControl { /// Create a new flash controller from device [`NVMC`] pub fn new(nvmc: NVMC) -> Self { // Chunk of memory available to flash control // TODO: work out how to extract segments from linker file..? let section = unsafe { core::slice::from_raw_parts_mut(FILE_START as *const u8 as *mut u8, FILE_LEN) }; Self{ nvm: UnsafeCell::new(Nvmc::new(nvmc, section)), len: FILE_LEN, } } } /// GhostFAT dynamic file implementation for our Flash controller impl <const BLOCK_SIZE: usize> ghostfat::DynamicFile<BLOCK_SIZE> for FlashControl { fn len(&self) -> usize { self.len } fn read_chunk(&self, index: usize, buff: &mut [u8]) -> usize { defmt::info!("Read file chunk: 0x{:02x} index: 0x{:08x} len: {}", index, index * BLOCK_SIZE, buff.len()); let res = unsafe { (*self.nvm.get()).read((index * BLOCK_SIZE) as u32, buff) }; // Read data if let Err(e) = res { defmt::error!("Failed to read index: 0x{:08x} len: {}: {:?}", index, Nvmc::<NVMC>::ERASE_SIZE, defmt::Debug2Format(&e)); return 0; } return buff.len() } fn write_chunk(&mut self, index: usize, data: &[u8]) -> usize { defmt::info!("Write file index: 0x{:08x}", index); // Erase on writes to the first address in the block // TODO: this assumes chunk writes are always aligned / ordered... // i _think_ but am not _sure_ this is correct if index % Nvmc::<NVMC>::ERASE_SIZE == 0 { if let Err(e) = self.nvm.get_mut().erase((index * BLOCK_SIZE) as u32, Nvmc::<NVMC>::ERASE_SIZE as u32) { defmt::error!("Failed to erase index: 0x{:08x} len: {}: {:?}", index, Nvmc::<NVMC>::ERASE_SIZE, defmt::Debug2Format(&e)); return 0; } } // Write data if let Err(e) = self.nvm.get_mut().write((index * BLOCK_SIZE) as u32, data) { defmt::error!("Failed to write index: 0x{:08x} len: {}: {:?}", index, Nvmc::<NVMC>::ERASE_SIZE, defmt::Debug2Format(&e)); return 0; } return data.len(); } }
which can then be used with rtic, usb_device, usb_scsi:
rtic
usb_device
usb_scsi
#[init(local = [ ... CLOCKS: Option<Clocks<ExternalOscillator, Internal, LfOscStopped>> = None, USB_ALLOCATOR: Option<UsbBusAllocator<Usbd<UsbPeripheral<'static>>>> = None, FILES: Option<[File<'static>; 2]> = None, FLASH: Option<FlashControl> = None, ])] fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { // Setup USB allocator *cx.local.USB_ALLOCATOR = Some(Usbd::new(UsbPeripheral::new(periph.USBD, &clocks))); let usb_bus = cx.local.USB_ALLOCATOR.as_ref().unwrap(); ... // Setup files *cx.local.FLASH = Some(FlashControl::new(periph.NVMC)); *cx.local.FILES = Some([ File::new_ro("a.txt", b"12345\r\n"), File::new_dyn("b.bin", cx.local.FLASH.as_mut().unwrap()), ]); ... // Setup block device let block_dev = GhostFat::new(cx.local.FILES.as_mut().unwrap(), Default::default()); let usb_store = Scsi::new(&usb_bus, 64, block_dev, "V", "P", "0.1"); // TODO: start periodic (~1kHz) poll on usb_dev via task ... }
extract / add example for use with nrf52, perhaps other platforms?
flash Control wrapper provides
DynamicFile
overNVMC
:which can then be used with
rtic
,usb_device
,usb_scsi
: