#![cfg_attr(not(test), no_std)]
use aligned::{A4, Aligned};
use embedded_hal_async::delay::DelayNs;
use crate::sd::{
BlockSize, CardCapacity, CardStatus, OCR, block_size, read_multiple_blocks, read_single_block,
stop_transmission, write_multiple_blocks, write_single_block,
};
pub mod common;
pub mod emmc;
pub mod sd;
pub mod sdio;
pub mod spi;
const INIT_FREQ: u32 = 400_000;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum MmcError {
Timeout,
Crc,
IllegalCommand,
Busy,
Io,
SignalingSwitchFailed,
Unsupported,
Other,
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BusWidth {
W1,
W4,
W8,
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ResponseLen {
Zero,
R48,
R136,
}
impl ResponseLen {
pub const fn words(&self) -> usize {
match self {
Self::Zero => 0,
Self::R48 => 1,
Self::R136 => 4,
}
}
}
pub trait Response: Sized {
const CRC: bool;
const BUSY: bool;
const LEN: ResponseLen;
fn from_words(buf: &[u32; 4]) -> Self;
}
pub trait Command {
const INDEX: u8;
type Resp<'a>: Response
where
Self: 'a;
fn index(&self) -> u8 {
Self::INDEX
}
fn arg(&self) -> u32;
}
pub trait BlockCommand: Command {
fn block_size(&self) -> BlockSize;
fn block_count(&self) -> u32;
}
pub trait ByteCommand: Command {
fn byte_count(&self) -> usize;
}
pub trait ControlCommand: Command {}
pub trait BlockReadCommand: BlockCommand {
fn buf(&mut self) -> &mut Aligned<A4, [u8]>;
}
pub trait BlockWriteCommand: BlockCommand {
fn buf(&self) -> &Aligned<A4, [u8]>;
}
pub trait ByteReadCommand: ByteCommand {
fn buf(&mut self) -> &mut Aligned<A4, [u8]>;
}
pub trait ByteWriteCommand: ByteCommand {
fn buf(&self) -> &Aligned<A4, [u8]>;
}
pub trait MmcBus {
fn send_command<'a, C>(
&mut self,
cmd: C,
) -> impl Future<Output = Result<C::Resp<'a>, MmcError>>
where
C: ControlCommand + 'a;
fn read_blocks<'a, C>(&mut self, cmd: C) -> impl Future<Output = Result<C::Resp<'a>, MmcError>>
where
C: BlockReadCommand + 'a;
fn write_blocks<'a, C>(
&mut self,
cmd: C,
) -> impl Future<Output = Result<C::Resp<'a>, MmcError>>
where
C: BlockWriteCommand + 'a;
fn read_bytes<'a, C>(&mut self, cmd: C) -> impl Future<Output = Result<C::Resp<'a>, MmcError>>
where
C: ByteReadCommand + 'a;
fn write_bytes<'a, C>(&mut self, cmd: C) -> impl Future<Output = Result<C::Resp<'a>, MmcError>>
where
C: ByteWriteCommand + 'a;
fn init_idle(&mut self, hz: u32) -> impl Future<Output = Result<(), MmcError>>;
#[allow(unused_variables)]
fn tune_bus<O>(
&mut self,
width: BusWidth,
hz: u32,
op: &mut O,
) -> impl Future<Output = Result<(), MmcError>>
where
O: TuningOp,
{
async { Ok(()) }
}
fn wait_for_event(&mut self) -> impl Future<Output = Result<(), MmcError>> {
async { Ok(()) }
}
fn set_bus(&mut self, width: BusWidth, hz: u32) -> Result<(), MmcError>;
fn supports_mmc(&self) -> bool {
false
}
fn supports_bus_width(&self) -> BusWidth {
BusWidth::W1
}
fn supports_1v8(&self) -> bool {
false
}
fn supports_frequency(&self) -> u32 {
25_000_000
}
}
impl<T: MmcBus> MmcBus for &mut T {
async fn send_command<'a, C>(&mut self, cmd: C) -> Result<C::Resp<'a>, MmcError>
where
C: ControlCommand + 'a,
{
T::send_command(self, cmd).await
}
async fn read_blocks<'a, C>(&mut self, cmd: C) -> Result<C::Resp<'a>, MmcError>
where
C: BlockReadCommand + 'a,
{
T::read_blocks(self, cmd).await
}
async fn write_blocks<'a, C>(&mut self, cmd: C) -> Result<C::Resp<'a>, MmcError>
where
C: BlockWriteCommand + 'a,
{
T::write_blocks(self, cmd).await
}
async fn read_bytes<'a, C>(&mut self, cmd: C) -> Result<C::Resp<'a>, MmcError>
where
C: ByteReadCommand + 'a,
{
T::read_bytes(self, cmd).await
}
async fn write_bytes<'a, C>(&mut self, cmd: C) -> Result<C::Resp<'a>, MmcError>
where
C: ByteWriteCommand + 'a,
{
T::write_bytes(self, cmd).await
}
async fn tune_bus<O>(&mut self, width: BusWidth, hz: u32, op: &mut O) -> Result<(), MmcError>
where
O: TuningOp,
{
T::tune_bus(self, width, hz, op).await
}
async fn wait_for_event(&mut self) -> Result<(), MmcError> {
T::wait_for_event(self).await
}
async fn init_idle(&mut self, hz: u32) -> Result<(), MmcError> {
T::init_idle(self, hz).await
}
fn set_bus(&mut self, width: BusWidth, hz: u32) -> Result<(), MmcError> {
T::set_bus(self, width, hz)
}
fn supports_1v8(&self) -> bool {
T::supports_1v8(self)
}
fn supports_bus_width(&self) -> BusWidth {
T::supports_bus_width(self)
}
fn supports_frequency(&self) -> u32 {
T::supports_frequency(self)
}
fn supports_mmc(&self) -> bool {
T::supports_mmc(self)
}
}
pub struct R0;
impl Response for R0 {
const CRC: bool = false;
const LEN: ResponseLen = ResponseLen::Zero;
const BUSY: bool = false;
fn from_words(_buf: &[u32; 4]) -> Self {
Self
}
}
pub struct R1 {
pub status: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CardState {
Idle, Ready, Ident, Standby, Transfer, Data, Receive, Programming, Reserved(u8), }
impl R1 {
pub const ERR_MASK: u32 = 0xFDF9_8008;
pub fn to_result(&self) -> Result<(), MmcError> {
if self.is_error() {
Err(MmcError::Other)
} else {
Ok(())
}
}
pub fn is_error(&self) -> bool {
self.status & Self::ERR_MASK != 0
}
pub fn app_cmd(&self) -> bool {
self.status & (1 << 5) != 0
}
pub fn ready_for_data(&self) -> bool {
self.status & (1 << 8) != 0
}
pub fn current_state(&self) -> CardState {
let v = ((self.status >> 9) & 0xF) as u8;
match v {
0 => CardState::Idle,
1 => CardState::Ready,
2 => CardState::Ident,
3 => CardState::Standby,
4 => CardState::Transfer,
5 => CardState::Data,
6 => CardState::Receive,
7 => CardState::Programming,
other => CardState::Reserved(other),
}
}
}
impl Response for R1 {
const CRC: bool = true;
const LEN: ResponseLen = ResponseLen::R48;
const BUSY: bool = false;
fn from_words(buf: &[u32; 4]) -> Self {
R1 { status: buf[0] }
}
}
pub struct R1b {
pub status: u32,
}
impl Response for R1b {
const CRC: bool = true;
const LEN: ResponseLen = ResponseLen::R48;
const BUSY: bool = true;
fn from_words(buf: &[u32; 4]) -> Self {
R1b { status: buf[0] }
}
}
pub struct R2 {
pub words: [u32; 4],
}
impl Response for R2 {
const CRC: bool = true;
const LEN: ResponseLen = ResponseLen::R136;
const BUSY: bool = false;
fn from_words(buf: &[u32; 4]) -> Self {
R2 {
words: [buf[0], buf[1], buf[2], buf[3]],
}
}
}
pub struct R3 {
pub ocr: u32,
}
impl Response for R3 {
const CRC: bool = false;
const LEN: ResponseLen = ResponseLen::R48;
const BUSY: bool = false;
fn from_words(buf: &[u32; 4]) -> Self {
R3 { ocr: buf[0] }
}
}
pub struct R6 {
pub rca: u16,
pub status: u16,
}
impl Response for R6 {
const CRC: bool = true;
const LEN: ResponseLen = ResponseLen::R48;
const BUSY: bool = false;
fn from_words(buf: &[u32; 4]) -> Self {
let v = buf[0];
R6 {
rca: (v >> 16) as u16,
status: (v & 0xFFFF) as u16,
}
}
}
pub struct R7 {
pub voltage: u8,
pub check_pattern: u8,
}
impl Response for R7 {
const CRC: bool = true;
const LEN: ResponseLen = ResponseLen::R48;
const BUSY: bool = false;
fn from_words(buf: &[u32; 4]) -> Self {
let v = buf[0];
R7 {
voltage: ((v >> 8) & 0xF) as u8,
check_pattern: (v & 0xFF) as u8,
}
}
}
pub struct R4 {
pub ocr: u32,
}
impl Response for R4 {
const CRC: bool = false;
const LEN: ResponseLen = ResponseLen::R48;
const BUSY: bool = false;
fn from_words(buf: &[u32; 4]) -> Self {
R4 { ocr: buf[0] }
}
}
pub struct R5 {
pub flags: u8,
pub data: u8,
}
impl R5 {
pub const FLAG_COM_CRC_ERROR: u8 = 1 << 7;
pub const FLAG_ILLEGAL_COMMAND: u8 = 1 << 6;
pub const FLAG_ERROR: u8 = 1 << 3;
pub const FLAG_FUNCTION_NUMBER: u8 = 1 << 1;
pub const FLAG_OUT_OF_RANGE: u8 = 1 << 0;
pub const ERROR_FLAGS: u8 = Self::FLAG_COM_CRC_ERROR
| Self::FLAG_ILLEGAL_COMMAND
| Self::FLAG_ERROR
| Self::FLAG_FUNCTION_NUMBER
| Self::FLAG_OUT_OF_RANGE;
pub fn to_result(&self) -> Result<(), MmcError> {
if self.is_error() {
Err(MmcError::Other)
} else {
Ok(())
}
}
pub fn is_error(&self) -> bool {
self.flags & Self::ERROR_FLAGS != 0
}
}
impl Response for R5 {
const CRC: bool = true;
const LEN: ResponseLen = ResponseLen::R48;
const BUSY: bool = false;
fn from_words(buf: &[u32; 4]) -> Self {
let v = buf[0];
R5 {
flags: ((v >> 8) & 0xFF) as u8,
data: (v & 0xFF) as u8,
}
}
}
pub trait TuningOp {
fn exec<B: MmcBus>(&mut self, bus: &mut B) -> impl Future<Output = Result<bool, MmcError>>;
}
impl<T: Command> Command for &T {
const INDEX: u8 = T::INDEX;
type Resp<'a>
= T::Resp<'a>
where
Self: 'a;
fn arg(&self) -> u32 {
T::arg(self)
}
}
impl<T: Command> Command for &mut T {
const INDEX: u8 = T::INDEX;
type Resp<'a>
= T::Resp<'a>
where
Self: 'a;
fn arg(&self) -> u32 {
T::arg(self)
}
}
impl<T: ControlCommand> ControlCommand for &T {}
impl<T: BlockCommand> BlockCommand for &mut T {
fn block_count(&self) -> u32 {
T::block_count(self)
}
fn block_size(&self) -> BlockSize {
T::block_size(self)
}
}
impl<T: BlockReadCommand> BlockReadCommand for &mut T {
fn buf(&mut self) -> &mut Aligned<A4, [u8]> {
T::buf(self)
}
}
struct BusAdapter<B: MmcBus, D: DelayNs> {
pub bus: B,
pub delay: D,
pub rca: u16,
}
impl<B: MmcBus, D: DelayNs> BusAdapter<B, D> {
async fn app_cmd(&mut self, app_cmd: bool) -> Result<(), MmcError> {
if app_cmd {
self.bus
.send_command(sd::app_cmd(self.rca))
.await?
.to_result()?
}
Ok(())
}
async fn check_card(&mut self) -> bool {
if let Ok(status) = self
.bus
.send_command(common::card_status(self.rca, false))
.await
&& CardStatus::<()>::from(status).ready_for_data()
{
true
} else {
false
}
}
async fn wait_if_required<R: Response>(&mut self) -> Result<(), MmcError> {
if !R::BUSY {
return Ok(());
}
for _ in 0..750 {
if self.check_card().await {
return Ok(());
}
self.delay.delay_ms(1).await;
}
Err(MmcError::Timeout)
}
pub async fn init_idle(&mut self) -> Result<(), MmcError> {
self.bus.init_idle(INIT_FREQ).await?;
self.delay.delay_us(74_000_000 / INIT_FREQ).await;
if self.bus.supports_mmc() {
self.send_command(common::idle(), false).await?;
} else {
self.send_command(common::idle_spi(), false).await?;
}
Ok(())
}
pub async fn select_card(&mut self, rca: Option<u16>) -> Result<(), MmcError> {
match self
.send_command(common::select_card(rca.unwrap_or(0)), false)
.await
{
Err(MmcError::Timeout) if rca.is_none() => Ok(()),
result => result.map(|_| ()),
}
}
pub async fn get_ocr<'a, C: ControlCommand + 'a, Ext>(
&mut self,
cmd: &'a C,
app_cmd: bool,
) -> Result<OCR<Ext>, MmcError>
where
OCR<Ext>: From<<C as Command>::Resp<'a>>,
{
for _ in 0..750 {
let ocr: OCR<Ext> = self.send_command(cmd, app_cmd).await?.into();
if !ocr.is_busy() {
return Ok(ocr);
}
self.delay.delay_ms(1).await;
}
Err(MmcError::Timeout)
}
pub async fn send_command<'a, C: ControlCommand + 'a>(
&mut self,
cmd: C,
app_cmd: bool,
) -> Result<C::Resp<'a>, MmcError> {
self.app_cmd(app_cmd).await?;
let res = self.bus.send_command(cmd).await?;
self.wait_if_required::<C::Resp<'a>>().await?;
Ok(res)
}
pub async fn read_blocks<'a, C: BlockReadCommand + 'a>(
&mut self,
cmd: C,
app_cmd: bool,
) -> Result<C::Resp<'a>, MmcError> {
self.app_cmd(app_cmd).await?;
let res = self.bus.read_blocks(cmd).await?;
self.wait_if_required::<C::Resp<'a>>().await?;
Ok(res)
}
pub async fn write_blocks<'a, C: BlockWriteCommand + 'a>(
&mut self,
cmd: C,
app_cmd: bool,
) -> Result<C::Resp<'a>, MmcError> {
self.app_cmd(app_cmd).await?;
let res = self.bus.write_blocks(cmd).await?;
self.wait_if_required::<C::Resp<'a>>().await?;
Ok(res)
}
}
#[non_exhaustive]
#[allow(missing_docs)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
pub enum Signalling {
#[default]
SDR12,
SDR25,
SDR50,
SDR104,
DDR50,
}
trait Acquirable: Sized + Clone + Default {
fn acquire<B: MmcBus, D: DelayNs>(
bus: &mut BusAdapter<B, D>,
block_size: BlockSize,
freq: u32,
) -> impl Future<Output = Result<Self, MmcError>>;
}
#[allow(private_bounds)]
pub trait Addressable: Acquirable {
type Ext;
fn get_capacity(&self) -> CardCapacity;
fn block_count(&self) -> u32;
fn supports_cmd23(&self) -> bool;
fn supports_acmd23(&self) -> bool;
}
pub struct BlockDevice<T: Addressable, B: MmcBus, D: DelayNs, const BLOCK_SIZE: usize> {
info: T,
bus: BusAdapter<B, D>,
}
impl<A: Addressable, B: MmcBus, D: DelayNs, const BLOCK_SIZE: usize>
BlockDevice<A, B, D, BLOCK_SIZE>
{
pub async fn new(bus: B, delay: D, freq: u32) -> Result<Self, MmcError> {
let mut this = Self::new_uninit(bus, delay);
this.reacquire(freq).await?;
Ok(this)
}
pub fn new_uninit(bus: B, delay: D) -> Self {
Self {
info: A::default(),
bus: BusAdapter { bus, delay, rca: 0 },
}
}
pub async fn reacquire(&mut self, freq: u32) -> Result<(), MmcError> {
let freq = freq.clamp(0, self.bus.bus.supports_frequency());
self.bus.init_idle().await?;
self.info = A::acquire(&mut self.bus, block_size(BLOCK_SIZE), freq).await?;
Ok(())
}
pub fn card(&self) -> A {
self.info.clone()
}
#[inline]
async fn read_block(
&mut self,
block_idx: u32,
block: &mut Aligned<A4, [u8; BLOCK_SIZE]>,
) -> Result<(), MmcError> {
let card_capacity = self.info.get_capacity();
let addr = match card_capacity {
CardCapacity::StandardCapacity => block_idx * BLOCK_SIZE as u32,
_ => block_idx,
};
self.bus
.read_blocks(read_single_block(addr, block), false)
.await?;
Ok(())
}
#[inline]
async fn read_blocks(
&mut self,
block_idx: u32,
blocks: &mut [Aligned<A4, [u8; BLOCK_SIZE]>],
) -> Result<(), MmcError> {
let card_capacity = self.info.get_capacity();
let addr = match card_capacity {
CardCapacity::StandardCapacity => block_idx * BLOCK_SIZE as u32,
_ => block_idx,
};
self.bus
.read_blocks(read_multiple_blocks(addr, blocks), false)
.await?;
Ok(())
}
#[inline]
async fn write_block(
&mut self,
block_idx: u32,
block: &Aligned<A4, [u8; BLOCK_SIZE]>,
) -> Result<(), MmcError> {
let card_capacity = self.info.get_capacity();
let addr = match card_capacity {
CardCapacity::StandardCapacity => block_idx * BLOCK_SIZE as u32,
_ => block_idx,
};
self.bus
.write_blocks(write_single_block(addr, block), false)
.await?;
Ok(())
}
#[inline]
async fn write_blocks(
&mut self,
block_idx: u32,
blocks: &[Aligned<A4, [u8; BLOCK_SIZE]>],
) -> Result<(), MmcError> {
let card_capacity = self.info.get_capacity();
let addr = match card_capacity {
CardCapacity::StandardCapacity => block_idx * BLOCK_SIZE as u32,
_ => block_idx,
};
if self.info.supports_acmd23() {
self.bus
.send_command(sd::set_wr_blk_erase_count(blocks.len() as u32), true)
.await?;
}
if self.info.supports_cmd23() {
self.bus
.send_command(sd::set_block_count(blocks.len() as u32), false)
.await?;
}
self.bus
.write_blocks(write_multiple_blocks(addr, blocks), false)
.await?;
if !self.info.supports_cmd23() {
self.bus.send_command(stop_transmission(), false).await?;
}
Ok(())
}
}
impl<A: Addressable, B: MmcBus, D: DelayNs, const BLOCK_SIZE: usize>
block_device_driver::BlockDevice<BLOCK_SIZE> for BlockDevice<A, B, D, BLOCK_SIZE>
{
type Align = A4;
type Error = MmcError;
#[inline]
async fn read(
&mut self,
block_address: u32,
blocks: &mut [aligned::Aligned<Self::Align, [u8; BLOCK_SIZE]>],
) -> Result<(), Self::Error> {
assert_eq!(BLOCK_SIZE % 4, 0);
if blocks.len() == 1 {
self.read_block(block_address, &mut blocks[0]).await?;
} else {
self.read_blocks(block_address, blocks).await?;
}
Ok(())
}
#[inline]
async fn write(
&mut self,
block_address: u32,
blocks: &[aligned::Aligned<Self::Align, [u8; BLOCK_SIZE]>],
) -> Result<(), Self::Error> {
assert_eq!(BLOCK_SIZE % 4, 0);
if blocks.len() == 1 {
self.write_block(block_address, &blocks[0]).await?;
} else {
self.write_blocks(block_address, blocks).await?;
}
Ok(())
}
async fn size(&mut self) -> Result<u64, Self::Error> {
Ok(self.info.block_count() as u64 * BLOCK_SIZE as u64)
}
}