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 | |