0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

STM32 如何驱动 瀚海微SD NAND

吕辉 来源:jf_40298777 作者:jf_40298777 2025-10-27 10:40 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

一、工程说明与接口定义

适用芯片:​STM32F4xx / STM32F7xx / STM32H7xx​(其他系列可按 HAL调整)

接口方式:​SDIO 4-bit总线​(默认)

协议标准:​SD 2.0​(含 SDHC/SDXC),通过 CMD8/ACMD41完成电压与容量识别

文件系统:​FatFS​(diskio接口对接,扇区大小固定为512B

硬件要点:

CD/DAT3作为片选​(硬件拉高,SDIO自动控制)

电源上电顺序​:VCC先上电并稳定,再拉低 CMD/CLK/DAT0~3,初始化完成后再释放 DAT3片选

建议在 ​3.3V​电源域,SDIO接口附近放置 ​0.1µF + 10µF​去耦

本历程默认使用 ​HAL库时钟与引脚在 CubeMX中配置后生成工程再集成

二、CubeMX与初始化配置

RCC:HSE/PLL正常输出,系统时钟按芯片手册设置

SDIO:

Mode:​SDIO

Prescaler:初始分频使 ​SDIO_CK ≤ 400 kHz​(识别阶段)

Bus Wide:​1-bit​(初始化),初始化成功后切换 ​4-bit

Hardware Flow Control:​Enable

GPIO:CMD、CLK、DAT0~3设为 ​SDIO复用推挽;CD/DAT3设为 ​输入上拉​(硬件片选)

NVIC:开启 ​SDIO中断​与 ​DMA中断​(优先级略高于 SDIO)

生成工程后,将以下 sdio_sd.c/h加入工程,并在 main中调用初始化与测试接口

三、核心驱动代码

头文件:sdio_sd.h

#ifndef __SDIO_SD_H

#define __SDIO_SD_H

#include "stm32f4xx_hal.h"

#include "ff_gen_drv.h"

//返回值定义(与 HAL一致)

#define RES_OK 0U

#define RES_ERROR 1U

#define RES_NOTRDY 2U

#define RES_PARERR 3U

// SD状态

typedef enum {

SD_CARD_UNINIT = 0,

SD_CARD_READY,

SD_CARD_IDENT,

SD_CARD_STBY,

SD_CARD_TRAN,

SD_CARD_DATA,

SD_CARD_RCV,

SD_CARD_PRG,

SD_CARD_DIS,

SD_CARD_ERROR

} sd_card_state_t;

//公共接口(供 diskio.c调用)

DSTATUS sd_disk_initialize (BYTE pdrv);

DSTATUS sd_disk_status (BYTE pdrv);

DRESULT sd_disk_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count);

#if _USE_WRITE == 1

DRESULT sd_disk_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count);

#endif

#if _USE_IOCTL == 1

DRESULT sd_disk_ioctl (BYTE pdrv, BYTE cmd, void *buff);

#endif

//内部接口(可选)

HAL_StatusTypeDef sd_init_card(void);

HAL_StatusTypeDef sd_switch_4bit(void);

sd_card_state_t sd_get_state(void);

uint32_t sd_get_sector_count(void);

uint32_t sd_get_block_size(void);

#endif

源文件:sdio_sd.c

#include "sdio_sd.h"

#include

SD_HandleTypeDef hsd;

HAL_SD_CardInfoTypeDef SDCardInfo;

static DSTATUS disk_status_ = STA_NOINIT;

//私有:等待卡退出空闲(CMD0 -> CMD1循环)

static HAL_StatusTypeDef sd_cmd0_cmd1(void)

{

uint32_t resp;

uint32_t timeout = 1000000;

// CMD0: GO_IDLE_STATE

if (HAL_SD_CmdGoIdleState(&hsd, &resp) != HAL_OK) return HAL_ERROR;

if ((resp & 0xFF) != 0x01) return HAL_ERROR;

// CMD1: SEND_OP_COND(SD 2.0)

do {

if (HAL_SD_CmdAppOpCond(&hsd, 0x00000000, &resp) != HAL_OK) return HAL_ERROR;

if (timeout-- == 0) return HAL_TIMEOUT;

} while ((resp & 0x80000000) != 0); // CCS位未置位

return HAL_OK;

}

//私有:ACMD41(带 HCS标志,识别 SDHC/SDXC)

static HAL_StatusTypeDef sd_acmd41(void)

{

uint32_t resp;

uint32_t timeout = 1000000;

do {

if (HAL_SD_CmdAppCommand(&hsd, 0x00000000, &resp) != HAL_OK) return HAL_ERROR; // CMD55

if ((resp & 0xFF) != 0x01) return HAL_ERROR;

if (HAL_SD_CmdAppOpCond(&hsd, 0x40000000, &resp) != HAL_OK) return HAL_ERROR; // ACMD41 with HCS

if (timeout-- == 0) return HAL_TIMEOUT;

} while ((resp & 0x80000000) == 0);

return HAL_OK;

}

//私有:读取 OCR(可选)

static HAL_StatusTypeDef sd_read_ocr(void)

{

uint32_t resp;

return HAL_SD_CmdReadOCR(&hsd, &resp);

}

//私有:获取 CSD/CID(可选)

static HAL_StatusTypeDef sd_get_cid_csd(void)

{

if (HAL_SD_GetCardCID(&hsd, (HAL_SD_CardCIDTypeDef*)&SDCardInfo.CID) != HAL_OK)

return HAL_ERROR;

if (HAL_SD_GetCardCSD(&hsd, (HAL_SD_CardCSDTypeDef*)&SDCardInfo.CSD) != HAL_OK)

return HAL_ERROR;

return HAL_OK;

}

//初始化卡(SD 2.0)

HAL_StatusTypeDef sd_init_card(void)

{

HAL_StatusTypeDef status;

// 1) CMD0

if ((status = sd_cmd0_cmd1()) != HAL_OK) return status;

// 2) CMD1或 ACMD41(SD 2.0走 ACMD41)

if ((status = sd_acmd41()) != HAL_OK) return status;

// 3) CMD2: ALL_SEND_CID

if (HAL_SD_CmdSendCID(&hsd, (uint32_t*)&SDCardInfo.CID) != HAL_OK) return HAL_ERROR;

// 4) CMD3: SEND_RELATIVE_ADDR(获取 RCA)

if (HAL_SD_CmdSetRelAdd(&hsd, (uint32_t*)&SDCardInfo.RCA) != HAL_OK) return HAL_ERROR;

// 5) CMD9: SEND_CSD

if (HAL_SD_CmdSendCSD(&hsd, (uint32_t*)&SDCardInfo.CSD) != HAL_OK) return HAL_ERROR;

// 6) CMD7: SELECT/DESELECT_CARD(选中卡)

if (HAL_SD_CmdSelDesel(&hsd, (uint32_t)(SDCardInfo.RCA << 16)) != HAL_OK) return HAL_ERROR;

// 7) CMD13: SEND_STATUS

if (HAL_SD_CmdSendStatus(&hsd, (uint32_t)(SDCardInfo.RCA << 16), &resp) != HAL_OK) return HAL_ERROR;

// 8)读取 OCR(可选)

if ((status = sd_read_ocr()) != HAL_OK) return status;

// 9)读取 CSD/CID(可选)

if ((status = sd_get_cid_csd()) != HAL_OK) return status;

// 10)设置块长度为 512(SDSC必要;SDHC/SDXC固定 512B,但某些主机仍要求)

if (HAL_SD_CmdBlockLength(&hsd, 512) != HAL_OK) return HAL_ERROR;

return HAL_OK;

}

//切换 4-bit总线(初始化后调用)

HAL_StatusTypeDef sd_switch_4bit(void)

{

uint32_t resp;

// CMD55 + ACMD6(bus width = 2 => 4-bit)

if (HAL_SD_CmdAppCommand(&hsd, 0x00000000, &resp) != HAL_OK) return HAL_ERROR;

if (HAL_SD_CmdAppSetBusWidth(&hsd, 2, &resp) != HAL_OK) return HAL_ERROR;

hsd.Instance->CLKCR |= SDIO_CLKCR_WIDBUS_0; // 4-bit

return HAL_OK;

}

//读取扇区

DRESULT sd_disk_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count)

{

(void)pdrv;

if (disk_status_ != RES_OK) return RES_NOTRDY;

if (HAL_SD_ReadBlocks(&hsd, (uint32_t*)buff, sector, count, 1000000) == HAL_OK) {

//等待传输完成

while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER) {}

return RES_OK;

}

return RES_ERROR;

}

//写入扇区

#if _USE_WRITE == 1

DRESULT sd_disk_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)

{

(void)pdrv;

if (disk_status_ != RES_OK) return RES_NOTRDY;

if (HAL_SD_WriteBlocks(&hsd, (uint32_t*)buff, sector, count, 1000000) == HAL_OK) {

while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER) {}

return RES_OK;

}

return RES_ERROR;

}

#endif

// IOCTL

#if _USE_IOCTL == 1

DRESULT sd_disk_ioctl (BYTE pdrv, BYTE cmd, void *buff)

{

(void)pdrv;

DRESULT res = RES_PARERR;

switch (cmd) {

case CTRL_SYNC:

while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER) {}

res = RES_OK;

break;

case GET_SECTOR_COUNT:

*(uint32_t*)buff = SDCardInfo.BlockNbr;

res = RES_OK;

break;

case GET_SECTOR_SIZE:

*(uint32_t*)buff = SDCardInfo.BlockSize;

res = RES_OK;

break;

case GET_BLOCK_SIZE:

*(uint32_t*)buff = SDCardInfo.BlockSize; // SD 2.0通常为 512

res = RES_OK;

break;

default:

res = RES_PARERR;

}

return res;

}

#endif

// Disk Status

DSTATUS sd_disk_status (BYTE pdrv)

{

(void)pdrv;

if (disk_status_ == RES_OK) {

if (HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_TRANSFER)

return RES_OK;

else

return STA_NOINIT;

}

return disk_status_;

}

// Disk Initialize

DSTATUS sd_disk_initialize (BYTE pdrv)

{

(void)pdrv;

if (disk_status_ == RES_OK) return RES_OK;

//上电复位:拉低 DAT3片选(若硬件未处理)

// __HAL_RCC_SDIO_CLK_ENABLE();

// SDIO power on/off sequence per reference manual

if (sd_init_card() == HAL_OK) {

if (sd_switch_4bit() == HAL_OK) {

disk_status_ = RES_OK;

return RES_OK;

}

}

disk_status_ = RES_ERROR;

return RES_ERROR;

}

四、FatFS对接与使用示例

diskio.c(最小化对接)

#include "diskio.h"

#include "ff_gen_drv.h"

#include "sdio_sd.h"

#define SD_DISK_NUM 0

DSTATUS disk_status (BYTE pdrv) { return sd_disk_status(pdrv); }

DSTATUS disk_initialize (BYTE pdrv) { return sd_disk_initialize(pdrv); }

DRESULT disk_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count) { return sd_disk_read(pdrv, buff, sector, count); }

#if _USE_WRITE

DRESULT disk_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count) { return sd_disk_write(pdrv, buff, sector, count); }

#endif

#if _USE_IOCTL

DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void *buff) { return sd_disk_ioctl(pdrv, cmd, buff); }

#endif

main.c最小示例

#include "ff.h"

#include "sdio_sd.h"

FATFS fs;

FIL f;

FRESULT fr;

UINT bw;

int main(void)

{

HAL_Init();

SystemClock_Config();

MX_GPIO_Init();

MX_SDIO_SD_Init();

//挂载文件系统

fr = f_mount(&fs, "", 1);

if (fr != FR_OK) {

//格式化(首次烧录或异常时)

fr = f_mkfs("", FM_ANY, 0, buff, sizeof(buff));

if (fr == FR_OK) fr = f_mount(&fs, "", 1);

}

if (fr == FR_OK) {

fr = f_open(&f, "test.txt", FA_WRITE | FA_CREATE_ALWAYS);

if (fr == FR_OK) {

f_puts("Hello, SD NAND (SDIO 4-bit, SD 2.0)rn", &f);

f_close(&f);

}

}

while (1) {

//主循环

}

}

五、常见问题与优化建议

初始化失败

检查​电源 3.3V稳定、去耦充分

确认​SDIO引脚复用与上拉​ 正确,DAT3片选逻辑符合

识别阶段​SDIO_CK ≤ 400 kHz,初始化完成后再提速

若卡不支持​ACMD41,可回退到​CMD1

速度优化

初始化成功后调用​sd_switch_4bit()​,并将​ClockDiv​ 调至芯片手册允许的最大值

启用​SDIO DMA​ 与合适的中断优先级

文件系统

SDHC​ 容量上限​32GB,​SDXC​ 为 64GB+;FatFS对大容量支持良好

若需​中文长文件名,在 ffconf.h启用​_USE_LFN=2​ 并配置​FF_CODE_PAGE=936

稳定性

长时间写入建议加入​写缓存/队列​ 与​掉电检测​(GPIO中断 +缓存落盘)

工业环境注意​ESD防护​ 与​TVS,贴片 SD NAND比 TF卡更抗震动

以上文件可直接集成到现有 STM32工程,配合 CubeMX生成的初始化代码即可完成​SD 2.0瀚海微SD NAND​ 的稳定驱动与​FATFS​ 文件读写。

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • STM32
    +关注

    关注

    2313

    文章

    11195

    浏览量

    374667
  • SD NAND
    +关注

    关注

    0

    文章

    124

    浏览量

    1874
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    STM32+SD NAND(贴片SD卡)完成FATFS文件系统移植与测试

    这篇文章就手把手教大家,在STM32上完成FATFS文件系统的移植;主控芯片采用STM32F103ZET6, 存储芯片我这里采用(雷龙) CS创世 SD NAND
    的头像 发表于 07-17 17:24 1.2w次阅读
    <b class='flag-5'>STM32+SD</b> <b class='flag-5'>NAND</b>(贴片<b class='flag-5'>SD</b>卡)完成FATFS文件系统移植与测试

    关于SD NAND 的概述

    的成本效益,特别是在需要中小容量存储的应用场景中。   4. 易用性与兼容性   免驱动使用:由于SD NAND内置了必要的控制器和固件,大多数CPU只要支持SD接口就能直接使用,无需
    发表于 12-06 11:22

    STM32系列与SD NAND 成功的经验分享

    缓存、协议栈等等。这种场景下可以说SD NANDSTM32系列是最佳拍档。首先从SD NAND的架构来说,简单来说内部采用使用寿命最长、性
    发表于 07-12 10:34

    SD NAND与MCU(STM32系列)最佳拍档

    SD NAND与MCU(STM32系列)最佳拍档
    发表于 11-18 16:51 72次下载
    <b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>与MCU(<b class='flag-5'>STM32</b>系列)最佳拍档

    瀚海SD NANDSD 协议(29)硬件接口

    SD存储卡硬件接口 SD存储卡有6条通信线路和3条供电线路: CMD:命令是双向信号。主机和卡驱动以推拉方式工作。 DAT0-3:数据线是双向信号。主机和卡驱动在推拉模式下运行 CLK
    的头像 发表于 09-24 10:19 1497次阅读
    <b class='flag-5'>瀚海</b><b class='flag-5'>微</b><b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>之<b class='flag-5'>SD</b> 协议(29)硬件接口

    瀚海SD NANDSD 协议(32)1.8V信令的驱动强度和总线时序

    输出驱动强度 4级驱动强度为了保持主机系统的灵活设计,输出驱动可以看到大范围的主机负载。 4 种可选驱动强度使主机系统能够调整驱动强度,以优
    的头像 发表于 09-26 10:31 967次阅读
    <b class='flag-5'>瀚海</b><b class='flag-5'>微</b><b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>之<b class='flag-5'>SD</b> 协议(32)1.8V信令的<b class='flag-5'>驱动</b>强度和总线时序

    瀚海SD NANDSD 协议(36)SPI模式

    简介 SPI模式由基于flash的SD存储卡提供的辅助通信协议组成。 这种模式是SD存储卡协议的一个子集,设计用于与SPI通道通信,通常在摩托罗拉(以及最近一些其他供应商)的微控制器中发现。 接口
    的头像 发表于 10-08 10:13 1479次阅读
    <b class='flag-5'>瀚海</b><b class='flag-5'>微</b><b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>之<b class='flag-5'>SD</b> 协议(36)SPI模式

    CS创世SD NAND在北京君正平台和瑞芯RK平台的应用

    介绍、对SD NAND进行读写操作的三大方式、SD驱动框架介绍以及SD NAND启动,前三个板
    的头像 发表于 08-22 16:52 2940次阅读
    CS创世<b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>在北京君正平台和瑞芯<b class='flag-5'>微</b>RK平台的应用

    瀚海SD NAND/TF卡——数据世界的全能搭档

    当智能设备渗透生活每个角落,从旅行时运动相机捕捉的山野风光,到工作中平板存储的设计方案,再到无人机航拍的城市全景,每一份数据都承载着价值与回忆。瀚海SD NAND/TF卡,以硬核性能
    的头像 发表于 10-13 11:12 581次阅读
    <b class='flag-5'>瀚海</b><b class='flag-5'>微</b><b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>/TF卡——数据世界的全能搭档

    瀚海SD NAND/TF卡:赋能全场景数据存储,定义高效安全新基准

    在数字技术深度融入生产生活的当下,无论是消费端的智能设备数据记录,还是工业领域的关键信息存储,都对存储产品的性能、安全性与适配性提出更高要求。瀚海SD NAND/TF卡凭借硬核技术实
    的头像 发表于 10-14 10:18 460次阅读
    <b class='flag-5'>瀚海</b><b class='flag-5'>微</b><b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>/TF卡:赋能全场景数据存储,定义高效安全新基准

    瀚海SD NAND/TF卡数据读写超时(Data Transfer Timeout)问题深度解析

    数据读写超时是SD NAND/TF卡在数据传输环节的高频故障,直接导致数据传输中断、设备卡顿甚至业务停工,广泛影响消费级、工业级等多场景使用。以下从故障涉及的核心方面、深层诱因及针对性解决方案展开
    的头像 发表于 11-17 10:04 1162次阅读

    瀚海SD NAND TF卡硬件识别与初始化类问题探讨

    瀚海SD NAND/TF卡的实际应用中,硬件识别与初始化是保障设备正常运行的首要环节,该环节出现故障会直接导致存储卡无法投入使用,尤其在工业控制、车载设备等关键场景中,可能引发设备
    的头像 发表于 11-18 09:58 792次阅读
    <b class='flag-5'>瀚海</b><b class='flag-5'>微</b><b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>  TF卡硬件识别与初始化类问题探讨

    解决SD NAND CRC校验失败的综合指南:瀚海存储产品的可靠性保障

    高品质存储解决方案的提供者,瀚海一直致力于帮助客户解决此类技术难题,确保产品可靠性。 CRC错误的核心含义与瀚海的质量理念 CRC校验失败本质上是数据完整性保护机制在发挥作用。当控
    的头像 发表于 11-21 09:49 664次阅读
    解决<b class='flag-5'>SD</b> <b class='flag-5'>NAND</b> CRC校验失败的综合指南:<b class='flag-5'>瀚海</b><b class='flag-5'>微</b>存储产品的可靠性保障

    瀚海SD NAND/TF卡数据损坏与校验错误(含CRC错误、数据比对失败)问题解析

    数据损坏与校验错误是瀚海SD NAND/TF卡在数据存储与传输过程中的关键故障,除常见的CRC错误外,数据比对失败(读取数据与写入数据不一致)是核心表现形式,直接影响数据准确性,在工
    的头像 发表于 11-30 15:15 1136次阅读

    ESP32 驱动瀚海SD NAND 完整方案 + FAT/FAT32 驱动核心区别

    ESP32 驱动 SD NAND 的核心是基于SDIO 接口(SD NAND 主流通信方式,兼容 SPI 但速率更高),借助乐鑫官方esp-
    的头像 发表于 02-02 11:38 847次阅读
    ESP32 <b class='flag-5'>驱动</b><b class='flag-5'>瀚海</b><b class='flag-5'>微</b><b class='flag-5'>SD</b> <b class='flag-5'>NAND</b> 完整方案 + FAT/FAT32 <b class='flag-5'>驱动</b>核心区别