当前位置:首页 > 技术 > Cortex-M3 > 正文内容

STM32CubeMX系列教程17:SDMMC

Watrt7年前 (2017-12-16)Cortex-M322100
一、SDMMC简介

    MMC:MMC就是MultiMediaCard的缩写,即多媒体卡
    SD:SD卡为Secure Digital Memory Card, 即安全数码卡
    SDIO:SD Input Output 带有输入输出接口,SDIO是在SD标准上定义了一种外设接口

SD种类
    SD卡:<=2GB
    SDHC卡(SD High Capacity,大容量SD卡):4GB~32GB
    SDXC卡(SD eXtended Capacity):64GB~2TB。

SD管脚图
   我们现在常用的是Micro SD卡,尺寸非常小的,其管脚图如下。



SD卡的接口可以支持SD卡模式和SPI模式两种操作模式。
SD模式:采用6线制,使用CLK、CMD、DAT0~DAT3。其中CLK为时钟线,CMD为命令控制线,DAT0~DAT3为数据线,允许4线的高速数据传输;
SPI模式:通用的SPI通道接口,使用CS、CLK、DI、DO进行数据通信。
SD模式的数据传输速度比SPI模块要快。我们这一章主要讲通过SD模式控制。

SD卡相关寄存器

        SD卡内部有7个寄存器,其中OCR,CID,CSD和SCR寄存器保存卡的配置信息;RCA寄存器保存着通信过程中卡当前暂时分配的地址;卡状态(Card Status)和SD状态(SD Status)寄存器保存着卡的状态,这两个寄存器的内容与通信模式(SD模式或SPI模式)相关

命令传输

命令是用于启动操作的令牌。命令在CMD线上以串行的方式传输。所以命令都为固定长度48位。命令路径以半双工模式运行,因此可以发送和接收和响应。
最大支持64个命令:CMD0~CMD63(其中CMD57~63是保留的)另外还有ACMD应用命令
(本章不打算详细介绍SD各条命令的含义,而且我们编写程序的时候也不会用到,只需大概了解一下即可)



响应是一个令牌,作为对先前接收命令的应答,从卡发送到主机,响应在CMD线上以串行方式传输。
SDMMC支持两种响应类型,48位短响应和136位长响应。两种类型均使用CRC错误检验。



数据传输

SD的读写操作是以块为操作对象。先发送命令开始传输,然后传输数据块,传输完数据块紧接着传输CRC检验值。最好发送停止命令停止数据传输。



SD卡识别流畅图和数据传输流程图:
(本章不打算详细介绍SD的状态图,编写程序的时候也不会用到,只需大概了解一下即可)





二.示例程序

    复制串口printf的工程,修改文件夹名。击STM32F746I.ioc打开STM32cubeMX的工程文件重新配置,SDMMC选择四线SD模式。

此时SDMMC对应的管脚也被选中。



配置SDMMC的时钟为48MHz(最高为48MHz)。



SDMMC配置参数只有一个分频因子,此处为默认0,不修改。




开启SDMMC接收和发送DMA。




特别注意,开启DMA后必须开启SDMMC中断,否则不能判断DMA传输是否完成,程序一直等待。且SDMMC中断的抢占优先级必须比SDMMC DMA中断高。

生成报告以及代码,编译程序。在sdmmc.c文件中可以看到SDMMC初始化函数。在stm32f7xx_hal_sd.h头文件中可以看SD卡的操作函数。

在main.c文件前面添加变量,Status保存程序返回状态,Buffer_Tx,Buffer_Rx存储读写数据。

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
HAL_SD_ErrorTypedef Status;
uint32_t Buffer_Tx[512/4], Buffer_Rx[512/4];
uint32_t i;
/* USER CODE END PV */


程序中用的memset函数填充缓存数据,所以要添加字符头文件。

/* USER CODE BEGIN Includes */
#include <string.h>
/* USER CODE END Includes */</string.h>

在main函数中添加下面应用程序。程序中首先输出SD卡信息,然后进行读写擦除块等操作。

/* USER CODE BEGIN 2 */
    printf(" Warning: this program may erase all the TF card data. \r\n");
     
    printf("\r\n Initialize SD card successfully!\r\n\r\n");
    printf(" SD card information! \r\n");
    printf(" CardCapacity  : %llu \r\n",SDCardInfo1.CardCapacity );
    printf(" CardBlockSize : %d \r\n",SDCardInfo1.CardBlockSize);
    printf(" RCA           : %d \r\n",SDCardInfo1.RCA);
    printf(" CardType      : %d \r\n",SDCardInfo1.CardType);
 
    /*------------------- Block Write --------------------------*/
    memset(Buffer_Tx,0x15,sizeof(Buffer_Tx));
    if(HAL_SD_WriteBlocks_DMA(&hsd1, Buffer_Tx, 0, 512, 1) == SD_OK)
    {  
        Status = HAL_SD_CheckWriteOperation(&hsd1, (uint32_t)100000000);
        if (Status == SD_OK)
        {
            printf("\r\n Write block successfully!\r\n");
            for(i=0;i<sizeof(buffer_tx)>>2;i++)
            {
                printf("%02x:0x%08x ",i,Buffer_Tx[i]);
            }
            printf("\r\n");
        }
        else 
            printf("\r\n Write block fail!\r\n");
    }
     
    /*------------------- Block Read --------------------------*/
    if(HAL_SD_ReadBlocks_DMA(&hsd1, Buffer_Rx, 0, 512, 1) == SD_OK)
    {
        Status = HAL_SD_CheckReadOperation(&hsd1, 0xFFFF);
        if (Status == SD_OK)
        {
            printf("\r\n Read block successfully!\r\n");
            for(i=0;i<sizeof(buffer_rx)>>2;i++)
            {
                printf("%02x:0x%08x ",i,Buffer_Rx[i]);
            }
            printf("\r\n");
        }
        else 
            printf("\r\n Read block fail!\r\n");
    }
     
    /*------------------- Block Erase -------------------------------*/
    Status = HAL_SD_Erase(&hsd1, 0, 512);
    if (Status == SD_OK)
    printf("\r\n Erase block successfully!\r\n");
    else 
        printf("\r\n Erase block fail!\r\n");
     
    /*------------------- Block Read --------------------------*/
    if(HAL_SD_ReadBlocks_DMA(&hsd1, Buffer_Rx, 0, 512, 1) == SD_OK)
    {
        Status = HAL_SD_CheckReadOperation(&hsd1, 0xFFFF);
        if (Status == SD_OK)
        {
            printf("\r\n Read block successfully!\r\n");
            for(i=0;i<sizeof(buffer_rx)>>2;i++)
            {
                printf("%02x:0x%08x ",i,Buffer_Rx[i]);
            }
            printf("\r\n");
        }
        else 
            printf("\r\n Read block fail!\r\n");
    }
  /* USER CODE END 2 */</sizeof(buffer_rx)></sizeof(buffer_rx)></sizeof(buffer_tx)>

        在SDMMC接口初始化函数MX_SDMMC1_SD_Init()中,调用HAL_SD_Init(&hsd1, &SDCardInfo1)函数初始SD卡(有兴趣的少年可以对比上面的状态图看看SD卡的初始化程序),将SD卡的信息保存在SDCardInfo1结构体中。

        SDCardInfo1结构体类型为HAL_SD_CardInfoTypedef,在stm32f7xx_hal_sd.h中可以看到结构体的成员变量。

        其中SD_csd,SD_cid分别对应SD卡的CSD,CID寄存器。CardCapacity为SD卡容量大小,CardBlockSize为SD卡块大小,CardType为SD类型。查看HAL_SD_CSDTypedef,HAL_SD_CIDTypedef两个类型可以知道CSD,CID寄存器各位的含义。

/** @defgroup SD_Exported_Types_Group5 SD Card information structure 
  * @{
  */
typedef struct
{
  HAL_SD_CSDTypedef   SD_csd;         /*!< SD card specific data register         */
  HAL_SD_CIDTypedef   SD_cid;         /*!< SD card identification number register */
  uint64_t            CardCapacity;   /*!< Card capacity                          */
  uint32_t            CardBlockSize;  /*!< Card block size                        */
  uint16_t            RCA;            /*!< SD relative card address               */
  uint8_t             CardType;       /*!< SD card type                           */
}HAL_SD_CardInfoTypedef;

程序中HAL_SD_WriteBlocks_DMA()和HAL_SD_ReadBlocks_DMA()读写块,注意调用这函数后面要调用HAL_SD_CheckWriteOperation()/HAL_SD_CheckReadOperation()判断传输是否完成。同样也可以用HAL_SD_WriteBlocks()/HAL_SD_ReadBlocks()通过轮询的方式读写块。HAL_SD_Erase()为擦除块操作。


编译程序并下载到开发板。将Micro SD卡插入Micro SD Storage Board中,再插到Open746I-C开发的SDMMC接口中。打开串口调试助手,设置波特率为115200,按下复位串口助手上面会显示如下信息。(注意:此程序会损坏SD卡里面的文件系统,导致SD里面的数据丢失,注意备份数据)




打赏 支付宝打赏 微信打赏
分享给朋友:

相关文章

STM32CubeMX系列教程1:GPIO

STM32CubeMX系列教程1:GPIO

打开STM32CubeMX新建工程,选择STMF746IGT6芯片。选择外部高速晶振(HSE).根据Open746I-C开发板原理图(原理图可在微雪电子网站上下载),选择按键和LED引脚PA0,PG2,PG3,PD4,PD5,PD11为按键输入管脚,选择GPIO_INPUT模式。PB6,PB7,PH4,PI8为LED输出控制管脚,选择GPIO_OUTPUT模式。点击Clock Configuration配置系统时钟为216M最高速度。点击Configuration->GPIO配置管脚。五向...

STM32CubeMX系列教程2:外部中断(EXIT)

STM32CubeMX系列教程2:外部中断(EXIT)

      这一章我们在前一章GPIO的工程修改。复制GPIO的工程,修改文件夹名。点击STM32F746I.ioc打开STM32cubeMX的工程文件重新配置。PA0管脚重新配置为GPIO_EXIT0模式。 WAKEUP按键已经外部下拉,按下是PA0为高电平。在GPIO配置中配置PA0为上升沿触发。内部既不上拉也不下拉,添加用户标签WAKEUP。在NVIC(嵌套向量中断控制器)中,勾选EXIT Line0 interrupt使能PA0中断。右边两个选项设置抢占优...

STM32CubeMX系列教程4:PWM

STM32CubeMX系列教程4:PWM

1.PWM简介       脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调试。是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。广泛应用在从测量、通信到功率控制与变换的许多领域中。例如上图中,图b)是微处理输出的数字信号,实际上他接到电机等功率设备上时,效果相当于图a)。这就是PWM调制。例如输出占空比为50%,频率为10Hz的脉冲,高电平为3.3V.则其输出的模拟效果相...

STM32CubeMX系列教程7:模数转换(ADC)

STM32CubeMX系列教程7:模数转换(ADC)

本章通过两个例程介绍STM32的模数转换器(ADC),第一个通过ADC采集内部温度传感器通道电压,然后得出MCU内部温度。第二个通过DMA的方式采集两个ADC通道电压。1.ADC       本章程序在串口printf工程的基础上修改,复制串口printf的工程,修改文件夹名。击STM32F746I.ioc打开STM32cubeMX的工程文件重新配置。ADC1外设选择温度传感器通道。ADC1配置如下,选择默认设置。其Date Alignment设置为数据...

STM32CubeMX系列教程21:SDRAM

STM32CubeMX系列教程21:SDRAM

在看下面教程之前,如果你之前没有使用过SDRAM,建议先看以下文档,以对SDRAM的原理和控制有一定的了解。高手进阶,终极内存技术指南——完整.doc一、SDRAM简介SDRAM(Synchronous Dynamic Random Access Memory)同步动态随机存取存储器·同步是指存储器工作需要同步时钟,内部命令的发送与数据传输都以它为基准·动态是指存储阵列需要不断的刷新来保证数据不丢失·随机存取是指存储器的内容可以以任意顺序访问,而不管前一次访问的是哪一个位置开发板使用的SDRAM...

STM32CubeMX系列教程24:STemWim移植

STM32CubeMX系列教程24:STemWim移植

摘要:本章教程带领大家移植StmemWin 5.22到STM32的LDTC接口控制的RGB接口屏幕。(注:本章只针对STM32芯片F7,F4系列带LDTC接口控制的RGB屏幕,对F1系列通过FMC控制的带控制器的屏幕不适用)一、STemWin 简介        emWin是segger公司出一种高效的而图形用户界面,是我们能够摆脱处理器和显示控制器而更专注于GUI的设计。uCGUI是segger公司授权Micrum公司推出的,uCOS操作系统也是这个公司...

STM32CubeMX系列教程27:ETH

STM32CubeMX系列教程27:ETH

在看本教程之前建议先看ST官方关于ETH的培训视频。本章不打算详细讲解LwIP协议栈,本章只是介绍如何通过STM32CubeMX软件生成初始化程序,并移植官方固件库里面的示例程序。http://www.stmcu.com.cn/videos.html        本章程序在LCD滚动显示字符工程的基础上修改,复制工程修改文件夹名。打开STM32cubeMX的工程文件重新配置,ETH选择RMII模式,使能LWIP。ETH 参数不作修改为默认设置。LWIP...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。