| 1 | use core::marker::PhantomData; |
| 2 | |
| 3 | /// Host to Card commands |
| 4 | pub struct Cmd<R: Resp> { |
| 5 | pub cmd: u8, |
| 6 | pub arg: u32, |
| 7 | resp: PhantomData<R>, |
| 8 | } |
| 9 | |
| 10 | impl<R: Resp> Cmd<R> { |
| 11 | pub fn response_len(&self) -> ResponseLen { |
| 12 | R::LENGTH |
| 13 | } |
| 14 | } |
| 15 | |
| 16 | /// Marker for commands that don't have any response |
| 17 | pub struct Rz; |
| 18 | /// R1: Normal response |
| 19 | pub struct R1; |
| 20 | /// R2: CID and CSD register |
| 21 | pub struct R2; |
| 22 | /// R3: OCR register |
| 23 | pub struct R3; |
| 24 | /// R6: Published RCA response |
| 25 | pub struct R6; |
| 26 | /// R7: Card interface condition |
| 27 | pub struct R7; |
| 28 | |
| 29 | pub trait Resp { |
| 30 | const LENGTH: ResponseLen = ResponseLen::R48; |
| 31 | } |
| 32 | |
| 33 | impl Resp for Rz { |
| 34 | const LENGTH: ResponseLen = ResponseLen::Zero; |
| 35 | } |
| 36 | |
| 37 | impl Resp for R2 { |
| 38 | const LENGTH: ResponseLen = ResponseLen::R136; |
| 39 | } |
| 40 | |
| 41 | impl Resp for R1 {} |
| 42 | impl Resp for R3 {} |
| 43 | impl Resp for R6 {} |
| 44 | impl Resp for R7 {} |
| 45 | |
| 46 | /// Command Response type |
| 47 | #[derive (Eq, PartialEq, Copy, Clone)] |
| 48 | pub enum ResponseLen { |
| 49 | /// No response expected |
| 50 | Zero, |
| 51 | /// Short (48 bit) response |
| 52 | R48, |
| 53 | /// Long (136 bit) response |
| 54 | R136, |
| 55 | } |
| 56 | |
| 57 | pub fn cmd<R: Resp>(cmd: u8, arg: u32) -> Cmd<R> { |
| 58 | Cmd { |
| 59 | cmd, |
| 60 | arg, |
| 61 | resp: PhantomData, |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | /// CMD0: Put card in idle mode |
| 66 | pub fn idle() -> Cmd<Rz> { |
| 67 | cmd(cmd:0, arg:0) |
| 68 | } |
| 69 | |
| 70 | /// CMD2: Ask any card to send their CID |
| 71 | pub fn all_send_cid() -> Cmd<R2> { |
| 72 | cmd(cmd:2, arg:0) |
| 73 | } |
| 74 | |
| 75 | /// CMD3: Send RCA |
| 76 | pub fn send_relative_address() -> Cmd<R6> { |
| 77 | cmd(cmd:3, arg:0) |
| 78 | } |
| 79 | |
| 80 | /// CMD6: Switch Function Command |
| 81 | pub fn cmd6(arg: u32) -> Cmd<R1> { |
| 82 | cmd(cmd:6, arg) |
| 83 | } |
| 84 | |
| 85 | /// CMD7: Select or deselect card |
| 86 | pub fn select_card(rca: u16) -> Cmd<R1> { |
| 87 | cmd(cmd:7, arg:u32::from(rca) << 16) |
| 88 | } |
| 89 | |
| 90 | /// CMD8: Sends memory card interface conditions |
| 91 | pub fn send_if_cond(voltage: u8, checkpattern: u8) -> Cmd<R7> { |
| 92 | let arg: u32 = u32::from(voltage & 0xF) << 8 | u32::from(checkpattern); |
| 93 | cmd(cmd:8, arg) |
| 94 | } |
| 95 | |
| 96 | /// CMD9: Send CSD |
| 97 | pub fn send_csd(rca: u16) -> Cmd<R2> { |
| 98 | cmd(cmd:9, arg:u32::from(rca) << 16) |
| 99 | } |
| 100 | |
| 101 | /// CMD10: Send CID |
| 102 | pub fn send_cid(rca: u16) -> Cmd<R2> { |
| 103 | cmd(cmd:10, arg:u32::from(rca) << 16) |
| 104 | } |
| 105 | |
| 106 | /// CMD11: Switch to 1.8V bus signaling level |
| 107 | pub fn voltage_switch() -> Cmd<R1> { |
| 108 | cmd(cmd:11, arg:0) |
| 109 | } |
| 110 | |
| 111 | /// CMD12: Stop transmission |
| 112 | pub fn stop_transmission() -> Cmd<R1> { |
| 113 | cmd(cmd:12, arg:0) |
| 114 | } |
| 115 | |
| 116 | /// CMD13: Ask card to send status or task status |
| 117 | pub fn card_status(rca: u16, task_status: bool) -> Cmd<R1> { |
| 118 | let arg: u32 = u32::from(rca) << 16 | u32::from(task_status) << 15; |
| 119 | cmd(cmd:13, arg) |
| 120 | } |
| 121 | |
| 122 | /// CMD15: Sends card to inactive state |
| 123 | pub fn go_inactive_state(rca: u16) -> Cmd<Rz> { |
| 124 | cmd(cmd:15, arg:u32::from(rca) << 16) |
| 125 | } |
| 126 | |
| 127 | /// CMD16: Set block len |
| 128 | pub fn set_block_length(blocklen: u32) -> Cmd<R1> { |
| 129 | cmd(cmd:16, arg:blocklen) |
| 130 | } |
| 131 | |
| 132 | /// CMD17: Read a single block from the card |
| 133 | pub fn read_single_block(addr: u32) -> Cmd<R1> { |
| 134 | cmd(cmd:17, arg:addr) |
| 135 | } |
| 136 | |
| 137 | /// CMD18: Read multiple block from the card |
| 138 | pub fn read_multiple_blocks(addr: u32) -> Cmd<R1> { |
| 139 | cmd(cmd:18, arg:addr) |
| 140 | } |
| 141 | |
| 142 | /// CMD19: Send tuning pattern |
| 143 | pub fn send_tuning_block(addr: u32) -> Cmd<R1> { |
| 144 | cmd(cmd:19, arg:addr) |
| 145 | } |
| 146 | |
| 147 | /// CMD20: Speed class control |
| 148 | pub fn speed_class_control(arg: u32) -> Cmd<R1> { |
| 149 | cmd(cmd:20, arg) |
| 150 | } |
| 151 | |
| 152 | /// CMD22: Address extension |
| 153 | pub fn address_extension(arg: u32) -> Cmd<R1> { |
| 154 | cmd(cmd:22, arg) |
| 155 | } |
| 156 | |
| 157 | /// CMD23: Address extension |
| 158 | pub fn set_block_count(blockcount: u32) -> Cmd<R1> { |
| 159 | cmd(cmd:23, arg:blockcount) |
| 160 | } |
| 161 | |
| 162 | /// CMD24: Write block |
| 163 | pub fn write_single_block(addr: u32) -> Cmd<R1> { |
| 164 | cmd(cmd:24, arg:addr) |
| 165 | } |
| 166 | |
| 167 | /// CMD25: Write multiple blocks |
| 168 | pub fn write_multiple_blocks(addr: u32) -> Cmd<R1> { |
| 169 | cmd(cmd:25, arg:addr) |
| 170 | } |
| 171 | |
| 172 | /// CMD27: Program CSD |
| 173 | pub fn program_csd() -> Cmd<R1> { |
| 174 | cmd(cmd:27, arg:0) |
| 175 | } |
| 176 | |
| 177 | /// CMD55: App Command. Indicates that next command will be a app command |
| 178 | pub fn app_cmd(rca: u16) -> Cmd<R1> { |
| 179 | cmd(cmd:55, arg:u32::from(rca) << 16) |
| 180 | } |
| 181 | |
| 182 | /// ACMD6: Bus Width |
| 183 | /// * `bw4bit` - Enable 4 bit bus width |
| 184 | pub fn set_bus_width(bw4bit: bool) -> Cmd<R1> { |
| 185 | let arg: u32 = if bw4bit { 0b10 } else { 0b00 }; |
| 186 | cmd(cmd:6, arg) |
| 187 | } |
| 188 | |
| 189 | /// ACMD13: SD Status |
| 190 | pub fn sd_status() -> Cmd<R1> { |
| 191 | cmd(cmd:13, arg:0) |
| 192 | } |
| 193 | |
| 194 | /// ACMD41: App Op Command |
| 195 | /// |
| 196 | /// * `high_capacity` - Host supports high capacity cards |
| 197 | /// * `xpc` - Controls the maximum power and default speed mode of SDXC and SDUC cards. |
| 198 | /// * `s18r` - Switch to 1.8V signaling |
| 199 | /// * `voltage_window` - The voltage window the host supports. |
| 200 | pub fn sd_send_op_cond(high_capacity: bool, xpc: bool, s18r: bool, voltage_window: u32) -> Cmd<R3> { |
| 201 | let arg: u32 = u32::from(high_capacity) << 30 |
| 202 | | u32::from(xpc) << 28 |
| 203 | | u32::from(s18r) << 24 |
| 204 | | voltage_window & 0x00FF_FFFF; |
| 205 | cmd(cmd:41, arg) |
| 206 | } |
| 207 | |
| 208 | /// ACMD51: Reads the SCR |
| 209 | pub fn send_scr() -> Cmd<R1> { |
| 210 | cmd(cmd:51, arg:0) |
| 211 | } |
| 212 | |