打印
[APM32F4]

APM32外设SDIO和SD卡的配置(下)

[复制链接]
1026|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 susutata 于 2023-5-8 11:19 编辑

APM32外设SDIO和SD卡的配置 - 下


01 APM32的SDIO接口
以下内容以APM32F407xx系列MCU为例。

SDIO的结构
APM32的SDIO由SDIO适配器和APB2接口组成。其中,SDIO适配器提供主机功能,包括SD时钟、发送命令和数据传输等。而APB2接口用于控制SDIO适配器的寄存器,并可产生中断和DMA请求。

SDIO的时钟SDIOCLK
是SDIO适配器的时钟,频率为48MHz。

PCLK2
是APB2总线的时钟。

SDIO_CK
是SDIO接口与SD卡同步的时钟,时钟源是SDIOCLK = 48MHz。当使能BYPASS模式时,SDIO_CK = SDIOCLK = HCLK。而禁止BYPASS时,SDIO_CK = SDIOCLK / (2 + CLKDIV)。

> 注意
1.配置时钟时,要留意不能超过25MHz
2.PCLK >= (3 / 8) x SDIO_CK

SDIO适配器
SDIO 适配器是SD卡系统中的主机端。共由五个单元组成,分别是:
  • 控制单元
  • 适配器寄存器单元
  • 命令路径单元
  • 数据路径单元
  • 数据FIFO

1.适配器寄存器和 FIFO 使用 APB2 总线时钟域 (PCLK2)
2.控制单元、命令路径和数据路径使用 SDIO 适配器时钟域 (SDIOCLK)


控制单元
控制单元由电源管理子单元和时钟管理子单元组成。电源管理子单元会在断电阶段和上电阶段中禁止卡总线输出信号。而时钟管理子单元负责生成和控制 SDIO_CK 信号。

命令路径
命令路径单元向卡发送命令并从卡接收响应。而命令的格式可以看上篇中的“SD总线协议 - 命令格式”章节。
> 命令路径以半双工模式运行,因此CMD线可以发送或者接收命令和响应


命令路径状态机
当发送命令和接收响应时,会启动CPSM状态机。
> 命令超时为64个SDIO_CK 时钟周期的固定值

响应
SDIO 支持两种响应类型,以适配SD卡的响应。两种类型均使用 CRC 错误校验。包括:
  • 136位长响应
  • 48位短响应

响应的格式可以看上篇中的“SD总线协议 - 响应”章节。

数据路径
数据路径子单元负责主机与卡相互传输数据。如果使能了 4 位宽度的总线模式,则 使用所有四个数据信号线 (SDIO_D[3:0]) 在每个时钟周期内传输 4 个数据位,8位宽度则是8个数据位。数据包的格式可以看上述“SD总线协议 - 数据包”章节。
> 未使能宽总线模式时,则每个时钟周期使用 SDIO_D0传输一位数据位

数据路径状态机
DPSM 以 SDIO_CK 的频率运**总线信号上的数据与 SDIO_CK 的上升沿保持同步。

数据FIFO
数据 FIFO子单元是一个数据缓冲器,带有发送和接收单元。传输 FIFO和接收FIFO是互斥关系的。传输或接收的标志可以触发中断或DMA请求。
> 数据 FIFO是在 APB2 时钟域 (PCLK2) 中运行的,所以来自 SDIO 时钟域 (SDIOCLK) 子单元中的所有信号都将要重新同步

02 SD卡的配置和应用SD卡热插拔检测
SD卡的热插拔可以通过CD/DAT3信号脚来检测,实现的步骤如下。
1.将CD/DAT3 信号连在MCU中断引脚上,并通过510K电阻下拉,而MCU配置为高电平触发中断;
2.在没有SD卡插入时,该信号为低电平,一但有SD卡插入,SD卡内部通过50KΩ把 DATA3 信号拉高至高电平,MCU随即产生一个中断,再在中断服务函数里写处理逻辑,从而实现热插拔的功能。

SD卡的初始化
SD卡的初始化一般分为“SDIO初始化”、“上电”、“获取卡信息”和“设置数据传输模式”四个过程。具体过程可以查看上篇中的“SD总线协议 - 卡识别模式”章节。

SDIO初始化
初始化SDIO为1位总线宽度,频率不超过400KHz。
/* SDIO Initialization Frequency (400KHz max) */
#define SDIO_INIT_CLK_DIV     ((uint8_t)0x76)    /* 48MHz / (SDMMC_INIT_CLK_DIV + 2) < 400KHz */

SDIO_Config_T sdioConfigStructure;;

/* Default SDIO peripheral configuration for SD card initialization */
sdioConfigStructure.clockEdge           = SDIO_CLOCK_EDGE_RISING;
sdioConfigStructure.clockBypass         = SDIO_CLOCK_BYPASS_DISABLE;
sdioConfigStructure.clockPowerSave      = SDIO_CLOCK_POWER_SAVE_DISABLE;
sdioConfigStructure.busWide             = SDIO_BUS_WIDE_1B;
sdioConfigStructure.hardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
sdioConfigStructure.clockDiv            = SDIO_INIT_CLK_DIV;

/* Initialize SDIO peripheral interface with default configuration */
SDIO_Config(&sdioConfigStructure);

SD卡上电
SD卡的上电过程如下图所示。注意上电后要给74个clock,给足够长的时间SD卡准备。

SD_ERROR_T errorStatus = SD_OK;

/* Disable SDIO Clock */
SDIO_DisableClock(hsd);

/* Set Power State to ON */
SDIO_ConfigPowerState(SDIO_POWER_STATE_ON);

/* Enable SDIO Clock */
SDIO_EnableClock(hsd);

/* power on SD card */
errorStatus = SD_PowerON();

获取卡信息
if(errorStatus == SD_OK)
{
    /** Initialize SD card */
    errorStatus = SD_InitializeCards();
}

if(errorStatus == SD_OK)
{
    /** Get SD card info */
    errorStatus = SD_GetCardInfo(&SDCardInfo);
}

if(errorStatus == SD_OK)
{
    /** Select and enable SD card */
    errorStatus = SD_CardSelect((uint32_t)(SDCardInfo.RCA << 16));
}


设置SDIO工作在数据传输模式
if(errorStatus==SD_OK)
{
    /** Set SDIO bus wide as 4B */
    errorStatus = SD_EnableWideBusOperation(SDIO_BUS_WIDE_4B);
}


SD卡的读写操作
void SD_SingleBlockTest(void)
{
    uint32_t sdSize;
    uint8_t sta = SD_OK;
    long long sectorAddress = 0;
    uint8_t buffer[512];

    /** Fill the data to be written  */
    for(sdSize = 0; sdSize < 512; sdSize++)
    {
        buffer[sdSize] = sdSize + 1 ;
    }
    /** Write one sector data to sector 0 address  */
    if((sta = SD_WriteBlock(buffer,sectorAddress,512)) == SD_OK)
    {
        printf("write success\r\n");
        Delay_ms(50);
    }
    else
    {
        printf("Write Error Status:%d\r\n",sta);
    }

    memset(buffer,0,512);

    if((sta = SD_ReadBlock(buffer,sectorAddress,512)) == SD_OK)
    {
        /** Print sector 0 data  */
        printf("Sector 0 Data:\r\n");

        for(sdSize = 1; sdSize <= 512; sdSize++)
        {
            printf("%X ",buffer[sdSize - 1]);

            if((sdSize != 0) && ((sdSize % 16) == 0))
            {
                printf("\r\n");
            }
        }
        printf("Sector 0 Data Ended\r\n");
    }
    else
    {
        printf("Read Error Status %d\r\n",sta);
    }

    printf("Single Block Test OK\r\n");
}


参考文献
1. SD Card association
2.《Sandiskmanual-SecureDigital2.2》
3.《SD Specifications Part 1 Physical Layer Simplified Specification》











使用特权

评论回复
沙发
caigang13| | 2023-5-8 22:01 | 只看该作者
不错,学习了。

使用特权

评论回复
板凳
麻花油条| | 2023-5-9 11:14 | 只看该作者
把上下篇都看看,学习

使用特权

评论回复
地板
tpgf| | 2023-6-3 17:34 | 只看该作者
SD卡为Secure Digital Memory Card, 即安全数码卡。它在MMC的基础上发展而来

使用特权

评论回复
5
nawu| | 2023-6-3 18:03 | 只看该作者
SDIO是在SD标准上定义了一种外设接口,它和SD卡规范间的一个重要区别是增加了低速标准

使用特权

评论回复
6
aoyi| | 2023-6-5 10:01 | 只看该作者
SDIO卡只需要SPI和1位SD传输模式

使用特权

评论回复
7
zljiu| | 2023-6-5 10:41 | 只看该作者
MMC,SD,SDI卡定义的接口都属于MCI接口

使用特权

评论回复
8
gwsan| | 2023-6-5 11:28 | 只看该作者
MCI是Multimedia Card Interface的简称,即多媒体卡接口

使用特权

评论回复
9
tfqi| | 2023-6-5 11:49 | 只看该作者
SD 传输模式有以下 3 种:

· SPI mode(required)

· 1-bit mode

· 4-bit mode

使用特权

评论回复
10
albertaabbot| | 2023-6-6 12:20 | 只看该作者
SDIO操作SD卡的速度瓶颈在哪里呢?

使用特权

评论回复
11
everyrobin| | 2023-6-6 13:07 | 只看该作者
一个SDIO口如何操作多张SD卡

使用特权

评论回复
12
jkl21| | 2023-6-6 13:19 | 只看该作者
对SDIO接口进行初始化,并设置相关参数,例如时钟频率、数据位宽、传输速率等

使用特权

评论回复
13
bartonalfred| | 2023-6-6 14:11 | 只看该作者
SDIO接口的配置和SD卡的读写操作都比较复杂,需要掌握相应的协议、时序和参数设置

使用特权

评论回复
14
wengh2016| | 2023-6-6 14:24 | 只看该作者
使用SDIO接口读取或写入数据,包括单块读写、多块读写、连续读写等操作。

使用特权

评论回复
15
sdlls| | 2023-6-6 15:17 | 只看该作者
使用SDIO+DMA 来读写SD卡,怎么提高写的速度

使用特权

评论回复
16
usysm| | 2023-6-6 17:22 | 只看该作者
一个SDIO接口 能够同时接两个SD卡么

使用特权

评论回复
17
gygp| | 2023-6-10 09:55 | 只看该作者
SDIO和SPI各自接了个SD卡,都想用FATFS文件系统,可以吗

使用特权

评论回复
18
pmp| | 2023-6-10 10:05 | 只看该作者
读取SD卡时SPI和SDIO有什么区别?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

19

主题

32

帖子

4

粉丝