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"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byte-slice-cast 1.2.2",
|
"byte-slice-cast 1.2.2",
|
||||||
|
"byteorder",
|
||||||
"cortex-m",
|
"cortex-m",
|
||||||
"cortex-m-rt",
|
"cortex-m-rt",
|
||||||
"critical-section",
|
"critical-section",
|
||||||
|
|
|
@ -49,5 +49,9 @@ pio = "0.2.1"
|
||||||
rand = { version = "0.8.5", default-features = false }
|
rand = { version = "0.8.5", default-features = false }
|
||||||
embedded-sdmmc = "0.7.0"
|
embedded-sdmmc = "0.7.0"
|
||||||
|
|
||||||
|
# Dependencies of embedded-sdmmc that I need to use directly
|
||||||
|
byteorder = {version = "1", default-features = false}
|
||||||
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = 2
|
debug = 2
|
||||||
|
|
124
src/main.rs
124
src/main.rs
|
@ -6,6 +6,7 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
|
use byteorder::ByteOrder;
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_embedded_hal::SetConfig;
|
use embassy_embedded_hal::SetConfig;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
|
@ -13,6 +14,7 @@ use embassy_rp::spi::Spi;
|
||||||
use embassy_rp::{gpio, spi};
|
use embassy_rp::{gpio, spi};
|
||||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||||
use embedded_sdmmc::sdcard::{DummyCsPin, SdCard};
|
use embedded_sdmmc::sdcard::{DummyCsPin, SdCard};
|
||||||
|
use embedded_sdmmc::{Block, BlockCount, BlockDevice, BlockIdx, FatVolume, VolumeIdx, VolumeType};
|
||||||
use gpio::{Level, Output};
|
use gpio::{Level, Output};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
@ -52,35 +54,129 @@ async fn main(_spawner: Spawner) {
|
||||||
let mut config = spi::Config::default();
|
let mut config = spi::Config::default();
|
||||||
config.frequency = 16_000_000;
|
config.frequency = 16_000_000;
|
||||||
sdcard.spi(|dev| dev.bus_mut().set_config(&config)).ok();
|
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.
|
// 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.
|
// 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());
|
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).
|
// Try and access Volume 0 (i.e. the first partition).
|
||||||
// The volume object holds information about the filesystem on that volume.
|
// 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));
|
info!("Volume 0: {:?}", defmt::Debug2Format(&volume0));
|
||||||
|
|
||||||
// Open the root directory (mutably borrows from the volume).
|
// Open the root directory (mutably borrows from the volume).
|
||||||
let mut root_dir = volume0.open_root_dir().unwrap();
|
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.
|
// Open a file called "MY_FILE.TXT" in the root directory
|
||||||
let mut my_file = root_dir
|
// This mutably borrows the directory.
|
||||||
.open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::Mode::ReadOnly)
|
let mut my_file = root_dir
|
||||||
.unwrap();
|
.open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::Mode::ReadOnly)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Print the contents of the file
|
// Print the contents of the file
|
||||||
while !my_file.is_eof() {
|
while !my_file.is_eof() {
|
||||||
let mut buf = [0u8; 32];
|
let mut buf = [0u8; 32];
|
||||||
if let Ok(n) = my_file.read(&mut buf) {
|
if let Ok(n) = my_file.read(&mut buf) {
|
||||||
info!("{:a}", buf[..n]);
|
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