STM32的SDIO(Secure Digital Input Output)
接口是一种用于SD卡和MMC卡的高速数据传输接口。它允许STM32微控制器与多种存储卡和外设进行通信,支持多媒体卡(MMC卡)、SD存储卡、SDI/O卡和CE-ATA设备。STM32的SDIO控制器与多媒体卡系统规格书版本4.2完全兼容,支持三种不同的数据总线模式:1位(默认)、4位和8位。
-
接口简介:STM32的SDIO接口基于SD卡接口发展而来,兼容之前的SD卡,并可连接SDIO接口设备,如蓝牙、WiFi、照相机等。STM32的SDIO控制器支持多媒体卡(MMC卡)、SD存储卡、SDI/O卡和CE-ATA设备。
-
特点:STM32的SDIO控制器与多媒体卡系统规格书版本4.2完全兼容,支持三种不同的数据总线模式:1位(默认)、4位和8位。它还与较早的多媒体卡系统规格版本全兼容,与SD存储卡规格版本2.0全兼容,并完全支持CE-ATA功能。
-
时钟配置:SDIO接口需要配置卡时钟(SDIO_CK)和SDIO适配器时钟(SDIOCLK)。SDIO_CK用于命令和数据线传输,而SDIOCLK用于驱动SDIO适配器。
-
命令与响应:SDIO的命令分为应用相关命令(ACMD)和通用命令(CMD)。所有命令和响应都在SDIO_CMD引脚上传输。响应分为短响应(48位)和长响应(136位)。
-
块数据传输:SDIO与SD卡通信通常以数据块的形式进行传输。多数据块读操作和写操作都带CRC校验,且需要在SD卡非繁忙时进行数据块写操作。
SDIO框图
STM32CudeMX
1配置时钟
2打开SDIO并选择存储类型和数据引脚的个数(我的是sd卡,4引脚)
SDIO的配置我的
在 Parameter Settings
进行具体参数配置。
Clock transition on which the bit capture is made: Rising transition
。主时钟 SDIOCLK 产生 CLK 引脚时钟有效沿选择,可选上升沿或下降沿,它设定 SDIO 时钟控制寄存器(SDIO_CLKCR)的 NEGEDGE 位的值,一般选择设置为上升沿
。
SDIO Clock divider bypass: Disable
。时钟分频旁路使用,可选使能或禁用,它设定 SDIO_CLKCR 寄存器的 BYPASS 位。如果使能旁路,SDIOCLK 直接驱动 CLK 线输出时钟;如果禁用,使用 SDIO_CLKCR 寄存器的 CLKDIV 位值分频 SDIOCLK,然后输出到 CLK 线。一般选择禁用时钟分频旁路
。
SDIO Clock output enable when the bus is idle: Disable the power save for the clock
。节能模式选择,可选使能或禁用,它设定 SDIO_CLKCR 寄存器的 PWRSAV 位的值。如果使能节能模式,CLK 线只有在总线激活时才有时钟输出;如果禁用节能模式,始终使能 CLK 线输出时钟。
SDIO hardware flow control: The hardware control flow is disabled
。硬件流控制选择,可选使能或禁用,它设定 SDIO_CLKCR 寄存器的 HWFC_EN 位的值。硬件流控制功能可以避免 FIFO 发送上溢和下溢错误。
SDIOCLK clock divide factor: 6
。时钟分频系数,它设定 SDIO_CLKCR 寄存器的 CLKDIV 位的值,设置 SDIOCLK 与 CLK 线输出时钟分频系数:CLK 线时钟频率=SDIOCLK/([CLKDIV+2])。
SDIO_CK 引脚的时钟信号在卡识别模式时要求不超过 400KHz,而在识别后的数据传输模式时则希望有更高的速度(最大不超过 25MHz),所以会针对这两种模式配置 SDIOCLK 的时钟。
这里参数描述建议将SDIOCLK clock divede factor 参数使用默认值为0,SDIOCLK为72MHz,可以得到最大频率36MHz,但请注意,有些型号的SD卡可能不支持36MHz这么高的频率,所以还是要以实际情况而定。
CLK 线时钟频率 = SDIOCLK / (CLKDIV + 2)
SDIOCLK
是 SDIO 总线的时钟源频率
CLKDIV
是时钟分频器的值
CLK 线时钟频率:SDIO输出的频率
可以生成代码了
代码编写
注意
在使用HAL库时,初始化时如果SD没有检测到会进入Error_Handler()
将会进入死循环
HAL_StatusTypeDef HAL_SD_ConfigWideBusOperation删除(我的卡不支持宽模式,不删除会影响程序)
Error_Handler() 函数通常是在嵌入式系统中的硬件抽象层(HAL)中定义的一个占位符函数,用于在发生错误时提供一个统一的处理点。默认情况下,这个函数可能是空的,也可能包含一些基本的错误处理代码,例如禁用中断、记录错误信息、进入一个死循环或者复位系统。
要将MX_SDIO_SD_Init();中的上面函数注释掉
void MX_SDIO_SD_Init(void)
{
/* USER CODE BEGIN SDIO_Init 0 */
/* USER CODE END SDIO_Init 0 */
/* USER CODE BEGIN SDIO_Init 1 */
/* USER CODE END SDIO_Init 1 */
hsd.Instance = SDIO;
hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_ENABLE;
hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
hsd.Init.BusWide = SDIO_BUS_WIDE_4B;
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_ENABLE;
hsd.Init.ClockDiv = 6;
if (HAL_SD_Init(&hsd) != HAL_OK)
{
//Error_Handler();
}
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
{
// Error_Handler();
}
/* USER CODE BEGIN SDIO_Init 2 */
/* USER CODE END SDIO_Init 2 */
}
用HAL_SD_Init(&hsd)函数看返回是否位HAL_OK 可以判断是否有SD卡,顺便重新初始化了
HAL_SD_Init(&hsd)
和 MX_SDIO_SD_Init()作用是一样的。
有哪些函数
- HAL_SD_Init - 初始化 SDIO 接口和 SD 卡。
- HAL_SD_ConfigWideBusOperation - 配置 SD 卡以使用宽总线模式(4位数据线)。
- HAL_SD_DeInit - 去初始化 SDIO 接口。
- HAL_SD_GetCardInfo - 获取 SD 卡的信息,如卡类型、容量等。
- HAL_SD_GetCardState - 获取 SD 卡的当前状态。
- HAL_SD_GetStatus - 获取 SD 卡的状态信息。
- HAL_SD_ReadBlocks - 从 SD 卡读取一个或多个块数据。(DMA 中断)
- HAL_SD_WriteBlocks - 向 SD 卡写入一个或多个块数据。
- HAL_SD_Get_OCR - 获取 SD 卡的操作条件寄存器(OCR)内容。
- HAL_SD_GetCID - 获取 SD 卡的卡识别(CID)信息。
- HAL_SD_GetCSD - 获取 SD 卡的卡特定数据(CSD)信息。
- HAL_SD_Abort - 中止当前的传输操作。
- HAL_SD_AbortIT - 中止当前的传输操作并产生中断。
- HAL_SD_IRQHandler - SDIO中断处理函数。
- HAL_SD_RxCpltCallback - 接收完成回调函数。
- HAL_SD_TxCpltCallback - 传输完成回调函数。
- HAL_SD_ErrorCallback - 错误回调函数。
检测是否有SD卡(实例1)
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file sdio.c
* @brief This file provides code for the configuration
* of the SDIO instances.
******************************************************************************
* @attention
*
* Copyright (c) 2024 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 "sdio.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
SD_HandleTypeDef hsd;
DMA_HandleTypeDef hdma_sdio;
/* SDIO init function */
void MX_SDIO_SD_Init(void)
{
/* USER CODE BEGIN SDIO_Init 0 */
/* USER CODE END SDIO_Init 0 */
/* USER CODE BEGIN SDIO_Init 1 */
/* USER CODE END SDIO_Init 1 */
hsd.Instance = SDIO;
hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_ENABLE;
hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
hsd.Init.BusWide = SDIO_BUS_WIDE_4B;
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_ENABLE;
hsd.Init.ClockDiv = 6;
if (HAL_SD_Init(&hsd) != HAL_OK)
{
//Error_Handler();
}
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
{
//Error_Handler();
}
/* USER CODE BEGIN SDIO_Init 2 */
/* USER CODE END SDIO_Init 2 */
}
void HAL_SD_MspInit(SD_HandleTypeDef* sdHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(sdHandle->Instance==SDIO)
{
/* USER CODE BEGIN SDIO_MspInit 0 */
/* USER CODE END SDIO_MspInit 0 */
/* SDIO clock enable */
__HAL_RCC_SDIO_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/**SDIO GPIO Configuration
PC8 ------> SDIO_D0
PC9 ------> SDIO_D1
PC10 ------> SDIO_D2
PC11 ------> SDIO_D3
PC12 ------> SDIO_CK
PD2 ------> SDIO_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.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* SDIO DMA Init */
/* SDIO Init */
hdma_sdio.Instance = DMA2_Channel4;
hdma_sdio.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_sdio.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_sdio.Init.MemInc = DMA_MINC_ENABLE;
hdma_sdio.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_sdio.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_sdio.Init.Mode = DMA_NORMAL;
hdma_sdio.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_sdio) != HAL_OK)
{
Error_Handler();
}
/* Several peripheral DMA handle pointers point to the same DMA handle.
Be aware that there is only one channel to perform all the requested DMAs. */
/* Be sure to change transfer direction before calling
HAL_SD_ReadBlocks_DMA or HAL_SD_WriteBlocks_DMA. */
__HAL_LINKDMA(sdHandle,hdmarx,hdma_sdio);
__HAL_LINKDMA(sdHandle,hdmatx,hdma_sdio);
/* SDIO interrupt Init */
HAL_NVIC_SetPriority(SDIO_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SDIO_IRQn);
/* USER CODE BEGIN SDIO_MspInit 1 */
/* USER CODE END SDIO_MspInit 1 */
}
}
void HAL_SD_MspDeInit(SD_HandleTypeDef* sdHandle)
{
if(sdHandle->Instance==SDIO)
{
/* USER CODE BEGIN SDIO_MspDeInit 0 */
/* USER CODE END SDIO_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_SDIO_CLK_DISABLE();
/**SDIO GPIO Configuration
PC8 ------> SDIO_D0
PC9 ------> SDIO_D1
PC10 ------> SDIO_D2
PC11 ------> SDIO_D3
PC12 ------> SDIO_CK
PD2 ------> SDIO_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);
/* SDIO DMA DeInit */
HAL_DMA_DeInit(sdHandle->hdmarx);
HAL_DMA_DeInit(sdHandle->hdmatx);
/* SDIO interrupt Deinit */
HAL_NVIC_DisableIRQ(SDIO_IRQn);
/* USER CODE BEGIN SDIO_MspDeInit 1 */
/* USER CODE END SDIO_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
main.h文件
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2024 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 "stdio.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* 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 */
char data_UART1[]={"SD卡已插入"};
char data_UART2[]={"SD卡未插入,请插入SD卡"};
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(HAL_SD_Init(&hsd)==HAL_OK){//判断是否插入SD卡
HAL_UART_Transmit(&huart1,(uint8_t*)data_UART1,11,50);
}else{
HAL_UART_Transmit(&huart1,(uint8_t*)data_UART2,22,50);
}
HAL_Delay(1000);
/* 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};
/** 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_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != 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_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != 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 */
返回SD卡信息(实例2)
HAL_SD_CardInfoTypeDef sd_typeDef;//结构体内的意思
-
sd_typeDef.BlockNbr
: 这个变量表示SD卡上的总块数。块是SD卡存储数据的基本单位,通常大小为512字节。 -
sd_typeDef.BlockSize
: 这个变量表示SD卡上每个数据块的大小,以字节为单位。对于标准SD卡,块大小通常是512字节。 -
sd_typeDef.CardType
: 这个变量表示SD卡的类型,例如标准SD卡、SDHC(高容量SD卡)或SDXC(扩展容量SD卡)。SD卡:标准SD卡 0 SDHC卡:高容量SD卡 1 SDXC卡:扩展容量SD卡 2
-
sd_typeDef.CardVersion
: 这个变量表示SD卡的版本信息。 -
sd_typeDef.Class
: 这个变量表示SD卡的类别,反映了卡的性能等级,例如_class_2, _class_4, class_6 或 class_10,这些等级定义了卡的最低写入速度。 -
sd_typeDef.LogBlockNbr
: 这个变量表示用于日志的块数。在某些情况下,SD卡可能会使用逻辑块地址,这个变量就是用来存储逻辑块的数量。 -
sd_typeDef.LogBlockSize
: 这个变量表示用于日志的块大小。与BlockSize
类似,但它可能用于特定的日志记录或文件系统结构。 -
sd_typeDef.RelCardAdd
: 这个变量表示SD卡的相对卡地址。在某些SD卡操作中,使用相对地址而不是绝对地址。
main.h文件
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2024 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 "stdio.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* 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 */
char data_UART1[]={"SD卡已插入"};
char data_UART2[]={"SD卡未插入,请插入SD卡"};
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_Delay(1000);
if(HAL_SD_Init(&hsd)==HAL_OK){//判断是否插入SD卡
//MX_SDIO_SD_Init();
HAL_UART_Transmit(&huart1,(uint8_t*)data_UART1,11,50);
char SD_Data [35];
HAL_SD_CardInfoTypeDef sd_typeDef;
if(HAL_SD_GetCardInfo(&hsd,&sd_typeDef)==HAL_OK){//获取SD卡信息
sprintf(SD_Data,"卡的类型:%lu 快的数量 :%lu",sd_typeDef.CardType,sd_typeDef.BlockNbr);
HAL_UART_Transmit(&huart1 ,(uint8_t*)SD_Data,30,50);
}
}else{
HAL_UART_Transmit(&huart1,(uint8_t*)data_UART2,22,50);
}
//HAL_Delay(1000);
/* 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};
/** 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_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != 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_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != 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 */
实现读写
开关在关闭(向下)位置时,SD卡可以读写;在打开(向上)位置时,SD卡处于写保护状态。
注意写入时也要时间
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2024 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 "stdio.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* 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 */
char data_UART1[]={"SD卡已插入"};
char data_UART2[]={"SD卡未插入,请插入SD卡"};
uint8_t buffer_1[512];
uint8_t buffer_2[512];
//数组赋值
for(int i=0;i<512;i++){
buffer_1[i]='l';
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_Delay(1000);
if(HAL_SD_Init(&hsd)==HAL_OK){//判断是否插入SD卡
HAL_UART_Transmit(&huart1,(uint8_t*)data_UART1,11,50);
char SD_Data [35];
HAL_SD_CardInfoTypeDef sd_typeDef;
if(HAL_SD_GetCardInfo(&hsd,&sd_typeDef)==HAL_OK){//获取SD卡信息
sprintf(SD_Data,"卡的类型:%lu 快的数量 :%lu",sd_typeDef.CardType,sd_typeDef.BlockNbr);
HAL_UART_Transmit(&huart1 ,(uint8_t*)SD_Data,30,50);
}
//读取数据DMA
//1:指针 2:数据 3:地址 4:几块
if(HAL_SD_ReadBlocks(&hsd,buffer_2,77,1,10000)==HAL_OK){
char SD_Data [10]={"读取成功"};
HAL_UART_Transmit(&huart1 ,(uint8_t*)SD_Data,10,50);
}else{
char SD_Data [10]={"读取失败"};
HAL_UART_Transmit(&huart1 ,(uint8_t*)SD_Data,10,50);
}
//写入数据阻塞
if(HAL_SD_WriteBlocks_DMA(&hsd,buffer_1,77,1)==HAL_OK){
char SD_Data [10]={"写入成功"};
HAL_UART_Transmit(&huart1 ,(uint8_t*)SD_Data,10,50);
}else{
char SD_Data [10]={"写入失败"};
HAL_UART_Transmit(&huart1 ,(uint8_t*)SD_Data,10,50);
}
//打印数据
for(int i=0;i<512;i++){
char a[3];
sprintf(a,"%c",buffer_2[i]);
HAL_UART_Transmit(&huart1 ,(uint8_t*)a,1,50);
}
}else{
HAL_UART_Transmit(&huart1,(uint8_t*)data_UART2,22,50);
}
//HAL_Delay(1000);
/* 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};
/** 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_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != 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_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != 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 */