Read volume label from SD
This commit is contained in:
parent
07a57d9b1d
commit
02b4c12d5d
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -490,6 +490,7 @@ name = "embassy-rp-skeleton"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byte-slice-cast 1.2.2",
|
||||
"byteorder",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"critical-section",
|
||||
|
|
|
@ -49,5 +49,9 @@ pio = "0.2.1"
|
|||
rand = { version = "0.8.5", default-features = false }
|
||||
embedded-sdmmc = "0.7.0"
|
||||
|
||||
# Dependencies of embedded-sdmmc that I need to use directly
|
||||
byteorder = {version = "1", default-features = false}
|
||||
|
||||
|
||||
[profile.release]
|
||||
debug = 2
|
||||
|
|
104
src/main.rs
104
src/main.rs
|
@ -6,6 +6,7 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use byteorder::ByteOrder;
|
||||
use defmt::*;
|
||||
use embassy_embedded_hal::SetConfig;
|
||||
use embassy_executor::Spawner;
|
||||
|
@ -13,6 +14,7 @@ use embassy_rp::spi::Spi;
|
|||
use embassy_rp::{gpio, spi};
|
||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||
use embedded_sdmmc::sdcard::{DummyCsPin, SdCard};
|
||||
use embedded_sdmmc::{Block, BlockCount, BlockDevice, BlockIdx, FatVolume, VolumeIdx, VolumeType};
|
||||
use gpio::{Level, Output};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
|
@ -52,21 +54,27 @@ async fn main(_spawner: Spawner) {
|
|||
let mut config = spi::Config::default();
|
||||
config.frequency = 16_000_000;
|
||||
sdcard.spi(|dev| dev.bus_mut().set_config(&config)).ok();
|
||||
info!("here");
|
||||
|
||||
// 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, DummyTimesource());
|
||||
info!("here");
|
||||
{
|
||||
let device = volume_mgr.device();
|
||||
let info = read_volume_info(device, VolumeIdx(0)).unwrap();
|
||||
info!("Volume 0: name: {:?}", defmt::Debug2Format(&info));
|
||||
}
|
||||
|
||||
// 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)).unwrap();
|
||||
let mut volume0 = volume_mgr
|
||||
.open_volume(embedded_sdmmc::VolumeIdx(0))
|
||||
.unwrap();
|
||||
info!("Volume 0: {:?}", defmt::Debug2Format(&volume0));
|
||||
|
||||
// Open the root directory (mutably borrows from the volume).
|
||||
let mut root_dir = volume0.open_root_dir().unwrap();
|
||||
|
||||
{
|
||||
// Open a file called "MY_FILE.TXT" in the root directory
|
||||
// This mutably borrows the directory.
|
||||
let mut my_file = root_dir
|
||||
|
@ -80,7 +88,95 @@ async fn main(_spawner: Spawner) {
|
|||
info!("{:a}", buf[..n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
let mut my_file = root_dir
|
||||
.open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::Mode::ReadWriteAppend)
|
||||
.unwrap();
|
||||
|
||||
loop {}
|
||||
my_file.write(b"Another one\n").unwrap();
|
||||
}
|
||||
|
||||
info!("Program end")
|
||||
}
|
||||
|
||||
pub fn read_volume_info<D>(
|
||||
block_device: &mut D,
|
||||
volume_idx: VolumeIdx,
|
||||
) -> Result<FatVolume, embedded_sdmmc::Error<D::Error>>
|
||||
where
|
||||
D: BlockDevice,
|
||||
{
|
||||
use byteorder::LittleEndian;
|
||||
use embedded_sdmmc::Error;
|
||||
const PARTITION1_START: usize = 446;
|
||||
const PARTITION2_START: usize = PARTITION1_START + PARTITION_INFO_LENGTH;
|
||||
const PARTITION3_START: usize = PARTITION2_START + PARTITION_INFO_LENGTH;
|
||||
const PARTITION4_START: usize = PARTITION3_START + PARTITION_INFO_LENGTH;
|
||||
const FOOTER_START: usize = 510;
|
||||
const FOOTER_VALUE: u16 = 0xAA55;
|
||||
const PARTITION_INFO_LENGTH: usize = 16;
|
||||
const PARTITION_INFO_STATUS_INDEX: usize = 0;
|
||||
const PARTITION_INFO_TYPE_INDEX: usize = 4;
|
||||
const PARTITION_INFO_LBA_START_INDEX: usize = 8;
|
||||
const PARTITION_INFO_NUM_BLOCKS_INDEX: usize = 12;
|
||||
/// Marker for a FAT32 partition. Sometimes also use for FAT16 formatted
|
||||
/// partitions.
|
||||
const PARTITION_ID_FAT32_LBA: u8 = 0x0C;
|
||||
/// Marker for a FAT16 partition with LBA. Seen on a Raspberry Pi SD card.
|
||||
const PARTITION_ID_FAT16_LBA: u8 = 0x0E;
|
||||
/// Marker for a FAT16 partition. Seen on a card formatted with the official
|
||||
/// SD-Card formatter.
|
||||
const PARTITION_ID_FAT16: u8 = 0x06;
|
||||
/// Marker for a FAT32 partition. What Macosx disk utility (and also SD-Card formatter?)
|
||||
/// use.
|
||||
const PARTITION_ID_FAT32_CHS_LBA: u8 = 0x0B;
|
||||
|
||||
let (part_type, lba_start, num_blocks) = {
|
||||
let mut blocks = [Block::new()];
|
||||
block_device
|
||||
.read(&mut blocks, BlockIdx(0), "read_mbr")
|
||||
.map_err(Error::DeviceError)?;
|
||||
let block = &blocks[0];
|
||||
// We only support Master Boot Record (MBR) partitioned cards, not
|
||||
// GUID Partition Table (GPT)
|
||||
if LittleEndian::read_u16(&block[FOOTER_START..FOOTER_START + 2]) != FOOTER_VALUE {
|
||||
return Err(Error::FormatError("Invalid MBR signature"));
|
||||
}
|
||||
let partition = match volume_idx {
|
||||
VolumeIdx(0) => &block[PARTITION1_START..(PARTITION1_START + PARTITION_INFO_LENGTH)],
|
||||
VolumeIdx(1) => &block[PARTITION2_START..(PARTITION2_START + PARTITION_INFO_LENGTH)],
|
||||
VolumeIdx(2) => &block[PARTITION3_START..(PARTITION3_START + PARTITION_INFO_LENGTH)],
|
||||
VolumeIdx(3) => &block[PARTITION4_START..(PARTITION4_START + PARTITION_INFO_LENGTH)],
|
||||
_ => {
|
||||
return Err(Error::NoSuchVolume);
|
||||
}
|
||||
};
|
||||
// Only 0x80 and 0x00 are valid (bootable, and non-bootable)
|
||||
if (partition[PARTITION_INFO_STATUS_INDEX] & 0x7F) != 0x00 {
|
||||
return Err(Error::FormatError("Invalid partition status"));
|
||||
}
|
||||
let lba_start = LittleEndian::read_u32(
|
||||
&partition[PARTITION_INFO_LBA_START_INDEX..(PARTITION_INFO_LBA_START_INDEX + 4)],
|
||||
);
|
||||
let num_blocks = LittleEndian::read_u32(
|
||||
&partition[PARTITION_INFO_NUM_BLOCKS_INDEX..(PARTITION_INFO_NUM_BLOCKS_INDEX + 4)],
|
||||
);
|
||||
(
|
||||
partition[PARTITION_INFO_TYPE_INDEX],
|
||||
BlockIdx(lba_start),
|
||||
BlockCount(num_blocks),
|
||||
)
|
||||
};
|
||||
match part_type {
|
||||
PARTITION_ID_FAT32_CHS_LBA
|
||||
| PARTITION_ID_FAT32_LBA
|
||||
| PARTITION_ID_FAT16_LBA
|
||||
| PARTITION_ID_FAT16 => {
|
||||
let volume = embedded_sdmmc::fat::parse_volume(block_device, lba_start, num_blocks)?;
|
||||
let VolumeType::Fat(fat) = volume;
|
||||
Ok(fat)
|
||||
}
|
||||
_ => Err(Error::FormatError("Partition type not supported")),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue