pub mod proto;
use crate::{trace, Block, BlockCount, BlockDevice, BlockIdx};
use core::cell::RefCell;
use proto::*;
use crate::{debug, warn};
pub struct SdCard<SPI, DELAYER>
where
SPI: embedded_hal::spi::SpiDevice<u8>,
DELAYER: embedded_hal::delay::DelayNs,
{
inner: RefCell<SdCardInner<SPI, DELAYER>>,
}
impl<SPI, DELAYER> SdCard<SPI, DELAYER>
where
SPI: embedded_hal::spi::SpiDevice<u8>,
DELAYER: embedded_hal::delay::DelayNs,
{
pub fn new(spi: SPI, delayer: DELAYER) -> SdCard<SPI, DELAYER> {
Self::new_with_options(spi, delayer, AcquireOpts::default())
}
pub fn new_with_options(
spi: SPI,
delayer: DELAYER,
options: AcquireOpts,
) -> SdCard<SPI, DELAYER> {
SdCard {
inner: RefCell::new(SdCardInner {
spi,
delayer,
card_type: None,
options,
}),
}
}
pub fn spi<T, F>(&self, func: F) -> T
where
F: FnOnce(&mut SPI) -> T,
{
let mut inner = self.inner.borrow_mut();
func(&mut inner.spi)
}
pub fn num_bytes(&self) -> Result<u64, Error> {
let mut inner = self.inner.borrow_mut();
inner.check_init()?;
inner.num_bytes()
}
pub fn erase_single_block_enabled(&self) -> Result<bool, Error> {
let mut inner = self.inner.borrow_mut();
inner.check_init()?;
inner.erase_single_block_enabled()
}
pub fn mark_card_uninit(&self) {
let mut inner = self.inner.borrow_mut();
inner.card_type = None;
}
pub fn get_card_type(&self) -> Option<CardType> {
let mut inner = self.inner.borrow_mut();
inner.check_init().ok()?;
inner.card_type
}
pub unsafe fn mark_card_as_init(&self, card_type: CardType) {
let mut inner = self.inner.borrow_mut();
inner.card_type = Some(card_type);
}
}
impl<SPI, DELAYER> BlockDevice for SdCard<SPI, DELAYER>
where
SPI: embedded_hal::spi::SpiDevice<u8>,
DELAYER: embedded_hal::delay::DelayNs,
{
type Error = Error;
fn read(&self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), Self::Error> {
let mut inner = self.inner.borrow_mut();
debug!("Read {} blocks @ {}", blocks.len(), start_block_idx.0,);
inner.check_init()?;
inner.read(blocks, start_block_idx)
}
fn write(&self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error> {
let mut inner = self.inner.borrow_mut();
debug!("Writing {} blocks @ {}", blocks.len(), start_block_idx.0);
inner.check_init()?;
inner.write(blocks, start_block_idx)
}
fn num_blocks(&self) -> Result<BlockCount, Self::Error> {
let mut inner = self.inner.borrow_mut();
inner.check_init()?;
inner.num_blocks()
}
}
struct SdCardInner<SPI, DELAYER>
where
SPI: embedded_hal::spi::SpiDevice<u8>,
DELAYER: embedded_hal::delay::DelayNs,
{
spi: SPI,
delayer: DELAYER,
card_type: Option<CardType>,
options: AcquireOpts,
}
impl<SPI, DELAYER> SdCardInner<SPI, DELAYER>
where
SPI: embedded_hal::spi::SpiDevice<u8>,
DELAYER: embedded_hal::delay::DelayNs,
{
fn read(&mut self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), Error> {
let start_idx = match self.card_type {
Some(CardType::SD1 | CardType::SD2) => start_block_idx.0 * 512,
Some(CardType::SDHC) => start_block_idx.0,
None => return Err(Error::CardNotFound),
};
if blocks.len() == 1 {
self.card_command(CMD17, start_idx)?;
self.read_data(&mut blocks[0].contents)?;
} else {
self.card_command(CMD18, start_idx)?;
for block in blocks.iter_mut() {
self.read_data(&mut block.contents)?;
}
self.card_command(CMD12, 0)?;
}
Ok(())
}
fn write(&mut self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Error> {
let start_idx = match self.card_type {
Some(CardType::SD1 | CardType::SD2) => start_block_idx.0 * 512,
Some(CardType::SDHC) => start_block_idx.0,
None => return Err(Error::CardNotFound),
};
if blocks.len() == 1 {
self.card_command(CMD24, start_idx)?;
self.write_data(DATA_START_BLOCK, &blocks[0].contents)?;
self.wait_not_busy(Delay::new_write())?;
if self.card_command(CMD13, 0)? != 0x00 {
return Err(Error::WriteError);
}
if self.read_byte()? != 0x00 {
return Err(Error::WriteError);
}
} else {
self.card_acmd(ACMD23, blocks.len() as u32)?;
self.wait_not_busy(Delay::new_write())?;
self.card_command(CMD25, start_idx)?;
for block in blocks.iter() {
self.wait_not_busy(Delay::new_write())?;
self.write_data(WRITE_MULTIPLE_TOKEN, &block.contents)?;
}
self.wait_not_busy(Delay::new_write())?;
self.write_byte(STOP_TRAN_TOKEN)?;
}
Ok(())
}
fn num_blocks(&mut self) -> Result<BlockCount, Error> {
let csd = self.read_csd()?;
debug!("CSD: {:?}", csd);
let num_blocks = match csd {
Csd::V1(ref contents) => contents.card_capacity_blocks(),
Csd::V2(ref contents) => contents.card_capacity_blocks(),
};
Ok(BlockCount(num_blocks))
}
fn num_bytes(&mut self) -> Result<u64, Error> {
let csd = self.read_csd()?;
debug!("CSD: {:?}", csd);
match csd {
Csd::V1(ref contents) => Ok(contents.card_capacity_bytes()),
Csd::V2(ref contents) => Ok(contents.card_capacity_bytes()),
}
}
pub fn erase_single_block_enabled(&mut self) -> Result<bool, Error> {
let csd = self.read_csd()?;
match csd {
Csd::V1(ref contents) => Ok(contents.erase_single_block_enabled()),
Csd::V2(ref contents) => Ok(contents.erase_single_block_enabled()),
}
}
fn read_csd(&mut self) -> Result<Csd, Error> {
match self.card_type {
Some(CardType::SD1) => {
let mut csd = CsdV1::new();
if self.card_command(CMD9, 0)? != 0 {
return Err(Error::RegisterReadError);
}
self.read_data(&mut csd.data)?;
Ok(Csd::V1(csd))
}
Some(CardType::SD2 | CardType::SDHC) => {
let mut csd = CsdV2::new();
if self.card_command(CMD9, 0)? != 0 {
return Err(Error::RegisterReadError);
}
self.read_data(&mut csd.data)?;
Ok(Csd::V2(csd))
}
None => Err(Error::CardNotFound),
}
}
fn read_data(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
let mut delay = Delay::new_read();
let status = loop {
let s = self.read_byte()?;
if s != 0xFF {
break s;
}
delay.delay(&mut self.delayer, Error::TimeoutReadBuffer)?;
};
if status != DATA_START_BLOCK {
return Err(Error::ReadError);
}
buffer.fill(0xFF);
self.transfer_bytes(buffer)?;
let mut crc_bytes = [0xFF; 2];
self.transfer_bytes(&mut crc_bytes)?;
if self.options.use_crc {
let crc = u16::from_be_bytes(crc_bytes);
let calc_crc = crc16(buffer);
if crc != calc_crc {
return Err(Error::CrcError(crc, calc_crc));
}
}
Ok(())
}
fn write_data(&mut self, token: u8, buffer: &[u8]) -> Result<(), Error> {
self.write_byte(token)?;
self.write_bytes(buffer)?;
let crc_bytes = if self.options.use_crc {
crc16(buffer).to_be_bytes()
} else {
[0xFF, 0xFF]
};
self.write_bytes(&crc_bytes)?;
let status = self.read_byte()?;
if (status & DATA_RES_MASK) != DATA_RES_ACCEPTED {
Err(Error::WriteError)
} else {
Ok(())
}
}
fn check_init(&mut self) -> Result<(), Error> {
if self.card_type.is_none() {
self.acquire()
} else {
Ok(())
}
}
fn acquire(&mut self) -> Result<(), Error> {
debug!("acquiring card with opts: {:?}", self.options);
let f = |s: &mut Self| {
let mut card_type;
trace!("Reset card..");
let mut delay = Delay::new(s.options.acquire_retries);
for _attempts in 1.. {
trace!("Enter SPI mode, attempt: {}..", _attempts);
match s.card_command(CMD0, 0) {
Err(Error::TimeoutCommand(0)) => {
warn!("Timed out, trying again..");
for _ in 0..0xFF {
s.write_byte(0xFF)?;
}
}
Err(e) => {
return Err(e);
}
Ok(R1_IDLE_STATE) => {
break;
}
Ok(_r) => {
warn!("Got response: {:x}, trying again..", _r);
}
}
delay.delay(&mut s.delayer, Error::CardNotFound)?;
}
debug!("Enable CRC: {}", s.options.use_crc);
if s.options.use_crc && s.card_command(CMD59, 1)? != R1_IDLE_STATE {
return Err(Error::CantEnableCRC);
}
let mut delay = Delay::new_command();
let arg = loop {
if s.card_command(CMD8, 0x1AA)? == (R1_ILLEGAL_COMMAND | R1_IDLE_STATE) {
card_type = CardType::SD1;
break 0;
}
let mut buffer = [0xFF; 4];
s.transfer_bytes(&mut buffer)?;
let status = buffer[3];
if status == 0xAA {
card_type = CardType::SD2;
break 0x4000_0000;
}
delay.delay(&mut s.delayer, Error::TimeoutCommand(CMD8))?;
};
let mut delay = Delay::new_command();
while s.card_acmd(ACMD41, arg)? != R1_READY_STATE {
delay.delay(&mut s.delayer, Error::TimeoutACommand(ACMD41))?;
}
if card_type == CardType::SD2 {
if s.card_command(CMD58, 0)? != 0 {
return Err(Error::Cmd58Error);
}
let mut buffer = [0xFF; 4];
s.transfer_bytes(&mut buffer)?;
if (buffer[0] & 0xC0) == 0xC0 {
card_type = CardType::SDHC;
}
}
debug!("Card version: {:?}", card_type);
s.card_type = Some(card_type);
Ok(())
};
let result = f(self);
let _ = self.read_byte();
result
}
fn card_acmd(&mut self, command: u8, arg: u32) -> Result<u8, Error> {
self.card_command(CMD55, 0)?;
self.card_command(command, arg)
}
fn card_command(&mut self, command: u8, arg: u32) -> Result<u8, Error> {
if command != CMD0 && command != CMD12 {
self.wait_not_busy(Delay::new_command())?;
}
let mut buf = [
0x40 | command,
(arg >> 24) as u8,
(arg >> 16) as u8,
(arg >> 8) as u8,
arg as u8,
0,
];
buf[5] = crc7(&buf[0..5]);
self.write_bytes(&buf)?;
if command == CMD12 {
let _result = self.read_byte()?;
}
let mut delay = Delay::new_command();
loop {
let result = self.read_byte()?;
if (result & 0x80) == ERROR_OK {
return Ok(result);
}
delay.delay(&mut self.delayer, Error::TimeoutCommand(command))?;
}
}
fn read_byte(&mut self) -> Result<u8, Error> {
self.transfer_byte(0xFF)
}
fn write_byte(&mut self, out: u8) -> Result<(), Error> {
let _ = self.transfer_byte(out)?;
Ok(())
}
fn transfer_byte(&mut self, out: u8) -> Result<u8, Error> {
let mut read_buf = [0u8; 1];
self.spi
.transfer(&mut read_buf, &[out])
.map_err(|_| Error::Transport)?;
Ok(read_buf[0])
}
fn write_bytes(&mut self, out: &[u8]) -> Result<(), Error> {
self.spi.write(out).map_err(|_e| Error::Transport)?;
Ok(())
}
fn transfer_bytes(&mut self, in_out: &mut [u8]) -> Result<(), Error> {
self.spi
.transfer_in_place(in_out)
.map_err(|_e| Error::Transport)?;
Ok(())
}
fn wait_not_busy(&mut self, mut delay: Delay) -> Result<(), Error> {
loop {
let s = self.read_byte()?;
if s == 0xFF {
break;
}
delay.delay(&mut self.delayer, Error::TimeoutWaitNotBusy)?;
}
Ok(())
}
}
#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
#[derive(Debug)]
pub struct AcquireOpts {
pub use_crc: bool,
pub acquire_retries: u32,
}
impl Default for AcquireOpts {
fn default() -> Self {
AcquireOpts {
use_crc: true,
acquire_retries: 50,
}
}
}
#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
#[derive(Debug, Copy, Clone)]
pub enum Error {
Transport,
CantEnableCRC,
TimeoutReadBuffer,
TimeoutWaitNotBusy,
TimeoutCommand(u8),
TimeoutACommand(u8),
Cmd58Error,
RegisterReadError,
CrcError(u16, u16),
ReadError,
WriteError,
BadState,
CardNotFound,
GpioError,
}
#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CardType {
SD1,
SD2,
SDHC,
}
struct Delay {
retries_left: u32,
}
impl Delay {
pub const DEFAULT_READ_RETRIES: u32 = 10_000;
pub const DEFAULT_WRITE_RETRIES: u32 = 50_000;
pub const DEFAULT_COMMAND_RETRIES: u32 = 10_000;
fn new(max_retries: u32) -> Delay {
Delay {
retries_left: max_retries,
}
}
fn new_read() -> Delay {
Delay::new(Self::DEFAULT_READ_RETRIES)
}
fn new_write() -> Delay {
Delay::new(Self::DEFAULT_WRITE_RETRIES)
}
fn new_command() -> Delay {
Delay::new(Self::DEFAULT_COMMAND_RETRIES)
}
fn delay<T>(&mut self, delayer: &mut T, err: Error) -> Result<(), Error>
where
T: embedded_hal::delay::DelayNs,
{
if self.retries_left == 0 {
Err(err)
} else {
delayer.delay_us(10);
self.retries_left -= 1;
Ok(())
}
}
}