很多工程师第一次用SD NAND,卡住的不是硬件接线,而是软件驱动。SD NAND兼容SD协议,理论上用STM32的SDIO或SPI接口都能驱动,但SPI模式接线简单(四根线搞定),在引脚资源紧张的MCU上更常用。

本文以正点原子精英板(STM32F103)+ 米客方德MKDV4GIL-AS SD NAND为例,拆解SPI模式下从初始化到文件写入的完整代码流程。由于开发板上是TF卡接口,需要用一块TF-SD NAND转接板把LGA封装转成TF卡金手指形态。

SD NAND上电后默认处于SDIO模式。要切换到SPI模式,需要在发送CMD0(复位命令)的同时把CS片选信号拉低。这个动作一旦成功,SD NAND就锁定在SPI模式,后续所有通信都走SPI协议,不会再回到SDIO模式。
从引脚定义看,MKDV4GIL-AS在SD模式下DAT3是数据线,在SPI模式下变成CS片选线;CMD在SD模式下是命令线,SPI模式下变成MOSI(数据输入);DAT0在SD模式下是数据线,SPI模式下变成MISO(数据输出)。同一颗芯片,模式不同,引脚功能完全不同,接线时要对照规格书的引脚分配表来接。
代码入口在main函数,先完成HAL库初始化、时钟配置、GPIO/SPI1/FATFS/UART外设初始化,然后调用GetSDCardCapacity()获取容量信息,进入主循环调用WritetoSD()写入数据。
GetSDCardCapacity()函数里,第一步是SDinit()——这是SD NAND的底层初始化,内部完成上电延时、发送CMD0进入SPI模式、CMD8检查电压兼容性、ACMD41激活卡片、CMD58读取OCR寄存器等SD协议规定的初始化序列。SDinit()返回0表示成功,返回1表示失败。
初始化成功后,调用FatFs文件系统的f_mount(&FS, "0:", 1)挂载文件系统。第三个参数"1"表示立即挂载(0则延迟挂载,等到第一次文件操作时才挂载)。挂载成功后,SD NAND在软件层面就变成了一个带文件系统的磁盘,可以用标准的文件API操作。
挂载成功后,调用fgetfree("0:", &freclust, &fs)获取空闲簇数量。这个函数返回的fs指针指向FATFS结构体,里面有文件系统的关键参数:n_fatent是总簇数,csize是每簇扇区数。
通过这两个参数可以算出总容量和可用容量:
// c TotalSpace = (uint16_t)(((fs->n_fatent - 2) * fs->csize) / 2 / 1024); AvailableSize = (uint16_t)((fre_clust * fs->csize) / 2 / 1024); UsedSize = TotalSpace - AvailableSize;
除以2是因为每扇区512字节,再除以1024换算成MB。最后通过串口打印出来,方便确认SD NAND的容量是否正常识别。
WritetoSD()函数展示了完整的文件写入流程。函数开头再次调用SDinit()和fmount()——每次写入前都重新初始化和挂载,这种写法虽然不够高效(实际项目中初始化一次就够了),但在测试阶段能保证每次写入都是干净状态。
关键逻辑在f_mount的返回值判断上:
// c res = f_mount(&fs, "0:", 1); if(res == FR_NO_FILESYSTEM) // 没有文件系统 { res = f_mkfs("", 0, 0); // 格式化 if(res == FR_OK) { f_mount(NULL, "0:", 1); // 先取消挂载 f_mount(&fs, "0:", 1); // 重新挂载 } }
这段代码处理了一个常见场景:全新的SD NAND没有文件系统,fmount会返回FRNOFILESYSTEM。这时候需要先调用fmkfs()创建FAT文件系统,格式化完成后取消挂载再重新挂载,文件系统才能正常使用。
文件写入部分用fopen打开(或创建)文件,flseek把指针移到文件末尾确保追加写入而不覆盖已有数据,fwrite写入数据,fclose关闭文件,最后f_mount(NULL)取消挂载。整个流程跟在PC上操作文件没有本质区别——这就是SD NAND内建控制器和FatFs文件系统配合的好处,工程师不需要关心底层Flash的页编程和块擦除,只需要调文件API。
代码中大量使用printf打印每一步的状态:初始化成功/失败、挂载结果、容量信息、格式化结果、文件打开/写入结果。这些串口输出在调试阶段非常关键——SD NAND的SPI驱动涉及多个协议层(SPI物理层→SD协议层→FatFs文件系统层),任何一层出问题都会导致操作失败,有了串口打印就能快速定位卡在哪一步。
程序下载后,串口助手能看到完整的初始化流程和容量信息,SD NAND内会生成一个写入测试数据的TXT文件,说明SPI模式驱动正常。
接线方面,SPI模式的四根线(CLK、MOSI、MISO、CS)对应STM32的SPI1外设引脚,MOSI接SD NAND的CMD(数据输入),MISO接DAT0(数据输出),CS接DAT3,CLK接CLK。如果用的是转接板,转接板已经帮你接好了,直接插TF卡槽就行。

FatFs配置方面,需要在ffconf.h中开启FFFSREADONLY = 0(允许写入)、FFUSEMKFS = 1(允许格式化)、FFCODEPAGE设置为支持中文的编码页(如果文件名含中文)。diskio.c中需要实现SPI模式下的SD卡读写底层函数(diskread、diskwrite、diskioctl等),这些函数对接STM32的HALSPI_TransmitReceive。
MKDV4GIL-AS在SPI模式下实测写入速度约10MB/s左右,读取速度约21MB/s,对于日志记录、参数存储这类嵌入式应用足够用了。如果对速度有更高要求,可以切到SDIO四线模式,带宽能翻几倍。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。