Skip to content

Commit 2c73330

Browse files
committed
hal: initial SD/MMC implementation
Adds the initial implementation of the `embedded-hal` SD/MMC traits. Includes types and traits useful for handling SD/MMC peripherals.
1 parent 5209452 commit 2c73330

File tree

11 files changed

+380
-0
lines changed

11 files changed

+380
-0
lines changed

embedded-hal/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
pub mod delay;
66
pub mod digital;
77
pub mod i2c;
8+
pub mod mmc;
89
pub mod pwm;
910
pub mod spi;
1011

embedded-hal/src/mmc.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//! Types and traits for SD/MMC peripherals.
2+
3+
mod bus_width;
4+
mod fifo_status;
5+
mod reset;
6+
7+
pub mod command;
8+
pub mod response;
9+
pub mod tuning;
10+
11+
pub use bus_width::BusWidth;
12+
pub use fifo_status::FifoStatus;
13+
pub use reset::Reset;
14+
15+
use command::MmcCommand;
16+
use response::MmcResponse;
17+
use tuning::TuningMode;
18+
19+
/// Common operations for DesignWare MMC controllers on JH7110 SoCs.
20+
pub trait MmcOps {
21+
/// Associated error type for the SD/MMC trait.
22+
type Error;
23+
24+
/// Gets whether the device is a MMC card.
25+
fn is_mmc(&self) -> bool;
26+
27+
/// Gets whether the device is a SD card.
28+
fn is_sd(&self) -> bool {
29+
!self.is_mmc()
30+
}
31+
32+
/// Gets whether the device is configured for SPI mode.
33+
fn is_spi(&self) -> bool;
34+
35+
/// Performs bus setup for the SD/MMC device.
36+
fn setup_bus(&mut self) -> Result<(), Self::Error>;
37+
38+
/// Performs device initialization sequence.
39+
fn init(&mut self) -> Result<(), Self::Error>;
40+
41+
/// Sets the sample phase for the MMC controller.
42+
fn set_sample_phase(&mut self, sample_phase: u8);
43+
44+
/// Waits for the FIFO to indicate readiness for read/write operations.
45+
fn fifo_ready(&self, fifo_status: FifoStatus) -> Result<(), Self::Error>;
46+
47+
/// Waits for the CMD line to reset (usually during power-up).
48+
fn wait_for_reset(&mut self, reset: Reset, timeout: u64) -> Result<(), Self::Error>;
49+
50+
/// Waits for the busy signal to clear for maximum `timeout_us` microseconds.
51+
fn wait_while_busy(&mut self, timout_us: u64) -> Result<(), Self::Error>;
52+
53+
/// Writes a SD/MMC command to the card.
54+
fn write_command<C: MmcCommand>(&mut self, cmd: &C) -> Result<(), Self::Error>;
55+
56+
/// Reads a SD/MMC response based on the provided command argument.
57+
///
58+
/// # Note
59+
///
60+
/// `cmd` should match the last call to `write_command`.
61+
fn read_response<C: MmcCommand, R: MmcResponse>(&mut self, cmd: &C) -> Result<R, Self::Error>;
62+
63+
/// Reads the raw response bytes from the MMC controller.
64+
///
65+
/// # Note
66+
///
67+
/// Set `exp_crc` to true if a CRC checksum is expected in the response.
68+
///
69+
/// The generic `N` parameter is for the expected length (in bytes) of the response.
70+
fn response_bytes<const N: usize>(&mut self, exp_crc: bool) -> Result<[u8; N], Self::Error>;
71+
72+
/// Reads data from the MMC data lines.
73+
fn read_data(&mut self, data: &mut [u8]) -> Result<(), Self::Error>;
74+
75+
/// Writes data to the MMC data lines.
76+
fn write_data(&mut self, data: &[u8]) -> Result<(), Self::Error>;
77+
78+
/// Requests the card to send a tuning block.
79+
fn send_tuning(&mut self, bus_width: BusWidth, mode: TuningMode) -> Result<(), Self::Error>;
80+
81+
/// Executes MMC tuning.
82+
fn execute_tuning(&mut self, bus_width: BusWidth, mode: TuningMode) -> Result<(), Self::Error>;
83+
84+
/// Gets the interrupts status as a 32-bit bitfield.
85+
fn interrupt(&self) -> u32;
86+
87+
/// Sets the interrupts based on a 32-bit bitfield.
88+
fn set_interrupt(&mut self, int: u32);
89+
90+
/// Clear all interrupts.
91+
fn clear_all_interrupt(&mut self);
92+
93+
/// Gets the response interrupts status as a 32-bit bitfield.
94+
fn response_interrupt(&self) -> u32;
95+
96+
/// Sets the response interrupts based on a 32-bit bitfield.
97+
fn set_response_interrupt(&mut self, int: u32);
98+
99+
/// Clear all interrupts.
100+
fn clear_all_response_interrupt(&mut self);
101+
}

embedded-hal/src/mmc/bus_width.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// Represents the variants of the `bus width` field of the [Argument](super::Argument).
2+
#[repr(u8)]
3+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4+
pub enum BusWidth {
5+
/// Represents the selection of a 1-bit bus width.
6+
Bits1 = 0b00,
7+
/// Represents the selection of a 4-bit bus width.
8+
Bits4 = 0b10,
9+
/// Represents the selection of a 8-bit bus width.
10+
Bits8 = 0b11,
11+
}
12+
13+
impl BusWidth {
14+
/// Creates a new [BusWidth].
15+
pub const fn new() -> Self {
16+
Self::Bits1
17+
}
18+
}
19+
20+
impl Default for BusWidth {
21+
fn default() -> Self {
22+
Self::new()
23+
}
24+
}

embedded-hal/src/mmc/command.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//! SD/MMC command types.
2+
3+
use super::response::ResponseType;
4+
5+
mod types;
6+
7+
pub use types::*;
8+
9+
/// Represents common functionality for SD/MMC command types.
10+
pub trait MmcCommand {
11+
/// Gets the SD/MMC command type.
12+
fn command_type(&self) -> CommandType;
13+
14+
/// Gets the SD/MMC response type expected for the command.
15+
fn response_type(&self) -> ResponseType;
16+
17+
/// Gets the SD/MMC command argument.
18+
///
19+
/// # Note
20+
///
21+
/// Returns `0` for commands that do not expect an argument.
22+
fn argument(&self) -> u32;
23+
24+
/// Gets the SD/MMC command argument.
25+
///
26+
/// # Note
27+
///
28+
/// No effect for commands that do not expect an argument.
29+
fn set_argument(&mut self, arg: u32);
30+
31+
/// Gets the CRC-7 of the command.
32+
fn crc(&self) -> u8;
33+
34+
/// Sets the CRC-7 of the command.
35+
fn set_crc(&mut self, crc: u8);
36+
}

embedded-hal/src/mmc/command/types.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/// Represents SD/MMC command types.
2+
#[repr(C)]
3+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4+
pub enum CommandType {
5+
/// Addressed commands: point-to-point, no data transfer on DAT.
6+
Ac = 0,
7+
/// Addressed commands: point-to-point, data transfer on DAT.
8+
Adtc = 1,
9+
/// Broadcast commands no response. Only available if all CMD lines connected.
10+
Bc = 2,
11+
/// Broadcast commands with response. Only available if all CMD lines separated.
12+
Bcr = 3,
13+
}

embedded-hal/src/mmc/fifo_status.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//! FIFO status types.
2+
3+
/// Represents the FIFO status of the host controller.
4+
#[repr(u8)]
5+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6+
pub enum FifoStatus {
7+
/// MMC FIFO is empty.
8+
Empty = 0,
9+
/// MMC FIFO is full.
10+
Full = 1,
11+
}
12+
13+
impl FifoStatus {
14+
/// Creates a new [FifoStatus].
15+
pub const fn new() -> Self {
16+
Self::Empty
17+
}
18+
}
19+
20+
impl Default for FifoStatus {
21+
fn default() -> Self {
22+
Self::new()
23+
}
24+
}

embedded-hal/src/mmc/reset.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//! SD/MMC reset types.
2+
3+
/// Represents the resets to enable on the MMC host controller.
4+
#[repr(u8)]
5+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6+
pub enum Reset {
7+
/// Reset the MMC peripheral.
8+
Mmc = 1,
9+
/// Reset the FIFO peripheral.
10+
Fifo = 2,
11+
/// Reset the DMA peripheral.
12+
Dma = 4,
13+
/// Reset the MMC + FIFO peripherals.
14+
MmcFifo = 3,
15+
/// Reset the MMC + DMA peripherals.
16+
MmcDma = 5,
17+
/// Reset the FIFO + DMA peripherals.
18+
FifoDma = 6,
19+
/// Reset all peripherals.
20+
All = 7,
21+
}
22+
23+
impl Reset {
24+
/// Creates a new [Reset].
25+
pub const fn new() -> Self {
26+
Self::Mmc
27+
}
28+
}
29+
30+
impl Default for Reset {
31+
fn default() -> Self {
32+
Self::new()
33+
}
34+
}

embedded-hal/src/mmc/response.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//! SD/MMC response types.
2+
3+
mod mode;
4+
mod types;
5+
6+
pub use mode::*;
7+
pub use types::*;
8+
9+
/// Represents common functionality for SD/MMC response types.
10+
pub trait MmcResponse {
11+
/// Gets the SD/MMC response type.
12+
fn response_type(&self) -> ResponseType;
13+
14+
/// Gets the SD/MMC response mode.
15+
fn response_mode(&self) -> ResponseMode;
16+
}

embedded-hal/src/mmc/response/mode.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/// Represents the response mode of the SD/MMC protocol.
2+
#[repr(C)]
3+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4+
pub enum ResponseMode {
5+
/// Standard SD mode of operation.
6+
Sd,
7+
/// SDIO mode of operation.
8+
Sdio,
9+
/// SPI mode of operation.
10+
Spi,
11+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//! SD/MMC response types.
2+
3+
use super::ResponseMode;
4+
5+
/// Represents the response types used in the SD/MMC protocol.
6+
#[repr(C)]
7+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8+
pub enum ResponseType {
9+
/// No response type.
10+
None,
11+
/// The standard response sent for most command types.
12+
R1,
13+
/// The same as the `R1` response, but drives a `BUSY` signal on the `DAT` line(s).
14+
R1b,
15+
/// 136-bit response that includes the contents of the card `CID` or `CSD` register.
16+
R2,
17+
/// Returns the contents of the card `OCR` register.
18+
R3,
19+
/// SDIO response to the `IO_SEND_OP_COND` command.
20+
///
21+
/// Returns the card `IO_OCR` register contents, and other operating conditions.
22+
R4,
23+
/// SDIO response to the `IO_RW_DIRECT` commands.
24+
R5,
25+
/// Response containing the published RCA information.
26+
R6,
27+
/// Response containing the card interface condition.
28+
R7,
29+
}
30+
31+
impl ResponseType {
32+
/// Represents the byte length for an 8-bit response.
33+
pub const LEN_8BIT: usize = 1;
34+
/// Represents the byte length for an 16-bit response.
35+
pub const LEN_16BIT: usize = 2;
36+
/// Represents the byte length for an 40-bit response.
37+
pub const LEN_40BIT: usize = 5;
38+
/// Represents the byte length for an 48-bit response.
39+
pub const LEN_48BIT: usize = 6;
40+
/// Represents the byte length for an 136-bit response.
41+
pub const LEN_136BIT: usize = 17;
42+
/// Represents the byte length for no response.
43+
pub const LEN_NONE: usize = 0;
44+
45+
/// Creates a new [ResponseType].
46+
pub const fn new() -> Self {
47+
Self::R1
48+
}
49+
50+
/// Gets the byte length of the [ResponseType] based on the operation mode.
51+
pub const fn len(&self, mode: ResponseMode) -> usize {
52+
match (mode, self) {
53+
(
54+
ResponseMode::Sd,
55+
Self::R1 | Self::R1b | Self::R3 | Self::R4 | Self::R6 | Self::R7,
56+
) => Self::LEN_48BIT,
57+
(ResponseMode::Sd | ResponseMode::Sdio, Self::R2) => Self::LEN_136BIT,
58+
(ResponseMode::Sdio, Self::R1 | Self::R1b | Self::R4 | Self::R5 | Self::R6) => {
59+
Self::LEN_48BIT
60+
}
61+
(ResponseMode::Spi, Self::R1 | Self::R1b) => Self::LEN_8BIT,
62+
(ResponseMode::Spi, Self::R2 | Self::R5) => Self::LEN_16BIT,
63+
(ResponseMode::Spi, Self::R3 | Self::R4 | Self::R7) => Self::LEN_40BIT,
64+
_ => Self::LEN_NONE,
65+
}
66+
}
67+
68+
/// Gets whether the response type includes a `CRC-7` checksum field.
69+
pub const fn has_crc(&self, mode: ResponseMode) -> bool {
70+
matches!(
71+
(mode, self),
72+
(
73+
ResponseMode::Sd,
74+
Self::R1 | Self::R1b | Self::R2 | Self::R4 | Self::R5 | Self::R6 | Self::R7
75+
)
76+
) || matches!((mode, self), (ResponseMode::Sdio, Self::R5 | Self::R6))
77+
}
78+
}
79+
80+
impl Default for ResponseType {
81+
fn default() -> Self {
82+
Self::new()
83+
}
84+
}

0 commit comments

Comments
 (0)