1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
//! SD 命令下发与完成/传输等待。
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
use super::Sdmmc;
use super::consts::*;
use crate::utils::delay;
impl Sdmmc {
/// 等待命令完成
///
/// 轮询中断状态寄存器,等待命令完成或错误发生
pub fn wait_for_cmd_done(&self) -> Result<(), CmdError> {
loop {
let sts = self.regs.norm_and_err_int_sts.extract();
// 检查是否发生错误中断
if sts.is_set(NORM_AND_ERR_INT_STS::ERR_INT) {
// 清除错误中断标志
self.regs
.norm_and_err_int_sts
.write(NORM_AND_ERR_INT_STS::ERR_INT::SET);
return Err(CmdError::IntError);
}
// 检查命令是否完成
if sts.is_set(NORM_AND_ERR_INT_STS::CMD_CMPL) {
// 清除命令完成标志
self.regs
.norm_and_err_int_sts
.write(NORM_AND_ERR_INT_STS::CMD_CMPL::SET);
return Ok(());
}
// 短暂延时,避免过度占用 CPU
delay(1);
}
}
/// 等待数据传输完成
///
/// 轮询中断状态寄存器,等待数据传输完成或错误发生
pub fn wait_for_xfer_done(&self) -> Result<(), CmdError> {
loop {
let sts = self.regs.norm_and_err_int_sts.extract();
// 检查传输是否完成
if sts.is_set(NORM_AND_ERR_INT_STS::XFER_CMPL) {
// 清除传输完成标志
self.regs
.norm_and_err_int_sts
.write(NORM_AND_ERR_INT_STS::XFER_CMPL::SET);
return Ok(());
}
// 检查是否发生错误中断
if sts.is_set(NORM_AND_ERR_INT_STS::ERR_INT) {
// 清除错误中断标志
self.regs
.norm_and_err_int_sts
.write(NORM_AND_ERR_INT_STS::ERR_INT::SET);
return Err(CmdError::IntError);
}
// 短暂延时
delay(1);
}
}
/// 发送 SD 命令并等待响应
///
/// # 参数
/// - `cmd`: 命令类型 (CMD 或 ACMD)
/// - `arg`: 命令参数 (32位)
/// - `blk_cnt`: 数据块数量 (0 表示无数据传输)
///
/// # 返回值
/// - `Ok(())`: 命令执行成功
/// - `Err(CmdError)`: 命令执行失败
pub fn cmd_transfer(
&self,
cmd: CommandType,
arg: u32,
blk_cnt: u32,
dma: bool,
) -> Result<(), CmdError> {
// 等待命令线和数据线空闲
while self.regs.present_state.any_matching_bits_set(
PRESENT_STATE::CMD_INHIBIT::SET + PRESENT_STATE::CMD_INHIBIT_DAT::SET,
) {
core::hint::spin_loop();
}
// 构建命令寄存器值
let mut xfer_mode = XFER_MODE_AND_CMD::CMD_IDX.val(cmd.num() as u32);
// 根据命令类型设置数据传输标志
match cmd {
CommandType::CMD(17) => {
// 单块读取: 显式设置块大小 512 字节、块数量 1,
// 使 read_block_single 不依赖此前残留的寄存器值。
self.regs.blk_size_and_cnt.write(
BLK_SIZE_AND_CNT::XFER_BLK_SIZE.val(BLOCK_SIZE as u32)
+ BLK_SIZE_AND_CNT::BLK_CNT.val(1),
);
// 读取命令: 有数据,读方向
xfer_mode +=
XFER_MODE_AND_CMD::DATA_PRESENT::SET + XFER_MODE_AND_CMD::DAT_XFER_DIR::Read;
}
CommandType::ACMD(51) => {
// 读取命令: 有数据,读方向
xfer_mode +=
XFER_MODE_AND_CMD::DATA_PRESENT::SET + XFER_MODE_AND_CMD::DAT_XFER_DIR::Read;
}
CommandType::CMD(18) => {
// 块大小 0x200 = 512 字节
self.regs.blk_size_and_cnt.write(
BLK_SIZE_AND_CNT::XFER_BLK_SIZE.val(BLOCK_SIZE as u32)
+ BLK_SIZE_AND_CNT::BLK_CNT.val(blk_cnt),
);
// 读取命令: 有数据,读方向
xfer_mode += XFER_MODE_AND_CMD::DATA_PRESENT::SET
+ XFER_MODE_AND_CMD::DAT_XFER_DIR::Read
+ XFER_MODE_AND_CMD::BLK_CNT_EN::SET
+ XFER_MODE_AND_CMD::AUTO_CMD_EN::AutoCmd12
+ XFER_MODE_AND_CMD::MULTI_BLK_SEL::SET;
}
CommandType::CMD(24) => {
// 单块写入: 显式设置块大小 512 字节、块数量 1。
self.regs.blk_size_and_cnt.write(
BLK_SIZE_AND_CNT::XFER_BLK_SIZE.val(BLOCK_SIZE as u32)
+ BLK_SIZE_AND_CNT::BLK_CNT.val(1),
);
// 写入命令: 有数据,写方向
xfer_mode +=
XFER_MODE_AND_CMD::DATA_PRESENT::SET + XFER_MODE_AND_CMD::DAT_XFER_DIR::Write;
}
CommandType::CMD(25) => {
// 多块写入 (WRITE_MULTIPLE_BLOCK): 块大小 512、块数量 blk_cnt。
self.regs.blk_size_and_cnt.write(
BLK_SIZE_AND_CNT::XFER_BLK_SIZE.val(BLOCK_SIZE as u32)
+ BLK_SIZE_AND_CNT::BLK_CNT.val(blk_cnt),
);
// 写入命令: 有数据,写方向,多块 + AUTO_CMD12 自动停止。
xfer_mode += XFER_MODE_AND_CMD::DATA_PRESENT::SET
+ XFER_MODE_AND_CMD::DAT_XFER_DIR::Write
+ XFER_MODE_AND_CMD::BLK_CNT_EN::SET
+ XFER_MODE_AND_CMD::AUTO_CMD_EN::AutoCmd12
+ XFER_MODE_AND_CMD::MULTI_BLK_SEL::SET;
}
_ => {}
}
log::debug!(
"blk cnt: {}",
self.regs.blk_size_and_cnt.read(BLK_SIZE_AND_CNT::BLK_CNT)
);
if dma {
xfer_mode += XFER_MODE_AND_CMD::DMA_EN::SET;
}
// 根据命令类型设置响应格式和校验标志
match cmd {
// R1 响应: 48 位,带 CRC 和索引校验
CommandType::CMD(7)
| CommandType::CMD(8)
| CommandType::CMD(16)
| CommandType::CMD(17)
| CommandType::CMD(18)
| CommandType::CMD(24)
| CommandType::CMD(25)
| CommandType::ACMD(6)
| CommandType::ACMD(42)
| CommandType::ACMD(51) => {
xfer_mode += XFER_MODE_AND_CMD::RESP_TYPE::Response48
+ XFER_MODE_AND_CMD::CMD_CRC_CHK_EN::SET
+ XFER_MODE_AND_CMD::CMD_IDX_CHK_EN::SET;
}
// R2 响应: 136 位,带 CRC 校验 (CID/CSD)
CommandType::CMD(2) | CommandType::CMD(9) => {
xfer_mode += XFER_MODE_AND_CMD::RESP_TYPE::Response136
+ XFER_MODE_AND_CMD::CMD_CRC_CHK_EN::SET;
}
// R3 响应: 48 位,无校验 (OCR)
CommandType::ACMD(41) | CommandType::CMD(58) => {
xfer_mode += XFER_MODE_AND_CMD::RESP_TYPE::Response48;
}
// R6 响应: 48 位带忙,带 CRC 和索引校验 (RCA)
CommandType::CMD(3) => {
xfer_mode += XFER_MODE_AND_CMD::RESP_TYPE::Response48Busy
+ XFER_MODE_AND_CMD::CMD_CRC_CHK_EN::SET
+ XFER_MODE_AND_CMD::CMD_IDX_CHK_EN::SET;
}
_ => {}
}
// 设置超时时间 (0xe 表示最大超时)
self.regs.clk_ctl.modify(CLK_CTL::TOUT_CNT::TMCLK2p27);
// 清除所有中断状态
self.regs.norm_and_err_int_sts.set(0xF3FFFFFF);
log::debug!(
"read cmd transfer: {:#x?}",
self.regs.norm_and_err_int_sts_en.get()
);
// 写入命令参数
self.regs.argument1.set(arg);
// 写入命令和传输模式寄存器,触发命令发送
self.regs.xfer_mode_and_cmd.write(xfer_mode);
// 等待命令完成
self.wait_for_cmd_done()?;
// 读取响应寄存器 (必须读取,否则可能导致问题)
let resp0 = self.regs.response0.get();
let resp1 = self.regs.response1.get();
let resp2 = self.regs.response2.get();
let resp3 = self.regs.response3.get();
log::trace!(
"resp0: {:#x} resp1: {:#x} resp2: {:#x} resp3: {:#x}",
resp0,
resp1,
resp2,
resp3
);
Ok(())
}
/// 获取响应寄存器 0 的值
pub fn get_response0(&self) -> u32 {
self.regs.response0.get()
}
}