基於stm32H730的解決方案開發之SD卡的讀寫調試

一 概述
在嵌入式小系統領域,SD卡存儲是一個非常重要的功能。可從難度上,它又是非常難的。因爲它涉及到兩個大的功能點,一個是文件系統,這個難度非一般。另外一個是sd卡的底層驅動。涉及到的接口多,所以也是一個難度高的地方。兩個混合在一起,非常容易出問題。筆者在這塊花費了很多時間。也遇到了很多問題。這裏需要做一個總結了。
二 源碼解析
通過使用Cube來生成的sd卡讀寫源碼,大概率是不成功的,這就要逐步的定位了,到底是哪兒出了問題呢?
面對紛繁複雜的局勢,第一步就是要學會拆解,逐步擊破。接下來,就讓我們來逐步的分析一下。
步驟一,首先排查硬件十分ok?
這個很簡單,寫一個GPIO拉高拉低的源碼,來逐個驗證一下這些IO口是否都是通的。代碼如下所示:
 
  while (1)
  {
    /* code */
    check_state_on();
    HAL_Delay(1000);
    check_state_off();
    HAL_Delay(1000);
    mprintf("check pc12a loopback cnt is:%d \n\r",g_leds_cnt++);

  }

 

通過萬用表來測量這些IO,假如是不通的,那就要檢查一下IO硬件了。
步驟二,接下來,就要拋開文件系統,來查看一下sd卡是否能識別了。
這部分源碼比較複雜,需要自己整理的,這裏給出筆者整理出來的源碼。
#define SD_TIMEOUT             ((uint32_t)0x00100000U) //等待時間
#define BLOCK_SIZE            512  //塊的數目
#define NUMBER_OF_BLOCKS      50 //塊的數據大小
#define MULTI_BUFFER_SIZE    (BLOCK_SIZE * NUMBER_OF_BLOCKS)


/**
  * @brief  數組匹配檢測函數
  * @param  pBuffer1:發送數組;pBuffer2:接受數組;BufferLength:數組長度
  * @retval HAL_OK:匹配;HAL_ERROR:不匹配
  */
static HAL_StatusTypeDef Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint32_t BufferLength)
{
    while (BufferLength--)
    {
      if (*pBuffer1 != *pBuffer2)
      {      
        return HAL_ERROR;      
      }
      else{

        pBuffer1++;
        pBuffer2++;
      }
    }
    return HAL_OK;
} 


uint8_t Buffer_Block_Tx[512]={0};//寫入數組
uint8_t Buffer_Block_Rx[512];//讀取數組
uint8_t SD_save_ok=0;

uint32_t sd_status_one = 0;
uint32_t time_sd_1=0;
uint32_t time_sd_2=0;
uint16_t sd_test_ii=0;

void SD_SingleBlockTest_easy(void)
{
        
    for(sd_test_ii=0;sd_test_ii<512;sd_test_ii++)
    {    //對寫入數組進行賦值
       Buffer_Block_Tx[sd_test_ii]=sd_test_ii%216;
    }
    
    sd_status_one =HAL_SD_WriteBlocks(&hsd1,(uint8_t *)Buffer_Block_Tx,0,1,0xfff);       //將寫入數組寫入SD卡中,0表示寫入地址爲0,1表示爲寫入1個扇區的數據

    if(sd_status_one == HAL_OK)
    {
        mprintf("write success \r\n");
    }
    else
    {
        mprintf("write failed status is:%d \r\n",sd_status_one);
    }
        
    for(sd_test_ii=0;sd_test_ii<512;sd_test_ii++)
    {   //對讀取數組賦值
        Buffer_Block_Rx[sd_test_ii]=0;
    }
        
     sd_status_one =HAL_SD_ReadBlocks(&hsd1,(uint8_t *)Buffer_Block_Rx,0,1,0xfff);;   //讀取SD卡數據,將數據存在讀取數組中
        
     sd_status_one=Buffercmp(Buffer_Block_Tx,Buffer_Block_Rx,512); //寫入數組和讀取數組進行對比
            
     if(sd_status_one == HAL_OK)
     {
          mprintf("SD test ok!!\r\n");
     }
     else
     {
          mprintf("SD_test fail!\r\n " );
     }
}


/**
  * @brief  SD卡等待擦除完成函數
  * @param  無
  * @retval HAL_OK:擦除成功;HAL_ERROR:擦除失敗
  */
static HAL_StatusTypeDef Wait_SDCARD_Ready(void)
{
    uint32_t loop = SD_TIMEOUT;
    
    while(loop > 0)
    {
      loop--;
      if(HAL_SD_GetCardState(&hsd1) == HAL_SD_CARD_TRANSFER)
      {
          return HAL_OK;
      }
    }
    return HAL_ERROR;
}


/* USER CODE BEGIN 1 */
/**
  * @brief  SD卡擦除測試
  * @param  無
  * @retval 無
  */
static void SD_EraseTest(void)
{
    HAL_StatusTypeDef Status = HAL_OK;
    HAL_StatusTypeDef EraseStatus = HAL_OK;
    if (Status == HAL_OK)
    {
        Status = HAL_SD_Erase(&hsd1, 0x00, (BLOCK_SIZE * NUMBER_OF_BLOCKS));// SD卡外設句柄、擦除的起始地址、擦除的結束地址
        //等待擦除完成
        if(Wait_SDCARD_Ready() != HAL_OK)
        {
            EraseStatus = HAL_ERROR;
        }
    }     
    if(EraseStatus == HAL_OK)
    {    
      mprintf("SD card efuse success \r\n");
    }
    else
    {
      mprintf("SD card efuse failed \n");
    }    
}


/**
  * @brief SDMMC1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_SDMMC1_SD_Init(void)
{

  /* USER CODE BEGIN SDMMC1_Init 0 */

  /* USER CODE END SDMMC1_Init 0 */

  /* USER CODE BEGIN SDMMC1_Init 1 */

  /* USER CODE END SDMMC1_Init 1 */
  hsd1.Instance = SDMMC1;
  hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
  hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
  hsd1.Init.BusWide = SDMMC_BUS_WIDE_4B;
  hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
  hsd1.Init.ClockDiv = 4;
  /* USER CODE BEGIN SDMMC1_Init 2 */

  if (HAL_SD_Init(&hsd1) != HAL_OK)
  {
    Error_Handler();
  }


  if(HAL_SD_GetCardState(&hsd1) == HAL_SD_CARD_TRANSFER)
  {
     mprintf("SD card init ok!\r\n\r\n");
            
     SD_EraseTest();  //SD卡擦除測試

     SD_SingleBlockTest_easy();//SD卡讀寫測試

  }
  else
  { 
      mprintf("SD card init fail!\r\n" );
  }

  /* USER CODE END SDMMC1_Init 2 */

}

 

這部分是來檢查sd卡能否讀寫的,繞過文件系統的。
通過測試,筆者發現是可以正常讀寫的,如下所示:
 
步驟三,接下來就要劍指文件系統了。肯定是這哪兒出了問題,具體怎麼定位呢?由於文件系統比較複雜,接下來一章節繼續分析吧。
三 總結
做bug定位,能做到化繁爲簡,這就成功了一半了。接下來,就是對知識點的掌握和對問題的深究能力了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章