STM32F1的SD卡实验


本实验我们使用SDIO协议驱动SD卡,SPI协议也可以驱动SD卡(MINI版)

SD卡简介

SD卡,Secure Digital Card,称为安全数字卡(安全数码卡),本质上就是:nand flash + 控制芯片

SD卡

在这里插入图片描述

CLK:时钟线,由SDIO主机产生,由STM32微控制器SDIO外设输出
CMD:命令线,SDIO主机通过该线发送命令控制SD卡, 若命令要求SD卡响应,
SD卡也是通过该线传输响应信息。
DAT0~3:数据线,用于接收或发送数据;SD卡可将DAT0拉低表示处于忙状态
注意:SPI接口的MISO也有该特性

Micro SD卡(又称为TF卡)

在这里插入图片描述
在这里插入图片描述
SD卡和TF卡只有引脚和形状大小不同,内部结构类似,操作时序完全相同,可用完全相同的代码驱动

SD卡容量等级

在这里插入图片描述

SD卡寄存器

SD卡有8个寄存器,但不能直接进行读写操作,需要通过命令来控制。SD卡协议定义了一些命令用于实现某一特定功能,SD卡根据收到的命令要求对内部寄存器进行修改。

在这里插入图片描述

OCR寄存器

在这里插入图片描述

SDIO模式下的SD卡常用命令

数据,命令传输

在这里插入图片描述
命令:应用相关命令(ACMD)和通用命令(CMD),通过命令线CMD传输,固定长度48位
响应:SD卡接收到命令,会有一个响应,用来反应SD卡状态。有2种响应类型:短响应(48位,格式与命令一样)和长响应(136位)。
数据:主机发送的数据 / SD发送的数据。SD数据是以块(Block)形式传输,SDHC卡数据块长度一般为512字节。数据块需要CRC保证数据传输成功。

命令和响应分类

命令格式

在这里插入图片描述
Byte1:命令字的第一个字节为命令号(如CMD0、CMD1等),格式为“0 1 x x x x x x”
Byte2~Byte5:命令参数,有些命令参数是保留位,没有定义参数的内容,保留位应设置为0
Byte6:用于校验命令传输内容正确性,前7位为CRC(循环冗余校验)校验位,最后一位为停止位0

命令分类

在这里插入图片描述
在这里插入图片描述

响应

SD卡和单片机的通信采用发送应答机制。
每发送一个命令,SD卡都会给出一个应答,以告知主机该命令的执行情况,或者返回主机需要获取的数据。使用SDIO接口时,响应通过CMD线传输。
SD卡响应因使用接口不同,格式也不同。响应具体有R1、R1b、R2、R3、R7。
响应内容大小可以分为短响应48bit和长响应136bit。
在这里插入图片描述

SD卡操作步骤

SD卡操作模式

在SD卡系统(主机和SD卡)定义了两种操作模式:卡识别模式(识别总线上的SD卡类型)和数据传输模式(读写操作)。
(卡识别模式在SD卡初始化之后)
系统复位后,主机和SD卡都处于卡识别模式,主机在总线上找设备;当SD卡被主机识别后,SD卡进入到数据传输模式,而主机在总线上所有卡都被识别后也进入数据传输模式。
在这里插入图片描述

SDIO接口介绍

SDIO,全称 Secure Digital Input and Output,即安全数字输入输出接口。
在这里插入图片描述

SDIO框图介绍

在这里插入图片描述
SDIO_CK:
由SDIO适配器中的时钟产生器在外部引脚输出的通信时钟信号
不同总线协议,最高时钟频率不同每个时钟脉冲传输的是命令或数据
SDIOCLK
SDIO适配器的工作时钟:48MHz来自主PLL的独立输出,和PLLCLK独立
HCLK/2 或 PCLK2
CPU以此时钟访问SDIO外设寄存器AHB总线接口时钟(HCLK/2),36MHz APB2总线接口时钟(PCLK2),84(F407) / 90(F429)MHz
SDIO_CK = SDIOCLK / (2 + CLKDIV)
注意:SD卡初始化时,SDIO_CK不可超过400KHz;
初始化完成后,可设为最大(不可超过SD卡最大操作频率25MHz)并可更改数据总线宽度(默认只用SDIO_D0进行初始化)

SDIO适配器

在这里插入图片描述
控制单元:电源管理和时钟管理功能
命令通道:控制命令发送并接收响应
命令通道状态机(CPSM):
数据通道:负责主机和卡之间传输数据
数据通道状态机(DPSM)
数据FIFO:具有发送和接收数据缓冲器
数据FIFO
在这里插入图片描述

SDIO寄存器

在这里插入图片描述

SDIO_POWER

在这里插入图片描述
在这里插入图片描述

SDIO时钟控制寄存器(SDIO_CLKCR)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

SDIO参数寄存器(SDIO_ARG)

在这里插入图片描述

SDIO命令寄存器(SDIO_CMD)

在这里插入图片描述
在这里插入图片描述
一般情况下,开启CPSM,即设置1
在这里插入图片描述
发送CMD1,其值为1,索引就设置为1

SDIO命令响应寄存器(SDIO_RESPCMD)

在这里插入图片描述
在这里插入图片描述

SDIO响应1到4寄存器(SDIO_RESP1到4)

在这里插入图片描述

在这里插入图片描述

SDIO数据长度寄存器(SDIO_DLEN)

在这里插入图片描述
在这里插入图片描述
对于块数据传输,该寄存器值必须是数据块长度的倍数。

SDIO数据控制寄存器(SDIO_DCTRL)

在这里插入图片描述
在这里插入图片描述

SDIO状态寄存器(SDIO_STA)

在这里插入图片描述

SDIO数据FIFO寄存器(SDIO_FIFO)

接收和发送FIFO是32位宽度读或写一组寄存器,它在连续的32个地址上包含32个寄存器,CPU可以使用FIFO读写多个操作数。
在这里插入图片描述

我们操作SDIO_FIFO(不论读出还是写入)必须是以4字节对齐的内存进行操作,否则将导致出错。

SDIO相关HAL库驱动

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

HAL_StatusTypeDef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, 	/* 句柄结构体指针变量*/
								      uint8_t *pData,	/* 接收数据的缓冲地址 */
								      uint32_t BlockAdd,	/* 要读取的扇区地址 */
								      uint32_t NumberOfBlocks,/* 要读取的扇区数 */
								      uint32_t Timeout		/* 传输过程超时时间 */
)
//这里512个字节表示一个扇区。
HAL_StatusTypeDef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, 	/* 句柄结构体指针变量*/
								      uint8_t *pData,	/* 接收数据的缓冲地址 */
								      uint32_t BlockAdd,	/* 要读取的扇区地址 */
								      uint32_t NumberOfBlocks,/* 要读取的扇区数 */
								      uint32_t Timeout		/* 传输过程超时时间 */
)

SDIO驱动SD卡步骤

在这里插入图片描述

F1SD卡电路图
在这里插入图片描述

实验源码(编写SDIO驱动SD卡源码)

sdio_sdcard.c

#include "string.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/SDIO/sdio_sdcard.h"

SD_HandleTypeDef g_sdcard_handler;              /* SD¿¨¾ä±ú */

/**
 * @brief       ³õʼ»¯SD¿¨
 * @param       ÎÞ
 * @retval      ·µ»ØÖµ:0 ³õʼ»¯ÕýÈ·£»ÆäËûÖµ£¬³õʼ»¯´íÎó
 */
uint8_t sd_init(void)
{
    uint8_t SD_Error;
    
    g_sdcard_handler.Instance = SDIO;
    g_sdcard_handler.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;//ÊÇ·ñʹÓÃÉÏÉýÑØ
    g_sdcard_handler.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;//ÊÇ·ñʹÓÃÅÔ·
    g_sdcard_handler.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
    g_sdcard_handler.Init.BusWide = SDIO_BUS_WIDE_1B;
    g_sdcard_handler.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_ENABLE;
    g_sdcard_handler.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV;

    SD_Error = HAL_SD_Init(&g_sdcard_handler);
    
    if (SD_Error != HAL_OK)
    {
        return 1;
    }

    return 0;
}

/**
 * @brief       SDIOµ×²ãÇý¶¯£¬Ê±ÖÓʹÄÜ£¬Òý½ÅÅäÖÃ
                ´Ëº¯Êý»á±»HAL_SD_Init()µ÷ÓÃ
 * @param       hsd:SD¿¨¾ä±ú
 * @retval      ÎÞ
 */
void HAL_SD_MspInit(SD_HandleTypeDef *hsd)
{
    GPIO_InitTypeDef gpio_init_struct;

    __HAL_RCC_SDIO_CLK_ENABLE();    /* ʹÄÜSDIOʱÖÓ */
    SD_D0_GPIO_CLK_ENABLE();        /* D0Òý½ÅIOʱÖÓʹÄÜ */
    SD_D1_GPIO_CLK_ENABLE();        /* D1Òý½ÅIOʱÖÓʹÄÜ */
    SD_D2_GPIO_CLK_ENABLE();        /* D2Òý½ÅIOʱÖÓʹÄÜ */
    SD_D3_GPIO_CLK_ENABLE();        /* D3Òý½ÅIOʱÖÓʹÄÜ */
    SD_CLK_GPIO_CLK_ENABLE();       /* CLKÒý½ÅIOʱÖÓʹÄÜ */
    SD_CMD_GPIO_CLK_ENABLE();       /* CMDÒý½ÅIOʱÖÓʹÄÜ */

    gpio_init_struct.Pin = SD_D0_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;            /* ÍÆÍ츴Óà */
    gpio_init_struct.Pull = GPIO_PULLUP;                /* ÉÏÀ­ */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;      /* ¸ßËÙ */
    HAL_GPIO_Init(SD_D0_GPIO_PORT, &gpio_init_struct);  /* ³õʼ»¯D0Òý½Å */

    gpio_init_struct.Pin = SD_D1_GPIO_PIN;
    HAL_GPIO_Init(SD_D1_GPIO_PORT, &gpio_init_struct);  /* ³õʼ»¯D1Òý½Å */
    
    gpio_init_struct.Pin = SD_D2_GPIO_PIN;
    HAL_GPIO_Init(SD_D2_GPIO_PORT, &gpio_init_struct);  /* ³õʼ»¯D2Òý½Å */

    gpio_init_struct.Pin = SD_D3_GPIO_PIN;
    HAL_GPIO_Init(SD_D3_GPIO_PORT, &gpio_init_struct);  /* ³õʼ»¯D3Òý½Å */

    gpio_init_struct.Pin = SD_CLK_GPIO_PIN;
    HAL_GPIO_Init(SD_CLK_GPIO_PORT, &gpio_init_struct); /* ³õʼ»¯CLKÒý½Å */

    gpio_init_struct.Pin = SD_CMD_GPIO_PIN;
    HAL_GPIO_Init(SD_CMD_GPIO_PORT, &gpio_init_struct); /* ³õʼ»¯CMDÒý½Å */
}

main.c


    while (1)
    {
        key = key_scan(0);

        if (key == KEY0_PRES)
        {
            operation_ret =  HAL_SD_ReadBlocks(&g_sdcard_handler, (uint8_t *)rec_buf, 0, 1, SD_TIMEOUT);
            
            for (uint16_t i = 0; i < 512; i++)
            {
                printf("%x ", rec_buf[i]);
            }
            printf("READ DATA OK \r\n");
        }
        
        if (key == KEY1_PRES)
        {
            for (uint16_t i = 0; i < 512; i++)
            {
                send_buf[i] = i;
                printf("%x ", send_buf[i]);
            }
            
            operation_ret =  HAL_SD_WriteBlocks(&g_sdcard_handler, (uint8_t *)send_buf, 0, 1, SD_TIMEOUT);
            printf("SEND DATA OK \r\n");
        }
   }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值