当前位置: 首页 > news >正文

【HAL库】STM32CubeMX开发----STM32F407----SD卡存储 SDIO通信DMA读写

前言

关于SDIO和SD卡的基础信息,请参考:【HAL库】STM32CubeMX开发----STM32F407----SD卡存储 SDIO基础通信
本次主要介绍SDIO通过DMA读写SD卡数据,不占用CPU的运行时间。

一、使用STM32CubeMX----新建工程

步骤1:打开 STM32CubeMX 软件

具体STM32CubeMX界面如下:

步骤2:选择 从MCU开始我的项目

步骤3:选择MCU芯片

我们本次实验选择STM32F407VET6芯片做MCU

进入工程编辑,具体界面如下:

步骤4:设置烧写方式为 SWD模式

这一步必须选择一种烧写方式,否则烧写一次程序后,芯片中就没法再次烧写程序了。需要硬件重启才可以重新烧写程序。

STM32烧写程序连接方式详解

步骤5:设置时钟源

设置外部晶振为芯片系统时钟源。

步骤6:设置SDIO

  • Mode:选择SD的四线模式,即 SD 4 bits Wide bus.
  • 参数部分:F4系列不用修改配置,默认即可。F103系列,需把时钟分频系数修改为 6,即SDIOCLK Clock divide factor这一项,由默认0改为6, 不然会通信失败。

步骤7:DMA配置

Add添加SDIO_RX,DMA功能,参数默认。

按照以上操作,添加SDIO_TX,DMA功能,参数默认。

勾选SDIO global interrupt

修改SDIO中断优先级,具体如下图:

步骤8:时钟配置


重点:箭头所指的Q值,它用于控制USB 、SDIO和随机数生成器的时钟,必须为48M

步骤9:项目编辑

步骤10:代码生成编辑

步骤11:点击 GENERATE CODE 生成代码


新建的工程,已经生成,接下来就是对工程代码的编辑。

二、使用keil5----编辑程序

想要使用keil5打开工程,需要电脑先安装 keil5编译环境,具体操作流程。
可以点击下方文章链接:Keil5编译环境搭建流程----STM32和GD32

步骤1:使用keil5打开工程

点击工程文件中的MDK-ARM文件

打开keil5工程

打开代码,编译运行一下,没有错误和告警为正常。

步骤2:用户代码 编辑位置

用户代码要写在USER xxxx BEGIN xxxUSER xxxx END xxx之间。
这样下次使用STM32CubeMX重新生成代码后,自己写的代码不会被删除。

步骤3:修改代码

CubeMX生成的SDIO初始化代码,有一个bug,需要手动修改,操作如下:

  • 编译后,右击 main.c 文件中函数 MX_SDIO_SD_Init(),
  • 在弹出菜单中:Go To Definition Of …; 将跳转到SD卡初始化函数;

    跳转到 sdio.c文件的 MX_SDIO_SD_Init()函数内部后,
    把下图位置中的 4B,改为 1B ;
    重点:每次重新生成后,都要手动修改一次。如果不修改,初始化过程会导致程序卡死。

步骤4:使用到的HAL库函数

typedefstruct{uint32_tCardType;//SD卡类型uint32_tCardVersion;//SD卡版本uint32_tClass;//SD卡等级uint32_tRelCardAdd;//SD卡地址uint32_tBlockNbr;//SD卡容量(块)uint32_tBlockSize;//SD卡块大小(字节)}HAL_SD_CardInfoTypeDef;//SD卡信息结构体typedefuint32_tHAL_SD_CardStateTypeDef;//SD卡状态信息#defineHAL_SD_CARD_READY0x00000001U//SD卡状态准备就绪#defineHAL_SD_CARD_IDENTIFICATION0x00000002U//SD卡识别状态#defineHAL_SD_CARD_STANDBY0x00000003U//SD卡待机状态#defineHAL_SD_CARD_TRANSFER0x00000004U//SD卡传输状态#defineHAL_SD_CARD_SENDING0x00000005U//SD卡正在发送状态#defineHAL_SD_CARD_RECEIVING0x00000006U//SD卡正在接收状态#defineHAL_SD_CARD_PROGRAMMING0x00000007U//SD卡编程状态#defineHAL_SD_CARD_DISCONNECTED0x00000008U//SD卡断开连接状态#defineHAL_SD_CARD_ERROR0x000000FFU//SD卡响应状态// 1、获取 SD 卡的状态---参数:SD卡的句柄HAL_SD_CardStateTypeDefHAL_SD_GetCardState(SD_HandleTypeDef*hsd);// 2、获取 SD 卡的信息---参数:SD卡的句柄、SD卡信息HAL_StatusTypeDefHAL_SD_GetCardInfo(SD_HandleTypeDef*hsd,HAL_SD_CardInfoTypeDef*pCardInfo);//3、读数据---参数:SD卡的句柄、数据、块地址、块数量、超时msHAL_StatusTypeDefHAL_SD_ReadBlocks(SD_HandleTypeDef*hsd,uint8_t*pData,uint32_tBlockAdd,uint32_tNumberOfBlocks,uint32_tTimeout);//4、写数据---参数:SD卡的句柄、数据、块地址、块数量、超时msHAL_StatusTypeDefHAL_SD_WriteBlocks(SD_HandleTypeDef*hsd,uint8_t*pData,uint32_tBlockAdd,uint32_tNumberOfBlocks,uint32_tTimeout);//5、擦除数据---参数:SD卡的句柄、块起始地址、块结束地址HAL_StatusTypeDefHAL_SD_Erase(SD_HandleTypeDef*hsd,uint32_tBlockStartAdd,uint32_tBlockEndAdd);//6、通过DMA读取数据---参数:SD句柄、数据、块起始地址、需要读取的块数量;HAL_StatusTypeDefHAL_SD_ReadBlocks_DMA(SD_HandleTypeDef*hsd,uint8_t*pData,uint32_tBlockAdd,uint32_tNumberOfBlocks);//7、通过DMA写入数据---参数:SD句柄、数据、块起始地址、需要写入的块数量;HAL_StatusTypeDefHAL_SD_WriteBlocks_DMA(SD_HandleTypeDef*hsd,uint8_t*pData,uint32_tBlockAdd,uint32_tNumberOfBlocks);//8、DMA Tx发送传输完成中断回调函数---参数:SD句柄voidHAL_SD_TxCpltCallback(SD_HandleTypeDef*hsd);//9、DMA Rx接收传输完成中断回调函数---参数:SD句柄voidHAL_SD_RxCpltCallback(SD_HandleTypeDef*hsd);

三、使用keil5----调试和运行

主要使用串口1通过printf函数打印运行数据,这部分操作主要参考:【HAL库】STM32CubeMX开发----STM32F407----Uart串口通信实验

实验:SD卡-DMA读写数据

在初始化的时候,调用SD卡-写数据,写入数据到SD卡,然后在运行时周期读取SD卡数据。

SD卡-DMA收发中断回调函数

volatileuint8_tmyFlagSDReadReady=0;// 读取传输完成标志; 重要:CubeMX生成的Keil工程,编译优化等级默认是3,如果变量没有标记为易变的(volatile),编译器可能会认为其值在循环中不会改变,从而导致优化后的代码无法正确检测到变量值的变化,特别是在空循环体中。volatileuint8_tmyFlagSDWriteReady=0;// 写入传输完成标志; 重要:CubeMX生成的Keil工程,编译优化等级默认是3,如果变量没有标记为易变的(volatile),编译器可能会认为其值在循环中不会改变,从而导致优化后的代码无法正确检测到变量值的变化,特别是在空循环体中。/*DMA Tx传输完成中断回调函数*/voidHAL_SD_TxCpltCallback(SD_HandleTypeDef*hsd){myFlagSDWriteReady=1;// 写入传输完成标志; 重要:CubeMX生成的Keil工程,编译优化等级默认是3,如果变量没有标记为易变的(volatile),编译器可能会认为其值在循环中不会改变,从而导致优化后的代码无法正确检测到变量值的变化,特别是在空循环体中。}/*DMA Rx传输完成中断回调函数*/voidHAL_SD_RxCpltCallback(SD_HandleTypeDef*hsd){myFlagSDReadReady=1;// 读取传输完成标志; 重要:CubeMX生成的Keil工程,编译优化等级默认是3,如果变量没有标记为易变的(volatile),编译器可能会认为其值在循环中不会改变,从而导致优化后的代码无法正确检测到变量值的变化,特别是在空循环体中。}

SD卡-DMA读数据

voidUser_SD_ReadData_DMA(void){/*读测试:读出测试位置原数据,保存在ReadData[] */uint8_tReadData[1024]={0};printf("\r读取测试块的原数据\r\n");myFlagSDReadReady=0;HAL_SD_ReadBlocks_DMA(&hsd,ReadData,8,2);// 读SD卡数据块; 参数:SD结构体、数据、块起始地址、读的块数量;while(myFlagSDReadReady==0);// 等待卡的读操作结束for(uint32_ti=0;i<1024;i++)// 打印 原数据{printf("%X ",ReadData[i]);}printf("\r\n");}

SD卡-DMA写数据

voidUser_SD_WriteData_DMA(void){/* 写测试:在测试的块上写入数据 */uint8_tWriteData[1024]={0};for(uint32_ti=0;i<1024;i++){WriteData[i]=1024-i;}printf("\rSD卡 写入测试\r\n");myFlagSDWriteReady=0;HAL_SD_WriteBlocks_DMA(&hsd,WriteData,8,2);// 向SD卡写入数据块; 参数:SD结构体、数据地址、块起始地址、写入的块数量、超时时间;while(myFlagSDWriteReady==0);// 等待卡的读写操作结束printf("对指定块写入结束! \r写入的数据是:\n");for(uint32_ti=0;i<1024;i++)// 打印 写入的数据{printf("%X ",WriteData[i]);}printf("\r\n");}

运行结果



http://www.jsqmd.com/news/1251338/

相关文章:

  • VLA动态自适应优化:基于强化学习的分布式系统调优
  • 别把治理当项目:让指标、权限、审计成为BI日常的三条流水线
  • 2026年湖北及周边企口水泥管生产厂商推荐哪家 - 品牌优推
  • 吸塑盒品牌厂商怎么选 老采购总结实用选型参考方法 - 品牌优推
  • 2026年益阳哪里有化粪池公司 城乡基建配套采购实用指引 - 品牌优推
  • Windows下F盘部署Ollama大模型全攻略
  • 学术论文AI降重工具评测与使用指南
  • MSPM0 RTC模块深度解析:从基础配置到精准校准与低功耗实战
  • 2026年郑州民办高中升学之选:哪所学校更胜一筹? - 品牌排行榜
  • 大理本地防水补漏精选TOP5推荐:正规漏水检测维修公司上门师傅推荐:厕所/棚顶/屋面/飘窗/阳台/地下室/厨房渗漏水精准测漏维修(2026最新) - 即刻修防水
  • MSP430 ADC12_A模块:寄存器配置、中断机制与低功耗数据采集实战
  • AI高薪岗位能力模型与转型路径解析
  • 抑制、故障和降级:辅助驾驶系统的退出策略
  • Laguna S 2.1 深度解析:118B MoE 开放权重编码模型,单机可跑的代码助手新标杆
  • 固话号码认证怎么选?从固话的特殊性看服务商评估要点
  • 自编码器原理与应用:从数据压缩到生成模型
  • 2025-2026计算机类期刊推荐:从顶刊到“保底”,选对期刊少走弯路
  • 河南1寸速联脉冲阀品牌厂商选型采购使用全攻略 - 品牌优推
  • Qwen-Image-2.0多模态模型:中文图像生成与编辑技术解析
  • 静海区冷弯风阀设备厂家直销 本地直供服务高效靠谱 - 品牌优推
  • 2026年选择靠谱的邵阳腻子粉门店 本地实用选购参考指南 - 品牌优推
  • 智能体技术解析与开发实战:从原理到部署
  • Java中如何利用装饰器模式增强外卖API调用前后的功能扩展性
  • uart 和 modbus 是属于应用层的 ttl 和 rsr232 属于硬件层
  • AGI技术发展现状与未来突破路径分析
  • 智能算法在电力系统潮流计算中的应用与优化
  • AI论文写作工具:千笔智能写作核心技术与应用解析
  • 2026年挑选靠谱购物卡回收公司品牌实用测评指南 - 品牌优推
  • 2026吉安漏水检测维修本地口碑榜TOP5权威推荐-专业仪器精准测漏-正规防水补漏公司推荐:卫生间/厨房/屋顶/阳台/外墙渗漏水检测师傅上门 - 安佳防水
  • TLV320AIC3254-Q1音频编解码器SPI接口配置与驱动开发详解