ZYNQ7000 EMMC/SD硬件测试实战:从裸机读写到文件系统集成
1. 硬件测试环境搭建第一次拿到ZYNQ7000开发板时最让人头疼的就是如何快速验证EMMC和SD卡这些存储设备是否正常工作。我清楚地记得当时为了调试一个简单的读写测试整整折腾了两天。现在把这些经验总结出来希望能帮你少走弯路。首先得准备好开发环境。Vivado的安装就不多说了建议直接用2018.3版本这个版本对ZYNQ7000支持最稳定。安装完成后新建一个工程选择对应的开发板型号。这里有个小技巧如果你用的是定制板卡可以直接导入官方板级支持包BSP能省去很多手动配置的麻烦。硬件配置环节要特别注意PS端的设置。在Block Design里添加ZYNQ7 Processing System后双击打开配置界面。在Peripheral I/O配置中找到SD 0和SD 1接口确保EMMC和SD卡对应的接口已经启用。我遇到过好几次因为忘记勾选这个选项导致后续测试失败的情况。生成比特流文件后导出硬件到SDK。这里有个细节容易被忽略导出时一定要勾选Include bitstream选项。曾经因为这个选项没选导致SDK里找不到硬件描述文件白白浪费了半天时间排查。2. EMMC裸机读写测试实战2.1 初始化配置要点EMMC的裸机测试是验证硬件功能的基础。在SDK中新建空白应用工程后首先要配置BSP。右键工程选择Board Support Package Settings确保xsdps驱动已经包含。这个驱动是Xilinx提供的标准SD/MMC控制器驱动支持EMMC4.5协议。初始化代码里最容易出错的是时钟配置。EMMC的工作频率需要根据芯片规格设置一般开发板上的EMMC支持0-50MHz的工作频率。我建议先用低频比如10MHz测试确认基本功能正常后再逐步提高频率。记得调用XSdPs_Change_ClkFreq函数后要检查返回值频率设置失败是常见问题。块大小设置也需要注意。虽然EMMC支持多种块大小但建议统一使用512字节这是最兼容的设置。调用XSdPs_SetBlkSize函数时使用XSDPS_BLK_SIZE_512_MASK参数最稳妥。2.2 数据校验技巧读写测试的核心是数据校验。我通常的做法是先填充测试数据这里用递增数列就很合适for(i0;iBuffer_size;i) { WR_Buf[i]i%256; // 限制在单字节范围 }写入后立即读取比对时建议在发现错误时打印出错位置这对调试很有帮助if(WR_Buf[i]!RD_Buf[i]) { xil_printf(Error at position %d: wrote 0x%x, read 0x%x\r\n, i, WR_Buf[i], RD_Buf[i]); SD_ERROR1; break; }实际项目中遇到过几次数据比对失败的情况最后发现都是DDR缓存一致性问题。解决方法是在读写操作前后加上缓存无效化和刷新操作Xil_DCacheInvalidateRange((u32)RD_Buf, Buffer_size); Xil_DCacheFlushRange((u32)WR_Buf, Buffer_size);3. SD卡文件系统集成3.1 FatFs库配置要点在SD卡上实现文件系统FatFs是最轻量级的选择。在BSP设置里勾选xilffs库后要注意配置以下几个关键参数USE_MKFS是否支持格式化开发阶段建议开启FS_READONLY根据需求选择测试时设为0FS_FAT32根据SD卡容量选择大于32GB的必须开启我遇到过FatFs挂载失败的问题最后发现是SD卡未格式化为FAT32。解决方法是在代码中加入自动格式化逻辑if(f_mount(SD_Dev,SD_Path, 0) FR_NO_FILESYSTEM) { f_mkfs(SD_Path, FM_FAT32, 0); f_mount(SD_Dev,SD_Path, 1); }3.2 文件操作最佳实践文件读写测试要注意缓冲区对齐问题。SD卡DMA传输要求缓冲区32字节对齐这个细节文档里很容易被忽略u8 WR_Buf[1024] __attribute__ ((aligned(32))); u8 RD_Buf[1024] __attribute__ ((aligned(32)));文件写入时建议使用FA_CREATE_ALWAYS标志这样每次测试都会创建新文件避免旧数据干扰测试结果。文件操作后一定要检查返回值我整理了几个常见错误码的处理建议FR_DISK_ERR检查SD卡是否插好电源是否稳定FR_NOT_READYSD卡初始化失败检查时钟配置FR_NO_FILE文件路径错误检查挂载点设置4. 常见问题排查指南4.1 硬件连接检查当测试失败时首先应该排除硬件问题。用万用表测量SD卡槽的供电电压正常应该在3.3V±10%范围内。时钟信号可以用示波器观察应该看到50MHz的方波如果设置了最高频率。EMMC的硬件排查比较麻烦因为通常是BGA封装。可以重点检查以下信号线的阻抗CMD线通常50欧姆DAT0-DAT7每根线阻抗一致CLK线注意终端匹配4.2 软件调试技巧在SDK调试时活用XSdPs_ReadReg和XSdPs_WriteReg函数可以直接读写控制器寄存器这对排查底层问题很有帮助。比如读取OCR寄存器可以确认卡是否上电完成u32 ocr; XSdPs_ReadReg(InstancePtr-Config.BaseAddress, XSDPS_OCR_OFFSET, ocr); if(!(ocr XSDPS_OCR_POWER_UP_BUSY_MASK)) { xil_printf(Card power up failed\r\n); }对于偶发的读写错误建议在中断服务例程中加入错误状态记录void SD_ISR(void *InstancePtr) { u32 int_status; XSdPs_ReadReg(InstancePtr-Config.BaseAddress, XSDPS_NORM_INTR_STAT_OFFSET, int_status); if(int_status XSDPS_INTR_ERR_MASK) { error_log | int_status; } }调试文件系统时可以开启FatFs的trace功能在ffconf.h中设置FF_USE_TRACE为1这样可以在串口看到详细的文件操作日志。