如何在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);
}