【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段

相关文章

《【SDIO】SDIO、SD卡、FatFs文件系统相关文章索引》

1.前言

本篇文章主要是介绍SD卡的读写测试,包括:SD卡擦除测试SD卡单一块读写测试SD卡多个块读写测试。这个3个测试主要是调用了stm324x9i_eval_sdio_sd.c里面的相关API,下面会详细的介绍这些API是如何实现的。SD卡在Transfer Mode阶段的状态图如下:
【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第1张图片
SD卡的读写测试的思维导图如下,下面会详细介绍这3个函数是如何实现的:
【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第2张图片

NOTE:阅读下面分析时最好参考SD卡读写测试的完整工程一起,这样有助于理解。工程下载地址下面有贴出来。

2.SD_EraseTest()

SD_EraseTest()函数主要的流程是擦除指定地址块的存储,通过DMA的方式读取这写块的数据,判断是否等于0xFF或者0x00(默认情况下擦除的Flash都是0xFF,特殊的情况下也有0x00)。SD_EraseTest()函数具体实现如下:
【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第3张图片

2.1 CMD32:SD_CMD_SD_ERASE_GRP_START

CMD32:SD_CMD_SD_ERASE_GRP_START该命令主要是作用是设置擦除的起始块地址

#define SD_CMD_SD_ERASE_GRP_START                  ((uint8_t)32) /*!< To set the address of the first write

/*!< Send CMD32 SD_ERASE_GRP_START with argument as addr  */
SDIO_CmdInitStructure.SDIO_Argument =(uint32_t)startaddr;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_ERASE_GRP_START;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp1Error(SD_CMD_SD_ERASE_GRP_START);

在这里插入图片描述

发送命令CMD32的Argument是 start data block addressSD_EraseTest()设置擦除地址是0 ~ 51200Bytes,所以这里填写的是0x00 (0/512)。实际发送出去的波形如下:
在这里插入图片描述
然后SD卡处理完后,以R1的形式Response Card Status。通过CmdResp1Error检测CMD是否正确响应,并且判断Card Status是否存在错误。Receive的波形如下:
在这里插入图片描述
Card Status = 0x00000900对应的表格如下:
【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第4张图片

2.2 CMD33:SD_CMD_SD_ERASE_GRP_END

CMD33:SD_CMD_SD_ERASE_GRP_END该命令主要是作用是设置擦除的结束块地址

#define SD_CMD_SD_ERASE_GRP_END                    ((uint8_t)33) /*!< To set the address of the last write block of the

/*!< Send CMD33 SD_ERASE_GRP_END with argument as addr  */
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)endaddr;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_ERASE_GRP_END;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp1Error(SD_CMD_SD_ERASE_GRP_END);

在这里插入图片描述
发送命令CMD33的Argument是 end data block addressSD_EraseTest()设置擦除地址是0 ~ 51200Bytes,所以这里填写的是0x64 (51200/512)。实际发送出去的波形如下:
在这里插入图片描述
然后SD卡处理完后,以R1的形式Response Card Status。通过CmdResp1Error检测CMD是否正确响应,并且判断Card Status是否存在错误。Receive的波形如下:
在这里插入图片描述

备注:R1 Response Card Status的状态值和CMD32一样,参考上面的截图分析。

2.3 CMD38:SD_CMD_ERASE

CMD38:SD_CMD_ERASE该命令主要是作用是擦除预先选定的块

#define SD_CMD_ERASE                               ((uint8_t)38)

/*!< Send CMD38 ERASE */
SDIO_CmdInitStructure.SDIO_Argument = 0;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_ERASE;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp1Error(SD_CMD_ERASE);

在这里插入图片描述
因为发送命令CMD38的Argument是stuff bits,所以这里需要填写0x00。实际发送出去的波形如下:
在这里插入图片描述
Host发送CMD38后,DATA0保持低电平,说明SD处于Busy状态。CMD响应会以R1的形式Response Card Status,通过CmdResp1Error检测CMD是否正确响应,并且判断Card Status是否存在错误。Receive的波形如下:
在这里插入图片描述
Card Status = 0x00000800对应的表格如下:
【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第5张图片

2.4 IsCardProgramming()

SD_Erase()函数中,通过IsCardProgramming()函数循环获取SD卡Card Status,判断并等待是否已经退出Programming State

  /*!< Wait till the card is in programming state */
  errorstatus = IsCardProgramming(&cardstate);
  delay = SD_DATATIMEOUT;
  while ((delay > 0) && (errorstatus == SD_OK) && ((SD_CARD_PROGRAMMING == cardstate) || (SD_CARD_RECEIVING == cardstate)))
  {
     
    errorstatus = IsCardProgramming(&cardstate);
    delay--;
  }

下面有贴出IsCardProgramming()函数的部分代码,主要步骤如下:

  • 发送CMD13:SD_CMD_SEND_STATUS获取SD卡Card Status
  • 循环获取SDIO 状态寄存器 (SDIO_STA),等待CMD13的Response被正确接收。
  • 通过SDIO_GetCommandResponse()获取SDIO 命令响应寄存器 (SDIO_RESPCMD)来获取Response Command Index,并且判断是否等于CMD13(SD_CMD_SEND_STATUS)
  • 通过SDIO_GetResponse(SDIO_RESP1)访问SDIO 响应 1 寄存器 (SDIO_RESP1),来获取Response Argument的参数,这个参数就是SD卡Card Status,然后返回SD卡Current State(Card Status[12:9])
static SD_Error IsCardProgramming(uint8_t *pstatus)
{
     
  SD_Error errorstatus = SD_OK;
  __IO uint32_t respR1 = 0, status = 0;

  SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16;
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_STATUS;
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  SDIO_SendCommand(&SDIO_CmdInitStructure);

  status = SDIO->STA;
  while (!(status & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)))
  {
     
    status = SDIO->STA;
  }

  if (status & SDIO_FLAG_CTIMEOUT)
  {
     
    errorstatus = SD_CMD_RSP_TIMEOUT;
    SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);
    return(errorstatus);
  }
  else if (status & SDIO_FLAG_CCRCFAIL)
  {
     
    errorstatus = SD_CMD_CRC_FAIL;
    SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL);
    return(errorstatus);
  }

  status = (uint32_t)SDIO_GetCommandResponse();

  /*!< Check response received is of desired command */
  if (status != SD_CMD_SEND_STATUS)
  {
     
    errorstatus = SD_ILLEGAL_CMD;
    return(errorstatus);
  }

  /*!< Clear all the static flags */
  SDIO_ClearFlag(SDIO_STATIC_FLAGS);

  /*!< We have received response, retrieve it for analysis  */
  respR1 = SDIO_GetResponse(SDIO_RESP1);

  /*!< Find out card status */
  *pstatus = (uint8_t) ((respR1 >> 9) & 0x0000000F);

  if ((respR1 & SD_OCR_ERRORBITS) == SD_ALLZERO)
  {
     
    return(errorstatus);
  }

  ...

}

在这里插入图片描述

发送CMD13:SD_CMD_SEND_STATUS的实际波形如下:
在这里插入图片描述
获取CMD13的Response Card Status,通过Argument可以知道SD卡CURRENT_STATE = programming state,实际接收到的波形如下:
在这里插入图片描述
Card Status = 0x00000E00对应的表格如下:
【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第6张图片
经过一段时间,DATA0从Low Level跳转到High Level,指示SD卡已经退出Busy状态。然后发送CMD13来获取Card Status,通过下面的波形我们可以知道Card Status = 0x00000900,说明SD卡已经退出programming state(CURRENT_STATE = transfer state)
在这里插入图片描述

3. SD_ReadMultiBlocks()

SD_EraseTest()擦除测试中有用到SD_ReadMultiBlocks(),该函数主要功能是通过DMA的方式读取SD卡多个数据块的数据
【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第7张图片

3.1 SDIO_ITConfig()

SDIO_ITConfig()函数主要是配置SDIO 屏蔽寄存器 (SDIO_MASK),中断屏蔽寄存器通过将对应的位置设置为 1 来确定哪一个状态标志位可以产生中断。。

SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_RXOVERR | SDIO_IT_STBITERR, ENABLE);

【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第8张图片

名称 描述 Value 备注
DCRCFAILIE 数据 CRC 失败中断使能 (Data CRC fail interrupt enable)
0:禁止数据 CRC 失败中断
1:使能数据 CRC 失败中断
1b SDIO_IT_DCRCFAIL
DTIMEOUTIE 数据超时中断使能 (Data timeout interrupt enable)
0:禁止数据超时中断
1:使能数据超时中断
1b SDIO_IT_DTIMEOUT
DATAENDIE 数据结束中断使能 (Data end interrupt enable)
0:禁止数据结束中断
1:使能数据结束中断
1b SDIO_IT_DATAEND
RXOVERRIE Rx FIFO 上溢错误中断使能 (Rx FIFO overrun error interrupt enable)
0:禁止 Rx FIFO 上溢错误中断
1:使能 Rx FIFO 上溢错误中断
1b SDIO_IT_RXOVERR
STBITERRIE 起始位错误中断使能 (Start bit error interrupt enable)
0:禁止起始位错误中断
1:使能起始位错误中断
1b SDIO_IT_STBITERR

3.2 SD_LowLevel_DMA_RxConfig()

DMA 简介:直接存储器访问 (DMA) 用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何 CPU 操作的情况下通过 DMA 快速移动数据。这样节省的 CPU 资源可供其它操作使用。主要的传输方式有3种:

  • 外设到存储器的传输
  • 存储器到外设的传输
  • 存储器到存储器的传输

【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第9张图片
STM32F4xx 系列资源丰富,具有个 DMA 控制器,同时外设繁多,为实现正常传输,DMA需要通道选择控制。每个 DMA控制器具有8个数据流,每个数据流对应 8个外设请求。在实现 DMA 传输之前,DMA控制器会通过 DMA数据流 x 配置寄存器 DMA_SxCR(x为 0~7,对应 8 个 DMA 数据流)的 CHSEL[2:0]位选择对应的通道作为该数据流的目标外设。

外设通道选择主要是为了选择哪一个外设作为该数据流的源地址或者目标地址
【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第10张图片
我们这里使用的是SDIO外设,在DMA2的映射表中可以找到,我们有2个可以选择:

  • 通道4 & 数据流3
  • 通道4 & 数据流6

SD_LowLevel_DMA_RxConfig()具体代码如下:

/**
 * @brief SD SDIO configration parameter
 *
 */
#define SD_SDIO_DMA                   DMA2
#define SD_SDIO_DMA_CLK               RCC_AHB1Periph_DMA2

#define SD_SDIO_DMA_STREAM			  DMA2_Stream3
#define SD_SDIO_DMA_CHANNEL 		  DMA_Channel_4
#define SD_SDIO_DMA_FLAG_FEIF		  DMA_FLAG_FEIF3
#define SD_SDIO_DMA_FLAG_DMEIF		  DMA_FLAG_DMEIF3
#define SD_SDIO_DMA_FLAG_TEIF		  DMA_FLAG_TEIF3
#define SD_SDIO_DMA_FLAG_HTIF		  DMA_FLAG_HTIF3
#define SD_SDIO_DMA_FLAG_TCIF		  DMA_FLAG_TCIF3 
#define SD_SDIO_DMA_IRQn			  DMA2_Stream3_IRQn
#define SD_SDIO_DMA_IRQHANDLER		  DMA2_Stream3_IRQHandler 

/**
  * @brief  Configures the DMA2 Channel4 for SDIO Rx request.
  * @param  BufferDST: pointer to the destination buffer
  * @param  BufferSize: buffer size
  * @retval None
  */
void SD_LowLevel_DMA_RxConfig(uint32_t *BufferDST, uint32_t BufferSize)
{
     
  DMA_InitTypeDef SDDMA_InitStructure;

  DMA_ClearFlag(SD_SDIO_DMA_STREAM, SD_SDIO_DMA_FLAG_FEIF | SD_SDIO_DMA_FLAG_DMEIF | SD_SDIO_DMA_FLAG_TEIF | SD_SDIO_DMA_FLAG_HTIF | SD_SDIO_DMA_FLAG_TCIF);

  /* DMA2 Stream3  or Stream6 disable */
  DMA_Cmd(SD_SDIO_DMA_STREAM, DISABLE);

  /* DMA2 Stream3 or Stream6 Config */
  DMA_DeInit(SD_SDIO_DMA_STREAM);

  SDDMA_InitStructure.DMA_Channel = SD_SDIO_DMA_CHANNEL;
  SDDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SDIO_FIFO_ADDRESS;
  SDDMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)BufferDST;
  SDDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
  SDDMA_InitStructure.DMA_BufferSize = 1;
  SDDMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  SDDMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  SDDMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
  SDDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
  SDDMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  SDDMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  SDDMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
  SDDMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
  SDDMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC4;
  SDDMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_INC4;
  DMA_Init(SD_SDIO_DMA_STREAM, &SDDMA_InitStructure);
  DMA_ITConfig(SD_SDIO_DMA_STREAM, DMA_IT_TC, ENABLE);
  DMA_FlowControllerConfig(SD_SDIO_DMA_STREAM, DMA_FlowCtrl_Peripheral);

  /* DMA2 Stream3 or Stream6 enable */
  DMA_Cmd(SD_SDIO_DMA_STREAM, ENABLE);
}

具体分析如下:

  • DMA_ClearFlag():清除DMA中断相关标志位。
  • DMA_Init():初始化DMA相关寄存器,涉及到寄存器有:
    • DMA 数据流 x 配置寄存器 (DMA_SxCR) (x = 0…7)
    • DMA 数据流 x FIFO 控制寄存器 (DMA_SxFCR) (x = 0…7)
    • DMA 数据流 x 数据项数寄存器 (DMA_SxNDTR) (x = 0…7)
    • DMA 数据流 x 外设地址寄存器 (DMA_SxPAR) (x = 0…7)
    • DMA 数据流 x 存储器 0 地址寄存器 (DMA_SxM0AR) (x = 0…7)
  • DMA_ITConfig():配置DMA相关中断寄存器,涉及到寄存器有:
    • DMA 数据流 x 配置寄存器 (DMA_SxCR) (x = 0…7)
    • DMA 数据流 x FIFO 控制寄存器 (DMA_SxFCR) (x = 0…7)
  • DMA_FlowControllerConfig():配置DMA相关流控制寄存器,涉及到寄存器有:
    • DMA 数据流 x 配置寄存器 (DMA_SxCR) (x = 0…7)
  • DMA_Cmd():配置DMA相关数据流通道Enable Or Disabled,涉及到寄存器有:
    • DMA 数据流 x 配置寄存器 (DMA_SxCR) (x = 0…7)

【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第11张图片

名称 描述 Value 备注
CHSEL[2:0] 通道选择 (Channel selection)
000:选择通道 0
001:选择通道 1
010:选择通道 2
011:选择通道 3
100:选择通道 4
101:选择通道 5
110:选择通道 6
111:选择通道 7
100b DMA_Channel_4
MBURST[1:0] 存储器突发传输配置 (Memory burst transfer configuration)
00:单次传输
01:INCR4(4 个节拍的增量突发传输)
10:INCR8(8 个节拍的增量突发传输)
11:INCR16(16 个节拍的增量突发传输)
01b DMA_MemoryBurst_INC4
PBURST[1:0] 外设突发传输配置 (Peripheral burst transfer configuration)
00:单次传输
01:INCR4(4 个节拍的增量突发传输)
10:INCR8(8 个节拍的增量突发传输)
11:INCR16(16 个节拍的增量突发传输)
01b DMA_PeripheralBurst_INC4
PL[1:0] 优先级 (Priority level)
00:低
01:中
10:高
11:非常高
11b DMA_Priority_VeryHigh
MSIZE[1:0] 存储器数据大小 (Memory data size)
00:字节(8 位)
01:半字(16 位)
10:字(32 位)
11:保留
10b DMA_MemoryDataSize_Word
PSIZE[1:0] 外设数据大小 (Peripheral data size)
00:字节(8 位)
01:半字(16 位)
10:字(32 位)
11:保留
10b DMA_MemoryDataSize_Word
MINC 存储器递增模式 (Memory increment mode)
0:存储器地址指针固定
1:每次数据传输后,存储器地址指针递增(增量为 MSIZE 值)
1b DMA_MemoryInc_Enable
PINC 外设递增模式 (Peripheral increment mode)
0:外设地址指针固定
1:每次数据传输后,外设地址指针递增(增量为 PSIZE 值)
0b DMA_PeripheralInc_Disable
DIR[1:0] 数据传输方向 (Data transfer direction)
00:外设到存储器
01:存储器到外设
10:存储器到存储器
00b DMA_DIR_PeripheralToMemory
PFCTRL 外设流控制器 (Peripheral flow controller)
0:DMA 是流控制器
1:外设是流控制器
0b DMA_FlowCtrl_Peripheral
TCIE 传输完成中断使能 (Transfer complete interrupt enable)
0:禁止 TC 中断
1:使能 TC 中断
1b DMA_IT_TC
EN 数据流使能/读作低电平时数据流就绪标志
(Stream enable / flag stream ready when read low)
0:禁止数据流
1:使能数据流
1b DMA_SxCR_EN

【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第12张图片

名称 描述 Value 备注
DMDIS 直接模式禁止 (Direct mode disable)
0:使能直接模式
1:禁止直接模式
1b DMA_FIFOMode_Enable
FTH[1:0] FIFO 阈值选择 (FIFO threshold selection)
00:FIFO 容量的 1/4
01:FIFO 容量的 1/2
10:FIFO 容量的 3/4
11:FIFO 完整容量
11b DMA_FIFOThreshold_Full

【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第13张图片

名称 描述 Value 备注
NDT[15:0] 要传输的数据项数目 (Number of data items to transfer)

要传输的数据项数目(0 到 65535)。只有在禁止数据流时,才能向此寄存器执行写操作。使能数据流后,此寄存器为只读,用于指示要传输的剩余数据项数。每次 DMA 传输后,此寄存器将递减。
1

【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第14张图片

名称 描述 Value 备注
PAR[31:0] 外设地址 (Peripheral address)

读/写数据的外设数据寄存器的基址。
0x40012C80 SDIO_FIFO_ADDRESS:
SDIO 数据 FIFO 寄存器 (SDIO_FIFO)的地址

【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第15张图片

名称 描述 Value 备注
M0A[31:0] 存储器 0 地址 (Memory 0 address)

读/写数据的存储区 0 的基址。
* BufferDST:
存放数据的内存地址

3.3 CMD16:SD_CMD_SET_BLOCKLEN

CMD16:SD_CMD_SET_BLOCKLEN该命令主要是作用是设置块命令的长度

#define SD_CMD_SET_BLOCKLEN                        ((uint8_t)16)

/*!< Set Block Size for Card */
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);

【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第16张图片
发送命令CMD16的Argument是 block sizeSD2.0协议规定了SDIO_HIGH_CAPACITY_SD_CARDblock size = 512Bytes,所以这里填写的是0x200 (512)。实际发送出去的波形如下:
在这里插入图片描述
然后SD卡处理完后,以R1的形式Response Card Status。通过CmdResp1Error检测CMD是否正确响应,并且判断Card Status是否存在错误。Receive的波形如下:
在这里插入图片描述
Card Status = 0x00000900对应的表格如下:
【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第17张图片

3.4 SDIO_DataConfig()

SDIO_DataConfig()函数主要的功能是配置传输数据的长度传输超时传输方向传输模式等。涉及到的SDIO寄存器如下:

  • SDIO 数据定时器寄存器 (SDIO_DTIMER)
  • SDIO 数据长度寄存器 (SDIO_DLEN)
  • SDIO 数据控制寄存器 (SDIO_DCTRL)
SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
SDIO_DataInitStructure.SDIO_DataLength = NumberOfBlocks * BlockSize;
SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) 9 << 4;
SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToSDIO;
SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
SDIO_DataConfig(&SDIO_DataInitStructure);

【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第18张图片

名称 描述 Value 备注
DATATIME 数据超时周期 (Data timeout period)

以卡总线时钟周期表示的数据超时周期。
0xFFFFFFFF SD_DATATIMEOUT

【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第19张图片

名称 描述 Value 备注
DATALENGTH 数据长度值 (Data length value)

要传输的数据字节数量。
0xC800(100 * 512) NumberOfBlocks * BlockSize

【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第20张图片

名称 描述 Value 备注
DBLOCKSIZE 数据块大小 (Data block size)
0000:(十进制数 0)块长度 = 20 = 1 字节
0001:(十进制数 1)块长度 = 21 = 2 字节
0010:(十进制数 2)块长度 = 22 = 4 字节
0011:(十进制数 3)块长度 = 23 = 8 字节
0100:(十进制数 4)块长度 = 24 = 16 字节
0101:(十进制数 5)块长度 = 25 = 32 字节
0110:(十进制数 6)块长度 = 26 = 64 字节
0111:(十进制数 7)块长度 = 27 = 128 字节
1000:(十进制数 8)块长度 = 28 = 256 字节
1001:(十进制数 9)块长度 = 29 = 512 字节
1010:(十进制数 10)块长度 = 210 = 1024 字节
1011:(十进制数 11)块长度 = 211 = 2048 字节
1100:(十进制数 12)块长度 = 212 = 4096 字节
1101:(十进制数 13)块长度 = 213 = 8192 字节
1110:(十进制数 14)块长度 = 214 = 16384 字节
1111:(十进制数 15)保留
9 9 << 4
DTMODE 数据传输模式选择 (Data transfer mode selection)
0:块数据传输
1:流或 SDIO 多字节数据传输
0 SDIO_TransferMode_Block
DTDIR 数据传输方向选择 (Data transfer direction selection)
0:从控制器到卡。
1:从卡到控制器。
0 SDIO_TransferDir_ToSDIO
DTEN 数据传输使能位 (Data transfer enabled bit)
如果 1 写入到 DTEN 位,则数据传输开始。
1 SDIO_DPSM_Enable

3.5 CMD18:SD_CMD_READ_MULT_BLOCK

CMD18:SD_CMD_READ_MULT_BLOCK该命令主要是作用是从指定地址连续从 SD 卡读取数据块

#define SD_CMD_READ_MULT_BLOCK                     ((uint8_t)18)

/*!< Send CMD18 READ_MULT_BLOCK with argument data address */
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)ReadAddr;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_READ_MULT_BLOCK;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);

errorstatus = CmdResp1Error(SD_CMD_READ_MULT_BLOCK);

在这里插入图片描述
发送命令CMD18的Argument是 start read data block addressReadAddr被设置为0,实际发送出去的波形如下:
在这里插入图片描述
然后SD卡处理完后,以R1的形式Response Card Status。通过CmdResp1Error检测CMD是否正确响应,并且判断Card Status是否存在错误。Receive的波形如下:
在这里插入图片描述

3.6 SD_WaitReadOperation()

SD_WaitReadOperation()这个函数主要的功能是等待SDIO DMA数据传输完成。通过DMA中断函数SD_ProcessDMAIRQ()来设置DMAEndOfTransfer标志,下面有介绍。

SD_Error SD_WaitReadOperation(void)
{
     
  SD_Error errorstatus = SD_OK;
  uint32_t timeout;

  timeout = SD_DATATIMEOUT;
  
  while ((DMAEndOfTransfer == 0x00) && (TransferEnd == 0) && (TransferError == SD_OK) && (timeout > 0))
  {
     
    timeout--;
  }
  
  DMAEndOfTransfer = 0x00;

  timeout = SD_DATATIMEOUT;
  
  while(((SDIO->STA & SDIO_FLAG_RXACT)) && (timeout > 0))
  {
     
    timeout--;  
  }

  if (StopCondition == 1)
  {
     
    errorstatus = SD_StopTransfer();
    StopCondition = 0;
  }
  
  ...
}

SD_ProcessDMAIRQ()这个函数是DMA中断函数,当SDIO DMA传输完成后会将DMAEndOfTransfer 设置为0x01

void SD_ProcessDMAIRQ(void)
{
     
  if(DMA2->LISR & SD_SDIO_DMA_FLAG_TCIF)
  {
     
    DMAEndOfTransfer = 0x01;
    DMA_ClearFlag(SD_SDIO_DMA_STREAM, SD_SDIO_DMA_FLAG_TCIF|SD_SDIO_DMA_FLAG_FEIF);
  }
}

在等待中,我们可以通过波形看到传输的数据都是0x00,说明SD_EraseTest()成功。
【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第21张图片

4.验证测试结果

测试代码如下:

static void SD_EraseTest(void)
{
     
	printf("\r\n---->Erase test is starting...\r\n");

	/*------------------- Block Erase ------------------------------------------*/
	if (Status == SD_OK)
	{
     
		/* Erase NumberOfBlocks Blocks of WRITE_BL_LEN(512 Bytes) */
		Status = SD_Erase(0x00, (BLOCK_SIZE * NUMBER_OF_BLOCKS));
	}

	if (Status == SD_OK)
	{
     
		Status = SD_ReadMultiBlocks(aBuffer_MultiBlock_Rx, 0x00, BLOCK_SIZE, NUMBER_OF_BLOCKS);

		/* Check if the Transfer is finished */
		Status = SD_WaitReadOperation();

		/* Wait until end of DMA transfer */
		while(SD_GetStatus() != SD_TRANSFER_OK);
	}

	/* Check the correctness of erased blocks */
	if (Status == SD_OK)
	{
     
		EraseStatus = eBuffercmp(aBuffer_MultiBlock_Rx, MULTI_BUFFER_SIZE);
	}

	if(EraseStatus == PASSED)
	{
     
		LED1(ON);
		printf("\tThe earase is successful.\r\n");
	}
	else
	{
     
		LED1(OFF);
		LED3(ON);
		printf("\tThe earase is fail!!!\r\n");
	}

	printf("<----Erase test is end.\r\n");
}

验证测试结果成功:
【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段_第22张图片

5. 参考资料

SDIO参考的资料如下:
在这里插入图片描述
下载地址如下:
https://download.csdn.net/download/ZHONGCAI0901/14975835

移植成功的完整代码下载地址如下:
https://download.csdn.net/download/ZHONGCAI0901/15265756

你可能感兴趣的:(MCU,sdio)