欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

如何在STM32CUBEMX中利用HAL库操作SD卡进行读写

最编程 2024-02-21 21:02:01
...

SD 卡系统(包括主机和 SD 卡)定义了两种操作模式:

  • 卡识别模式
  • 数据传输模式

系统复位后,主机处于卡识别模式,寻找总线上可用的 SD卡设备;同时,SD 卡也处于卡 识别模式,直到被主机识别到。

使用STM32CubeMX初始化的工程中会自动生成 SDMMC 初始化函数,向 SD 卡发送命令,当 SD 卡接收到命令后, SD 卡就会进入数据传输模式,而主机在总线上所有卡被识别后也进入数据传输模式

所以在操作之前,需要先检查 SD 卡是否处于数据传输模式并且处于数据传输状态:

然后在while(1)之前编写如下读取信息代码:

/* USER CODE BEGIN 2 */
printf("Micro SD Card Test...\r\n");

/* 检测SD卡是否正常(处于数据传输模式的传输状态) */
sdcard_status = HAL_SD_GetCardState(&hsd1);
if(sdcard_status == HAL_SD_CARD_TRANSFER)
{
    printf("SD card init ok!\r\n\r\n");
}
else
{ 
    printf("SD card init fail!\r\n" );
    return 0;
}
/* USER CODE END 2 */



HAL_SD_ReadBlocks和HAL_SD_WriteBlocks后续SD卡状态判断改下就行了,while(HAL_SD_GetCardState(&hsd1) != HAL_SD_CARD_READY ),之前一直以为卡就绪是HAL_SD_CARD_READY ,问题就出在这里,改成HAL_SD_CARD_TRANSFER就可以了。


int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 6 */
 
      int8_t ret = -1;
      uint32_t timeout = 100000;
 
      HAL_SD_ReadBlocks(&hsd1, (uint32_t *)buf,  blk_addr, blk_len, 100000000);
      while(HAL_SD_GetCardState(&hsd1) != HAL_SD_CARD_TRANSFER )
      {
        if (timeout-- == 0)
        {
          return ret;
        }
      }
      ret = 0;
      return ret;
  /* USER CODE END 6 */
}
 
/**
  * @brief  .
  * @param  lun: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 7 */
      int8_t ret = -1;
      uint32_t timeout = 100000;
 
      HAL_SD_WriteBlocks(&hsd1, (uint32_t *)buf,  blk_addr, blk_len, 100000000);
      while(HAL_SD_GetCardState(&hsd1) != HAL_SD_CARD_TRANSFER )
      {
        if (timeout-- == 0)
        {
          return ret;
        }
      }
      ret = 0;
      return ret;
  /* USER CODE END 7 */
}

#define PRINT  printf


int SDMMC_PrintCardInfo(void)
{
	int ret = 0;
	SD_HandleTypeDef *phsd = &hsd;
	
	PRINT("CardVolume:\t%.2fGB\r\n", (float)(phsd->SdCard.BlockNbr >> 1) / 1024 / 1024);
	PRINT("BlockNbr:\t%u\r\n", phsd->SdCard.BlockNbr);
	PRINT("BlockSize:\t%u\r\n", phsd->SdCard.BlockSize);
	PRINT("CardType:\t%u\r\n", phsd->SdCard.CardType);
	
	PRINT("CardVersion:\t%u\r\n", phsd->SdCard.CardVersion);
	PRINT("Class:\t\t%u\r\n", phsd->SdCard.Class);
	PRINT("LogBlockNbr:\t%u\r\n", phsd->SdCard.LogBlockNbr);
	
	PRINT("LogBlockSize:\t%u\r\n", phsd->SdCard.LogBlockSize);
	PRINT("RelCardAdd:\t%u\r\n", phsd->SdCard.RelCardAdd);
	PRINT("\r\n");
	
	return ret;
}


void print_buf_hex(uint8_t buf[], uint16_t size, const char *title)
{
	if (!buf || !size) {
		return;
	}
	
	if (title) {
		PRINT("%s:\r\n", title);
	}
	
	for (uint16_t i = 0; i < size; ++i) {
		if (i && i % 16 == 0) {
			PRINT("\r\n");
		}
		PRINT("%02X ", buf[i]);
	}
	PRINT("\r\n");
}


#define SD_IO_BLK_OFFSET  (1000)  // 


int SD_IO_Erase(uint32_t blk_addr, uint32_t blk_num)
{
		return HAL_SD_Erase(&hsd, SD_IO_BLK_OFFSET + blk_addr, SD_IO_BLK_OFFSET + blk_addr + blk_num);
}

int SD_IO_SectRead(uint8_t buf[], uint32_t blk_addr, uint32_t blk_num)
{
		HAL_StatusTypeDef hal_ret;
	
		hal_ret = HAL_SD_ReadBlocks(&hsd, buf, SD_IO_BLK_OFFSET + blk_addr, blk_num, 5000);
		if (HAL_OK == hal_ret) {
			while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER ) {				
			}
			return 0;
		}
		
		return hal_ret;
}

int SD_IO_SectWrite(uint8_t buf[], uint32_t blk_addr, uint32_t blk_num)
{
		HAL_StatusTypeDef hal_ret;

		hal_ret = HAL_SD_WriteBlocks(&hsd, buf, SD_IO_BLK_OFFSET + blk_addr, blk_num, 5000);
		if (HAL_OK == hal_ret) {
			while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER ) {				
			}
			return 0;
		}
		
		return hal_ret;
}


#define WR_RD_BUFF_LEN   1024
static uint8_t m_wr_buf[WR_RD_BUFF_LEN];
static uint8_t m_rd_buf[WR_RD_BUFF_LEN];


int SDMMC_WriteReadTest(void)
{
	  int ret = 0;
	
		for (uint16_t i = 0; i < WR_RD_BUFF_LEN; ++i) {
			  m_wr_buf[i] = i + 1;
		}
		
		
		for (uint16_t sect = 0; sect < 10; sect += 2) {
			HAL_Delay(10);
			
			ret = SD_IO_SectWrite(m_wr_buf, sect, 2);
			if (0 != ret) {
				PRINT("SD_IO_SectWrite error %d, sect %u\r\n", ret, sect);
				return -1;
			}
		}
		PRINT("write OK\r\n");
		
		
		for (uint16_t sect = 0; sect < 10; sect += 2) {
			HAL_Delay(10);
			
			ret = SD_IO_SectRead(m_rd_buf, sect, 2);
			if (0 != ret) {
				PRINT("SD_IO_SectRead error %d, sect %u\r\n", ret, sect);
				return -2;
			}
			
			
			if (0 == memcmp(m_wr_buf, m_rd_buf, WR_RD_BUFF_LEN)) {
					PRINT("(0 == memcmp(m_wr_buf, m_rd_buf, sizeof m_rd_buf)), sect %u\r\n", sect);
			}
			else {
					PRINT("(0 != memcmp(m_wr_buf, m_rd_buf, sizeof m_rd_buf)), sect %u\r\n", sect);
					return -4;
			}
		}
		PRINT("read and compare OK\r\n");


	  PRINT("SDMMC_WriteReadTest passed \r\n\r\n");
	  return 0;
}

stm32L4 DMA  SDIO ,收发之前需要调用DMA配置函数

#include "sdmmc.h"


/* USER CODE END 0 */

SD_HandleTypeDef hsd1;
DMA_HandleTypeDef hdma_sdmmc1_rx;
DMA_HandleTypeDef hdma_sdmmc1_tx;

/* SDMMC1 init function */

void MX_SDMMC1_SD_Init(void)
{

  /* USER CODE BEGIN SDMMC1_Init 0 */
	HAL_StatusTypeDef hal_ret = HAL_OK;
  /* 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.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE;
  hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
  hsd1.Init.BusWide = SDMMC_BUS_WIDE_1B;
  hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_ENABLE;
  hsd1.Init.ClockDiv = 200;
  /* USER CODE BEGIN SDMMC1_Init 2 */

//  if (HAL_SD_Init(&hsd1) != HAL_OK)
//  {
//    Error_Handler();
//  }
//  if (HAL_SD_ConfigWideBusOperation(&hsd1, SDMMC_BUS_WIDE_4B) != HAL_OK)
//  {
//    Error_Handler();
//  }
	
//	if (SD_SECT_RESERVED_NUM < hsd1.SdCard.BlockNbr) {
//		SD_SetReservedSectOffset(hsd1.SdCard.BlockNbr - SD_SECT_RESERVED_NUM);
//		PRINT("hsd1.SdCard.BlockNbr %u\r\n", hsd1.SdCard.BlockNbr);
//		PRINT("SD_SECT_RESERVED_NUM %u\r\n", SD_SECT_RESERVED_NUM);
//		PRINT("SD_GetReservedSectOffset() res %u\r\n", SD_GetReservedSectOffset());
//	}
//	else {
//		PRINT("error, SD_SECT_RESERVED_NUM %u hsd1.SdCard.BlockNbr %u\r\n", SD_SECT_RESERVED_NUM, hsd1.SdCard.BlockNbr);
//	}
	
  /* USER CODE END SDMMC1_Init 2 */

}

void HAL_SD_MspInit(SD_HandleTypeDef* sdHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  if(sdHandle->Instance==SDMMC1)
  {
  /* USER CODE BEGIN SDMMC1_MspInit 0 */

  /* USER CODE END SDMMC1_MspInit 0 */
  /** Initializes the peripherals clock
  */
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SDMMC1;
    PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_HSI48;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
      Error_Handler();
    }

    /* SDMMC1 clock enable */
    __HAL_RCC_SDMMC1_CLK_ENABLE();

    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();
    /**SDMMC1 GPIO Configuration
    PC8     ------> SDMMC1_D0
    PC9     ------> SDMMC1_D1
    PC10     ------> SDMMC1_D2
    PC11     ------> SDMMC1_D3
    PC12     ------> SDMMC1_CK
    PD2     ------> SDMMC1_CMD
    */
    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
                          |GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    /* SDMMC1 DMA Init */
    /* SDMMC1_RX Init */
    hdma_sdmmc1_rx.Instance = DMA2_Channel4;
    hdma_sdmmc1_rx.Init.Request = DMA_REQUEST_7;
    hdma_sdmmc1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_sdmmc1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_sdmmc1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_sdmmc1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_sdmmc1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_sdmmc1_rx.Init.Mode = DMA_NORMAL;
    hdma_sdmmc1_rx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_sdmmc1_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(sdHandle,hdmarx,hdma_sdmmc1_rx);

    /* SDMMC1_TX Init */
    hdma_sdmmc1_tx.Instance = DMA2_Channel5;
    hdma_sdmmc1_tx.Init.Request = DMA_REQUEST_7;
    hdma_sdmmc1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_sdmmc1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_sdmmc1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_sdmmc1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_sdmmc1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_sdmmc1_tx.Init.Mode = DMA_NORMAL;
    hdma_sdmmc1_tx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_sdmmc1_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(sdHandle,hdmatx,hdma_sdmmc1_tx);

    /* SDMMC1 interrupt Init */
    HAL_NVIC_SetPriority(SDMMC1_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(SDMMC1_IRQn);
  /* USER CODE BEGIN SDMMC1_MspInit 1 */
		
		
		SD_DMAConfigRx(&hsd1);
		SD_DMAConfigTx(&hsd1);
		
		
  /* USER CODE END SDMMC1_MspInit 1 */
  }
}

void HAL_SD_MspDeInit(SD_HandleTypeDef* sdHandle)
{

  if(sdHandle->Instance==SDMMC1)
  {
  /* USER CODE BEGIN SDMMC1_MspDeInit 0 */

  /* USER CODE END SDMMC1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SDMMC1_CLK_DISABLE();

    /**SDMMC1 GPIO Configuration
    PC8     ------> SDMMC1_D0
    PC9     ------> SDMMC1_D1
    PC10     ------> SDMMC1_D2
    PC11     ------> SDMMC1_D3
    PC12     ------> SDMMC1_CK
    PD2     ------> SDMMC1_CMD
    */
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
                          |GPIO_PIN_12);

    HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2);

    /* SDMMC1 DMA DeInit */
    HAL_DMA_DeInit(sdHandle->hdmarx);
    HAL_DMA_DeInit(sdHandle->hdmatx);

    /* SDMMC1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(SDMMC1_IRQn);
  /* USER CODE BEGIN SDMMC1_MspDeInit 1 */

  /* USER CODE END SDMMC1_MspDeInit 1 */
  }
}

//----------------------------------------------------------

HAL_StatusTypeDef SD_DMAConfigRx(SD_HandleTypeDef *hsd)
{
  HAL_StatusTypeDef status = HAL_ERROR;
 
 
  /* Configure DMA Rx parameters */
  hdma_sdmmc1_rx.Instance = DMA2_Channel4;
  hdma_sdmmc1_rx.Init.Request = DMA_REQUEST_7;
  hdma_sdmmc1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
  hdma_sdmmc1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
  hdma_sdmmc1_rx.Init.MemInc = DMA_MINC_ENABLE;
  hdma_sdmmc1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  hdma_sdmmc1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
  hdma_sdmmc1_rx.Init.Mode = DMA_NORMAL;
  hdma_sdmmc1_rx.Init.Priority = DMA_PRIORITY_LOW;
 
 
  /* Associate the DMA handle */
  __HAL_LINKDMA(hsd,hdmarx,hdma_sdmmc1_rx);
 
 
  /* Stop any ongoing transfer and reset the state*/
  HAL_DMA_Abort(&hdma_sdmmc1_rx);
  /* Deinitialize the Channel for new transfer */
  HAL_DMA_DeInit(&hdma_sdmmc1_tx);
  /* Configure the DMA Channel */
  status = HAL_DMA_Init(&hdma_sdmmc1_rx);
 
 
  return (status);
}
 
 
/**
  * @brief Configure the DMA to transmit data to the SD card
  * @retval
  *  HAL_ERROR or HAL_OK
  */
HAL_StatusTypeDef SD_DMAConfigTx(SD_HandleTypeDef *hsd)
{
  HAL_StatusTypeDef status;
 
 
  /* SDMMC1_TX Init */
  hdma_sdmmc1_tx.Instance = DMA2_Channel5;
  hdma_sdmmc1_tx.Init.Request = DMA_REQUEST_7;
  hdma_sdmmc1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
  hdma_sdmmc1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
  hdma_sdmmc1_tx.Init.MemInc = DMA_MINC_ENABLE;
  hdma_sdmmc1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  hdma_sdmmc1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
  hdma_sdmmc1_tx.Init.Mode = DMA_NORMAL;
  hdma_sdmmc1_tx.Init.Priority = DMA_PRIORITY_LOW;
 
 
  /* Associate the DMA handle */
  __HAL_LINKDMA(hsd, hdmatx, hdma_sdmmc1_tx);
 
 
  /* Stop any ongoing transfer and reset the state*/
  HAL_DMA_Abort(&hdma_sdmmc1_tx);
  /* Deinitialize the Channel for new transfer */
  HAL_DMA_DeInit(&hdma_sdmmc1_rx);  
  /* Configure the DMA Channel */
  status = HAL_DMA_Init(&hdma_sdmmc1_tx); 
 
 
  return (status);
}