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模式(使用额外的针脚以及某些重新设置的针脚。支持四位宽的并行传输)。
三种模式的引脚定义如下:
三、SDIO 总线基础知识
认识一个外设,最好的方式就是看它官方资料的框图,方便我们快速的了解 SDIO 的基本功能,然后再看官方数据手册了解细节。
- 功能:访问SDIO,并且可以生成中断和DMA请求信号
- 与 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 之间变化
- 给APB2 Interface提供时钟
- SDIO外设时钟,最大值为50MHZ(我使用开发板是STM32F429BIT6,别的型号以官方数据为准!)
- SD/SDIO/MMC卡 双向/响应信号
- 默认情况下, SDIO_D0 用于数据传输,SDIO 时钟运行在 400KHz。初始化后可以设置到 SDIO 支 持的最高时钟,并且可以更改数据总线宽度。(不同型号数据可能不同,应以官方数据为准!)
四、实验步骤
- 读取SD卡基本信息
- 擦除SD卡块数据
- 将数据写入SD卡
- 将写入的数据读出
五、CubeMX配置
1.点击ACCESS TO MCU SELECTOR
2.在Part Number处搜索板子型号
3.在SYS的Debug处选择Serial Wire
4.HSE 是外部的高速振荡器,通过外接时钟源,有源或者无源晶振驱动,时钟范围 4-26MHz。优势是:精度高
5.配置串口本实验要将实验现象打印到串口
6.配置SDIO
7.时钟配置
8.
9.
六、实验代码
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 */
七、实验现象