本文介绍如何三招搞定Linux SD
卡驱动调试。
一、SD卡介绍
SD Card(Secure Digital Memory Card)
:即安全数码卡,是一种基于半导体快闪存储器的新一代高速存储设备。
SD
卡架构如下:
下面简单整理下SD
卡的外部引脚、内部寄存器、速度等级和容量等级。
1、外部引脚
SD
卡支持三种传输模式:SPI
模式、1bit SD
模式和4bit SD
模式。
在实际项目中,自己主要调试后面两种模式,SD
卡共有9个引脚,汇总如下:
引脚名称 | 引脚描述 | 备注 |
---|---|---|
CLK | 时钟信号 | |
CMD | 命令/回复引脚 | |
DATA0 ~ 3 | 数据线 | 1bit SD 模式:只使用DATA0 ,CD :卡检测。4bit SD 模式:CD/DATA3 :卡检测/数据3 |
VDD | 电源 | |
VSS1/2 | 地 |
2、内部寄存器
SD卡相关寄存器整理如下:
寄存器名称 | 寄存器描述 |
---|---|
OCR(Operating Conditions Register) | 运行条件寄存器 |
CID(Card IDentification Register) | 卡识号寄存器,每张卡都有唯一的识别号 |
CSD(Card Specific Data Register) | 描述数据寄存器 |
SCR(SD Card Configuration Register) | SD卡配置寄存器 |
RCA(Relative Card Address) | 卡地址寄存器 |
DSR(Driver Stage Register) | 驱动级寄存器 |
3、速度等级
根据数据传输速度,SD
卡有不同的速度等级表示方法。
协议规范 | 简介 |
---|---|
SD1.0 | 使用X 表示不同的速度等级,较少使用。 |
SD2.0 | 普通卡(Class2、Class4、Class6)和高速卡(Class10)。 |
SD3.0 | 使用UHS速度等级1和3。 |
SD4.0 | 使用UHS-II |
4、容量等级
SD
卡容量目前支持:SD
、SDHC
和SDXC
。
SD卡类型 | 协议规范 | 容量大小 | 支持文件格式 |
---|---|---|---|
SD | SD1.0 | ~2GB | FAT 12,16 |
SDHC(SD High Capacity) | SD2.0 | 2GB ~ 32GB | FAT 32 |
SDXC(SD eXtended Capacity) | SD3.0 | 32GB ~ 2TB | exFAT |
二、SD卡调试
1、原理图
预调驱动,先看原理图。
下图是RK3568
和microSD
卡槽之间的连接方式。
2、SDCard配置
RK3568 SD
卡配置文件:
1)arch/arm64/boot/dts/rockchip/rk3568.dtsi
sdmmc0: dwmmc@fe2b0000 { compatible = "rockchip,rk3568-dw-mshc", "rockchip,rk3288-dw-mshc"; reg = <0x0 0xfe2b0000 0x0 0x4000>; interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; max-frequency = <150000000>; clocks = <&cru HCLK_SDMMC0>, <&cru CLK_SDMMC0>, <&cru SCLK_SDMMC0_DRV>, <&cru SCLK_SDMMC0_SAMPLE>; clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; fifo-depth = <0x100>; resets = <&cru SRST_SDMMC0>; reset-names = "reset"; status = "disabled"; };
2)arch/arm64/boot/dts/rockchip/rk3568-firefly-core.dtsi
&sdmmc0 { max-frequency = <150000000>; supports-sd; bus-width = <4>; cap-mmc-highspeed; cap-sd-highspeed; disable-wp; sd-uhs-sdr104; vmmc-supply = <&vcc3v3_sd>; vqmmc-supply = <&vccio_sd>; pinctrl-names = "default"; pinctrl-0 = <&sdmmc0_bus4 &sdmmc0_clk &sdmmc0_cmd &sdmmc0_det>; status = "okay"; };
其中:
clocks
:表示SD
卡控制器时钟、driver
和sample
时钟。
max-frequency
:SD
卡的最大运行频率,根据不同的模式进行调整。
supports-sd
:表示为SD
卡功能,必须添加。否则无法初始化SD
卡。
bus-width
:SD
卡使用4线模式。如果不配置,默认1线模式。
cap-mmc-highspeed/cap-sd-highspeed
:支持highspeed
的SD
卡。
vmmc-supply、vqmmc-supply
:SD
卡电源域。
SD3.0
速度模式:
sd-uhs-sdr12:时钟频率不超过24M,信号电压1.8V sd-uhs-sdr25:时钟频率不超过50M,信号电压1.8V sd-uhs-sdr50:时钟频率不超过100M,信号电压1.8V sd-uhs-ddr50:时钟频率不超过50M,采用双沿采样,信号电压1.8V sd-uhs-sdr104:时钟频率不超过208M,信号电压1.8V
pinctrl-0
:SD
卡pinmux
配置。
3、SDCard驱动
RK3568
驱动文件:drivers/mmc/host/dw_mmc-rockchip.c
,主要关注:
static const struct dw_mci_drv_data rk3288_drv_data = { .caps = dw_mci_rk3288_dwmmc_caps, .num_caps = ARRAY_SIZE(dw_mci_rk3288_dwmmc_caps), .set_ios = dw_mci_rk3288_set_ios, ## 配置时钟、总线、电源、片选、时序等 .execute_tuning = dw_mci_rk3288_execute_tuning, ## 调节driver clk和sample clk phase .parse_dt = dw_mci_rk3288_parse_dt, .init = dw_mci_rockchip_init, };
RK3568 SD
控制器使用Synopsys IP
,主要关注:dw_mci_rk3288_set_ios()
和dw_mci_rk3288_execute_tuning()
。
系统启动后,可通过如下命令查看SD
卡属性(驱动实现:drivers/mmc/core/debugfs.c
):
[root@xiaotianbsp:/]# cat /sys/kernel/debug/mmc1/ios clock: 150000000 Hz actual clock: 148500000 Hz vdd: 21 (3.3 ~ 3.4 V) bus mode: 2 (push-pull) chip select: 0 (don't care) power mode: 2 (on) bus width: 2 (4 bits) timing spec: 6 (sd uhs SDR104) signal voltage: 1 (1.80 V) driver type: 0 (driver type B)
三、SDCard测试
下面测试基于SanDisk Ultra 1 32G SD
卡完成。
1、SD卡检测
系统启动后,SD
卡启动日志如下:
[ 1.225398] dwmmc_rockchip fe2b0000.dwmmc: Successfully tuned phase to 266 [ 1.225420] mmc1: new ultra high speed SDR104 SDHC card at address aaaa [ 1.226456] mmcblk1: mmc1:aaaa SD32G 29.7 GiB [ 1.227643] mmcblk1: p1
如果SD
卡没有正常初始化,出现如下日志:
[ 182.501273] mmc_host mmc1: Bus speed (slot 0) = 375000Hz (slot req 400000Hz, actual 375000HZ div = 0) [ 182.672282] mmc1: error -123 whilst initialising SD card [ 182.686489] mmc_host mmc1: Bus speed (slot 0) = 375000Hz (slot req 300000Hz, actual 187500HZ div = 1) [ 182.699318] mmc_host mmc1: Bus speed (slot 0) = 375000Hz (slot req 375000Hz, actual 375000HZ div = 0) [ 182.717513] mmc_host mmc1: Bus speed (slot 0) = 375000Hz (slot req 200000Hz, actual 187500HZ div = 1)
原因:mmc_sd_init_card()
失败。出错信息定义(include/uapi/asm-generic/errno.h
):
#define ETIMEDOUT 110 /* Connection timed out */ ... #define ENOMEDIUM 123 /* No medium found */
2、SD卡寄存器
通过如下命令,可以查看SD
卡相关寄存器的值。
[root@xiaotianbsp:/]# cd /sys/class/mmc_host/mmc1/mmc1:aaaa [root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# ls block driver hwrev oemid scr type cid dsr manfid power serial uevent csd erase_size name preferred_erase_size ssr date fwrev ocr rca subsystem [root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat cid 03534453443332478554c496d501636f ## 其它寄存器查看方式类似
SD
卡其它参数的查看方法如下:
[root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat erase_size 512 [root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat fwrev 0x5 [root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat hwrev 0x8 [root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat manfid 0x000003 [root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat name SD32G [root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat oemid 0x5344 [root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat serial 0x54c496d5 [root@xiaotianbsp:/sys/devices/platform/fe2b0000.dwmmc/mmc_host/mmc1/mmc1:aaaa]# cat type SD
3、挂载/卸载
SD
卡分区挂载命令:
[root@xiaotianbsp:/]# mount -t vfat /dev/mmcblk1p1 /tmp/ [ 244.746983] FAT-fs (mmcblk1p1): utf8 is not a recommended IO charset for FAT filesystems, filesystem will be case sensitive! [ 244.749331] FAT-fs (mmcblk1p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck. [root@xiaotianbsp:/]# mount ... /dev/mmcblk1p1 on /tmp type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=936,iocharset=utf8,shortname=mixed,errors=remount-ro)
SD
卡分区卸载命令:
umount /dev/mmcblk1p1
4、创建分区
使用fdisk
命令,可在SD
卡上重新创建分区。
[root@xiaotianbsp:/]# fdisk /dev/mmcblk1 ... Command (m for help): p ## 1、查看现有分区 Disk /dev/mmcblk1: 30 GB, 31914983424 bytes, 62333952 sectors 3880 cylinders, 255 heads, 63 sectors/track Units: cylinders of 16065 * 512 = 8225280 bytes Device Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type /dev/mmcblk1p1 0,0,17 1023,254,63 16 62333951 62333936 29.7G c Win95 FAT32 (LBA) Command (m for help): d ## 2、删除分区 Selected partition 1 Command (m for help): p Disk /dev/mmcblk1: 30 GB, 31914983424 bytes, 62333952 sectors 3880 cylinders, 255 heads, 63 sectors/track Units: cylinders of 16065 * 512 = 8225280 bytes Device Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type Command (m for help): n ## 3、创建新分区,共创建了2个分区 Command action e extended p primary partition (1-4) p Partition number (1-4): 1 First cylinder (1-3880, default 1): Using default value 1 Last cylinder or +size or +sizeM or +sizeK (1-3880, default 3880): 1940 Command (m for help): p Disk /dev/mmcblk1: 30 GB, 31914983424 bytes, 62333952 sectors 3880 cylinders, 255 heads, 63 sectors/track Units: cylinders of 16065 * 512 = 8225280 bytes Device Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type /dev/mmcblk1p1 0,1,1 1023,254,63 63 31166099 31166037 14.8G 83 Linux Command (m for help): n Command action e extended p primary partition (1-4) p Partition number (1-4): 2 First cylinder (1941-3880, default 1941): Using default value 1941 Last cylinder or +size or +sizeM or +sizeK (1941-3880, default 3880): Using default value 3880 Command (m for help): p Disk /dev/mmcblk1: 30 GB, 31914983424 bytes, 62333952 sectors 3880 cylinders, 255 heads, 63 sectors/track Units: cylinders of 16065 * 512 = 8225280 bytes Device Boot StartCHS EndCHS StartLBA EndLBA Sectors Size Id Type /dev/mmcblk1p1 0,1,1 1023,254,63 63 31166099 31166037 14.8G 83 Linux /dev/mmcblk1p2 1023,254,63 1023,254,63 31166100 62332199 31166100 14.8G 83 Linux Command (m for help): w ## 4、保存新分区
5、读写测试
测试SD
卡写命令:
[root@RK356X:/]# time dd oflag=direct,nonblock if=/dev/zero of=/dev/mmcblk1p1 bs=1M count=100 100+0 records in 100+0 records out 104857600 bytes (105 MB, 100 MiB) copied, 3.4844 s, 30.1 MB/s real 0m 3.49s user 0m 0.00s sys 0m 0.16s
测试SD
卡读命令:
[root@RK356X:/]# time dd iflag=direct,nonblock if=/dev/mmcblk1p1 of=/dev/null bs=1M count=100 100+0 records in 100+0 records out 104857600 bytes (105 MB, 100 MiB) copied, 1.65236 s, 63.5 MB/s real 0m 1.65s user 0m 0.00s sys 0m 0.03s
上面命令中配置的iflag
和oflag
属性,可以规避文件系统cache
,直接读写,不使用buffer cache
。
注:转载请标注作者和出处。
RustDesk 由于诈骗猖獗,暂停国内服务 淘宝 (taobao.com) 重启网页版优化工作 Apple 发布 M4 芯片 高中生自创开源编程语言作为成人礼——网友锐评:依托答辩 云风从阿里离职,未来计划制作 Windows 平台的独立游戏 程序员的归宿 Visual Studio Code 1.89 发布 华为官宣余承东职务调整 15 年前被钉在“FFmpeg 耻辱柱”,今天他却得谢谢咱——腾讯QQ影音一雪前耻? 华中科技大学开源镜像站正式开放外网访问