基于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);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值