Skip to content

Commit 034459e

Browse files
jonathanpallantthejpster
authored andcommitted
Can read blocks from SD card.
1 parent cc4849b commit 034459e

4 files changed

Lines changed: 115 additions & 61 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ shared-bus = "0.2"
5151
# Gets us compare-swap atomic operations
5252
atomic-polyfill = "1.0.2"
5353
# SD Card driver
54-
embedded-sdmmc = { version = "0.4", default-features = false, features = ["defmt-log"] }
54+
embedded-sdmmc = { git = "https://github.com/rust-embedded-community/embedded-sdmmc-rs.git", branch="more-api-cleanups", default-features = false, features = ["defmt-log"] }
55+
# embedded-sdmmc = { version = "0.4", default-features = false, features = ["defmt-log"] }
5556

5657
[[bin]]
5758
name = "neotron-pico-bios"

src/main.rs

Lines changed: 59 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub static BOOT2_FIRMWARE: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
4848
pub mod mcp23s17;
4949
pub mod mutex;
5050
pub mod rtc;
51+
pub mod sdcard;
5152
pub mod vga;
5253

5354
// -----------------------------------------------------------------------------
@@ -127,6 +128,8 @@ enum CardState {
127128
struct CardInfo {
128129
/// Number of blocks on the SD card
129130
num_blocks: u64,
131+
/// Type of card
132+
card_type: embedded_sdmmc::sdcard::CardType
130133
}
131134

132135
/// All the hardware we use on the Pico
@@ -1197,63 +1200,21 @@ impl Hardware {
11971200
fn sdcard_poll(&mut self) {
11981201
match self.card_state {
11991202
CardState::Uninitialised => {
1200-
// Init the card here
1201-
use embedded_sdmmc::BlockDevice;
1202-
struct FakeSpi<'a>(&'a mut Hardware);
1203-
struct FakeCs();
1204-
static IS_CS_LOW: AtomicBool = AtomicBool::new(false);
1205-
impl<'a> embedded_hal::blocking::spi::Transfer<u8> for FakeSpi<'a> {
1206-
type Error = core::convert::Infallible;
1207-
fn transfer<'w>(
1208-
&mut self,
1209-
words: &'w mut [u8],
1210-
) -> Result<&'w [u8], Self::Error> {
1211-
if IS_CS_LOW.load(Ordering::SeqCst) {
1212-
defmt::trace!("SD out: {:?}", words);
1213-
self.0.with_bus_cs(1, |spi, _buffer| {
1214-
spi.transfer(words).unwrap();
1215-
});
1216-
defmt::trace!("SD in: {:?}", words);
1217-
Ok(words)
1218-
} else {
1219-
// Select a slot we don't use so the SD card won't be activated
1220-
self.0.with_bus_cs(7, |spi, _buffer| {
1221-
spi.transfer(words).unwrap();
1222-
});
1223-
Ok(words)
1224-
}
1225-
}
1226-
}
1227-
impl embedded_hal::digital::v2::OutputPin for FakeCs {
1228-
type Error = core::convert::Infallible;
1229-
fn set_low(&mut self) -> Result<(), Self::Error> {
1230-
IS_CS_LOW.store(true, Ordering::SeqCst);
1231-
Ok(())
1232-
}
1233-
1234-
fn set_high(&mut self) -> Result<(), Self::Error> {
1235-
IS_CS_LOW.store(true, Ordering::SeqCst);
1236-
Ok(())
1237-
}
1238-
}
12391203
// Downclock SPI to 100 kHz
12401204
// hw.spi_bus.set_baudrate(hw.clocks, todo!());
1241-
let spi = FakeSpi(self);
1242-
let cs = FakeCs();
1243-
let mut spi_interface = embedded_sdmmc::SdMmcSpi::new(spi, cs);
1244-
let num_blocks = match spi_interface.acquire() {
1245-
Ok(card) => {
1246-
defmt::info!("Found card size!");
1247-
card.num_blocks()
1248-
}
1249-
Err(e) => {
1250-
defmt::warn!("Failed to acquire SD card: {:?}", e);
1251-
Err(e)
1252-
}
1253-
};
1254-
if let Ok(num_blocks) = num_blocks {
1205+
use embedded_sdmmc::BlockDevice;
1206+
let spi = sdcard::FakeSpi(self);
1207+
let cs = sdcard::FakeCs();
1208+
let delayer = sdcard::FakeDelayer();
1209+
let sdcard = embedded_sdmmc::SdCard::new(spi, cs, delayer);
1210+
// Talk to the card to trigger a scan if its type
1211+
let num_blocks = sdcard.num_blocks();
1212+
let card_type = sdcard.get_card_type();
1213+
defmt::info!("Found card size {:?} blocks, type {:?}", num_blocks, card_type);
1214+
if let (Ok(num_blocks), Some(card_type)) = (num_blocks, card_type) {
12551215
self.card_state = CardState::Online(CardInfo {
12561216
num_blocks: num_blocks.0 as u64,
1217+
card_type
12571218
});
12581219
}
12591220
// Bring SPI clock back up again
@@ -1983,12 +1944,52 @@ pub extern "C" fn block_write(
19831944
/// There are no requirements on the alignment of `data` but if it is
19841945
/// aligned, the BIOS may be able to use a higher-performance code path.
19851946
pub extern "C" fn block_read(
1986-
_device: u8,
1987-
_block: common::block_dev::BlockIdx,
1988-
_num_blocks: u8,
1989-
_data: common::ApiBuffer,
1947+
device: u8,
1948+
block: common::block_dev::BlockIdx,
1949+
num_blocks: u8,
1950+
data: common::ApiBuffer,
19901951
) -> common::Result<()> {
1991-
common::Result::Err(common::Error::Unimplemented)
1952+
use embedded_sdmmc::BlockDevice;
1953+
if data.data_len != usize::from(num_blocks) * 512 {
1954+
return common::Result::Err(common::Error::UnsupportedConfiguration(0));
1955+
}
1956+
match device {
1957+
0 => {
1958+
let mut lock = HARDWARE.lock();
1959+
let hw = lock.as_mut().unwrap();
1960+
hw.sdcard_poll();
1961+
let info = match &hw.card_state {
1962+
CardState::Online(info) => {
1963+
info.clone()
1964+
}
1965+
_ => return common::Result::Err(common::Error::NoMediaFound)
1966+
};
1967+
let spi = sdcard::FakeSpi(hw);
1968+
let cs = sdcard::FakeCs();
1969+
let delayer = sdcard::FakeDelayer();
1970+
let sdcard = embedded_sdmmc::SdCard::new(spi, cs, delayer);
1971+
unsafe {
1972+
sdcard.mark_card_as_init(info.card_type);
1973+
}
1974+
let blocks = unsafe {
1975+
core::slice::from_raw_parts_mut(data.data as *mut embedded_sdmmc::Block, data.data_len / 512)
1976+
};
1977+
let start_block_idx = embedded_sdmmc::BlockIdx(block.0 as u32);
1978+
match sdcard.read(blocks, start_block_idx, "bios") {
1979+
Ok(_) => {
1980+
common::Result::Ok(())
1981+
}
1982+
Err(e) => {
1983+
defmt::warn!("SD error reading {}: {:?}", block.0, e);
1984+
common::Result::Err(common::Error::DeviceError(0))
1985+
}
1986+
}
1987+
}
1988+
_ => {
1989+
// Nothing else supported by this BIOS
1990+
common::Result::Err(common::Error::InvalidDevice)
1991+
}
1992+
}
19921993
}
19931994

19941995
/// Verify one or more sectors on a block device (that is read them and

src/sdcard.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//! SD Card support
2+
3+
use atomic_polyfill::{AtomicBool, Ordering};
4+
5+
use super::Hardware;
6+
7+
pub(crate) struct FakeSpi<'a>(pub(crate) &'a mut Hardware);
8+
9+
pub(crate) struct FakeCs();
10+
11+
pub(crate) struct FakeDelayer();
12+
13+
static IS_CS_LOW: AtomicBool = AtomicBool::new(false);
14+
15+
impl<'a> embedded_hal::blocking::spi::Transfer<u8> for FakeSpi<'a> {
16+
type Error = core::convert::Infallible;
17+
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
18+
if IS_CS_LOW.load(Ordering::SeqCst) {
19+
defmt::debug!("SD out: {:02x}", words);
20+
self.0.with_bus_cs(1, |spi, _buffer| {
21+
spi.transfer(words).unwrap();
22+
});
23+
defmt::debug!("SD: {:02x}", words);
24+
Ok(words)
25+
} else {
26+
// Select a slot we don't use so the SD card won't be activated
27+
self.0.with_bus_cs(7, |spi, _buffer| {
28+
spi.transfer(words).unwrap();
29+
});
30+
Ok(words)
31+
}
32+
}
33+
}
34+
35+
impl embedded_hal::digital::v2::OutputPin for FakeCs {
36+
type Error = core::convert::Infallible;
37+
fn set_low(&mut self) -> Result<(), Self::Error> {
38+
IS_CS_LOW.store(true, Ordering::SeqCst);
39+
Ok(())
40+
}
41+
42+
fn set_high(&mut self) -> Result<(), Self::Error> {
43+
IS_CS_LOW.store(true, Ordering::SeqCst);
44+
Ok(())
45+
}
46+
}
47+
48+
impl embedded_hal::blocking::delay::DelayUs<u8> for FakeDelayer {
49+
fn delay_us(&mut self, us: u8) {
50+
// It doesn't have to be accurate. Just within an order of magnitude is fine.
51+
cortex_m::asm::delay(u32::from(us) * 150)
52+
}
53+
}

0 commit comments

Comments
 (0)