Linux内核移植 part3:sdmmc驱动

本文详细记录了从发现问题到解决SD卡驱动问题的过程,并总结了SD卡驱动移植的关键步骤,包括管脚配置和驱动配置等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一种纯粹靠读书学来的真理,与我们的关系,就像假肢、假牙、蜡鼻子甚或人工植皮。而由独立思考获得的真理就如我们天生的四肢:只有它们才属于我们。 —— 叔本华

读书的价值在于认识你自己,而不是用填鸭式的知识来武装自己。今天的主题是sd卡驱动。分为故事描述和总结两部分,第一部分是发现问题到解决问题的过程,第二部分是总结,不想知道过程的可以直接跳到总结。

一 故事是这样的

自从更新博客以来,有不少童鞋通过qq,邮箱来提问,其中有个频率比较高的问题:支不支持emmc启动。很遗憾,由于前期注意力不在Linux上,没有去探究过这方面的问题,今天把sd host驱动编译进了内核,看了下启动日志,发现问题了。

[    0.682835] of_get_named_gpiod_flags: can't parse 'cd-gpios' property of node '/sdhci@12530000[0]'
[    0.682930] s3c-sdhci 12530000.sdhci: clock source 2: mmc_busclk.2 (40000000 Hz)
[    0.689939] s3c-sdhci 12530000.sdhci: GPIO lookup for consumer cd
[    0.689949] s3c-sdhci 12530000.sdhci: using device tree for GPIO lookup
[    0.689959] of_get_named_gpiod_flags: can't parse 'cd-gpios' property of node '/sdhci@12530000[0]'
[    0.689967] of_get_named_gpiod_flags: can't parse 'cd-gpio' property of node '/sdhci@12530000[0]'
[    0.689976] s3c-sdhci 12530000.sdhci: using lookup tables for GPIO lookup
[    0.689986] s3c-sdhci 12530000.sdhci: lookup for GPIO cd failed
[    0.689996] s3c-sdhci 12530000.sdhci: GPIO lookup for consumer wp
[    0.690004] s3c-sdhci 12530000.sdhci: using device tree for GPIO lookup
[    0.690012] of_get_named_gpiod_flags: can't parse 'wp-gpios' property of node '/sdhci@12530000[0]'
[    0.690020] of_get_named_gpiod_flags: can't parse 'wp-gpio' property of node '/sdhci@12530000[0]'
[    0.690028] s3c-sdhci 12530000.sdhci: using lookup tables for GPIO lookup
[    0.690037] s3c-sdhci 12530000.sdhci: lookup for GPIO wp failed
[    0.690312] s3c-sdhci 12530000.sdhci: No vmmc regulator found
[    0.695645] s3c-sdhci 12530000.sdhci: No vqmmc regulator found
[    0.729613] mmc0: SDHCI controller on samsung-hsmmc [12530000.sdhci] using ADMA

log显示找不到需要的cd-gpio和wp-gpio。

什么是cd-gpio和wp-gpio?

参考 mmc设备树介绍

cd-gpios: Specify GPIOs for card detection
wp-gpios: Specify GPIOs for write protection

查看Exynos4412用户手册可以知道:cd-gpio是和gpk2[2]复用的。

sdhci@12530000 {
        bus-width = <4>;
        pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
        pinctrl-names = "default";
        status = "okay";
        cd-gpios = <&gpk2 2 0>;
    };

启动后找不到cd-gpio的错误没有了,

[    0.795664] mmc0: new high speed SDHC card at address aaaa
[    0.800107] mmcblk0: mmc0:aaaa SU08G 7.40 GiB 
[    0.805839]  mmcblk0:

检测到了tf卡,然后来测试一下访问tf卡。

首先通过fdisk对tf卡进行分区,具体怎么用fdisk就不介绍了,但是执行fdisk -l的时候会报超时,再次执行的时候又没有了,有点奇怪,先不管这个。

[root@osee ]#fdisk -l
[ 1961.203023] mmcblk0: error -110 sending status command, retrying
[ 1961.207601] mmcblk0: error -110 sending status command, retrying
[ 1961.213572] mmcblk0: error -110 sending status command, aborting
[ 1961.375122] mmc0: tried to reset card
Disk /dev/mmcblk0: 7580 MB, 7948206080 bytes, 15523840 sectors
242560 cylinders, 4 heads, 16 sectors/track
Units: cylinders of 64 * 512 = 32768 bytes

Disk /dev/mmcblk0 doesn't contain a valid partition table
[root@osee ]#fdisk -l
Disk /dev/mmcblk0: 7580 MB, 7948206080 bytes, 15523840 sectors
242560 cylinders, 4 heads, 16 sectors/track
Units: cylinders of 64 * 512 = 32768 bytes

分区完之后写个文件,然后再去笔记本上打开,发现正常。

重新拔插一下tf卡,在执行fdisk -l的时候不能识别,报I/O error,而且使能了sdmmc2的INSERT和REMOVAL中断,却没有抓到中断log。

二 总结

如何移植sd卡驱动呢?基本过程其实都是类似的。

2.1 管脚配置

regulators {
        compatible = "simple-bus";
        #address-cells = <1>;
        #size-cells = <0>;

        mmc_reg: regulator@0 {
            compatible = "regulator-fixed";
            reg = <0>;
            regulator-name = "VMEM_VDD_2.8V";
            regulator-min-microvolt = <2800000>;
            regulator-max-microvolt = <2800000>;
        };
};
...
sdhci@12530000 {
        bus-width = <4>;
        pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
        cd-gpios = <&gpk2 2 GPIO_ACTIVE_HIGH>;
        pinctrl-names = "default";
        vmmc-supply = <&mmc_reg>;
        status = "okay";
    };

2.2 驱动配置

sdmmc.png

在sd初始化的时候使能了INSERET和REMOVAL中断,但是没有反应,还不知道为什么。

static void sdhci_init(struct sdhci_host *host, int soft)
{
    if (soft)
        sdhci_do_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
    else
        sdhci_do_reset(host, SDHCI_RESET_ALL);

    host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
            SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
            SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC |
            SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
            SDHCI_INT_RESPONSE | SDHCI_INT_CARD_INSERT |
            SDHCI_INT_CARD_REMOVE;

    sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
    sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);

    if (soft) {
        /* force clock reconfiguration */
        host->clock = 0;
        sdhci_set_ios(host->mmc, &host->mmc->ios);
    }
}

查看系统中断的时候,可以发现是有sd中断的,所以gic配置是没问题的。也许是控制器有问题?要探究一下sd卡插入中断是如何产生的才行。

[root@osee ]#cat /proc/interrupts 
           CPU0       CPU1       CPU2       CPU3       
 36:          0          0          0          0       GIC  89 Edge      mct_comp_irq
 37:      45888       5049       3401       1244       GIC  28 Edge      MCT
 44:         36          0          0          0       GIC 107 Edge      mmc0
<think>好的,我现在需要帮助用户解决ESP32在使用SDMMC时遇到的错误:sdmmc_read_sectors_dma error0x107和diskio_sdmmc错误263。首先,我得回忆一下之前用户的问题历史,之前他们询问过关于LVGL图片缓存的优化,现在转向了SD卡相关的硬件问题。这可能意味着他们在开发一个涉及图形显示和存储的项目,比如嵌入式设备的数据采集或显示系统。用户提到的错误代码0x107和263,我需要查证这些错误的具体含义。根据ESP-IDF的文档,错误代码0x107通常与SDMMC的DMA传输有关,而错误263可能涉及块读取失败。可能的原因包括硬件连接问题、电源不稳定、SD卡格式或文件系统问题,以及软件配置错误。 接下来,我需要考虑用户可能的操作环境。他们可能在ESP32上使用SD卡存储数据,并通过SDMMC控制器进行读取。遇到DMA错误时,硬件问题如接线不良、电压不足或卡槽接触不良是常见原因。此外,SD卡的文件系统格式(如FAT32)是否正确,以及是否启用了正确的驱动程序设置也需要检查。用户可能已经尝试过基本的连接检查,但问题仍然存在,所以需要更深入的排查步骤。例如,建议他们检查DMA缓冲区是否对齐,或者降低时钟频率以测试稳定性。同时,软件层面的配置,如是否启用了正确的GPIO引脚,以及是否正确初始化了SDMMC驱动程序,也需要核实。 另外,考虑到用户之前的问题涉及LVGL,可能存在内存使用冲突,比如DMA缓冲区与其它内存区域重叠,或者内存不足导致DMA传输失败。因此,建议检查内存分配,确保缓冲区符合要求(如32位对齐),并优化内存使用。 在解决方案中,需要分步骤指导用户进行硬件检查、软件配置调整、错误处理以及可能的替代方案。同时,生成相关问题可以帮助用户进一步排查其他潜在问题,比如SD卡兼容性、SPI模式下的解决方法,以及如何监测硬件信号稳定性。 最后,要确保回答结构清晰,符合用户要求的格式,使用正确的中文和LaTeX语法,引用相关文档,并提供实用代码示例和命令,如使用esp_log来查看详细错误信息,调整SDMMC配置参数等。</think>### ESP32 SDMMC读取错误解决方案指南 --- #### 一、错误代码解析 1. **错误0x107** $$ \text{SDMMC\_ERR\_DMA\_FAIL} = 0x107 $$ 表示DMA传输失败,通常由内存对齐问题或硬件中断导致[^1] 2. **错误263** $$ \text{DISKIO\_ERR\_READ\_FAIL} = 263 $$ 对应`ESP_ERR_NOT_FOUND`,可能由文件系统损坏或物理读取错误引起[^2] --- #### 二、分步解决方案 ##### 1. 硬件检查 ```c // 检查GPIO配置(以4线模式为例) #define PIN_NUM_MISO 2 #define PIN_NUM_MOSI 15 #define PIN_NUM_CLK 14 #define PIN_NUM_CS 13 // 确保所有GPIO引脚阻抗匹配(建议串联33Ω电阻)[^3] ``` **关键测试点**: - 使用示波器测量CLK信号频率稳定性(建议≤20MHz) - 验证电源电压波动范围≤5% (3.3V±0.165V) - 检查SD卡槽接触阻抗(<0.5Ω) ##### 2. 软件配置优化 ```c // 修改sdmmc_host_t配置 sdmmc_host_t host = SDMMC_HOST_DEFAULT(); host.max_freq_khz = 20000; // 降频至20MHz测试稳定性 host.flags = SDMMC_HOST_FLAG_DDR; // 设置DMA缓冲区(需32字节对齐) uint8_t dma_buffer[512] __attribute__((aligned(32))); ``` ##### 3. 错误处理增强 ```c // 添加重试机制 esp_err_t ret; int retry_count = 0; do { ret = sdmmc_read_sectors_dma(...); if (ret == ESP_OK) break; vTaskDelay(pdMS_TO_TICKS(10)); } while (retry_count++ < 5); // 启用详细错误日志 esp_log_level_set("SDMMC", ESP_LOG_VERBOSE); ``` ##### 4. 替代方案 ```c // 改用SPI模式(兼容性更好) sdmmc_host_t spi_host = SDSPI_HOST_DEFAULT(); spi_host.slot = HSPI_HOST; ``` --- #### 三、配置参数对照表 | 参数 | 推荐值 | 作用域 | |--------------------|-----------------|------------------| | max_freq_khz | 10000-20000 | 时钟稳定性 | | DMA缓冲区对齐 | 32字节 | 内存访问优化[^1] | | 重试次数 | 3-5次 | 错误恢复 | | 电源滤波电容 | 100μF+0.1μF | 信号完整性 | --- #### 四、调试工具 1. **逻辑分析仪配置** $$ \text{采样率} \geq 4 \times \text{CLK频率} $$ 建议使用Saleae Logic Pro 16捕获完整协议时序[^4] 2. **ESP32内存监测** ```shell # 查看内存分配 idf.py size-components | grep "sdmmc" ``` --- #### 五、预防措施 1. **文件系统维护** ```c // 定期检查文件系统 FATFS *fs; FRESULT res = f_mount(fs, "", 1); if (res == FR_DISK_ERR) { f_mkfs("", FM_FAT32, 0, work, sizeof(work)); } ``` 2. **硬件保护电路** - 在DATA线加TVS二极管(如SMAJ3.3A) - CLK线串联120Ω电阻 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶玄青

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值