基于STM32F407的SDCard读写操作

基于STM32F407的SDCard读写操作

目录

基于STM32F407的SDCard读写操作

硬件电路

SD卡结构示意图

 管脚连接(SDIO方式) 

SDCard初始化

SDCacr寄存器介绍

SDCacr初始化代码


       在之前没有做过SD卡相关,做这个之前参考了正点原子、野火等等资料,花了1天时间,其实在有参考的情况下,难倒是不难,就是资料挺乱的,然后代码上面有的还有不兼容(可能因为我有的资料是F103的),对于做好的东西做一个备份和总结——后续篇幅是关于SD通过USB端口挂载U盘以及通过HAL库的SD卡操作。

  • 硬件电路

  • SD卡结构示意图

 管脚连接(SDIO方式) 

STM32-GPIO

STM32-GPIO 复用功能

SDCard管脚

其他

PC8

SDIO-D0

DATA0

PC9

SDIO-D1

DATA1

PC10

SDIO-D2

DATA2

PC11

SDIO-D3

CD/DATA3

PC12

SDIO-CLK

CLK

PD2

SDIO-CMD

CMD

 

  • SDCard初始化

  • SDCacr寄存器介绍

        SD卡共有8个寄存器,用于设定或表示SD卡信息,参考下表,这些寄存器只能通过对应的命令访问,对SD卡进行读写控制操作并不是像操作控制寄存器GPIO相关寄存器那样一次读写一个寄存器的,它是通过命令来控制的,SDIO定义了64个命令,每个命令都有意义,可以实实现某一特定功能,SD卡接收到命令之后,根据命令的要求对SD卡内部寄存器进行修改,程序控制中只需要发送组合命令就可以实现SD卡的控制以及读写操作。

名称

Bit宽度

描述

CID

128

卡识别号:用来识别SD卡的个体号码

RCA

16

相对地址:卡的本地系统地址

DSR

16

驱动级寄存器:配置卡的输出驱动

CSD

128

卡的特定数据:卡的操作条件信息

SCR

64

SD配置寄存器:SD卡特性信息

OCR

32

操作条件寄存器

SSR

512

SD状态:SD卡专有特征的信息

CSR

32

卡的状态:卡的当前状态信息

SDCacr初始化代码

首先对SDIO及中断进行设置;

使能GPIOC、GPIOD、DMA2及SDIO时钟

复位SDIO时钟

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_DMA2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE);
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_SDIO, ENABLE);

初始化PC8~PC12及PD2(SDIO接口)

PC8~PC12设置复用功能、推挽输出、上拉

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

PC8~PC12复用功能映射

    GPIO_PinAFConfig(GPIOC,GPIO_PinSource8,GPIO_AF_SDIO);
    GPIO_PinAFConfig(GPIOC,GPIO_PinSource9,GPIO_AF_SDIO);
    GPIO_PinAFConfig(GPIOC,GPIO_PinSource10,GPIO_AF_SDIO);
    GPIO_PinAFConfig(GPIOC,GPIO_PinSource11,GPIO_AF_SDIO);
    GPIO_PinAFConfig(GPIOC,GPIO_PinSource12,GPIO_AF_SDIO);    
    GPIO_PinAFConfig(GPIOD,GPIO_PinSource2,GPIO_AF_SDIO); 

解除SDIO时钟复位

    RCC_APB2PeriphResetCmd(RCC_APB2Periph_SDIO, DISABLE);

设置SD卡的外设寄存器

    SDIO->POWER=0x00000000;
    SDIO->CLKCR=0x00000000;
    SDIO->ARG=0x00000000;
    SDIO->CMD=0x00000000;
    SDIO->DTIMER=0x00000000;
    SDIO->DLEN=0x00000000;
    SDIO->DCTRL=0x00000000;
    SDIO->ICR=0x00C007FF;
    SDIO->MASK=0x00000000;   

设置SDIO中断并打开中断

    NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

GPIO相关设置就结束了

接着根据流程图对SD卡进行配置

 1.配置SDIO传输模式

    SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV;
    SDIOCLK = 72MHz, SDIO_CK = HCLK/(178 + 2) = 400 KHz */
    SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
    SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable; 
    SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;     
    SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;                     
    SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;

2.进行SD卡上电、初始化及设备参数读取

        首先进行SD卡上电:

        发送CMD0,等待回应后

        发送CMD8,等待R7响应,判断是2.0还是高容量卡。

        然后发送CMD41,等待R3响应,判断上电是否完成。

        接着进行SD卡初始化:

        发送CMD2,等待R2响应,取得CID,

        发送CMD3,等待R6响应,

        再次发送CMD3,等待R2响应。

        最后读取SD卡信息,选中SD卡,

        设置数据宽度,设置SD时钟,设置传输模式(查询或DMA)。

3.SDCard初始化

(1)SDCacr基本读写

偷懒的话可以直接去下载已经写好的sdcard读写函数,这种网上有好多

(附sdcard.c及sdcard.h(正点原子STM32F407的)容我研究下怎么上传文件)

        对一个块(Block)的读写操作

        所用函数:

        SD_WriteBlock(*buf,addr,blksize)

        SD_ReadBlock(*buf,addr,blksize)

        其中,buf是读、写数据缓存区,addr是起始地址,blksize是块大小。

        对多个块(MultiBlock)的读写操作

        所用函数:

        SD_WriteMultiBlocks(*buf,addr,blksize,nblks)

        SD_ReadMultiBlocks(*buf,addr,blksize,nblks)

        其中,buf是读、写数据缓存区,addr是起始地址,blksize是块大小,nblks是读、写块的数量。

        对扇区(Disk)的读写操作

        所用函数:

        SD_ WriteDisk(*buf,sector,cnt)

        SD_ReadDisk(*buf,sector,cnt)

        其中,buf是读、写数据缓存区,sector是扇区地址,cnt是扇区个数。

(2)SDCacr文件系统(FATFS)读写

        只有在SD卡基本读写块操作成功之后,才能进行FATFS文件的操作。

        移植FATFS文件系统之前,先下载FAT文件源码,解压后里面文件挺多的,我们需要的文件主要是diskio.c、diskio.h、ff.c、ff.h、ffconf.h、integer.h。

PS:Fatfs版本还挺多的,好像还有点差别,所以以下仅供参考

(附上述文件,容我研究下怎么上传文件)

        Integer.h:是一些数值类型的定义

        diskio.c:底层磁盘的操作函数

        ff.c:独立于底层介质操作文件的函数

        将文件移植到项目文件中,进行编译,如果出现报错一般都是重复定义啊之类的小毛病,KO掉它们。等到编译无错之后,文件系统移植成功。

        FATFS是独立于底层介质的应用函数库,对底层介质的操作都需要自己实现,文件仅仅提供一个函数接口,自己添加代码。偷懒的话可以直接去下载已经写好的sdcard读写函数,这种网上有好多,我上传的也是已经加完的。        

        完成代码的添加后,我们开始进行文件系统操作。

        首先我们对SD卡硬件进行初始化

    disk_initialize( 0 );

        初始化成功才能进行接下来的步骤。

        在文件系统中挂载一个工作区,工作区的设备号为0(相当于盘符),fs为指向工作区的指针。

    f_mount(&fs,"0",0);

        剩下的操作就比较简单了,和一般的读写文件差不多,通过,f_open、f_write、f_read等函数进行操作,详细函数操作可以查询FatFs - Generic FAT Filesystem Module

        不过fatfs版本不同,函数形参会略有不通,我用过几个版本,一开始用的也忘了哪个版本了,总出错,也不知道是我下的有问题,还是一开始代码有问题,后来换了个版本重写倒是好了,

最后,举个栗子:

写入

    res = f_open( &fsrc , "0:/Demo.csv" , FA_OPEN_APPEND | FA_WRITE);   		
	res = f_write(&fsrc, &WD, sizeof(WD), &br);  	
	res = f_write(&fsrc, "\n", sizeof("\n"), &br);   	
    f_close(&fsrc); 

读取

    res = f_open(&fsrc, "0:/Demo.csv", FA_OPEN_EXISTING | FA_READ);
    res = f_read( &fsrc, *&textFileBuffer, sizeof(textFileBuffer), &br ); 
    f_close(&fsrc);	

删除

    res = f_unlink ("0:/Demo.csv");

操作完记得卸载

    f_mount(0, "0",0);

### 回答1: 使用STM32F103 HAL库初始化SD卡的步骤如下: 1. 首先,确保已连接好SD卡的硬件接口和相关引脚,并通过HAL库设置好I/O引脚的模式和功能。 2. 在代码中引用HAL库的头文件,并初始化SD卡驱动。 ``` #include "sd_hal.h" SD_HandleTypeDef hsd; ``` 3. 设置SD卡的时序和通信参数。 ``` hsd.Instance = SDIO; hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; hsd.Init.BusWide = SDIO_BUS_WIDE_1B; // 设置为4位宽模式可以提高传输速率 hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; hsd.Init.ClockDiv = 0; // 设置时钟分频系数,具体数值根据SD卡的时钟要求来定 ``` 4. 初始化SD卡驱动。 ``` if (HAL_SD_Init(&hsd) != HAL_OK) { // 初始化失败的处理代码 } ``` 5. 如果需要使用DMA进行数据传输,还需配置DMA参数。 ``` hdma_sdio.Instance = DMA2_Channel4; hdma_sdio.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_sdio.Init.PeriphInc = DMA_PINC_DISABLE; hdma_sdio.Init.MemInc = DMA_MINC_ENABLE; hdma_sdio.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; hdma_sdio.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; hdma_sdio.Init.Mode = DMA_NORMAL; hdma_sdio.Init.Priority = DMA_PRIORITY_HIGH; __HAL_LINKDMA(&hsd, hdma, hdma_sdio); ``` 6. 配置SD卡的块大小和块数。 ``` if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK) { // 配置4位宽模式失败的处理代码 } if (HAL_SD_SetBlockSize(&hsd, BLOCK_SIZE) != HAL_OK) { // 设置块大小失败的处理代码 } if (HAL_SD_SetBlockCount(&hsd, BLOCK_COUNT) != HAL_OK) { // 设置块数失败的处理代码 } ``` 7. 最后,通过发送命令初始化SD卡。 ``` SD_CmdInitTypeDef sd_cmd; sd_cmd.Argument = 0; sd_cmd.CmdIndex = SD_CMD_GO_IDLE_STATE; sd_cmd.CmdResponse = SD_RESPONSE_NO; if (HAL_SD_SendCommand(&hsd, &sd_cmd, SD_TIMEOUT) != HAL_OK) { // 发送命令失败的处理代码 } ``` 以上就是使用STM32F103 HAL库初始化SD卡的基本步骤,具体的参数设置和错误处理需要根据实际情况进行调整。 ### 回答2: 要使用STM32F103 HAL库初始化SD卡,可以按照以下步骤进行操作: 1. 硬件连接:将SD卡插槽正确地连接到STM32F103系列微控制器的相应引脚和电源线上。确保为SD卡提供正确的电压。 2. 包含必要的库文件:在代码中包含与SD卡操作相关的库文件,以便能够使用HAL库提供的函数。 3. 初始化GPIO:使用HAL库函数初始化与SD卡连接的GPIO引脚。根据具体引脚连接配置初始化时钟和GPIO模式,使其能够与SD卡进行通信。 4. 配置SPI接口:使用HAL库函数配置SPI接口,设置通信速度、数据位和架构等参数。确保SPI接口能够与SD卡进行正确的通信。 5. 初始化SD卡:使用HAL库函数初始化SD卡。此函数将通过SPI接口发送命令和参数来正确地初始化SD卡。初始化过程中,需要等待SD卡的响应。 6. 配置和选择SPI片选线:使用SPI外设的HAL函数配置和选择SPI片选线,以便与SD卡进行通信。 7. 配置DMA(如果需要):根据需要配置DMA来实现更高效的数据传输。使用HAL库函数来初始化和配置DMA通道。 8. 编写SD卡读写函数:编写读写SD卡数据的函数,使用HAL库函数来实现SPI接口与SD卡的数据传输。 9. 测试SD卡功能:编写测试函数来验证SD卡的功能。可以通过读写测试数据来确认SD卡是否正常工作。 10. 错误处理:使用HAL库的错误处理机制来处理可能出现的错误。根据错误代码进行相应的错误处理。 以上是使用STM32F103 HAL库初始化SD卡的基本步骤。根据具体需求,还可以进一步扩展和优化代码,实现更复杂的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值