SD卡扇區擦除之整卡擦除(以及一些細節問題和疑惑)

前言

  1. 其實這個博文是強迫症的產物,對產物;如果要在一個SD卡上建立文件系統FATFS,我帶從這張卡的第0個字節,清除到最後一個字節,確保卡上“無殘留”,從而不會影響我後續的工作;當整張卡被清除的那一刻,開心!!!
  2. 文章中的例程包含標準容量卡SDSC的和高容量卡SDHC的例程;
  3. 以我16G的金士頓SD卡爲例;

流程

  • 首先你需要獲取SD卡上的CSD寄存器值,從而計算出當前卡的準確容量,可以看我下面這個博客:https://blog.csdn.net/wuyuzun/article/details/90581825
    這裏爲啥說當前卡的準確容量,來看下面這個圖片比較:
    計算機顯示我的內存卡的總容量如下
    在這裏插入圖片描述
    通過STM32的 SD_GetCardStatus() 函數獲取SD卡容量,計算過程看上面我那個博客就行。通過串口打印出來如下:
    在這裏插入圖片描述
    顯然:15707668480 != 15690891264;但是兩個差值= 16777216 = 16KB;難道這是主引導區MBR?這就是我異或得地方,這是怎麼回事?如果有知道的朋友,還麻煩給告訴一下,不勝感激;
    所以這裏我們以大的15707668480值爲此16GSD卡的字節內存空間;

  • 執行命令
    圖片來源於SD卡V2.0使用手冊在這裏插入圖片描述

  1. SDSC卡 (0~2G,包含2G)是以字節位單位擦除;
    ERASE_WR_BLK_START和ERASE_WR_BLK_END是以字節位單位的物理地址
    地址範圍:[ERASE_WR_BLK_START,ERASE_WR_BLK_END] == [0,0x001FFFFF]

  2. SDHC卡(2-32G,包括32G)以塊爲單位進行擦除(固定爲512字節);
    ERASE_WR_BLK_START和ERASE_WR_BLK_END是以字節位單位的塊物理地址
    地址範圍: ERASE_WR_BLK_START,ERASE_WR_BLK_END] == [0,0x01FF FFFF];(16G);
    4G: [0,0xFFFF FFFF]
    8G: [0,0x00FF FFFF‬]
    32G: [0,0x03FF FFFF]
    當然上面這都是理論值;實際值是以 15707668480字節爲基準的 [0,0x01D41FFF],這裏的這個實際也是本文討論的重點;

  • 相關代碼如下

代碼是移植於STM32的SD卡例程

/**
  * @brief  Allows to erase memory Block area specified for the given card.
  * @param  Block_startaddr: Sets the address of the first write block to be erased.
  * @param  Block_endaddr: Sets the address of the last write block of the continuous range to be erased.
  * @retval SD_Error: SD Card Error code.
  *注意:參數裏的起始地址和中止地址都是以塊地址爲單位;可以擦除整個16G空間;
		這裏有幾個值一定要特別注意:
		0x01D42000是我的16G的SD卡,以512字節位塊單位,狀態寄存器返回的內存空間大小,但是這個值並不能作爲擦除空間的endaddr;
		0x01D3E000是電腦顯示的16GSD卡的以512字節位塊單位的地址空間,可以作爲endaddr;
		0x0x01D41FFF纔是能作爲最終endaddr的值;
  */
SD_Error SD_Block_Erase(uint32_t Block_startaddr, uint32_t Block_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)   //0x00000020
  {
    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);
  }
	
  /*!< 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 = Block_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 = Block_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);

  while ((errorstatus == SD_OK) && ((SD_CARD_PROGRAMMING == cardstate) || (SD_CARD_RECEIVING == cardstate)))
  {
    errorstatus = IsCardProgramming(&cardstate);
  }

  return(errorstatus);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章