Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions embedded-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
pub mod delay;
pub mod digital;
pub mod i2c;
pub mod mmc;
pub mod pwm;
pub mod spi;

Expand Down
101 changes: 101 additions & 0 deletions embedded-hal/src/mmc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//! Types and traits for SD/MMC peripherals.

mod bus_width;
mod fifo_status;
mod reset;

pub mod command;
pub mod response;
pub mod tuning;

pub use bus_width::BusWidth;
pub use fifo_status::FifoStatus;
pub use reset::Reset;

use command::MmcCommand;
use response::MmcResponse;
use tuning::TuningMode;

/// Common operations for DesignWare MMC controllers on JH7110 SoCs.
pub trait MmcOps {
/// Associated error type for the SD/MMC trait.
type Error;

/// Gets whether the device is a MMC card.
fn is_mmc(&self) -> bool;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imo all these bools should be enums, like CardType::Sd and TransportMode::Spi

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, I also prefer new-types, so I'll make those changes.


/// Gets whether the device is a SD card.
fn is_sd(&self) -> bool {
!self.is_mmc()
}

/// Gets whether the device is configured for SPI mode.
fn is_spi(&self) -> bool;

/// Performs bus setup for the SD/MMC device.
fn setup_bus(&mut self) -> Result<(), Self::Error>;

/// Performs device initialization sequence.
fn init(&mut self) -> Result<(), Self::Error>;

/// Sets the sample phase for the MMC controller.
fn set_sample_phase(&mut self, sample_phase: u8);

/// Waits for the FIFO to indicate readiness for read/write operations.
fn fifo_ready(&self, fifo_status: FifoStatus) -> Result<(), Self::Error>;

/// Waits for the CMD line to reset (usually during power-up).
fn wait_for_reset(&mut self, reset: Reset, timeout: u64) -> Result<(), Self::Error>;

/// Waits for the busy signal to clear for maximum `timeout_us` microseconds.
fn wait_while_busy(&mut self, timout_us: u64) -> Result<(), Self::Error>;

/// Writes a SD/MMC command to the card.
fn write_command<C: MmcCommand>(&mut self, cmd: &C) -> Result<(), Self::Error>;

/// Reads a SD/MMC response based on the provided command argument.
///
/// # Note
///
/// `cmd` should match the last call to `write_command`.
fn read_response<C: MmcCommand, R: MmcResponse>(&mut self, cmd: &C) -> Result<R, Self::Error>;

/// Reads the raw response bytes from the MMC controller.
///
/// # Note
///
/// Set `exp_crc` to true if a CRC checksum is expected in the response.
///
/// The generic `N` parameter is for the expected length (in bytes) of the response.
fn response_bytes<const N: usize>(&mut self, exp_crc: bool) -> Result<[u8; N], Self::Error>;

/// Reads data from the MMC data lines.
fn read_data(&mut self, data: &mut [u8]) -> Result<(), Self::Error>;

/// Writes data to the MMC data lines.
fn write_data(&mut self, data: &[u8]) -> Result<(), Self::Error>;

/// Requests the card to send a tuning block.
fn send_tuning(&mut self, bus_width: BusWidth, mode: TuningMode) -> Result<(), Self::Error>;

/// Executes MMC tuning.
fn execute_tuning(&mut self, bus_width: BusWidth, mode: TuningMode) -> Result<(), Self::Error>;

/// Gets the interrupts status as a 32-bit bitfield.
fn interrupt(&self) -> u32;

/// Sets the interrupts based on a 32-bit bitfield.
fn set_interrupt(&mut self, int: u32);

/// Clear all interrupts.
fn clear_all_interrupt(&mut self);

/// Gets the response interrupts status as a 32-bit bitfield.
fn response_interrupt(&self) -> u32;

/// Sets the response interrupts based on a 32-bit bitfield.
fn set_response_interrupt(&mut self, int: u32);

/// Clear all interrupts.
fn clear_all_response_interrupt(&mut self);
}
24 changes: 24 additions & 0 deletions embedded-hal/src/mmc/bus_width.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/// Represents the variants of the `bus width` field of the [Argument](super::Argument).
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BusWidth {
/// Represents the selection of a 1-bit bus width.
Bits1 = 0b00,
/// Represents the selection of a 4-bit bus width.
Bits4 = 0b10,
/// Represents the selection of a 8-bit bus width.
Bits8 = 0b11,
}

impl BusWidth {
/// Creates a new [BusWidth].
pub const fn new() -> Self {
Self::Bits1
}
}

impl Default for BusWidth {
fn default() -> Self {
Self::new()
}
}
36 changes: 36 additions & 0 deletions embedded-hal/src/mmc/command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//! SD/MMC command types.

use super::response::ResponseType;

mod types;

pub use types::*;

/// Represents common functionality for SD/MMC command types.
pub trait MmcCommand {
/// Gets the SD/MMC command type.
fn command_type(&self) -> CommandType;

/// Gets the SD/MMC response type expected for the command.
fn response_type(&self) -> ResponseType;

/// Gets the SD/MMC command argument.
///
/// # Note
///
/// Returns `0` for commands that do not expect an argument.
fn argument(&self) -> u32;

/// Gets the SD/MMC command argument.
///
/// # Note
///
/// No effect for commands that do not expect an argument.
fn set_argument(&mut self, arg: u32);

/// Gets the CRC-7 of the command.
fn crc(&self) -> u8;

/// Sets the CRC-7 of the command.
fn set_crc(&mut self, crc: u8);
}
13 changes: 13 additions & 0 deletions embedded-hal/src/mmc/command/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/// Represents SD/MMC command types.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CommandType {
/// Addressed commands: point-to-point, no data transfer on DAT.
Ac = 0,
/// Addressed commands: point-to-point, data transfer on DAT.
Adtc = 1,
/// Broadcast commands no response. Only available if all CMD lines connected.
Bc = 2,
/// Broadcast commands with response. Only available if all CMD lines separated.
Bcr = 3,
}
24 changes: 24 additions & 0 deletions embedded-hal/src/mmc/fifo_status.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//! FIFO status types.

/// Represents the FIFO status of the host controller.
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FifoStatus {
/// MMC FIFO is empty.
Empty = 0,
/// MMC FIFO is full.
Full = 1,
}

impl FifoStatus {
/// Creates a new [FifoStatus].
pub const fn new() -> Self {
Self::Empty
}
}

impl Default for FifoStatus {
fn default() -> Self {
Self::new()
}
}
34 changes: 34 additions & 0 deletions embedded-hal/src/mmc/reset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//! SD/MMC reset types.

/// Represents the resets to enable on the MMC host controller.
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Reset {
/// Reset the MMC peripheral.
Mmc = 1,
/// Reset the FIFO peripheral.
Fifo = 2,
/// Reset the DMA peripheral.
Dma = 4,
/// Reset the MMC + FIFO peripherals.
MmcFifo = 3,
/// Reset the MMC + DMA peripherals.
MmcDma = 5,
/// Reset the FIFO + DMA peripherals.
FifoDma = 6,
/// Reset all peripherals.
All = 7,
}

impl Reset {
/// Creates a new [Reset].
pub const fn new() -> Self {
Self::Mmc
}
}

impl Default for Reset {
fn default() -> Self {
Self::new()
}
}
16 changes: 16 additions & 0 deletions embedded-hal/src/mmc/response.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//! SD/MMC response types.

mod mode;
mod types;

pub use mode::*;
pub use types::*;

/// Represents common functionality for SD/MMC response types.
pub trait MmcResponse {
/// Gets the SD/MMC response type.
fn response_type(&self) -> ResponseType;

/// Gets the SD/MMC response mode.
fn response_mode(&self) -> ResponseMode;
}
11 changes: 11 additions & 0 deletions embedded-hal/src/mmc/response/mode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// Represents the response mode of the SD/MMC protocol.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ResponseMode {
/// Standard SD mode of operation.
Sd,
/// SDIO mode of operation.
Sdio,
/// SPI mode of operation.
Spi,
}
84 changes: 84 additions & 0 deletions embedded-hal/src/mmc/response/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//! SD/MMC response types.

use super::ResponseMode;

/// Represents the response types used in the SD/MMC protocol.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ResponseType {
/// No response type.
None,
/// The standard response sent for most command types.
R1,
/// The same as the `R1` response, but drives a `BUSY` signal on the `DAT` line(s).
R1b,
/// 136-bit response that includes the contents of the card `CID` or `CSD` register.
R2,
/// Returns the contents of the card `OCR` register.
R3,
/// SDIO response to the `IO_SEND_OP_COND` command.
///
/// Returns the card `IO_OCR` register contents, and other operating conditions.
R4,
/// SDIO response to the `IO_RW_DIRECT` commands.
R5,
/// Response containing the published RCA information.
R6,
/// Response containing the card interface condition.
R7,
}

impl ResponseType {
/// Represents the byte length for an 8-bit response.
pub const LEN_8BIT: usize = 1;
/// Represents the byte length for an 16-bit response.
pub const LEN_16BIT: usize = 2;
/// Represents the byte length for an 40-bit response.
pub const LEN_40BIT: usize = 5;
/// Represents the byte length for an 48-bit response.
pub const LEN_48BIT: usize = 6;
/// Represents the byte length for an 136-bit response.
pub const LEN_136BIT: usize = 17;
/// Represents the byte length for no response.
pub const LEN_NONE: usize = 0;

/// Creates a new [ResponseType].
pub const fn new() -> Self {
Self::R1
}

/// Gets the byte length of the [ResponseType] based on the operation mode.
pub const fn len(&self, mode: ResponseMode) -> usize {
match (mode, self) {
(
ResponseMode::Sd,
Self::R1 | Self::R1b | Self::R3 | Self::R4 | Self::R6 | Self::R7,
) => Self::LEN_48BIT,
(ResponseMode::Sd | ResponseMode::Sdio, Self::R2) => Self::LEN_136BIT,
(ResponseMode::Sdio, Self::R1 | Self::R1b | Self::R4 | Self::R5 | Self::R6) => {
Self::LEN_48BIT
}
(ResponseMode::Spi, Self::R1 | Self::R1b) => Self::LEN_8BIT,
(ResponseMode::Spi, Self::R2 | Self::R5) => Self::LEN_16BIT,
(ResponseMode::Spi, Self::R3 | Self::R4 | Self::R7) => Self::LEN_40BIT,
_ => Self::LEN_NONE,
}
}

/// Gets whether the response type includes a `CRC-7` checksum field.
pub const fn has_crc(&self, mode: ResponseMode) -> bool {
matches!(
(mode, self),
(
ResponseMode::Sd,
Self::R1 | Self::R1b | Self::R2 | Self::R4 | Self::R5 | Self::R6 | Self::R7
)
) || matches!((mode, self), (ResponseMode::Sdio, Self::R5 | Self::R6))
}
}

impl Default for ResponseType {
fn default() -> Self {
Self::new()
}
}
36 changes: 36 additions & 0 deletions embedded-hal/src/mmc/tuning.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//! Tuning data for SD/MMC peripherals.

/// Represents the tuning mode for the SD/MMC device.
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TuningMode {
/// Represents a 4-bit tuning block.
Block4bit = 0,
/// Represents a 8-bit tuning block.
Block8bit = 1,
}

/// Represents the byte length of the 4-bit tuning block.
pub const TUNING_BLOCK_4BIT_LEN: usize = 64;
/// Represents the byte length of the 8-bit tuning block.
pub const TUNING_BLOCK_8BIT_LEN: usize = 128;

/// Represents the tuning pattern used for 4-bit SD/MMC cards.
pub const TUNING_BLOCK_PATTERN_4BIT: [u8; TUNING_BLOCK_4BIT_LEN] = [
0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
];

/// Represents the tuning pattern used for 8-bit SD/MMC cards.
pub const TUNING_BLOCK_PATTERN_8BIT: [u8; TUNING_BLOCK_8BIT_LEN] = [
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
];
Loading