STM32CUBEIDE SD卡+FATFS正点原子战舰开发板
配置SD卡
配置SD卡时候注意四线通讯还是一线通讯
正点原子战舰选四线会卡死所以选一线
频率要在0到25Mhz之间
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2023 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> #include <string.h> /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif PUTCHAR_PROTOTYPE { //具体哪个串口可以更改huart1为其它串�??????????????????????????????????????????????????????????????? //HAL_GPIO_WritePin(USART3_EN_GPIO_Port, USART3_EN_Pin, GPIO_PIN_SET); HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1 , 0xffff); return ch; } #define BLOCK_START_ADDR 0 /* Block start address */ #define NUM_OF_BLOCKS 1 /* Total number of blocks */ #define BUFFER_WORDS_SIZE ((BLOCKSIZE * NUM_OF_BLOCKS) >> 2) /* Total data size in bytes */ uint8_t Buffer_Tx[512],Buffer_Rx[512] = {0}; uint32_t i; /* 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_USART1_UART_Init(); MX_SDIO_SD_Init(); /* USER CODE BEGIN 2 */ // HAL_SD_InitCard(&hsd); //初始化SD卡,注意句柄 这个初始化函数可以单独初始化SD卡 如果sd卡初始化失败可以单独测试下 printf("Micro SD Card Test...\r\n"); /* �?测SD卡是否正常(处于数据传输模式的传输状态) */ if(HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_TRANSFER) { printf("Initialize SD card successfully!\r\n"); // 打印SD卡基本信�? printf(" SD card information! \r\n"); printf(" CardCapacity : %llu \r\n", (unsigned long long)hsd.SdCard.BlockSize * hsd.SdCard.BlockNbr);// 显示容量 printf(" CardBlockSize : %d \r\n", hsd.SdCard.BlockSize); // 块大�? printf(" LogBlockNbr : %d \r\n", hsd.SdCard.LogBlockNbr); // 逻辑块数�? printf(" LogBlockSize : %d \r\n", hsd.SdCard.LogBlockSize);// 逻辑块大�? printf(" RCA : %d \r\n", hsd.SdCard.RelCardAdd); // 卡相对地�? printf(" CardType : %d \r\n", hsd.SdCard.CardType); // 卡类�? // 读取并打印SD卡的CID信息 HAL_SD_CardCIDTypeDef sdcard_cid; HAL_SD_GetCardCID(&hsd,&sdcard_cid); printf(" ManufacturerID: %d \r\n",sdcard_cid.ManufacturerID); } else { printf("SD card init fail!\r\n" ); } /* 擦除SD卡块 */ printf("------------------- Block Erase -------------------------------\r\n"); if(HAL_SD_Erase(&hsd, BLOCK_START_ADDR, NUM_OF_BLOCKS) == HAL_OK) { /* Wait until SD cards are ready to use for new operation */ while(HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER) { } printf("\r\nErase Block Success!\r\n"); } else { printf("\r\nErase Block Failed!\r\n"); } /* 填充缓冲区数�? */ memset(Buffer_Tx, 0x15, sizeof(Buffer_Tx)); /* 向SD卡块写入数据 */ printf("------------------- Write SD card block data Test ------------------\r\n"); if(HAL_SD_WriteBlocks(&hsd, Buffer_Tx, BLOCK_START_ADDR, NUM_OF_BLOCKS, 10) == HAL_OK) { while(HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER) { } printf("\r\nWrite Block Success!\r\n"); for(i = 0; i < sizeof(Buffer_Tx); i++) { printf("0x%02x:%02x ", i, Buffer_Tx[i]); } printf("\r\n"); } else { printf("\r\nWrite Block Failed!\r\n"); } /* 读取操作之后的数�? */ printf("------------------- Read SD card block data after Write ------------------\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("\r\nRead Block Success!\r\n"); for(i = 0; i < sizeof(Buffer_Rx); i++) { printf("0x%02x:%02x ", i, Buffer_Rx[i]); } printf("\r\n"); } else { printf("\r\nRead Block Failed!\r\n"); } /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin); // HAL_UART_Transmit(&huart1, 123, 1 , 0xffff); HAL_Delay(200); } /* 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_MUL16; 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_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != 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 */
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_DISABLE; hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; hsd.Init.BusWide = SDIO_BUS_WIDE_1B; hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; hsd.Init.ClockDiv = 4; if (HAL_SD_Init(&hsd) != HAL_OK)//会调用 HAL_SD_InitCard(&hsd)
{
Error_Handler();
}
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_1B) != HAL_OK)//设置位宽要统一与 hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
{
Error_Handler();
} /* USER CODE BEGIN SDIO_Init 2 */ /* USER CODE END SDIO_Init 2 */ }
验证SD卡读写没问题加入文件系统
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2023 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 "fatfs.h" #include "sdio.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include"bsp_driver_sd.h" #include "sdio_test.h" #include"ff.h" #include "ff_gen_drv.h" #include "sd_diskio.h" #include "stddef.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ HAL_StatusTypeDef flag; #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif PUTCHAR_PROTOTYPE { //具体哪个串口可以更改huart1为其它串�????????????????????????????????????????????????????????? //HAL_GPIO_WritePin(USART3_EN_GPIO_Port, USART3_EN_Pin, GPIO_PIN_SET); HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1 , 0xffff); return ch; } static void printf_fatfs_error(FRESULT fresult) { switch(fresult) { case FR_OK: printf("》操作成功�?�\r\n"); break; case FR_DISK_ERR: printf("!!硬件输入输出驱动出错。\r\n"); break; case FR_INT_ERR: printf("!!断言错误。\r\n"); break; case FR_NOT_READY: printf("!!物理设备无法工作。\r\n"); break; case FR_NO_FILE: printf("!!无法找到文件。\r\n"); break; case FR_NO_PATH: printf("!!无法找到路径。\r\n"); break; case FR_INVALID_NAME: printf("!!无效的路径名。\r\n"); break; case FR_DENIED: case FR_EXIST: printf("!!拒绝访问。\r\n"); break; case FR_INVALID_OBJECT: printf("!!无效的文件或路径。\r\n"); break; case FR_WRITE_PROTECTED: printf("!!逻辑设备写保护�?�\r\n"); break; case FR_INVALID_DRIVE: printf("!!无效的�?�辑设备。\r\n"); break; case FR_NOT_ENABLED: printf("!!无效的工作区。\r\n"); break; case FR_NO_FILESYSTEM: printf("!!无效的文件系统�?�\r\n"); break; case FR_MKFS_ABORTED: printf("!!因函数参数问题导致f_mkfs函数操作失败。\r\n"); break; case FR_TIMEOUT: printf("!!操作超时。\r\n"); break; case FR_LOCKED: printf("!!文件被保护�?�\r\n"); break; case FR_NOT_ENOUGH_CORE: printf("!!长文件名支持获取堆空间失败�?�\r\n"); break; case FR_TOO_MANY_OPEN_FILES: printf("!!打开太多文件。\r\n"); break; case FR_INVALID_PARAMETER: printf("!!参数无效。\r\n"); break; } } FATFS fs; FIL file; FRESULT f_res; UINT fnum; BYTE ReadBuffer[1024] = {0}; BYTE WriteBuffer[1024] = "新建文件系统的事文件\r\n"; /* 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_USART1_UART_Init(); MX_SDIO_SD_Init(); MX_FATFS_Init(); /* USER CODE BEGIN 2 */ // printf("\r\r\n****** 这是�??????????个SD�?????????? 文件系统实验 ******\r\r\n"); // //MX_FATFS_Init已经连接,注册了�??????????个sd卡设备�?? // //sd卡挂在文件系�?????????? f_res = f_mount(&fs, (TCHAR const*)SDPath, 1); printf_fatfs_error(f_res); //格式化测�??????????----------如果没有文件系统就格式化创建文件系统 if(f_res == FR_NO_FILESYSTEM) { f_res = f_mkfs((TCHAR const*)SDPath,0,0);//SDPath在fatfs生成的文件系统里有定义 if(f_res == FR_OK) { f_res = f_mount(NULL, (TCHAR const*)SDPath, 0); f_res = f_mount(&fs, (TCHAR const*)SDPath, 0); } else { printf("《�?�格式化失败。�?��?�\r\n"); while(1); } } else if(f_res != FR_OK) { printf("!!SD卡挂载文件系统失败�??(%d)\r\n",f_res); printf_fatfs_error(f_res); // while(1); } else { printf("》文件系统挂载成功,可以进行读写测试\r\n"); } /*----------------------- 文件系统测试:写测试 -----------------------------*/ /* 打开文件,如果文件不存在则创建它 */ printf("****** 即将进行文件写入测试... ******\r\n"); f_res = f_open(&file, "0:FatFs读写测试文件。txt", FA_CREATE_ALWAYS | FA_WRITE ); if(f_res == FR_OK) { printf("》打�??????????/创建FatFs读写测试文件.txt文件成功,向文件写入数据。\r\n"); /* 将指定存储区内容写入到文件内 */ f_res=f_write(&file,WriteBuffer,sizeof(WriteBuffer),&fnum); if(f_res == FR_OK) { printf("》文件写入成功,写入字节数据�??????????%d\r\n",fnum); printf("》向文件写入的数据为:\r\n%s\r\n",WriteBuffer); } else { printf("!!文件写入失败�??????????(%d)\r\n",f_res); } f_close(&file); } else { printf("!!打开/创建文件失败。\r\n"); } /*------------------- 文件系统测试:读测试 ------------------------------------*/ printf("****** 即将进行文件读取测试... ******\r\n"); f_res = f_open(&file, "0:Fatfs读写文件测试.txt", FA_OPEN_EXISTING | FA_READ); if(f_res == FR_OK) { printf("》打�??????????文件成功。\r\n"); f_res = f_read(&file, ReadBuffer, sizeof(ReadBuffer), &fnum); if(f_res == FR_OK) { printf("》文件读取成�??????????,读到字节数据�??????????%d\r\n",fnum); printf("》读取得的文件数据为:\r\n%s \r\n", ReadBuffer); } else { printf("!!文件读取失败�??????????(%d)\r\n",f_res); } } else { printf("!!打开文件失败。\r\n"); } f_close(&file); f_mount(NULL, "0:", 0); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin); flag = HAL_UART_Transmit(&huart1, 123, 1 , 0xffff); HAL_Delay(200); } /* 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_MUL16; 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_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != 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 */