SD卡无法识别的问题解决 ”mmc0: error -110 whilst initialising SD card”

 硬件环境:am335x + SD卡

SD卡类型:class4,class10

问题现象:板子使用sd卡启动,内核启动后,在检测sd卡的时候出错:”mmc0: error -110 whilst initialising SD card” ,换一张就的sd卡却可以正常识别。不能识别的卡是class10的,可以识别的卡是class4的,那么由此推断卡的速度太快导致无法正常识别卡?想想也说不通,因为并不是所有的class4的卡都能够识别,只有最旧的那一批卡才能识别。那么怎样才能定位问题所在呢?

方法一:对比开发板和自己的板子,发现硬件原理差不多,但开发板无论用哪一种卡都能正常启动,两者采用的内核镜像都一样的,但自己的板子用高速卡(class10)总是启动不了。

方法二:在内核源码中找到sd卡初始化的那部分(/driver/mmc/core/sd.c和/driver/mmc/core/core.c),用printk在关键的地方标注,那么就可以定位问题出在哪里。经过测试,发现每次卡起不来的地方都在设置总线宽度的地方,屏蔽总线宽度的设置后问题依然。

方法三:下载SD卡的协议文档仔细研究一下。SD4.0协议文档只有一百页左右,很快可以看完,我之所以找4.0的协议文档是因为有中文版,看起来方便。sd卡使用的是sdio总线,其中很重要的是要知道CMDx命令代表什么含义。通讯时主机端发送cmd请求,客户端就会应答,如果客户端超时不应答,主机端就会重发,默认重发三次,如果仍然不响应则会报出超时的错误“error -110”。

方法四:开启内核debug模式,打印sd卡初始化时发送的命令及响应码。开启debug模式可以直接在内核菜单里开启,在mmc配置里面有debug的开关,打开即可。

[    1.449158] sdhci: Secure Digital Host Controller Interface driver
[    1.455431] sdhci: Copyright(c) Pierre Ossman
[    1.461366] omap_hsmmc 48060000.mmc: Got CD GPIO
[    1.505216] mmc0: mmc_rescan_try_freq: trying to init card at 400000 Hz
[    1.511893] mmc0: starting CMD52 arg 00000c00 flags 00000195
[    1.518133] mmc0: req done (CMD52): -110: 00000000 00000000 00000000 00000000
[    1.525686] mmc0: starting CMD52 arg 80000c08 flags 00000195
[    1.531767] mmc0: req done (CMD52): -110: 00000000 00000000 00000000 00000000
[    1.540039] mmc0: starting CMD0 arg 00000000 flags 000000c0
[    1.546684] Synopsys Designware Multimedia Card Interface Driver
[    1.553058] mmc0: req done (CMD0): 0: 00000000 00000000 00000000 00000000
[    1.561968] mmc0: starting CMD8 arg 000001aa flags 000002f5
[    1.569251] sdhci-pltfm: SDHCI platform and OF driver helper
[    1.575356] mmc0: req done (CMD8): 0: 000001aa 00000000 00000000 00000000
[    1.582234] mmc0: starting CMD5 arg 00000000 flags 000002e1
[    1.595498] mmc0: req failed (CMD5): -110, retrying...
[    1.609506] mmc0: req failed (CMD5): -110, retrying...
[    1.615220] mmc0: req failed (CMD5): -110, retrying...
[    1.620786] mmc0: req done (CMD5): -110: 00000000 00000000 00000000 00000000
[    1.633543] mmc0: starting CMD55 arg 00000000 flags 000000f5
[    1.639573] mmc0: req done (CMD55): 0: 00400120 00000000 00000000 00000000
[    1.646606] mmc0: starting CMD41 arg 00000000 flags 000000e1
[    1.652621] mmc0: req done (CMD41): 0: 40ff8000 00000000 00000000 00000000
[    1.660622] mmc0: starting CMD0 arg 00000000 flags 000000c0
[    1.672314] can: controller area network core (rev 20120528 abi 9)
[    1.678806] mmc0: req done (CMD0): 0: 00000000 00000000 00000000 00000000
[    1.687765] mmc0: starting CMD8 arg 000001aa flags 000002f5
[    1.713784] mmc0: req done (CMD8): 0: 000001aa 00000000 00000000 00000000
[    1.720692] mmc0: starting CMD55 arg 00000000 flags 000000f5
[    1.739251] mmc0: req done (CMD55): 0: 00000120 00000000 00000000 00000000
[    1.746258] mmc0: starting CMD41 arg 40200000 flags 000000e1
[    1.751972] omap common late init begin 111
[    1.756200] mmc0: req done (CMD41): 0: 40ff8000 00000000 00000000 00000000
[    1.785306] mmc0: starting CMD55 arg 00000000 flags 000000f5
[    1.794037] mmc0: req done (CMD55): 0: 00000120 00000000 00000000 00000000
[    1.801024] mmc0: starting CMD41 arg 40200000 flags 000000e1
[    1.810307] mmc0: req done (CMD41): 0: 40ff8000 00000000 00000000 00000000
[    1.832705] mmc0: starting CMD55 arg 00000000 flags 000000f5
[    1.838722] mmc0: req done (CMD55): 0: 00000120 00000000 00000000 00000000
[    1.845734] mmc0: starting CMD41 arg 40200000 flags 000000e1
[    1.851805] mmc0: req done (CMD41): 0: c0ff8000 00000000 00000000 00000000
[    1.858836] mmc0: starting CMD2 arg 00000000 flags 00000067
[    1.864729] pdevinfo->name = cpufreq-dt,pdevinfo->id = 0xffffffff
[    1.870875] pdev = 0xddc0ec00
[    1.873962] pdevinfo->dma_mask= 0x0
[    1.877496] mmc0: req done (CMD2): 0: 03534453 43313647 80b91040 970127ab
[    1.884410] mmc0: starting CMD3 arg 00000000 flags 00000075
[    1.890044] pdev= 0xddc0ec00, pdevinfo->res=0x0,pdevinfo->num_res = 0x0, xxxxx444
[    1.897583] mmc0: req done (CMD3): 0: aaaa0520 00000000 00000000 00000000
[    1.904513] mmc0: starting CMD9 arg aaaa0000 flags 00000007
[    1.917946] mmc0: req done (CMD9): 0: 400e0032 5b590000 76b27f80 0a404013
[    1.924879] mmc0: starting CMD7 arg aaaa0000 flags 00000015
[    1.930817] mmc0: req done (CMD7): 0: 00000700 00000000 00000000 00000000
[    1.937740] mmc0: starting CMD55 arg aaaa0000 flags 00000095
[    1.959956] mmc0: req done (CMD55): 0: 00000920 00000000 00000000 00000000
[    1.966953] mmc0: starting CMD51 arg 00000000 flags 000000b5
[    1.972699] mmc0:     blksz 8 blocks 1 flags 00000200 tsac 100 ms nsac 0
[    1.979846] omap common late init begin 444
[    1.984153] mmc0: req done (CMD51): 0: 00000920 00000000 00000000 00000000
[    1.984162] mmc0:     8 bytes transferred: 0
[    1.995457] mmc0: starting CMD55 arg aaaa0000 flags 00000095
[    2.001188] am33xx_int process omap late init
[    2.005590] mmc0: req done (CMD55): 0: 00000920 00000000 00000000 00000000
[    2.012624] mmc0: starting CMD13 arg 00000000 flags 000001b5
[    2.018326] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 100 ms nsac 0
[    2.044602] mmc0: req done (CMD13): 0: 00000920 00000000 00000000 00000000
[    2.044611] mmc0:     64 bytes transferred: 0
[    2.055988] mmc0: starting CMD6 arg 00fffff0 flags 000000b5
[    2.061604] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 100 ms nsac 0
[    2.077084] mmc0: req done (CMD6): 0: 00000900 00000000 00000000 00000000
[    2.077093] mmc0:     64 bytes transferred: 0
[    2.088364] mmc0: host does not support reading read-only switch, assuming write-enable
[    2.103847] mmc0: starting CMD6 arg 80fffff1 flags 000000b5
[    2.109466] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 100 ms nsac 0
[    2.116389] ThumbEE CPU extension supported.
[    2.120739] Registering SWP/SWPB emulation handler
[    2.130224] mmc0: req done (CMD6): 0: 00000900 00000000 00000000 00000000
[    2.137086] mmc0:     64 bytes transferred: 0
[    2.141742] mmc0: starting CMD55 arg aaaa0000 flags 00000095
[    2.176752] mmc0: req done (CMD55): -110: 00000000 00000000 00000000 00000000
[    2.186582] mmc0: starting CMD55 arg aaaa0000 flags 00000095
[    2.192354] mmc0: req done (CMD55): -110: 00000000 00000000 00000000 00000000
[    2.199695] mmc0: starting CMD55 arg aaaa0000 flags 00000095
[    2.234747] mmc0: req done (CMD55): -110: 00000000 00000000 00000000 00000000
[    2.242419] mmc0: starting CMD55 arg aaaa0000 flags 00000095
[    2.277455] mmc0: req done (CMD55): -110: 00000000 00000000 00000000 00000000
[    2.284800] mmc0: error -110 whilst initialising SD card
[    2.290352] mmc0: starting CMD1 arg 00000000 flags 000000e1
[    2.325414] mmc0: req done (CMD1): -110: 00000000 00000000 00000000 00000000

从debug的信息里面可以知道SD卡识别出错是报了超时的错误,CMD55响应超时,那么CMD55代表什么意思?查看SD协议可知CMD55是“特定应用命令 ”,就是说发送特定应用的命令之前必须先发送CMD55, 那么究竟是哪个命令导致CMD55超时呢?往前一个命令是CMD6,这个CMD6是切换功能命令,包含四种功能组:
(1) 访问模式:SD 总线接口速度模式的选择
(2) 命令系统:通过一套共有的命令来扩展和控制特定的功能
(3) 驱动强度:在 UHS-I 模式下选择合适的输出驱动强度,取决于主机环

(4) 电流/功率限制:UHS-I 卡在 UHS-I 模式下最大电流的选择,取决于
主机电源能力和散热能力(heat release)。这个字段在 UHS-II
卡中被重新定义为功率限制,因为 UHS-II 卡具有两种电源电压。

通过命令参数“mmc0: starting CMD6 arg 80fffff1 flags 000000b5”,可知该命令是用于切换SD卡的速度,猜测这里是由于切换SD卡速度导致通讯发生异常,CMD55也就会响应超时。带着这个假设,我把SD卡切换高速模式的那部分代码屏蔽掉,重新编译内核,发现问题依旧。

方法5::着对比旧的SD卡,看看有什么不同。把带有debug信息的内核拷贝到旧SD卡里面,插到板子上电测试,系统启动后打印下面的信息:

[    1.870768] mmc0: starting CMD7 arg 00010000 flags 00000015
[    1.886008] mmc0: req done (CMD7): 0: 00000700 00000000 00000000 00000000
[    1.892918] mmc0: starting CMD55 arg 00010000 flags 00000095
[    1.902160] mmc0: req done (CMD55): 0: 00000920 00000000 00000000 00000000
[    1.909148] mmc0: starting CMD51 arg 00000000 flags 000000b5
[    1.914896] mmc0:     blksz 8 blocks 1 flags 00000200 tsac 100 ms nsac 0
[    1.929329] mmc0: req done (CMD51): 0: 00000920 00000000 00000000 00000000
[    1.929340] mmc0:     8 bytes transferred: 0
[    1.940623] mmc0: starting CMD55 arg 00010000 flags 00000095
[    1.954517] mmc0: req done (CMD55): 0: 00000920 00000000 00000000 00000000
[    1.961477] mmc0: starting CMD13 arg 00000000 flags 000001b5
[    1.974016] mmc0:     blksz 64 blocks 1 flags 00000200 tsac 100 ms nsac 0
[    1.980902] omap2_common_pm_late_init: omap2 common 11xxx
[    1.986420] mmc0: req done (CMD13): 0: 00000920 00000000 00000000 00000000
[    1.986429] mmc0:     64 bytes transferred: 0
[    1.997795] mmc0: host does not support reading read-only switch, assuming write-enable
[    2.014792] mmc0: starting CMD55 arg 00010000 flags 00000095
[    2.020523] mmc0: req done (CMD55): 0: 00000920 00000000 00000000 00000000
[    2.027510] mmc0: starting CMD6 arg 00000002 flags 00000015
[    2.033162] am33xx_int process omap late init
[    2.037552] pdevinfo->name = pm33xx,pdevinfo->id = 0x0
[    2.042795] mmc0: req done (CMD6): 0: 00000920 00000000 00000000 00000000
[    2.049720] mmc0: new SDHC card at address 0001
[    2.070290] mmcblk0: mmc0:0001 SD8GB 7.28 GiB 
[    2.076244] mmc0: starting CMD18 arg 00000000 flags 000000b5
[    2.081961] mmc0:     blksz 512 blocks 8 flags 00000200 tsac 100 ms nsac 0
[    2.097570] mmc0:     CMD12 arg 00000000 flags 00000095
[    2.103326] xxxxxx888 ret = 0x0
[    2.106499] am33xx_int process pm init
[    2.110326] ThumbEE CPU extension supported.
[    2.119725] mmc0: req done (CMD18): 0: 00000900 00000000 00000000 00000000
[    2.119734] mmc0:     4096 bytes transferred: 0
[    2.119749] mmc0:     (CMD12): 0: 00000b00 00000000 00000000 00000000
[    2.137958]  mmcblk0: p1 p2

只需对比sd卡启动的部分,发现旧的SD卡并没有切换SD卡速度的命令(切换速度的命令是CMD6,ACMD6是用于切换总线宽度,区别是前面带有CMD55),由此得出的结论是旧卡没有切换SD的到高速模式,所以能正常工作,新卡切换了高速模式,导致通讯异常,卡无法识别。那为什么屏蔽设置高速模式的那部分代码并不能解决问题呢?其实在测试过程中就得到了答案,当我打开调试模式时,屏蔽高速模式的那部分代码后SD卡是能正常工作,而去掉调试模式后SD卡却无法正常工作,那么两者有啥区别?答案是有调试模式时,代码执行速度变慢了,导致时序也变慢,SD卡识别的时候就没那么容易超时了。那么解决问题的切入点就在延时方面下手,如果加delay应该在哪加呢?看了一会代码,发现加delay会影响SD卡的读写速度,可以选择另外一种方式:调整CMD命令的重发次数,默认重发次数是3,修改为10后再测试,发现问题解决了。以此印证之前的猜想,重发次数改为10,再配合去掉SD卡高速切换就能解决问题。说明板子用新卡的时候重发次数有可能超过三次,从而导致无法识别卡。

  • 13
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值