Coder Social home page Coder Social logo

embedded-sdmmc-rs's Introduction

Embedded SD/MMC crates.io Documentation

This crate is intended to allow you to read/write files on a FAT formatted SD card on your Rust Embedded device, as easily as using the SdFat Arduino library. It is written in pure-Rust, is #![no_std] and does not use alloc or collections to keep the memory footprint low. In the first instance it is designed for readability and simplicity over performance.

Using the crate

You will need something that implements the BlockDevice trait, which can read and write the 512-byte blocks (or sectors) from your card. If you were to implement this over USB Mass Storage, there's no reason this crate couldn't work with a USB Thumb Drive, but we only supply a BlockDevice suitable for reading SD and SDHC cards over SPI.

// Build an SD Card interface out of an SPI device, a chip-select pin and the delay object
let sdcard = embedded_sdmmc::SdCard::new(sdmmc_spi, sdmmc_cs, delay);
// Get the card size (this also triggers card initialisation because it's not been done yet)
println!("Card size is {} bytes", sdcard.num_bytes()?);
// Now let's look for volumes (also known as partitions) on our block device.
// To do this we need a Volume Manager. It will take ownership of the block device.
let mut volume_mgr = embedded_sdmmc::VolumeManager::new(sdcard, time_source);
// Try and access Volume 0 (i.e. the first partition).
// The volume object holds information about the filesystem on that volume.
let mut volume0 = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0))?;
println!("Volume 0: {:?}", volume0);
// Open the root directory (mutably borrows from the volume).
let mut root_dir = volume0.open_root_dir()?;
// Open a file called "MY_FILE.TXT" in the root directory
// This mutably borrows the directory.
let mut my_file = root_dir.open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::Mode::ReadOnly)?;
// Print the contents of the file, assuming it's in ISO-8859-1 encoding
while !my_file.is_eof() {
    let mut buffer = [0u8; 32];
    let num_read = my_file.read(&mut buffer)?;
    for b in &buffer[0..num_read] {
        print!("{}", *b as char);
    }
}

Open directories and files

By default the VolumeManager will initialize with a maximum number of 4 open directories, files and volumes. This can be customized by specifying the MAX_DIR, MAX_FILES and MAX_VOLUMES generic consts of the VolumeManager:

// Create a volume manager with a maximum of 6 open directories, 12 open files, and 4 volumes (or partitions)
let mut cont: VolumeManager<_, _, 6, 12, 4> = VolumeManager::new_with_limits(block, time_source);

Supported features

  • Open files in all supported methods from an open directory
  • Open an arbitrary number of directories and files
  • Read data from open files
  • Write data to open files
  • Close files
  • Delete files
  • Iterate root directory
  • Iterate sub-directories
  • Log over defmt or the common log interface (feature flags).

No-std usage

This repository houses no examples for no-std usage, however you can check out the following examples:

Todo List (PRs welcome!)

  • Create new dirs
  • Delete (empty) directories
  • Handle MS-DOS /path/foo/bar.txt style paths.

Changelog

The changelog has moved to CHANGELOG.md

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

embedded-sdmmc-rs's People

Contributors

anytimetraveler avatar bsodmike avatar ceigel avatar dcz-self avatar diondokter avatar eldruin avatar elpiel avatar ftilde avatar fu5ha avatar gauteh avatar glbsalazar avatar jacobrosenthal avatar jakezhu9 avatar jannic avatar jbeaurivage avatar jonathanpallant avatar mdarrik avatar nereuxofficial avatar olback avatar orsinium avatar ostenning avatar peterkrull avatar qiuchengxuan avatar thalesfragoso avatar thejpster avatar wassasin avatar x37v avatar yanorei32 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

embedded-sdmmc-rs's Issues

SdMmcSpi::acquire should consume self, not use &mut ref

Currently SdMmcSpi::acquire returns a BlockSpi object which contains a mutable reference to the SdMmcSpi. This is a construct that is very hard to work with. I'm reading parts of a file inside an interrupt, so I have to keep alive both a SdMmcSpi and a BlockSpi. Moreover the SdMmcSpi has to be placed in a static variable so that it is not moved once the BlockSpi is constructed. This is quite hard to use.
I believe it would be easier if the SdMmcSpi would be moved inside BlockSpi.

Offer open-file type of function that receives a DirEntry

I am trying to iterate through a directory and open all files with a certain extension. There is no way to use the DirEntry received from iterate_dir as an input to open_file_in_dir. Ideally there would be a counterpart of open_file_in_dir which receives a DirEntry. One extra advantage of such a function is that it wouldn't be used with Mode::ReadWriteCreate, which means the volume can be a non-mutable reference.
Also the ShortFileName doesn't support retrieving the file extension.

How to read the LFN for a file?

Apologies if this is already in an example somewhere but I’ve not spotted it.

I need to somehow read the large file name for a file. I don’t mind getting an iter back of all the short file names for the file & having to compose the long file name myself, if that fits better with no_std & how FAT works.

I see the is_lfn property but I’ve not yet found anywhere that comes back as true - even the files which end in ~1.

Ideally I want to retrieve a file using the large file name (but I can see how that could be out of scope)

Make default busy-wait delay much shorter

Using a sdcard with a low-frequency STM32L0, the default 100000 spins was much too long, I reduced it to 100. (With that, everything works perfectly, thanks very much for the library!)

IMO if we're busy-waiting anyway, there shouldn't be a downside to polling more often also on faster CPUs?

Consider switching to `embedded_hal::blocking::spi` traits

Disclaimer: I'm not actively using this crate right now. I was made aware of this potential problem by @Maldus512 (in Rahix/shared-bus#18) and wanted to start a discussion about it here.

Currently, the SdMmcSpi type is based on the FullDuplex trait from embedded-hal. The contract for FullDuplex has requirements on the order of calls to its methods which makes it impossible to allow sound bus sharing in the way shared-bus works. Quoting my comment in Rahix/shared-bus#18 with the reason why:

[...] the FullDuplex trait unfortunately has an API that cannot be safely shared in the way shared-bus solves sharing. The reason is that there is an implicit dependency between calls to send() and read() which could be broken if multiple bus users interweave these calls. For example:

    User 1           User 2
      |                |
    send()             |
      |                |
      |              send() - - # Now received byte from first send is discarded (or worse)
      |                |
    read()  - - - - - - - - - - # Reads data from second write
                       |
                     read() - - # HAL-API violation!!

To allow bus sharing with SdMmcSpi, I would suggest switching embedded-sdmmc to use the traits from embedded_hal::blocking::spi instead as they do not suffer this problem and can be used for bus sharing more safely (though still not concurrently across multiple execution contexts¹).

If I am not mistaken, the only place where this change would need to happen would be this method:

/// Send one byte and receive one byte.
fn transfer(&self, out: u8) -> Result<u8, Error> {
let mut spi = self.spi.borrow_mut();
block!(spi.send(out)).map_err(|_e| Error::Transport)?;
block!(spi.read()).map_err(|_e| Error::Transport)
}

By using embedded_hal::blocking::spi::Transfer instead, I think it could just look like this:

    /// Send one byte and receive one byte.
    fn transfer(&self, out: u8) -> Result<u8, Error> {
        let mut spi = self.spi.borrow_mut();
        spi.transfer(&mut [out])
            .map(|b| *b[0])
            .map_err(|_e| Error::Transport)
    }

(Of course, by doing a larger change, this could be done more efficiently).

Need a way to unsafely assume the card is already initialised

I have a use-case where I can't leave the result of acquire() lying around, because I'd need to store both it, and the parent object it holds a reference to, in the same structure and that's not allowed in Rust because the structure might move.

I'd like an unsafe API to make a BlockSpi object (e.g. unsafe pub fn acquire_without_init(&mut self) , without actually doing any card initialisation. It will then be on me to spot when the card is inserted and ejected, and perform actual initialisation with the acquire() method on insertion.

Split crate to two

This crate are great but it consist two functionalities: fat file system interface and implementation and sd/mcc card high level driver. I think we need to split this crate to two - one for fat fs and one for sd card abstraction. Thanks.

Suggestion: FAT filesystem impl as its own crate.

Firstly, thank you for this repo. It saved me a ton of time. 👍🏾 (I'm posting this as an issue as I couldn't find a discussions tab)

I'd like to make a suggestion - can we split the FAT filesystem impl into its own crate as the current implementation is pretty modular and it doesn't take a lot to turn it into a standalone crate. I wrote a bare-metal EMMC driver for the raspberry-pi 4 using embedded-sdmmc-rs (sans the SdMmcSpi controller).

  • Reason: rpi4 now has an emmc2-controller with dedicated pins connecting it to the on-board microSD slot and this slot isn't accessible via SPI.

I think a standalone no_std fat-fs crate would be easier to work with when adding fat-support to block devices driven by other (non-spi) controllers.

read and write: critical section?

Hi,

I have put reading and writing a file in a critical section by wrapping them in free on a cortex-m MCU. Is this necessary? How long interrupts are acceptable in the middle of e.g. a write or read operation? The writes take so long time that they are causing issues with other stuff (FIFO overruns).

Best regards,
Gaute

Question - raw read/write sdmmc support.

Hi

I'm working on rustBoot. Its an arch-agnostic secure bootloader.

rustBoot performs firmware updates by swapping (raw) contents of 2 pre-designated flash partitions (like say boot and update). It supports Cortex-M boards for now but I plan to add support for Cortex-A boards which usually rely on an sd-card for booting.

So, just wanted to check before I go out and re-invent something that already exists - does embedded-sdmmc-rs support raw read/write operations apart from reads+writes for FAT-filesystem based partitions?

From a first glance at this repo, I'm presuming the erase operation works with & without a file-system - right.

Logging is always active

It would be a nice feature to have the option to disable the logging.
For me, it gets in the way of what I actually want logged and it slows down the library a lot.

Delay and busy-waiting

I was looking to improve the Delay struct used for busy-waiting when waiting for the card to do some work.

I wanted to discuss:

  1. How we can improve the current Delay which acts more like a Retry counter than a delay.
  2. Rely on embedded-hal crates for the delay waiting instead of reading from volatile:
  • support the embedded-hal (0.2) timer::CountDown
  • support the embedded-hal (1.0.0-alpha.10) delay::DelayUs
  • support the embedded-hal-async delay::DelayUs

This issue is also part of my efforts to improve speed, reliability and introduce async interface in this upstream repo.

Also related to #80

How do I keep a reference to the SPI peripheral?

Hello,
I'm working on a custom embedded board with an SPI-interfaced microSD card.
I've tried using this library to write logs on the card and it works using the SdMmcSpi interface. Unfortunately the SD card is not the only device with which I should communicate via SPI and the SdMmcSpi struct requires ownership of the embedded_hal peripheral object.

What this means for me is that I cannot have a Controller and communicate with other SPI devices in the same program. Is there a way to keep a reference to the SPI network after I'm done with the SD card?

I've noticed that there is a spi method for the SdMmcSpi struct that returns a mutable reference to the network, but it would be quite cumbersome (and counterintuitive) to keep the SPI reference inside the emmc Controller and pass it around to other devices.

Note that I'm far from an expert in Rust, so I might be missing something obvious here (I apologize if that's the case).

Reinitialization support

Hey, I'm using this library in conjunction with an SDIO SDMMC controller and a removable SDCard.

I would like to be able to reinitialize this library if the user removes the SDCard and reinserts it.

What I am doing is:

  1. Initialize everything, the SDMMC and this library, with SDCard present ✅
  2. Remove the SDCard, and then reinsert it (or another card) ✅
  3. Reinitialize the SDMMC controller ✅
  4. Reinitialize this library ❌

I need to refresh the handles for the Volume, e.g:

let mut volume = self.controller.get_volume(VolumeIdx(0)).unwrap();

But I then encounter the error:

panicked at 'called Result::unwrap() on an Err value: FormatError("Invalid MBR signature")', src/drivers/sdcard.rs:117:67

Proposed solution:

Either allow the Controller and volumes to be reinitialized, or provide a means to relinquish the block device so that the Controller can be reinitialized from scratch.

Kind regards

Multiple opened files with empty content triggers `DirAlreadyOpen`

Trying to open multiple empty files at the same time with Controller::open_file_in_dir in Mode different than ReadWriteCreate triggers open_dir_entry causes a DirAlreadyOpen error.

Is returning DirAlreadyOpen a correct response here as well? It seems that it's going over opened files and yet returns DirAlreadyOpen?

Add a block cache

It would improve performance if we had a write-through block cache, particularly in the cluster allocation loop or for multiple small writes (as we'd avoid the repeated reads).

The user would need to supply the storage, and we just need a basic structure to track which sectors are cached (e.g. a HashMap). Maybe using heapless?

Default values for const generic parameters MAX_DIRS, MAX_FILES, don't work as expected.

Commit 566f202 added two const generic parameters MAX_DIRS and MAX_FILES to Controller.

Those parameters have default values equal to the values used before, and the new docs say: "By default the Controller will initialize with a maximum number of 4 open directories and files. This can be customized by specifying the MAX_DIR and MAX_FILES generic consts of the Controller"

However, the default values don't work as expected. The following code causes a compile failure:

let mut cont = Controller::new(block, DummyTimesource::default());
error[E0282]: type annotations needed for `embedded_sdmmc::Controller<BlockSpi<'_, rp_pico::rp2040_hal::Spi<rp_pico::rp2040_hal::spi::Enabled, SPI0, 8>, rp_pico::rp2040_hal::gpio::Pin<Gpio5, rp_pico::rp2040_hal::gpio::Output<rp_pico::rp2040_hal::gpio::PushPull>>>, DummyTimesource, MAX_DIRS, MAX_FILES>`
   --> boards/rp-pico/examples/pico_spi_sd_card.rs:276:9
    |
276 |     let mut cont = Controller::new(block, DummyTimesource::default());
    |         ^^^^^^^^
    |
help: consider giving `cont` an explicit type, where the the value of const parameter `MAX_DIRS` is specified
    |
276 |     let mut cont: embedded_sdmmc::Controller<BlockSpi<'_, rp_pico::rp2040_hal::Spi<rp_pico::rp2040_hal::spi::Enabled, SPI0, 8>, rp_pico::rp2040_hal::gpio::Pin<Gpio5, rp_pico::rp2040_hal::gpio::Output<rp_pico::rp2040_hal::gpio::PushPull>>>, DummyTimesource, MAX_DIRS, MAX_FILES> = Controller::new(block, DummyTimesource::default());
    |                 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

For more information about this error, try `rustc --explain E0282`.

(This was noticed in rp-hal, see this ticket for context.)

There is a blog post which nicely explains why this happens: https://gankra.github.io/blah/defaults-affect-inference/#default-type-parameters

Add a flush API

An open file is risky because the data is still in RAM. Add a flush API which is like a close and a reopen.

LFN support doesn't handle emoji

The LFN code assumes the code points are all valid UTF-16 and not surrogate pairs exist. This may not be a valid assumption. We should do a proper UTF-16 to UTF-8 conversion.

log pulls in std: how do I disable the std feature on the log crate?

Optionally add default-features = false to log in you Cargo.toml.

Is this even possible?

embedded-sdmmc-rs on  develop [$] via 🦀 v1.59.0-nightly
❯ cargo build --target=thumbv7em-none-eabihf
   Compiling log v0.4.14
error[E0463]: can't find crate for `std`
  |
  = note: the `thumbv7em-none-eabihf` target may not support the standard library
  = note: `std` is required by `log` because it does not declare `#![no_std]`
  = help: consider building the standard library from source with `cargo build -Zbuild-std`

For more information about this error, try `rustc --explain E0463`.
error: could not compile `log` due to previous error

Support for asynchronous I/O

I am currently experimenting with the nRF52 and using the embassy project. I intend to use an SD Card in the project. However, this library does not appear to support asynchronous APIs. This includes two levels:

  1. DMA related SPI store/fetch operations
  • You give it a tx+rx buffer, it at some point interrupts you once everything has been sent/received
  • Allows the user/application to do other work in the meantime
  • Currently unsupported by the SdMmcSpi struct as it solely uses byte-by-byte synchronous send/receive methods
  1. Asynchronous block devices
  • Most disk I/O is inherently asynchronous as the CPU waits for the device
  • In a majority of use cases microcontrollers might not have much else to do
  • In some cases, other, time-critical tasks need to run (e.g. handling wireless transmissions)

My question here is: Would you be interested in integrating support for asynchronous SPI backends?
Follow-up question: If yes, do you have any thoughts on how to do that besides just "implementing everything twice"

I can definitely see both arguments; for integrating it to have a unified place to look for when using SD cards; against stuffing everything into one crate even though it is basically its own thing (sadly, we can't simply pick and choose between async/sync APIs like we can with traits/generics).

Acquire SD card

I've come to realise that in version 0.5 in order to acquire the SD card you need to call check_init or acquire but it's not exposed from SdCardInner.
Instead you need to call either num_bytes or directly try to read/write to the SD card in order to initialize it.
It would be nice to be able to expose acquire or better the check_init function in SdCard in order to be able to initialize it upfront before the first read/write takes place.

Intermittent BorrowMutError

I'm using this crate in a GPS logging project https://gitlab.com/TheZoq2/sailgps/-/blob/master/src/main.rs which was working fine until yesterday when I started making some unrelated changes (https://gitlab.com/TheZoq2/sailgps/-/commit/ccd1b9b880fb7d3cfada5375badb2700b2b84094). After this change, the device seems to panic after a few minutes of running with

already borrowed: BorrowMutError', /home/frans/.cargo/registry/src/github.com-
1ecc6299db9ec823/embedded-sdmmc-0.3.0/src/sdmmc.rs:416:32

As far as I can tell, this is comming from RefCell, and if I understand it correctly, this error would happen if two mutable borrows happen at the same time. However, since I'm using RTIC, that should be impossible, since my sdmmc struct is a RTIC resource, right?

Could this be a bug in this lib? (I think I may also be fairly close to filling up my RAM on the device, so that might also be an issue)

Stream from file

I see its possible to read an entire file into a buffer, but my application requires streaming from an SDCard to reduce the amount of onboard memory usage.

Is this a welcome feature? I could take a look at implementing this myself and creating a PR when ready

File `starting_cluster` has a value of zero within the `open_files`

I've found an issue when trying to close files and open them again. Basically what ends up happening is that upon opening the file, the starting_cluster of the File initialized to zero, and then this zero value is subsequently set on the open_files.

At some point the starting_cluster value of the File is adjusted, but the value stored within open_files is not.

Which in turn causes the close_file function within the controller to not close the file.

If you attempt to open/close files multiple times (beyond the specified MAX_FILES) value, the library returns an Error.

I'm trying to figure out a solution to this at the moment. Any help is appreciated. Thanks

Simplify dir calcs

We do this a lot. Can it be simplfied or made into a function:

                let mut first_dir_block_num = match dir.cluster {
                    ClusterId::ROOT_DIR => self.lba_start + fat16_info.first_root_dir_block,
                    _ => self.cluster_to_block(dir.cluster),
                };
                let dir_size = match dir.cluster {
                    ClusterId::ROOT_DIR => {
                        let len_bytes =
                            u32::from(fat16_info.root_entries_count) * OnDiskDirEntry::LEN_U32;
                        BlockCount::from_bytes(len_bytes)
                    }
                    _ => BlockCount(u32::from(self.blocks_per_cluster)),
                };

Explore interior mutability

Now that critical-section is a thing, maybe we can consider interior mutability:

  • Volume can hold an &VolumeManager
  • Directory and File can hold an &Volume
let volume = volume_mgr.get_volume(VolumeIdx(0))?;
let root_dir = volume.open_root_dir()?;
let file = root_dir.open("HELLO.TXT")?;
let mut buffer = [0u8; 64];
let contents = file.read_to_buffer(&mut buffer)?;

confusion with directory documentation

A couple notes/questions:

  1. open_root_dir and open_dir both indicate: Open a directory. You can then read the directory entries in a random order using get_directory_entry. But get_directory_entry doesn't exist in the code AFAIK. I see find_directory_entry and iterate_dir so I assume this must just be left over cruft?

  2. open_root_dir and open_dir return a Directory, the docs for close_dir indicate:
    Close a directory. You cannot perform operations on an open directory and so must close it if you want to do something with it. but close_dir consumes a directory so how do you use it after its closed? For instance, how would you supply a directory to open_file_in_dir ?

Make functions that modify underlying state through SPI receive `&mut self` instead of `&self`

Currently, BlockDevice::read and BlockDevice::write (and practically all functions in SdMmcSpi and BlockSpi) receive &self.

Why is this done?

In my opinion, they should receive &mut self, so that responsibility of choosing what method of resource sharing a user wants is up to the user. Issues such as #37 could easily be avoided, and would also make more sense logically: writeing something is clearly modifying something, so why does it not need mutable access?

Especially in embedded settings (which this crate is intended for), where being interrupted while having a borrow is quite possible, I don't quite understand why this design choice was made.

I'm willing to contribute a design proposal and PRs to make this change, if it is deemed that this change makes sense.

This issue is, in essence, the same as #8, but for slightly different reasons. I hope that the reasons mentioned there may have disappeared in the mean time (I can't find a concrete example of why it was dismissed back then). If these issues persist, I would propose that we clearly document that SdMmcSpi makes use of RefCells internally.

Remove dependencies on no_std

I discovered a strange behavior when I add embedded-sdmmc crate. I created a new embedded project (https://github.com/ceigel/sdmmc-test) with command cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart
I added the embedded-sdmmc crate and mfrc522 (this one just as control) as dependencies. The project compiles fine. When I add bindgen as a dev dependency, I get the following error:

Updating crates.io index Compiling byteorder v1.3.4 Compiling log v0.4.8 error[E0463]: can't find crate forstd| = note: thethumbv7m-none-eabi` target may not be installed

error: aborting due to previous error

For more information about this error, try rustc --explain E0463.
error: could not compile log.
warning: build failed, waiting for other jobs to finish...
error: build failed`

I wanted to use bindgen to generate bindings to a C++ library during compile time, but it seems that I need to do that part manually.

To me this is very strange behavior and I wonder if it will break even after I remove my dev-dependency to bindgen.

Re-add the File methods

They'll need to take a VolumeManager reference, but maybe this will work better?

// Like this
let is_eof = volume_manager.file_eof(file)?;
// or like this
let is_eof = file.eof(&mut VolumeManager)?;

State::Idle should be State::Initialized

Idle vs Initialized state

Accordingly to this answer on StackExchange, the current State::Idle that we set after the initialisation process is actually an Initialised state.

https://electronics.stackexchange.com/a/602106

Clock initialise speed

It also seems that this initialisation process should be made in 100 - 400 kHz SPI clock speed (acquire) and should later be increased to the running clock speed.

I suggest that we at least include this in the documentation and later improve (if possible) the crate to handle the clock speed.
Since there isn't any Config for the spi interface in embedded-hal (0.2) I see documentation as the only option for now.

README example

One of the examples in the readme (the first one) is not correct since it wraps a SDMmcSpi inside itself:

let mut spi_dev = embedded_sdmmc::SdMmcSpi::new(embedded_sdmmc::SdMmcSpi::new(sdmmc_spi, sdmmc_cs), time_source);

Since the Controller is created a few lines below, it seems that this line should simply be:

let mut spi_dev = embedded_sdmmc::SdMmcSpi::new(sdmmc_spi, sdmmc_cs);

SdMmcSpi is not thread-safe

As far as I can tell, it's possible that multiple immutable references are held to a single SdMmcSpi object and because the read and write methods accept &self rather than &mut self, they can be run concurrently using interrupt handlers or async/await. This will obviously not work when SPI bytes get mixed. I suggest making any method that requires SPI communication accept &mut self to ensure at compile time that access to it is limited to one at a time. I suggest doing the same for the methods of the BlockDevice trait as most implementations will require it.

Please let me know if I misunderstand something or if I should go ahead and create a PR for this.

Refactor to avoid code duplication

Right now there is a lot of code duplication between Fat32Volume and Fat16Volume types. Since the filesystem type is only known at runtime, everything gets compiled in. It might be better to refactor both into a single type and do the matching internally instead of outside, the downside is that not everything translates between the two, it would need more fields with Option in the struct and probably some more methods would have to be made failable.

Version release

@thejpster there hasn't been a release on crates.io for quite a long time. Some features on the HEAD, such as deletion of files is not accessible for those using the crate directly from the crates.io.

Is it possible to schedule a new release soon?

Kind regards

interoperability with esp_rs

I could not find any information about the microcontrollers I can use this crate with. The other repositories in this organization seem to be aimed at cortex-m series microcontrollers. Can I use this with esp32 using the esp_rs crate?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.