Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add example / improve docs for use (particularly with RTIC) #5

Open
ryankurte opened this issue Apr 18, 2022 · 0 comments
Open

Add example / improve docs for use (particularly with RTIC) #5

ryankurte opened this issue Apr 18, 2022 · 0 comments
Labels
documentation Improvements or additions to documentation good first issue Good for newcomers

Comments

@ryankurte
Copy link
Owner

extract / add example for use with nrf52, perhaps other platforms?

flash Control wrapper provides DynamicFile over 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:

#[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
    ...
}
@ryankurte ryankurte added documentation Improvements or additions to documentation good first issue Good for newcomers labels Apr 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

1 participant