SDIO CMD6 介绍

SDIO CMD6 - SD Card

CMD6是SD卡用来扩展功能的一条重要命令。在SD协议1.00和2.00的版本是,该命令主要用于切换卡进入高速模式。而在3.00的协议中,该命令被赋予了更多的功能。

SD卡协议中定义了6组功能,每组功能相当于是一组单框,我们可以根据自己不同的需要,来对每一组功能进行不同的选择。

以SD协议2.00版本为例,共定义了两种功能:
Group1该组功能的名称叫AccessMode,主要就是用于速度上的选择了。默认选项为0x0,即25MHz的总线速度。我们可以将其选为0x1 High-Speed,即可进入到50MHz的总线速度模式了。
Group2功能的名称叫Command system,看样子是做一些命令上的扩展。怀疑可能会与加密卡有关,这里没有进行进一步的研究。

SD协议3.00版本,定义四种功能:

  1. 访问模式(Access Mode):SD总线接口速度模式的选择;
  2. 命令系统(Command System):通过一套莫共有的命令来扩展和控制特定的功能;
  3. 驱动强度(driver strength):在UHS-I模式下等选择合适的输出驱动强度,和主机环境相关;
  4. 电流/功率限制(Current/power limits):UHS-I卡在UHS-I模式大电海底捞针选择,和主机环境相关;

CMD6的响应是R1响应,也就是从data线返回512bit状态信息,相当于一个单块的读操作。

CMD6本身支持6个功能组(目前只用到了两个),每个功能组支持16种分支,每个功能组只能有一个分支有效,默认是function 0,
注意:每次只能选择一组进行访问,其他组参数设为1
CMD6有两个不同的模式:Mode 0查询功能,查看卡是否支持特定功能, Mode 1设置功能,直接切换卡的功能。

alt text

CMD6参数格式:

alt text

示例1:切换到4位总线模式
参数值:0x80FFFF01(十六进制)

Function Group 1 = 0x3FF(二进制 11 1111 1111)→ 选择 Function Select 1(总线宽度控制)

Function Group 3 = 0x000(不修改扩展功能)

Mode = 0x01(切换功能)

示例2:启用高速模式
参数值:0x03F00001(十六进制)

Function Group 1 = 0x000(不修改核心功能)

Function Group 3 = 0x3F0(二进制 11 1111 0000)→ 选择 Function Select 1(性能模式)

Mode = 0x01(切换功能)

alt text

  1. 响应格式
    CMD6 的响应为 R1(1字节状态),状态位的含义如下:
位域 名称 描述
7 OUT_OF_RANGE 参数错误(如地址无效)
6 FUNCTION_FAILED 功能切换失败
5 ILLEGAL_COMMAND 命令不支持
4 COM_CRC_ERROR CRC校验失败
3 CARD_LOCKED 卡被锁定
1 WP_VIOLATION 写保护冲突
0 READY_FOR_DATA 卡准备好传输数据

注意事项
参数有效性:

如果卡不支持某个 Function Group,响应中会置位 ILLEGAL_COMMAND 或 FUNCTION_FAILED。

切换功能前需通过 CMD8 或 ACMD41 确认卡的支持能力。

总线宽度切换:

切换到4位总线模式后,需通过 CMD52/CMD53 修改主控制器的总线宽度(SDIO控制器需同步配置)。

高速模式:

启用高速模式(如SDR25)需确保主控制器支持更高的时钟频率(如50MHz)。

code demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)

{
       struct mmc_cmd cmd;
       struct mmc_data data;
       /* Switch the frequency */
mode = !!mode;
       cmd.cmdidx = SD_CMD_SWITCH_FUNC;
       cmd.resp_type = MMC_RSP_R1;
       cmd.cmdarg = (mode << 31) | 0xffffff; //每次只能选择一组进行访问,其他组参数设为1
       cmd.cmdarg &= ~(0xf << (group << 2));
       cmd.cmdarg |= value << (group << 2);

       data.dest = (char *)resp;
       data.blocksize = 64;
       data.blocks = 1;
       data.flags = MMC_DATA_READ;

       return mmc_send_cmd(mmc, &cmd, &data);
}

linux内核里的调用:

alt text

其中第一个搜索项参数都为0。 “Find out the card’s support bits with a mode 0 operation.The argument does not matter, as the support bits do not matter, as the support bits do not change with the argum”

linux内核用这一次调用来判断是否SD Card支持HIGH_SPEED:

if (status[13] & SD_MODE_HIGH_SPEED)
    card->sw_caps.hs_max_dtr = HIGH_SEEPD_MAX_DTR;
 

group0 -> speed
group2 –> drive_strength
group3 –> current_limit

SDIO CMD6 - eMMc

CMD6(SWITCH命令)在SD卡和eMMC中的参数格式和用途存在显著差异。尽管两者均用于动态配置设备功能,但协议规范不同,需严格区分。

对比eMMc来说 CMD6的用途:
修改eMMC的扩展CSD寄存器(EXT_CSD),用于配置高速模式、总线宽度、驱动强度等。

需结合EXT_CSD寄存器地址操作(如JESD84规范定义)。

示例:设置HS200模式(EXT_CSD[0xB9]=0x02)
参数:0x03B90201

Access = 0x03(写入模式)

Index = 0xB9(目标寄存器地址)

Value = 0x02(HS200模式)

alt text

code demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
#define CMD6_ACCESS_MODE_WRITE_BYTE (0x03 << 24)
#define CMD6_SWITCH_FUNC 6

#define CMD6_INDEX(i) ((i) << 16)
#define CMD6_VALUE(v) ((v) << 8)
#define CMD6_REG_WRITE(index, value) CMD6_ACCESS_MODE_WRITE_BYTE | CMD6_INDEX(index) | CMD6_VALUE(value)

void mmc_set_bus_width()
{
para = CMD6_REG_WRITE(183, bit_width);
ret = sdmmc_send_cmd(CMD6_SWITCH_FUNC, para);
}

上面的代码针对emmc,用于切换总线宽度,183 = 0xB7,是EXT_CSD中Bus width mode字段所在字节

alt text

0x3B70201 B7=183 02 ->BUS WIDTH = 8 设置emmc的总线宽度8
0x3B30101 B7=179 01 ->partition config 设置emmc 分区配置为1

sdcard
0x00FFFFF0

sdcard
0x003FF001
为什么Function Group1,也就是[25:16]域内,写入值0x3ff就是配置总线宽度为1了?

子字段 位域范围 位数 描述

Function Select [25:22] 4位 选择FG1的具体功能(如总线宽度控制)。
参数值 [21:16] 6位 配置该功能的具体参数(如启用4位模式)。

总线宽度控制 对应的 Function Select = 1(二进制 0001)。
此值需写入 FG1的高4位(位25到22),即 0x1。

SD规范要求,当选择总线宽度控制时,参数值的低6位([21:16])必须全为 1(即二进制 111111,十六进制 0x3F)
含义:全 1 表示请求切换到 4位总线模式(SD卡不支持8位,仅支持1位或4位)。