#![no_std]
#![no_main]
use core::fmt::Write;
use rpi_hal::dma::Dma;
use rpi_hal::halt;
use rpi_hal::mailbox::Mailbox;
use rpi_hal::pac;
use rpi_hal::sd::{Block, Error, Sd};
use rpi_hal::timer::Timer;
use rpi_hal::uart::Uart;
const RUN_BLOCKS: usize = 8;
const RUN_WRITE_TEST: bool = true;
const WRITE_TEST_BLOCK: u32 = 0x0010_0000;
#[repr(C, align(64))]
struct Blocks([Block; RUN_BLOCKS]);
static mut PIO_BUF: Blocks = Blocks([[0; 512]; RUN_BLOCKS]);
static mut DMA_BUF: Blocks = Blocks([[0; 512]; RUN_BLOCKS]);
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
let peripherals = unsafe { pac::Peripherals::steal() };
let mut uart = Uart::init(&peripherals.GPIO, peripherals.UART0);
let _ = writeln!(uart, "PANIC: {info}");
halt();
}
#[no_mangle]
pub extern "C" fn kmain() -> ! {
let peripherals = unsafe { pac::Peripherals::steal() };
let mut uart = Uart::init(&peripherals.GPIO, peripherals.UART0);
let timer = Timer::new(peripherals.SYSTMR);
let mut mailbox = Mailbox::new(peripherals.VCMAILBOX);
let _ = writeln!(uart, "initializing SD card...");
let sd = match Sd::init(&peripherals.GPIO, peripherals.EMMC, &mut mailbox, &timer) {
Ok(sd) => sd,
Err(e) => {
let _ = writeln!(uart, "SD init failed: {e:?}");
halt();
}
};
let _ = writeln!(
uart,
"SD card ready ({}, {}-bit bus)",
if sd.high_capacity() {
"SDHC/SDXC"
} else {
"SDSC"
},
if sd.four_bit_bus() { 4 } else { 1 }
);
let mut dma = Dma::new();
let mut channel = dma.channel(5).expect("channel 5 available");
let pio = unsafe { &mut *core::ptr::addr_of_mut!(PIO_BUF) };
let dma_buf = unsafe { &mut *core::ptr::addr_of_mut!(DMA_BUF) };
if let Err(e) = sd.read_blocks(0, &mut pio.0, &timer) {
let _ = writeln!(uart, "polled multi-block read failed: {e:?}");
halt();
}
if let Err(e) = sd.read_blocks_dma(0, &mut dma_buf.0, &mut channel, &timer) {
let _ = writeln!(uart, "DMA multi-block read failed: {e:?}");
halt();
}
let mismatches = pio
.0
.as_flattened()
.iter()
.zip(dma_buf.0.as_flattened())
.filter(|(a, b)| a != b)
.count();
if mismatches == 0 {
let _ = writeln!(
uart,
"read PASS: {RUN_BLOCKS} blocks agree between the polled and DMA paths"
);
} else {
let _ = writeln!(uart, "read FAIL: {mismatches} byte(s) differ between paths");
}
let block0 = &pio.0[0];
let _ = writeln!(
uart,
"block 0 signature (510-511): {:02x} {:02x}{}",
block0[510],
block0[511],
if block0[510] == 0x55 && block0[511] == 0xaa {
" -- matches 0x55 0xAA"
} else {
" -- not 0x55 0xAA (unpartitioned card, or blank region)"
}
);
if RUN_WRITE_TEST {
write_round_trip(&sd, &mut channel, pio, dma_buf, &timer, &mut uart);
}
let _ = writeln!(uart, "done -- halting");
halt();
}
fn write_round_trip(
sd: &Sd,
channel: &mut rpi_hal::dma::Channel,
original: &mut Blocks,
scratch: &mut Blocks,
timer: &Timer,
uart: &mut Uart,
) {
if let Err(e) = sd.read_blocks(WRITE_TEST_BLOCK, &mut original.0, timer) {
let _ = writeln!(
uart,
"write test: initial read failed: {e:?} (card untouched)"
);
return;
}
for (dst, src) in scratch
.0
.as_flattened_mut()
.iter_mut()
.zip(original.0.as_flattened())
{
*dst = !*src;
}
let polled_write = sd.write_blocks(WRITE_TEST_BLOCK, &scratch.0, timer);
let polled_verify = sd
.read_blocks(WRITE_TEST_BLOCK, &mut scratch.0, timer)
.map(|()| {
scratch
.0
.as_flattened()
.iter()
.zip(original.0.as_flattened())
.all(|(read, orig)| *read == !*orig)
});
let dma_write = sd.write_blocks_dma(WRITE_TEST_BLOCK, &original.0, channel, timer);
let dma_verify = sd
.read_blocks(WRITE_TEST_BLOCK, &mut scratch.0, timer)
.map(|()| scratch.0.as_flattened() == original.0.as_flattened());
report_write(uart, "polled write_blocks", polled_write, polled_verify);
report_write(
uart,
"DMA write_blocks_dma (restore)",
dma_write,
dma_verify,
);
}
fn report_write(
uart: &mut Uart,
label: &str,
write: Result<(), Error>,
verify: Result<bool, Error>,
) {
let _ = match (write, verify) {
(Err(e), _) => writeln!(uart, "{label} FAIL: write errored: {e:?}"),
(Ok(()), Err(e)) => writeln!(uart, "{label} FAIL: verify read errored: {e:?}"),
(Ok(()), Ok(true)) => writeln!(uart, "{label} PASS: read-back matched"),
(Ok(()), Ok(false)) => {
writeln!(
uart,
"{label} FAIL: read-back did not match what was written"
)
}
};
}