STM32——SDIO的学习(驱动SD卡)(实战篇)

这篇具有很好参考价值的文章主要介绍了STM32——SDIO的学习(驱动SD卡)(实战篇)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、SDIO寄存器

1.1 SDIO电源控制寄存器(SDIO_POWER)

1.2 SDIO时钟控制寄存器(SDIO_CLKCR)

1.3 SDIO参数寄存器(SDIO_ARG)

1.4 SDIO命令寄存器(SDIO_CMD)

1.5 SDIO命令响应寄存器(SDIO_RESPCMD)

1.6 SDIO响应 1..4 寄存器(SDIO_RESPx)

1.7 SDIO数据定时器寄存器(SDIO_DTIMER)

1.8 SDIO数据长度寄存器(SDIO_DLEN)

1.9 SDIO数据控制寄存器(SDIO_DCTRL)

1.10 SDIO数据计数器寄存器(SDIO_DCOUNT)

1.11 SDIO状态寄存器(SDIO_STA)

1.12 SDIO清除中断寄存器(SDIO_ICR)

1.13 SDIO中断屏蔽寄存器(SDIO_MASK)

1.14 SDIO FIFO计数器寄存器(SDIO_FIFOCNT)

1.15 SDIO数据FIFO寄存器(SDIO_FIFO)

1.16 SDIO寄存器映像

二、开发思路

三、具体实例


书接上回:

STM32——SDIO的学习(驱动SD卡)(理论篇)_宇努力学习的博客-CSDN博客

在写程序前在最后了解一下SDIO的寄存器

一、SDIO寄存器

设备通过可以在AHB上操作的32位控制寄存器与系统通信。
必须以字(32位)的方式操作这些外设寄存器。

1.1 SDIO电源控制寄存器(SDIO_POWER)

地址偏移: 0x00
复位值: 0x0000 0000
sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

注意: 写数据后的7个HCLK时钟周期内,不能写入这个寄存器.

1.2 SDIO时钟控制寄存器(SDIO_CLKCR)


地址偏移: 0x04
复位值: 0x0000 0000
SDIO_CLKCR寄存器控制SDIO_CK输出时钟
sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO
sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

注意:

1 当SD/SDIO卡或多媒体卡在识别模式, SDIO_CK的频率必须低于400kHz。
2 当所有卡都被赋予了相应的地址后,时钟频率可以改变到卡总线允许的最大频率。
3 写数据后的7个HCLK时钟周期内不能写入这个寄存器。对于SD I/O卡,在读等待期间可以停
止SDIO_CK,此时SDIO_CLKCR寄存器不控制SDIO_CK
 

1.3 SDIO参数寄存器(SDIO_ARG)


地址偏移: 0x08
复位值: 0x0000 0000
SDIO_ARG寄存器包含32位命令参数,它将作为命令的一部分发送到卡中。
sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

1.4 SDIO命令寄存器(SDIO_CMD)


地址偏移: 0x0C
复位值: 0x0000 0000
SDIO_CMD寄存器包含命令索引和命令类型位。命令索引是作为命令的一部分发送到卡中。命
令类型位控制命令通道状态机(CPSM)。
 

sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

注意:

1 写数据后的7个HCLK时钟周期内不能写入这个寄存器。
2 多媒体卡可以发送2种响应: 48位长的短响应,或136位长的长响应。 SD卡和SD I/O卡只能发
送短响应,参数可以根据响应的类型而变化,软件将根据发送的命令区分响应的类型。 CE-ATA
设备只发送短响应
 

1.5 SDIO命令响应寄存器(SDIO_RESPCMD)


地址偏移: 0x10
复位值: 0x0000 0000
SDIO_RESPCMD寄存器包含最后收到的命令响应中的命令索引。如果传输的命令响应不包含
命令索引(长响应或OCR响应),尽管它应该包含111111b(响应中的保留域值),但RESPCMD域
的内容未知。

sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

 sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

1.6 SDIO响应 1..4 寄存器(SDIO_RESPx)


地址偏移: 0x14 + 4*(x-1),其中 x = 1..4
复位值: 0x0000 0000
SDIO_RESP1/2/3/4寄存器包含卡的状态,即收到响应的部分信息。
 sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

1.7 SDIO数据定时器寄存器(SDIO_DTIMER)


地址偏移: 0x24
复位值: 0x0000 0000
SDIO_DTIMER寄存器包含以卡总线时钟周期为单位的数据超时时间。
一个计数器从SDIO_DTIMER寄存器加载数值,并在数据通道状态机(DPSM)进入Wait_R或繁忙
状态时进行递减计数,当DPSM处在这些状态时,如果计数器减为0,则设置超时标志。
 sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

注意 在写入数据控制寄存器进行数据传输之前,必须先写入数据定时器寄存器和数据长度寄存器。

1.8 SDIO数据长度寄存器(SDIO_DLEN)


地址偏移: 0x28
复位值: 0x0000 0000
SDIO_DLEN寄存器包含需要传输的数据字节长度。当数据传输开始时,这个数值被加载到数据
计数器中。
 sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO 

注意 对于块数据传输,数据长度寄存器中的数值必须是数据块长度(见SDIO_DCTRL)的倍数。在写
入数据控制寄存器进行数据传输之前,必须先写入数据定时器寄存器和数据长度寄存器。

1.9 SDIO数据控制寄存器(SDIO_DCTRL)


地址偏移: 0x2C
复位值: 0x0000 0000
SDIO_DCTRL寄存器控制数据通道状态机(DPSM)。
sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO
 sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

注意 写数据后的7个HCLK时钟周期内不能写入这个寄存器。
 

1.10 SDIO数据计数器寄存器(SDIO_DCOUNT)


地址偏移: 0x30
复位值: 0x0000 0000
当DPSM从空闲状态进入Wait_R或Wait_S状态时, SDIO_DCOUNT寄存器从数据长度寄存器加
载数值(见SDIO_DLEN),在数据传输过程中,该计数器的数值递减直到减为0,然后DPSM进入
空闲状态并设置数据状态结束标志DATAEND。

 sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

注意 只能在数据传输结束时读这个寄存器

1.11 SDIO状态寄存器(SDIO_STA)


地址偏移: 0x34
复位值: 0x0000 0000
SDIO_STA是一个只读寄存器,它包含两类标志:
● 静态标志(位[23:22、 10:0]):写入SDIO中断清除寄存器(见SDIO_ICR),可以清除这些位。
● 动态标志(位[21:11]):这些位的状态变化根据它们对应的那部分逻辑而变化(例如: FIFO满
和空标志变高或变低随FIFO的数据写入变化)。

sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO 

1.12 SDIO清除中断寄存器(SDIO_ICR)


地址偏移: 0x38
复位值: 0x0000 0000
SDIO_ICR是一个只写寄存器,在对应寄存器位写’1’将清除SDIO_STA状态寄存器中的对应位。
 sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO 

 

1.13 SDIO中断屏蔽寄存器(SDIO_MASK)


地址偏移: 0x3C
复位值: 0x0000 0000
在对应位置’1’, SDIO_MASK中断屏蔽寄存器决定哪一个状态位产生中断。

 sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO 

 sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

1.14 SDIO FIFO计数器寄存器(SDIO_FIFOCNT)


地址偏移: 0x48
复位值: 0x0000 0000
SDIO_FIFOCNT寄存器包含还未写入FIFO或还未从FIFO读出的数据字数目。当在数据控制寄
存器(SDIO_DCTRL)中设置了数据传输使能位DTEN,并且DPSM处于空闲状态时, FIFO计数
器从数据长度寄存器(见SDIO_DLEN)加载数值。如果数据长度未与字对齐(4的倍数),则最后剩
下的1~3个字节被当成一个字处理。
 sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

1.15 SDIO数据FIFO寄存器(SDIO_FIFO)


地址偏移: 0x80
复位值: 0x0000 0000
接收和发送FIFO是32位的宽度读或写一组寄存器,它在连续的32个地址上包含32个寄存器,
CPU可以使用FIFO读写多个操作数。
sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

1.16 SDIO寄存器映像


下表是SDIO寄存器的总结。
 

sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO

sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO 

sdio命令,STM32,stm32,学习,单片机,嵌入式,SDIO 

二、开发思路

        略掉。我们按照ST官方文档来学习。从程序中学习他们的开发流程。我觉得这时最快的方式。在外面都学会了以后开创直接的东西的时候才需要按照基础知识到程序的流程。

三、具体实例

使用之前先来看看怎么取消初始化。 

/**
  * @brief  DeInitializes the SDIO interface.
  * @param  None
  * @retval None
  */
void SD_LowLevel_DeInit(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  
  /*!< Disable SDIO Clock */
  SDIO_ClockCmd(DISABLE);
  
  /*!< Set Power State to OFF */
  SDIO_SetPowerState(SDIO_PowerState_OFF);

  /*!< DeInitializes the SDIO peripheral */
  SDIO_DeInit();
  
  /*!< Disable the SDIO AHB Clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_SDIO, DISABLE);

  /*!< Configure PC.08, PC.09, PC.10, PC.11, PC.12 pin: D0, D1, D2, D3, CLK pin */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  /*!< Configure PD.02 CMD line */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
}

 先关闭时钟和电源。

然后对SDIO外设的相关寄存器进行设置。

/**
  * @brief  Deinitializes the SDIO peripheral registers to their default reset values.
  * @param  None
  * @retval None
  */
void SDIO_DeInit(void)
{
  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;
}

其实就是按照流程给对应寄存器写对应的值。

然后关闭AHB总线

这时得注意有没有其它设备使用这条总线。

然后配置使用的引脚模式为浮空输入。

上面的五个引脚分别是四根数据线和一根时钟线。

下面那根是控制线。

看完取消使能再看使能

/**
  * @brief  Initializes the SD Card and put it into StandBy State (Ready for 
  *         data transfer).
  * @param  None
  * @retval None
  */
void SD_LowLevel_Init(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;

  /*!< GPIOC and GPIOD Periph clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);

  /*!< Configure PC.08, PC.09, PC.10, PC.11, PC.12 pin: D0, D1, D2, D3, CLK pin */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  /*!< Configure PD.02 CMD line */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
  
  /*!< Enable the SDIO AHB Clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_SDIO, ENABLE);

  /*!< Enable the DMA2 Clock */
  RCC_AHBPeriphClockCmd(SD_SDIO_DMA_CLK, ENABLE);
}

和取消相反,先使能引脚对应的时钟总线。

将四个数据引脚 和时钟引脚初始化为复用推挽输出。

使能控制引脚和SDIO与DMA的总线。

/**
  * @brief  Allows to erase memory area specified for the given card.
  * @param  startaddr: the start address.
  * @param  endaddr: the end address.
  * @retval SD_Error: SD Card Error code.
  */
SD_Error SD_Erase(uint32_t startaddr, uint32_t endaddr)
{
  SD_Error errorstatus = SD_OK;
  uint32_t delay = 0;
  __IO uint32_t maxdelay = 0;
  uint8_t cardstate = 0;

  /*!< Check if the card coomnd class supports erase command */
  if (((CSD_Tab[1] >> 20) & SD_CCCC_ERASE) == 0)
  {
    errorstatus = SD_REQUEST_NOT_APPLICABLE;
    return(errorstatus);
  }

  maxdelay = 120000 / ((SDIO->CLKCR & 0xFF) + 2);

  if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED)
  {
    errorstatus = SD_LOCK_UNLOCK_FAILED;
    return(errorstatus);
  }

  if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)
  {
    startaddr /= 512;
    endaddr /= 512;
  }
  
  /*!< According to sd-card spec 1.0 ERASE_GROUP_START (CMD32) and erase_group_end(CMD33) */
  if ((SDIO_STD_CAPACITY_SD_CARD_V1_1 == CardType) || (SDIO_STD_CAPACITY_SD_CARD_V2_0 == CardType) || (SDIO_HIGH_CAPACITY_SD_CARD == CardType))
  {
    /*!< Send CMD32 SD_ERASE_GRP_START with argument as addr  */
    SDIO_CmdInitStructure.SDIO_Argument = 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);
    if (errorstatus != SD_OK)
    {
      return(errorstatus);
    }

    /*!< Send CMD33 SD_ERASE_GRP_END with argument as addr  */
    SDIO_CmdInitStructure.SDIO_Argument = 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);
    if (errorstatus != SD_OK)
    {
      return(errorstatus);
    }
  }

  /*!< 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);

  if (errorstatus != SD_OK)
  {
    return(errorstatus);
  }

  for (delay = 0; delay < maxdelay; delay++)
  {}

  /*!< 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--;
  }

  return(errorstatus);
}

上面这个函数是擦除SD卡某个区域的。

下面的函数是初始化整个SD卡,并让其进入待机状态。

/**
  * @brief  Initializes the SD Card and put it into StandBy State (Ready for data 
  *         transfer).
  * @param  None
  * @retval SD_Error: SD Card Error code.
  */
SD_Error SD_Init(void)
{
  __IO SD_Error errorstatus = SD_OK;
  
  NVIC_Configuration();
  
  /* SDIO Peripheral Low Level Init */
  SD_LowLevel_Init();

  SDIO_DeInit();

  errorstatus = SD_PowerON();

  if (errorstatus != SD_OK)
  {
    /*!< CMD Response TimeOut (wait for CMDSENT flag) */
    return(errorstatus);
  }

  errorstatus = SD_InitializeCards();

  if (errorstatus != SD_OK)
  {
    /*!< CMD Response TimeOut (wait for CMDSENT flag) */
    return(errorstatus);
  }

  /*!< Configure the SDIO peripheral */
  /*!< SDIO_CK = SDIOCLK / (SDIO_TRANSFER_CLK_DIV + 2) */
  SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;
  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;
  SDIO_Init(&SDIO_InitStructure);

  /*----------------- Read CSD/CID MSD registers ------------------*/
  errorstatus = SD_GetCardInfo(&SDCardInfo);

  if (errorstatus == SD_OK)
  {
    /*----------------- Select Card --------------------------------*/
    errorstatus = SD_SelectDeselect((uint32_t) (SDCardInfo.RCA << 16));
  }

  if (errorstatus == SD_OK)
  {
    errorstatus = SD_EnableWideBusOperation(SDIO_BusWide_4b);
  }  

  return(errorstatus);
}

 对单个数据块做读写测试。之前学习系统移植的时候,我们了解到SD卡是以512个字节为一个块的。所以这个Blocksize就是一个宏定义的512

/*
 * 函数名:SD_SingleBlockTest
 * 描述  :	单个数据块读写测试
 * 输入  :无
 * 输出  :无
 */
void SD_SingleBlockTest(void)
{  
  /* Fill the buffer to send */
  Fill_Buffer(Buffer_Block_Tx, BLOCK_SIZE, 0x320F);

  if (Status == SD_OK)
  {
    /* Write block of 512 bytes on address 0 */
    Status = SD_WriteBlock(Buffer_Block_Tx, 0x00, BLOCK_SIZE);
		
    /* Check if the Transfer is finished */
    Status = SD_WaitWriteOperation();	  
    while(SD_GetStatus() != SD_TRANSFER_OK); 
  }

  if (Status == SD_OK)
  {
    /* Read block of 512 bytes from address 0 */
    Status = SD_ReadBlock(Buffer_Block_Rx, 0x00, BLOCK_SIZE);//读取数据
    /* Check if the Transfer is finished */
    Status = SD_WaitReadOperation();
    while(SD_GetStatus() != SD_TRANSFER_OK);
  }

  /* Check the correctness of written data */
  if (Status == SD_OK)
  {
    TransferStatus1 = Buffercmp(Buffer_Block_Tx, Buffer_Block_Rx, BLOCK_SIZE);	//比较
  }
  
  if(TransferStatus1 == PASSED)
    printf("》单块读写测试成功!\n" );
 
  else  
  	printf("》单块读写测试失败!\n " );  
}

 这里是自己实现的三个小函数。方便在操作时使用对应功能。

/*
 * 函数名:Buffercmp
 * 描述  :比较两个缓冲区中的数据是否相等
 * 输入  :-pBuffer1, -pBuffer2 : 要比较的缓冲区的指针
 *         -BufferLength 缓冲区长度
 * 输出  :-PASSED 相等
 *         -FAILED 不等
 */
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint32_t BufferLength)
{
  while (BufferLength--)
  {
    if (*pBuffer1 != *pBuffer2)
    {
      return FAILED;
    }

    pBuffer1++;
    pBuffer2++;
  }

  return PASSED;
}


/*
 * 函数名:Fill_Buffer
 * 描述  :在缓冲区中填写数据
 * 输入  :-pBuffer 要填充的缓冲区
 *         -BufferLength 要填充的大小
 *         -Offset 填在缓冲区的第一个值
 * 输出  :无 
 */
void Fill_Buffer(uint8_t *pBuffer, uint32_t BufferLength, uint32_t Offset)
{
  uint16_t index = 0;

  /* Put in global buffer same values */
  for (index = 0; index < BufferLength; index++ )
  {
    pBuffer[index] = index + Offset;
  }
}

/*
 * 函数名:eBuffercmp
 * 描述  :检查缓冲区的数据是否为0
 * 输入  :-pBuffer 要比较的缓冲区
 *         -BufferLength 缓冲区长度        
 * 输出  :PASSED 缓冲区的数据全为0
 *         FAILED 缓冲区的数据至少有一个不为0 
 */
TestStatus eBuffercmp(uint8_t* pBuffer, uint32_t BufferLength)
{
  while (BufferLength--)
  {
    /* In some SD Cards the erased state is 0xFF, in others it's 0x00 */
    if ((*pBuffer != 0xFF) && (*pBuffer != 0x00))//擦除后是0xff或0x00
    {
      return FAILED;
    }

    pBuffer++;
  }

  return PASSED;
}

对多块读写如下:

/*
 * 函数名:SD_MultiBlockTest
 * 描述  :	多数据块读写测试
 * 输入  :无
 * 输出  :无
 */
void SD_MultiBlockTest(void)
{
  /* Fill the buffer to send */
  Fill_Buffer(Buffer_MultiBlock_Tx, MULTI_BUFFER_SIZE, 0x0);

  if (Status == SD_OK)
  {
    /* Write multiple block of many bytes on address 0 */
    Status = SD_WriteMultiBlocks(Buffer_MultiBlock_Tx, 0x00, BLOCK_SIZE, NUMBER_OF_BLOCKS);
    /* Check if the Transfer is finished */
    Status = SD_WaitWriteOperation();
    while(SD_GetStatus() != SD_TRANSFER_OK);
  }

  if (Status == SD_OK)
  {
    /* Read block of many bytes from address 0 */
    Status = SD_ReadMultiBlocks(Buffer_MultiBlock_Rx, 0x00, BLOCK_SIZE, NUMBER_OF_BLOCKS);
    /* Check if the Transfer is finished */
    Status = SD_WaitReadOperation();
    while(SD_GetStatus() != SD_TRANSFER_OK);
  }

  /* Check the correctness of written data */
  if (Status == SD_OK)
  {
    TransferStatus2 = Buffercmp(Buffer_MultiBlock_Tx, Buffer_MultiBlock_Rx, MULTI_BUFFER_SIZE);
  }
  
  if(TransferStatus2 == PASSED)	  
  	printf("》多块读写测试成功!\n " );

  else 
  	printf("》多块读写测试失败!\n  " );  

}

以上驱动程序来自ST官方驱动库。应用层测试demo来自硬石头。文章来源地址https://www.toymoban.com/news/detail-604399.html

到了这里,关于STM32——SDIO的学习(驱动SD卡)(实战篇)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • stm32在SDIO模式下SD写入错误的问题

    1、问题描述 使用FAT32 f_write 多次执行写操作时,会报FR_DISK_ERR错误,而且是刚开始写不报错,写几次后会一直报错。 设断点跟踪到HAL_SD_WriteBlocks中,在调用SDMMC_CmdWriteMultiBlock时,会报SDMMC_ERROR_TX_UNDERRUN,意思 是Transmit FIFO underrun 2、原因分析 如下图所示,SDMMC开始写操作时,首

    2023年04月24日
    浏览(47)
  • STM32对SD卡的读、写、擦除操作(SDIO模式)(DMA)

    对于STM32操作SD卡来说,最重要的就算 初始化 、 写操作 、 读操作 、 擦除 这几个操作了。 对于初始化部分上一篇文章已经分析,本篇就主要分析写、读、擦除操作。 本篇函数来自于 STM32提供的例程 。参考野火的程序进行了解释,与野火函数有些不同。 这几种函数完成之后

    2023年04月08日
    浏览(50)
  • STM32CubeMX系列09——SDIO(SD卡读写、SD卡移植FATFS文件系统)

    ==== 文章汇总(有代码汇总) ==== 准备看看这方面的知识,一时间还没不清有什么区别,先补补课,不需要的跳过。 参考文章(内容来源):http://www.360doc.com/content/21/1125/22/59057945_1005908465.shtml 主要写这两个:SD卡、TF卡 共同点:SD、TF、MMC都是在MMC基础上演化发展不同的规范,

    2024年02月09日
    浏览(49)
  • STM32CubeMX教程28 SDIO - 使用FatFs文件系统读写SD卡

    正点原子stm32f407探索者开发板V2.4 STM32CubeMX软件(Version 6.10.0) keil µVision5 IDE(MDK-Arm) ST-LINK/V2驱动 野火DAP仿真器 XCOM V2.6串口助手 使用STM32CubeMX软件配置STM32F407开发板 SDIO使用FatFs中间件读写4线SD卡,并实现以轮询方式读写SD卡或以DMA方式读取SD卡 FatFs文件系统相关知识请读者

    2024年02月19日
    浏览(50)
  • STM32F4X SDIO(七) 例程讲解-SD_InitializeCards & SD_GetCardInfo

    本节例程基于 野火电子的STM32F407的SD卡读写例程 进行讲解。上一节中讲解了SD卡上电过程,这节将会讲解一下SD卡的初始化过程,包括 获取SD卡的CID、CSD和SD卡RCA地址 。 CMD2的作用是 通知所有卡通过CMD线返回CID值 ,CID值包括 SD卡的识别号、制造商ID、OEMID、产品名称、版本号、

    2024年02月05日
    浏览(50)
  • stm32中的SDIO

    存储单元是存储数据部件,存储单元通过存储单元接口与卡控制单元进行数据传输; 电源检测单元保证SD卡工作在合适的电压下,如出现掉电或上状态时,它会使控制单元和存储单元接口复位; 卡及接口控制单元控制SD卡的运行状态,它包括有8个寄存器; 接口驱动器控制S

    2024年02月19日
    浏览(70)
  • STM32F4X SDIO(四) SDIO控制器

    STM32F4X内部有一个SDIO控制器,开发者可以使用这个控制器跟SD卡进行通信,下面就来简单了解一下STM32F4X的SDIO控制器的使用。 下图为STM32F4X的SDIO控制器框图,框图可以分为以下5部分, 适配器寄存器 、 FIFO 、 控制单元 、 命令路径 、 数据路径 。 SDIO控制器时钟 STM32F4X的所有

    2024年02月07日
    浏览(55)
  • STM32使用STM32CUBEMX配置FreeRTOS+SDIO4bit+FATFS注意事项

    以STM32F429为例: 1、SDIO配置 配置为4bit模式,此配置不是最终配置,后面会在代码进行修改。 2、Fatfs配置 Set Defines 选项中的配置可以默认,最重要注意Advanced Setting 选择中的配置,如下 该界面配置默认Use dma template是默认使能的 ,并且不可以选择,只能选择使能,所以需要使

    2024年02月11日
    浏览(60)
  • SDIO读写SD卡速度有多快?

    前两天测试了SPI方式读写SD卡的速度《SPI方式读写SD卡速度测试》,今天来测试一下SDIO方式的读写速度。 测试条件: 单片机:STM32F407VET6 编译环境:MDK 5.30+HAL库 SD卡:闪迪32GB/64GB TF卡 文件系统:FatFS R0.12c 之前测试中说过了,非DMA方式速度和资源利用率都不如DMA方式,所以今

    2024年02月02日
    浏览(45)
  • K_A12_014 基于STM32等单片机驱动S12SD紫外线传感器模块 串口与OLED0.96双显示

    注:PCF8591为8位ADC通过计算后分辨率会相对不是很理想 建议用10位及其以上ADC模块或者用STM32 具体计算公式可参考文档手册中CJMCU-S12D-test-arduino.txt文件 单片机型号 测试条件 模块名称 代码功能 STC89C52RC 晶振11.0592M S12SD紫外线传感器模块 STC89C52RC采集S12SD紫外线传感器模块参数

    2024年02月05日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包