> 文档中心 > HAL库-SD卡学习

HAL库-SD卡学习


前言

每天进步一点点!

一、SD卡是什么?

SD存储卡是一种基于半导体快闪记忆器的新一代记忆设备,由于它体积小数据传输速度快可热插拔等优良的特性,被广泛地于便携式装置上使用,例如数码相机、平板电脑和多媒体播放器等。

SD卡的结构能保证数字文件传送的安全性,也很容易重新格式化,所以有着广泛的应用领域。音乐、电影等多媒体文件都可以方便地保存到SD卡中。目前市场上SD卡的品牌很多诸如:SANDISK、Kingmax、Panasonic和Kingston。

特点
高存储容量,最常用的容量:8GB、16GB、32GB、128GB、256GB等。
内置加密技术,适应基于SDMI协议的著作版权保护功能。
高速数据传送;最大读写速率为100MB/s。
●体积轻小,便于携带,具有很强的抗冲击能力。

二、SD卡模式

SD卡有两种驱动模式:

SPI模式SDIO模式。它们所使用的接口信号是不同的。在SPI模式下,只会用到SD卡的4根信号线,即CS、DI、SCLK与DO(分别是SD卡的片选、数据输入、时钟与数据输出)。
(本实验使用SDIO模式,接下来会讲到)

传输模式
SD卡共支持三种传输模式:SPI模式(独立序列输入和序列输出),1位SD模式(独立指令和数据通道,独有的传输格式),4位SD模式(使用额外的针脚以及某些重新设置的针脚。支持四位宽的并行传输)。

三种模式的引脚定义如下:
HAL库-SD卡学习

三、SDIO 总线基础知识

认识一个外设,最好的方式就是看它官方资料的框图,方便我们快速的了解 SDIO 的基本功能,然后再看官方数据手册了解细节。
HAL库-SD卡学习

  1. 功能:访问SDIO,并且可以生成中断和DMA请求信号
  2. 与 SD/SDIO/MMC 卡相连的时钟。对于 MMC V3.31,时钟频率可以在 0 MHz 到 20 MHz 之间变化,对于 MMC V4.0/4.2,可以在 0 到 48 MHz 之间变化,对于 SD/SD I/O 卡,可以在 0 到25 MHz 之间变化
  3. 给APB2 Interface提供时钟
  4. SDIO外设时钟,最大值为50MHZ(我使用开发板是STM32F429BIT6,别的型号以官方数据为准!)
  5. SD/SDIO/MMC卡 双向/响应信号
  6. 默认情况下 SDIO_D0 用于数据传输,SDIO 时钟运行在 400KHz。初始化后可以设置到 SDIO 支 持的最高时钟,并且可以更改数据总线宽度。(不同型号数据可能不同,应以官方数据为准!)

四、实验步骤

  1. 读取SD卡基本信息
  2. 擦除SD卡块数据
  3. 将数据写入SD卡
  4. 将写入的数据读出

五、CubeMX配置

1.点击ACCESS TO MCU SELECTOR
HAL库-SD卡学习
2.在Part Number处搜索板子型号HAL库-SD卡学习
3.在SYSDebug处选择Serial Wire
HAL库-SD卡学习
4.HSE外部的高速振荡器,通过外接时钟源,有源或者无源晶振驱动,时钟范围 4-26MHz。优势是:精度高
HAL库-SD卡学习
5.配置串口本实验要将实验现象打印到串口
HAL库-SD卡学习
6.配置SDIO
HAL库-SD卡学习
7.时钟配置
HAL库-SD卡学习
8.
HAL库-SD卡学习
9.
HAL库-SD卡学习

六、实验代码

1.My_SD.h文件代码
#ifndef _MY_SD_H_#define _MY_SD_H_#include "main.h"#include "sdio.h"#include "My_uart.h"#include "string.h" /*  */#define BLOCK_START_ADDR      0 /*  */#define NUM_OF_BLOCKS  1void SD_Basic_Information(void);void SD_Erase_Data(void);void SD_Write_Data(uint8_t *Buffer_Tx);void SD_Read_Data(uint8_t *Buffer_Rx);#endif
2.My_SD.c文件代码

步骤一、打印SD卡基本信息函数

/** * @brief 打印SD卡基本信息 * @param 无 * @param 无 * @retval 无*/void SD_Basic_Information(void){  /*  */   SD_Card_State = HAL_SD_GetCardState(&hsd);    if(SD_Card_State == HAL_SD_CARD_TRANSFER) //HAL_SD_GetCardState(&hsd)获取SD卡状态(如果处于传输状态)  {    printf("SD卡信息\r\n"); printf("SD卡容量:%llu\r\n", (unsigned long long)hsd.SdCard.BlockSize * hsd.SdCard.BlockNbr);    printf("SD卡块的大xiao (单位:字节):%d\r\n", hsd.SdCard.BlockSize);    printf("SD卡逻辑块的数量(单位:块): %d\r\n",  hsd.SdCard.LogBlockNbr);    printf("SD卡逻辑块的大小(单位:字节): %d\r\n", hsd.SdCard.LogBlockSize);    printf("SD卡相对地址: %d\r\n", hsd.SdCard.RelCardAdd);    printf("SD卡的类型:%d\r\n", hsd.SdCard.CardType);   /*  */    HAL_SD_CardCIDTypeDef SD_Card_CID; HAL_SD_GetCardCID(&hsd, &SD_Card_CID);     /*  */    printf("制造商ID: %d\r\n",SD_Card_CID.ManufacturerID);      }  else  {    printf("SD卡初始化失败!");  }}

步骤二、擦除SD块数据函数

/** * @brief 擦除SD卡块数据 * @param 无 * @param 无 * @retval 无*/void SD_Erase_Data(void){  //擦除SD块 操作SD卡后最好先用函数HAL_SD_GetCardState()确定一下卡的状态再进行其他操作。  SD_Card_State = HAL_SD_Erase(&hsd, BLOCK_START_ADDR, NUM_OF_BLOCKS);  if(SD_Card_State == HAL_OK)  {    /*  */    while(HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER);     printf("删除块成功!\r\n");  }  else  {    printf("删除块失败!\r\n");  }}

步骤三、向SD卡写入数据函数

/** * @brief 向SD卡写入数据 * @param 写入的数据的缓冲区的指针 * @param 无 * @retval    无*/void SD_Write_Data(uint8_t *Buffer_Tx){  uint8_t i;      //向SD卡块写入数据  printf("写SD卡块数据测试\r\n"); /*  */  SD_Card_State = HAL_SD_WriteBlocks(&hsd, Buffer_Tx, BLOCK_START_ADDR, NUM_OF_BLOCKS, 10);  if(SD_Card_State == HAL_OK)  {    /*  */    while(HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER);    printf("写入SD卡块成功!\r\n");  }  else  {    printf("写入SD卡块失败!\r\n");  }}

步骤四、读取SD卡数据函数

/** * @brief 读取SD卡块数据 * @param 接收数据的缓冲区的指针 * @param 无 * @retval    无*/void SD_Read_Data(uint8_t *Buffer_Rx){  uint8_t i;    printf("写入后读取SD卡块数据\r\n");  if(HAL_SD_ReadBlocks(&hsd, Buffer_Rx, BLOCK_START_ADDR, NUM_OF_BLOCKS, 10) == HAL_OK)  {    while(HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER); printf("读取SD卡块数据成功!\r\n");      }  else  {    printf("读取SD卡块数据失败!\r\n");  }}
3.main.c文件代码
/* USER CODE BEGIN Header *//**  ******************************************************************************  * @file    : main.c  * @brief   : Main program body  ******************************************************************************  * @attention  *  * Copyright (c) 2022 STMicroelectronics.  * All rights reserved.  *  * This software is licensed under terms that can be found in the LICENSE file  * in the root directory of this software component.  * If no LICENSE file comes with this software, it is provided AS-IS.  *  ******************************************************************************  *//* USER CODE END Header *//* Includes ------------------------------------------------------------------*/#include "main.h"#include "dma.h"#include "sdio.h"#include "usart.h"#include "gpio.h"/* Private includes ----------------------------------------------------------*//* USER CODE BEGIN Includes *///用户头文件 开始#include "My_uart.h"#include "string.h"#include "My_SD.h"//用户头文件 结束/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*//* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*//* USER CODE BEGIN PD *///用户宏定义   开始//#define BLOCK_START_ADDR      0//#define NUM_OF_BLOCKS  1//用户宏定义   结束/* USER CODE END PD *//* Private macro -------------------------------------------------------------*//* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *///用户变量    开始uint8_t Buffer_Tx[512];uint8_t Buffer_Rx[512] = {0};int i;//用户变量    结束/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/void SystemClock_Config(void);/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*//* USER CODE BEGIN 0 *//* USER CODE END 0 *//**  * @brief  The application entry point.  * @retval int  */int main(void){  /* USER CODE BEGIN 1 */  /* USER CODE END 1 */  /* MCU Configuration--------------------------------------------------------*/  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */  HAL_Init();  /* USER CODE BEGIN Init */  /* USER CODE END Init */  /* Configure the system clock */  SystemClock_Config();  /* USER CODE BEGIN SysInit */  /* USER CODE END SysInit */  /* Initialize all configured peripherals */  MX_GPIO_Init();  MX_DMA_Init();  MX_SDIO_SD_Init();  MX_USART1_UART_Init();  /* USER CODE BEGIN 2 */    /*  */  memset(Buffer_Tx, 0x10, sizeof(Buffer_Tx));   /*  */    SD_Basic_Information();/*  */  /*  */  SD_Erase_Data();  /*  */     /*  */     SD_Write_Data(Buffer_Tx);    for(i = 0; i < sizeof(Buffer_Tx); i++)  {    printf("0x%02x:%02x   ", i, Buffer_Tx[i]);  }  printf("\r\n");/*  */    /*  */  SD_Read_Data(Buffer_Rx);    for(i = 0; i<sizeof(Buffer_Rx); i++)  {    printf("0x%02x:%02x   ", i, Buffer_Rx[i]);  }  /*  */      /* USER CODE END 2 */  /* Infinite loop */  /* USER CODE BEGIN WHILE */  while (1)  {    /* USER CODE END WHILE */    /* USER CODE BEGIN 3 */  }  /* USER CODE END 3 */}/**  * @brief System Clock Configuration  * @retval None  */void SystemClock_Config(void){  RCC_OscInitTypeDef RCC_OscInitStruct = {0};  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};  /** Configure the main internal regulator output voltage  */  __HAL_RCC_PWR_CLK_ENABLE();  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);  /** Initializes the RCC Oscillators according to the specified parameters  * in the RCC_OscInitTypeDef structure.  */  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;  RCC_OscInitStruct.HSIState = RCC_HSI_ON;  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;  RCC_OscInitStruct.PLL.PLLM = 8;  RCC_OscInitStruct.PLL.PLLN = 180;  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;  RCC_OscInitStruct.PLL.PLLQ = 8;  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)  {    Error_Handler();  }  /** Activate the Over-Drive mode  */  if (HAL_PWREx_EnableOverDrive() != HAL_OK)  {    Error_Handler();  }  /** Initializes the CPU, AHB and APB buses clocks  */  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK  |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)  {    Error_Handler();  }}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//**  * @brief  This function is executed in case of error occurrence.  * @retval None  */void Error_Handler(void){  /* USER CODE BEGIN Error_Handler_Debug */  /* User can add his own implementation to report the HAL error return state */  __disable_irq();  while (1)  {  }  /* USER CODE END Error_Handler_Debug */}#ifdef  USE_FULL_ASSERT/**  * @brief  Reports the name of the source file and the source line number  *  where the assert_param error has occurred.  * @param  file: pointer to the source file name  * @param  line: assert_param error line source number  * @retval None  */void assert_failed(uint8_t *file, uint32_t line){  /* USER CODE BEGIN 6 */  /* User can add his own implementation to report the file name and line number,     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */  /* USER CODE END 6 */}#endif /* USE_FULL_ASSERT */

七、实验现象

HAL库-SD卡学习
HAL库-SD卡学习