精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

stm32 CubeMx 實現SD卡/sd nand FATFS讀寫測試

深圳市雷龍發展有限公司 ? 2023-06-03 09:20 ? 次閱讀

文章目錄

stm32 CubeMx 實現SD卡/SD nand FATFS讀寫測試

1. 前言

2. 環境介紹

2.1 軟硬件說明

2.2 外設原理圖

3. 工程搭建

3.1 CubeMx 配置

3.2 SDIO時鐘配置說明

3.2 讀寫測試

3.2.1 添加讀寫測試代碼

3.3 FATFS文件操作

3.3.1 修改讀寫測試代碼

3.4 配置問題記錄

3.4.1 CubeMx生成代碼bug

3.4.2 SD插入檢測引腳配置

4. 結束語

1. 前言

SD卡/SD nand是嵌入式開發中常為使用的大容量存儲設備,SD nand雖然當前價格比SD卡高,但勝在價格、封裝以及穩定性上有優勢,實際操作和SD卡沒什么區別。

關于 SD卡/SDnand 的驅動,有了CubeMx之后其實基本上都自動生成了對應的驅動了,基本上把驅動配置一下之后,自己寫一些應用就可以完成基本的讀寫了,同時關于FATFS文件系統,也可以直接采用CubeMx配置,也不用自己移植,因此使用STM32開發這些還是比較爽的!不過使用過程中也有一些坑,自動生成的驅動有時候也還是有一些bug,因此還是需要大家對對應驅動有一定的了解。

本文將主要分享關于使用 CubeMx 配置 stm32 的工程,通過SDIO總線完成 SD卡/SD nand 的讀寫,并配置FATFS,采用文件操作實現對 SD卡/SD nand 的讀寫操作;此外還將分享博主在調試過程中遇到的一些問題,比如CubeMx自動生成的驅動存在的bug等,以及分享關于驅動部分的代碼分析!

2. 環境介紹

2.1 軟硬件說明

硬件環境:

主控:stm32f103vet6

SD nand: CSNP1GCR01-AOW【樣品CS創世SD NAND由深圳市雷龍發展有限公司免費提供的,感興趣的可到雷龍官網申請】

軟件環境:

CubeMx版本:Version 6.6.1

注意:當前最新版本 V6.8.0,生成的工程配置存在bug,具體細節在后文描述

2.2 外設原理圖

SD卡槽原理圖部分如下:

image.php?url=YD_cnt_77_01Mx085OLIn5

?

image.php?url=YD_cnt_77_01Mx08XWjQKw

?

3. 工程搭建

3.1 CubeMx 配置

  1. 1.選擇芯片ACCESS TO MCU SELECTOR
image.php?url=YD_cnt_77_01Mx08XJhnc8

?

  1. 2.搜索對應的芯片型號,在對應列表下方選擇對應芯片
  2. 3.配置時鐘方案,采用外部高速時鐘,無源晶振方案
image.php?url=YD_cnt_77_01Mx08VaagmX

?

  1. 4.配置調試器,由于我采用SWD調試接口,因此選擇 Serial Wrie 串行總線
image.php?url=YD_cnt_77_01Mx08UssGAQ

?

  1. 5.配置SDIO外設,由于我們所使用的SD nand支持4線傳輸,因此此處選擇4線寬度;如果你所使用的SD nand或SD卡不支持4線傳輸,此處應選擇1線寬度;支持4線寬度的SD卡肯定可以使用1線寬度,因此如果你實在不知道你的SD卡支持幾線寬度,你可以直接選擇1線寬度!4線和1線寬度的差別也就在于速度上相差了4倍!
  2. (注意這里暫時不需要對SDIO的參數進行配置,后面我們再回來配置!)
image.php?url=YD_cnt_77_01Mx08Trm7ST

?

  1. 6.完成時鐘樹配置:
  • 配置外部晶振頻率
  • 調整時鐘選擇,SYSCLK由PLL產生,PLL由外部時鐘倍頻產生
  • 配置SDIO外設時鐘,注意此處SDIO外設比較特殊,有兩個時鐘!具體原因見后文!
image.php?url=YD_cnt_77_01Mx08T1NKIR

?

  1. 7.
  2. 修改SDIO參數配置,主要是修改SDIOCLK的分頻
  • 由于我們上述配置的SDIO時鐘為 72M,而SD卡支持的通訊速率在0MHz至25MHz之間,因此我們需要分頻,配置 SDIO Clock divider bypass 為 Disable
  • 此處設置 SDIOCLK clock divide factor CLKDIV分頻系數為 8,這個受限于具體的SD卡支持的最大速度。如果設置值較小,可能由于SDIO_CK速度過高,SD卡/SDnand不支持,導致通訊失敗,因此建議先將此值設大點(或查看SD卡/SDnand手冊,或先設一個較大值,軟件完成SD信息讀取后再配置)
  • 注意這個配置的時鐘是用于SD讀寫通訊時候的時鐘,而不是SD卡信息識別過程時的速度!
image.php?url=YD_cnt_77_01Mx08Ri0q0N

?

image.php?url=YD_cnt_77_01Mx08RnA1Z4

編輯

?

8.勾選 FATFS 配置,選擇 SD Card

image.php?url=YD_cnt_77_01Mx08R9Am7n

編輯

?

9.配置SD卡檢測引腳,有以下兩種方案

  • 方案一:選擇一個輸入IO,作為觸發引腳
image.php?url=YD_cnt_77_01Mx08PfCgh3

編輯

?

  • 方案二:不配置輸入IO,最后生成代碼的時候無視警報即可,生成的代碼會自動取消輸入檢測判斷
image.php?url=YD_cnt_77_01Mx08P3dHpR

編輯

?

10.配置調試串口,用來打印信息,此處我選擇USART1,大家可根據自己硬件環境自行選擇

image.php?url=YD_cnt_77_01Mx08OFrG9X

編輯

?

11.配置工程信息

  • 配置工程名
  • 選擇工程路徑
  • 配置應用程序結構,我習慣選擇 Basic 結構
  • 選擇IDE工具及版本
  • 修改堆棧大小,適當改大一點,怕不夠用
image.php?url=YD_cnt_77_01Mx08NTJ89o

編輯

?

12.勾選將外設初始化放置在獨立的.c和.h文件,這樣每個外設的初始化是獨立的,方便閱讀移植!

image.php?url=YD_cnt_77_01Mx08LoQemv

編輯

?

13.生成代碼

image.php?url=YD_cnt_77_01Mx08LBLxXn

編輯

?

3.2 SDIO時鐘配置說明

在上述CubeMx時鐘配置中,外設的時鐘一般都是只有一路過去,但是在此處我們會發現SDIO的時鐘在時鐘樹中有兩個!沒弄清楚還會以為這是CubeMx出現bug了!

image.php?url=YD_cnt_77_01Mx08KVSMts

編輯

?

其實這是SDIO外設的特殊點,我們查看數據手冊上的時鐘樹,便可以發現,實際上是真的有兩路時鐘,分別是:1)SDIOCLK;2)至SDIO的AHB接口;

image.php?url=YD_cnt_77_01Mx08JPVVjB

?

之后,我們看到數據手冊的SDIO章節,我們可以看到SDIO外設分為:1)AHB總線接口 和 2)SDIO適配器兩大塊,且使用不同的時鐘,這也就是我們在時鐘樹配置中可以看到有兩路時鐘配置的原因了!

從下圖我們可以知道,SDIO外設不同于其他外設,其外設模塊部分與中斷、DMA是分開的,并采用不同的時鐘!

image.php?url=YD_cnt_77_01Mx08IWsorx

?

關于AHB總線接口及SDIO適配器更多細節,大家可自行閱讀參考手冊部分章節內容,此處不做贅述。

此外,關于時鐘配置有一個特別需要注意的,也就是SDIO_CK時鐘信號。SDIO_CK時鐘,也就是我們SDIO外設與SD卡/SD nand通訊的CLK時鐘,從上圖我們可知,SDIO_CK時鐘來自SDIO適配器,也就是來自SDIOCLK,對應CubeMX時鐘配置中的:

image.php?url=YD_cnt_77_01Mx08HKsQvu

?

image.php?url=YD_cnt_77_01Mx08H2hi40

?

3.2 讀寫測試

3.2.1 添加讀寫測試代碼

  1. 1.使能 MicroLIB 微庫,否則調用 printf 函數會卡住
image.php?url=YD_cnt_77_01Mx08G9BZVO

?

2.修改編碼規則為 UTF-8,這是由于我們CubeMx中配置的FATFS的編碼格式為 UTF-8導致,如果不修改為 UTF-8 則部分中文會亂碼! //TODO:確認是由FATFS配置導致

image.php?url=YD_cnt_77_01Mx08FO8oOv

?

image.php?url=YD_cnt_77_01Mx08EYFRKS

?

3.添加 printf 重映射 (位置可根據自行決定)

  1. #include
  2. int fputc(int ch, FILE *f)
  3. {
  4. HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1,0xffff);
  5. return (ch);
  6. }

4.添加 sdcard 信息打印函數,查看卡片信息

  1. HAL_SD_CardInfoTypeDef SDCardInfo;
  2. void printf_sdcard_info(void)
  3. {
  4. uint64_t CardCap; //SD卡容量
  5. HAL_SD_CardCIDTypeDef SDCard_CID;
  6. HAL_SD_GetCardCID(&hsd,&SDCard_CID); //獲取CID
  7. HAL_SD_GetCardInfo(&hsd,&SDCardInfo); //獲取SD卡信息
  8. CardCap=(uint64_t)(SDCardInfo.LogBlockNbr)*(uint64_t)(SDCardInfo.LogBlockSize); //計算SD卡容量
  9. switch(SDCardInfo.CardType)
  10. {
  11. case CARD_SDSC:
  12. {
  13. if(SDCardInfo.CardVersion == CARD_V1_X)
  14. printf("Card Type:SDSC V1\r\n");
  15. else if(SDCardInfo.CardVersion == CARD_V2_X)
  16. printf("Card Type:SDSC V2\r\n");
  17. }
  18. break;
  19. case CARD_SDHC_SDXC:printf("Card Type:SDHC\r\n");break;
  20. default:break;
  21. }
  22. printf("Card ManufacturerID: %d \r\n",SDCard_CID.ManufacturerID); //制造商ID
  23. printf("CardVersion: %d \r\n",(uint32_t)(SDCardInfo.CardVersion)); //卡版本號
  24. printf("Class: %d \r\n",(uint32_t)(SDCardInfo.Class)); //SD卡類別
  25. printf("Card RCA(RelCardAdd):%d \r\n",SDCardInfo.RelCardAdd); //卡相對地址
  26. printf("Card BlockNbr: %d \r\n",SDCardInfo.BlockNbr); //塊數量
  27. printf("Card BlockSize: %d \r\n",SDCardInfo.BlockSize); //塊大小
  28. printf("LogBlockNbr: %d \r\n",(uint32_t)(SDCardInfo.LogBlockNbr)); //邏輯塊數量
  29. printf("LogBlockSize: %d \r\n",(uint32_t)(SDCardInfo.LogBlockSize)); //邏輯塊大小
  30. printf("Card Capacity: %d MB\r\n",(uint32_t)(CardCap>>20)); //卡容量
  31. }

5.添加初始化及讀寫測試代碼,注意此處我們沒有直接使用FATFS的讀寫接口,我們先測試生成的SD驅動函數接口

  1. int main(void)
  2. {
  3. /* USER CODE BEGIN 1 */
  4. BYTE send_buf[512];
  5. DRESULT ret;
  6. /* USER CODE END 1 */
  7. /* ...省略若干自動生成代碼... */
  8. /* USER CODE BEGIN 2 */
  9. SD_Driver.disk_initialize(0);
  10. printf_sdcard_info();
  11. printf("\r\n\r\n********** 英文讀寫測試 **********\r\n");
  12. ret = SD_Driver.disk_write(0,
  13. (BYTE *)"Life is too short to spend time with people who suck the happiness out of you. \
  14. If someone wants you in their life, they’ll make room for you. You shouldn’t have to fight for a spot. Never, ever\
  15. insist yourself to someone who continuously overlooks your worth. And remember, it’s not the people that stand by \
  16. your side when you’re at your best, but the ones who stand beside you when you’re at your worst that are your true\
  17. friends",20,2);
  18. printf("sd write result:%d\r\n", ret);
  19. ret = SD_Driver.disk_read(0, send_buf, 20, 2);
  20. printf("sd reak result:%d\r\n", ret);
  21. printf("sd read content:\r\n%s\r\n", send_buf);
  22. printf("\r\n\r\n********** 中文讀寫測試 **********\r\n");
  23. ret = SD_Driver.disk_write(0,
  24. (BYTE *)"開發者社區的明天需要大家一同開源共創,期待下一次你的分享,讓我們一同攜手共進,推動人類科技的發展!!!\r\n\
  25. 創作不易,轉載請注明出處~\r\n\
  26. 更多文章敬請關注:愛出名的狗腿子\r\n", 22, 2);
  27. printf("sd write result:%d\r\n", ret);
  28. ret = SD_Driver.disk_read(0, send_buf, 22, 2);
  29. printf("sd reak result:%d\r\n", ret);
  30. printf("sd read content:\r\n%s\r\n", send_buf);
  31. /* USER CODE END 2 */
  32. while (1)
  33. {
  34. /* USER CODE END WHILE */
  35. /* USER CODE BEGIN 3 */
  36. }
  37. /* USER CODE END 3 */
  38. }

6.修改燒錄器配置,配置為燒錄后自動運行

image.php?url=YD_cnt_77_01Mx08M2ko1H

?

7.下載測試,這里由于我們采用UTF-8編碼,所以使用的串口上位機也需要支持UTF-8解析,我們這里使用Mobaxterm上位機,測試結果如下:

image.php?url=YD_cnt_77_01Mx08DUiQpY

?

8.main.c 文件全部代碼如下,供大家參考:

  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file : main.c
  5. * @brief : Main program body
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * Copyright (c) 2023 STMicroelectronics.
  10. * All rights reserved.
  11. *
  12. * This software is licensed under terms that can be found in the LICENSE file
  13. * in the root directory of this software component.
  14. * If no LICENSE file comes with this software, it is provided AS-IS.
  15. *
  16. ******************************************************************************
  17. */
  18. /* USER CODE END Header */
  19. /* Includes ------------------------------------------------------------------*/
  20. #include "main.h"
  21. #include "fatfs.h"
  22. #include "sdio.h"
  23. #include "usart.h"
  24. #include "gpio.h"
  25. /* Private includes ----------------------------------------------------------*/
  26. /* USER CODE BEGIN Includes */
  27. #include
  28. /* USER CODE END Includes */
  29. /* Private typedef -----------------------------------------------------------*/
  30. /* USER CODE BEGIN PTD */
  31. /* USER CODE END PTD */
  32. /* Private define ------------------------------------------------------------*/
  33. /* USER CODE BEGIN PD */
  34. /* USER CODE END PD */
  35. /* Private macro -------------------------------------------------------------*/
  36. /* USER CODE BEGIN PM */
  37. /* USER CODE END PM */
  38. /* Private variables ---------------------------------------------------------*/
  39. /* USER CODE BEGIN PV */
  40. /* USER CODE END PV */
  41. /* Private function prototypes -----------------------------------------------*/
  42. void SystemClock_Config(void);
  43. /* USER CODE BEGIN PFP */
  44. /* USER CODE END PFP */
  45. /* Private user code ---------------------------------------------------------*/
  46. /* USER CODE BEGIN 0 */
  47. HAL_SD_CardInfoTypeDef SDCardInfo;
  48. void printf_sdcard_info(void)
  49. {
  50. uint64_t CardCap; //SD卡容量
  51. HAL_SD_CardCIDTypeDef SDCard_CID;
  52. HAL_SD_GetCardCID(&hsd,&SDCard_CID); //獲取CID
  53. HAL_SD_GetCardInfo(&hsd,&SDCardInfo); //獲取SD卡信息
  54. CardCap=(uint64_t)(SDCardInfo.LogBlockNbr)*(uint64_t)(SDCardInfo.LogBlockSize); //計算SD卡容量
  55. switch(SDCardInfo.CardType)
  56. {
  57. case CARD_SDSC:
  58. {
  59. if(SDCardInfo.CardVersion == CARD_V1_X)
  60. printf("Card Type:SDSC V1\r\n");
  61. else if(SDCardInfo.CardVersion == CARD_V2_X)
  62. printf("Card Type:SDSC V2\r\n");
  63. }
  64. break;
  65. case CARD_SDHC_SDXC:printf("Card Type:SDHC\r\n");break;
  66. default:break;
  67. }
  68. printf("Card ManufacturerID: %d \r\n",SDCard_CID.ManufacturerID); //制造商ID
  69. printf("CardVersion: %d \r\n",(uint32_t)(SDCardInfo.CardVersion)); //卡版本號
  70. printf("Class: %d \r\n",(uint32_t)(SDCardInfo.Class)); //SD卡類別
  71. printf("Card RCA(RelCardAdd):%d \r\n",SDCardInfo.RelCardAdd); //卡相對地址
  72. printf("Card BlockNbr: %d \r\n",SDCardInfo.BlockNbr); //塊數量
  73. printf("Card BlockSize: %d \r\n",SDCardInfo.BlockSize); //塊大小
  74. printf("LogBlockNbr: %d \r\n",(uint32_t)(SDCardInfo.LogBlockNbr)); //邏輯塊數量
  75. printf("LogBlockSize: %d \r\n",(uint32_t)(SDCardInfo.LogBlockSize)); //邏輯塊大小
  76. printf("Card Capacity: %d MB\r\n",(uint32_t)(CardCap>>20)); //卡容量
  77. }
  78. int fputc(int ch, FILE *f)
  79. {
  80. HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1,0xffff);
  81. return (ch);
  82. }
  83. /* USER CODE END 0 */
  84. /**
  85. * @brief The application entry point.
  86. * @retval int
  87. */
  88. int main(void)
  89. {
  90. /* USER CODE BEGIN 1 */
  91. BYTE send_buf[512];
  92. DRESULT ret;
  93. /* USER CODE END 1 */
  94. /* MCU Configuration--------------------------------------------------------*/
  95. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  96. HAL_Init();
  97. /* USER CODE BEGIN Init */
  98. /* USER CODE END Init */
  99. /* Configure the system clock */
  100. SystemClock_Config();
  101. /* USER CODE BEGIN SysInit */
  102. /* USER CODE END SysInit */
  103. /* Initialize all configured peripherals */
  104. MX_GPIO_Init();
  105. MX_SDIO_SD_Init();
  106. MX_USART1_UART_Init();
  107. MX_FATFS_Init();
  108. /* USER CODE BEGIN 2 */
  109. SD_Driver.disk_initialize(0);
  110. printf_sdcard_info();
  111. printf("\r\n\r\n********** 英文讀寫測試 **********\r\n");
  112. ret = SD_Driver.disk_write(0,
  113. (BYTE *)"Life is too short to spend time with people who suck the happiness out of you. \
  114. If someone wants you in their life, they’ll make room for you. You shouldn’t have to fight for a spot. Never, ever\
  115. insist yourself to someone who continuously overlooks your worth. And remember, it’s not the people that stand by \
  116. your side when you’re at your best, but the ones who stand beside you when you’re at your worst that are your true\
  117. friends",20,2);
  118. printf("sd write result:%d\r\n", ret);
  119. ret = SD_Driver.disk_read(0, send_buf, 20, 2);
  120. printf("sd reak result:%d\r\n", ret);
  121. printf("sd read content:\r\n%s\r\n", send_buf);
  122. printf("\r\n\r\n********** 中文讀寫測試 **********\r\n");
  123. ret = SD_Driver.disk_write(0,
  124. (BYTE *)"開發者社區的明天需要大家一同開源共創,期待下一次你的分享,讓我們一同攜手共進,推動人類科技的發展!!!\r\n\
  125. 創作不易,轉載請注明出處~\r\n\
  126. 更多文章敬請關注:愛出名的狗腿子\r\n", 22, 2);
  127. printf("sd write result:%d\r\n", ret);
  128. ret = SD_Driver.disk_read(0, send_buf, 22, 2);
  129. printf("sd reak result:%d\r\n", ret);
  130. printf("sd read content:\r\n%s\r\n", send_buf);
  131. /* USER CODE END 2 */
  132. /* Infinite loop */
  133. /* USER CODE BEGIN WHILE */
  134. while (1)
  135. {
  136. /* USER CODE END WHILE */
  137. /* USER CODE BEGIN 3 */
  138. }
  139. /* USER CODE END 3 */
  140. }
  141. /**
  142. * @brief System Clock Configuration
  143. * @retval None
  144. */
  145. void SystemClock_Config(void)
  146. {
  147. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  148. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  149. /** Initializes the RCC Oscillators according to the specified parameters
  150. * in the RCC_OscInitTypeDef structure.
  151. */
  152. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  153. RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  154. RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  155. RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  156. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  157. RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  158. RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  159. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  160. {
  161. Error_Handler();
  162. }
  163. /** Initializes the CPU, AHB and APB buses clocks
  164. */
  165. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  166. |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  167. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  168. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  169. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  170. RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  171. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  172. {
  173. Error_Handler();
  174. }
  175. }
  176. /* USER CODE BEGIN 4 */
  177. /* USER CODE END 4 */
  178. /**
  179. * @brief This function is executed in case of error occurrence.
  180. * @retval None
  181. */
  182. void Error_Handler(void)
  183. {
  184. /* USER CODE BEGIN Error_Handler_Debug */
  185. /* User can add his own implementation to report the HAL error return state */
  186. __disable_irq();
  187. while (1)
  188. {
  189. }
  190. /* USER CODE END Error_Handler_Debug */
  191. }
  192. #ifdef USE_FULL_ASSERT
  193. /**
  194. * @brief Reports the name of the source file and the source line number
  195. * where the assert_param error has occurred.
  196. * @param file: pointer to the source file name
  197. * @param line: assert_param error line source number
  198. * @retval None
  199. */
  200. void assert_failed(uint8_t *file, uint32_t line)
  201. {
  202. /* USER CODE BEGIN 6 */
  203. /* User can add his own implementation to report the file name and line number,
  204. ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  205. /* USER CODE END 6 */
  206. }
  207. #endif /* USE_FULL_ASSERT */

3.3 FATFS文件操作

移植了FATFS,當然也就可以只用通用的文件系統操作函數完成文件的讀寫,通用的文件系統操作API 在 ff.c 文件內,聲明在 ff.h 文件內,主要使用的API接口如下:

  1. FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
  2. FRESULT f_close (FIL* fp); /* Close an open file object */
  3. FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
  4. FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
  5. FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
  6. FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */
  7. FRESULT f_truncate (FIL* fp); /* Truncate file */
  8. FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
  9. FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
  10. FRESULT f_closedir (DIR* dp); /* Close an open directory */
  11. FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
  12. FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
  13. FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
  14. FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
  15. FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
  16. FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
  17. FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
  18. FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */
  19. FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */
  20. FRESULT f_chdir (const TCHAR* path); /* Change current directory */
  21. FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
  22. FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
  23. FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
  24. FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
  25. FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
  26. FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
  27. FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */
  28. FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
  29. int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
  30. int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
  31. int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
  32. TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */

關于API的使用此處不做過多贅述,大家可以自行上官網查閱 FATFS官網,或者網上搜索,或直接看下述示例亦可。

3.3.1 修改讀寫測試代碼

修改3.2.1章節所使用的讀寫測試代碼,此處我們直接使用FATFS文件系統的讀寫函數接口,修改主函數如下,注意需要包含fatfs.h頭文件!

  1. #include "fatfs.h"
  2. int main()
  3. {
  4. /* USER CODE BEGIN 1 */
  5. #define USERPath "0:/"
  6. BYTE write_buf[] = "\r\n\r\n\
  7. hello world!\r\n\
  8. 開發者社區的明天需要大家一同開源共創,期待下一次你的分享,讓我們一同攜手共進,推動人類科技的發展!!!\r\n\
  9. 創作不易,轉載請注明出處~\r\n\
  10. 更多文章敬請關注:愛出名的狗腿子\r\n\r\n\
  11. ";
  12. BYTE read_buf[1024] = {0};
  13. UINT num;
  14. FRESULT ret;
  15. /* USER CODE END 1 */
  16. /* ... 省略初始化代碼... */
  17. /* USER CODE BEGIN 2 */
  18. /* 掛載文件系統,掛載的時候會完成對應硬件設備(SD卡/SDnand)初始化 */
  19. ret = f_mount(&SDFatFS, USERPath, 1);
  20. if (ret != FR_OK) {
  21. printf("f_mount error!\r\n");
  22. goto mount_error;
  23. } else if(ret == FR_NO_FILESYSTEM) { /* 檢測是否存在文件系統,如果沒有則進行格式化 */
  24. printf("未檢測到FATFS文件系統,執行格式化...\r\n");
  25. ret = f_mkfs(USERPath, 0, 0);
  26. if(ret == FR_OK) {
  27. printf("格式化成功!\r\n");
  28. f_mount(NULL, USERPath, 1); /* 先取消掛載,后重新掛載 */
  29. ret = f_mount(&SDFatFS, USERPath, 1);
  30. } else {
  31. printf("格式化失敗!\r\n");
  32. goto mount_error;
  33. }
  34. } else {
  35. printf("f_mount success!\r\n");
  36. }
  37. /* 讀寫測試 */
  38. printf("\r\n ========== write test ==========\r\n");
  39. ret = f_open(&SDFile, "hello.txt", FA_CREATE_ALWAYS | FA_WRITE);
  40. if(ret == FR_OK) {
  41. printf("open file sucess!\r\n");
  42. ret = f_write(&SDFile, write_buf, sizeof(write_buf), &num);
  43. if(ret == FR_OK) {
  44. printf("write "%s" success!\r\nwrite len:%d\r\n", write_buf, num);
  45. } else {
  46. printf("write error! ret:%d \r\n", ret);
  47. goto rw_error;
  48. }
  49. f_close(&SDFile);
  50. } else {
  51. printf("open file error!\r\n");
  52. goto rw_error;
  53. }
  54. printf("\r\n ========== read test ==========\r\n");
  55. ret = f_open(&SDFile, "hello.txt",FA_OPEN_EXISTING | FA_READ);
  56. if(ret == FR_OK) {
  57. printf("open file sucess!\r\n");
  58. ret = f_read(&SDFile, read_buf, sizeof(read_buf), &num);
  59. if(ret == FR_OK) {
  60. printf("read data:"%s"!\r\nread len:%d\r\n", read_buf, num);
  61. } else {
  62. printf("read error! ret:%d \r\n", ret);
  63. goto rw_error;
  64. }
  65. } else {
  66. printf("open file error!\r\n");
  67. goto rw_error;
  68. }
  69. rw_error:
  70. f_close(&SDFile);
  71. mount_error:
  72. f_mount(NULL, USERPath, 1);
  73. /* USER CODE END 2 */
  74. while (1) {
  75. }
  76. }

#define USERPath "0:/" 表示掛載的位置,這是由于FATFS初始化的時候鏈接的根目錄為 0:/ ,所以掛載的文件系統需要在此目錄下,當然也可以是此目錄下的路徑,如0:/hello,但不能是其他目錄,如 1:/

image.php?url=YD_cnt_77_01Mx08CWe7Ji

?

測試結果如下:

image.php?url=YD_cnt_77_01Mx08BWSRPJ

?

main.c完整內容如下:

  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file : main.c
  5. * @brief : Main program body
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * Copyright (c) 2023 STMicroelectronics.
  10. * All rights reserved.
  11. *
  12. * This software is licensed under terms that can be found in the LICENSE file
  13. * in the root directory of this software component.
  14. * If no LICENSE file comes with this software, it is provided AS-IS.
  15. *
  16. ******************************************************************************
  17. */
  18. /* USER CODE END Header */
  19. /* Includes ------------------------------------------------------------------*/
  20. #include "main.h"
  21. #include "fatfs.h"
  22. #include "sdio.h"
  23. #include "usart.h"
  24. #include "gpio.h"
  25. /* Private includes ----------------------------------------------------------*/
  26. /* USER CODE BEGIN Includes */
  27. #include
  28. #include "fatfs.h"
  29. /* USER CODE END Includes */
  30. /* Private typedef -----------------------------------------------------------*/
  31. /* USER CODE BEGIN PTD */
  32. /* USER CODE END PTD */
  33. /* Private define ------------------------------------------------------------*/
  34. /* USER CODE BEGIN PD */
  35. /* USER CODE END PD */
  36. /* Private macro -------------------------------------------------------------*/
  37. /* USER CODE BEGIN PM */
  38. /* USER CODE END PM */
  39. /* Private variables ---------------------------------------------------------*/
  40. /* USER CODE BEGIN PV */
  41. /* USER CODE END PV */
  42. /* Private function prototypes -----------------------------------------------*/
  43. void SystemClock_Config(void);
  44. /* USER CODE BEGIN PFP */
  45. /* USER CODE END PFP */
  46. /* Private user code ---------------------------------------------------------*/
  47. /* USER CODE BEGIN 0 */
  48. HAL_SD_CardInfoTypeDef SDCardInfo;
  49. void printf_sdcard_info(void)
  50. {
  51. uint64_t CardCap; //SD卡容釿
  52. HAL_SD_CardCIDTypeDef SDCard_CID;
  53. HAL_SD_GetCardCID(&hsd,&SDCard_CID); //獲取CID
  54. HAL_SD_GetCardInfo(&hsd,&SDCardInfo); //獲取SD卡信恿
  55. CardCap=(uint64_t)(SDCardInfo.LogBlockNbr)*(uint64_t)(SDCardInfo.LogBlockSize); //計算SD卡容釿
  56. switch(SDCardInfo.CardType)
  57. {
  58. case CARD_SDSC:
  59. {
  60. if(SDCardInfo.CardVersion == CARD_V1_X)
  61. printf("Card Type:SDSC V1\r\n");
  62. else if(SDCardInfo.CardVersion == CARD_V2_X)
  63. printf("Card Type:SDSC V2\r\n");
  64. }
  65. break;
  66. case CARD_SDHC_SDXC:printf("Card Type:SDHC\r\n");break;
  67. default:break;
  68. }
  69. printf("Card ManufacturerID: %d \r\n",SDCard_CID.ManufacturerID); //制?商ID
  70. printf("CardVersion: %d \r\n",(uint32_t)(SDCardInfo.CardVersion)); //卡版本號
  71. printf("Class: %d \r\n",(uint32_t)(SDCardInfo.Class)); //SD卡類劌
  72. printf("Card RCA(RelCardAdd):%d \r\n",SDCardInfo.RelCardAdd); //卡相對地坿
  73. printf("Card BlockNbr: %d \r\n",SDCardInfo.BlockNbr); //塊數釿
  74. printf("Card BlockSize: %d \r\n",SDCardInfo.BlockSize); //塊大尿
  75. printf("LogBlockNbr: %d \r\n",(uint32_t)(SDCardInfo.LogBlockNbr)); //邏輯塊數釿
  76. printf("LogBlockSize: %d \r\n",(uint32_t)(SDCardInfo.LogBlockSize)); //邏輯塊大尿
  77. printf("Card Capacity: %d MB\r\n",(uint32_t)(CardCap>>20)); //卡容釿
  78. }
  79. int fputc(int ch, FILE *f)
  80. {
  81. HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1,0xffff);
  82. return (ch);
  83. }
  84. /* USER CODE END 0 */
  85. /**
  86. * @brief The application entry point.
  87. * @retval int
  88. */
  89. int main(void)
  90. {
  91. /* USER CODE BEGIN 1 */
  92. #define USERPath "0:/"
  93. BYTE write_buf[] = "\r\n\r\n\
  94. hello world!\r\n\
  95. 開發者社區的明天需要大家一同開源共創,期待下一次你的分享,讓我們一同攜手共進,推動人類科技的發展!!!\r\n\
  96. 創作不易,轉載請注明出處~\r\n\
  97. 更多文章敬請關注:愛出名的狗腿子\r\n\r\n\
  98. ";
  99. BYTE read_buf[1024] = {0};
  100. UINT num;
  101. FRESULT ret;
  102. /* USER CODE END 1 */
  103. /* MCU Configuration--------------------------------------------------------*/
  104. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  105. HAL_Init();
  106. /* USER CODE BEGIN Init */
  107. /* USER CODE END Init */
  108. /* Configure the system clock */
  109. SystemClock_Config();
  110. /* USER CODE BEGIN SysInit */
  111. /* USER CODE END SysInit */
  112. /* Initialize all configured peripherals */
  113. MX_GPIO_Init();
  114. MX_SDIO_SD_Init();
  115. MX_USART1_UART_Init();
  116. MX_FATFS_Init();
  117. /* USER CODE BEGIN 2 */
  118. /* 掛載文件系統,掛載的時候會完成對應硬件設備(SD卡/SDnand)初始化 */
  119. ret = f_mount(&SDFatFS, USERPath, 1);
  120. if (ret != FR_OK) {
  121. printf("f_mount error!\r\n");
  122. goto mount_error;
  123. } else if(ret == FR_NO_FILESYSTEM) { /* 檢測是否存在文件系統,如果沒有則進行格式化 */
  124. printf("未檢測到FATFS文件系統,執行格式化...\r\n");
  125. ret = f_mkfs(USERPath, 0, 0);
  126. if(ret == FR_OK) {
  127. printf("格式化成功!\r\n");
  128. f_mount(NULL, USERPath, 1); /* 先取消掛載,后重新掛載 */
  129. ret = f_mount(&SDFatFS, USERPath, 1);
  130. } else {
  131. printf("格式化失敗!\r\n");
  132. goto mount_error;
  133. }
  134. } else {
  135. printf("f_mount success!\r\n");
  136. }
  137. /* 讀寫測試 */
  138. printf("\r\n ========== write test ==========\r\n");
  139. ret = f_open(&SDFile, "hello.txt", FA_CREATE_ALWAYS | FA_WRITE);
  140. if(ret == FR_OK) {
  141. printf("open file sucess!\r\n");
  142. ret = f_write(&SDFile, write_buf, sizeof(write_buf), &num);
  143. if(ret == FR_OK) {
  144. printf("write "%s" success!\r\nwrite len:%d\r\n", write_buf, num);
  145. } else {
  146. printf("write error! ret:%d \r\n", ret);
  147. goto rw_error;
  148. }
  149. f_close(&SDFile);
  150. } else {
  151. printf("open file error!\r\n");
  152. goto rw_error;
  153. }
  154. printf("\r\n ========== read test ==========\r\n");
  155. ret = f_open(&SDFile, "hello.txt",FA_OPEN_EXISTING | FA_READ);
  156. if(ret == FR_OK) {
  157. printf("open file sucess!\r\n");
  158. ret = f_read(&SDFile, read_buf, sizeof(read_buf), &num);
  159. if(ret == FR_OK) {
  160. printf("read data:"%s"!\r\nread len:%d\r\n", read_buf, num);
  161. } else {
  162. printf("read error! ret:%d \r\n", ret);
  163. goto rw_error;
  164. }
  165. } else {
  166. printf("open file error!\r\n");
  167. goto rw_error;
  168. }
  169. rw_error:
  170. f_close(&SDFile);
  171. mount_error:
  172. f_mount(NULL, USERPath, 1);
  173. /* USER CODE END 2 */
  174. /* Infinite loop */
  175. /* USER CODE BEGIN WHILE */
  176. while (1)
  177. {
  178. /* USER CODE END WHILE */
  179. /* USER CODE BEGIN 3 */
  180. }
  181. /* USER CODE END 3 */
  182. }
  183. /**
  184. * @brief System Clock Configuration
  185. * @retval None
  186. */
  187. void SystemClock_Config(void)
  188. {
  189. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  190. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  191. /** Initializes the RCC Oscillators according to the specified parameters
  192. * in the RCC_OscInitTypeDef structure.
  193. */
  194. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  195. RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  196. RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  197. RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  198. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  199. RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  200. RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  201. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  202. {
  203. Error_Handler();
  204. }
  205. /** Initializes the CPU, AHB and APB buses clocks
  206. */
  207. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  208. |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  209. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  210. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  211. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  212. RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  213. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  214. {
  215. Error_Handler();
  216. }
  217. }
  218. /* USER CODE BEGIN 4 */
  219. /* USER CODE END 4 */
  220. /**
  221. * @brief This function is executed in case of error occurrence.
  222. * @retval None
  223. */
  224. void Error_Handler(void)
  225. {
  226. /* USER CODE BEGIN Error_Handler_Debug */
  227. /* User can add his own implementation to report the HAL error return state */
  228. __disable_irq();
  229. while (1)
  230. {
  231. }
  232. /* USER CODE END Error_Handler_Debug */
  233. }
  234. #ifdef USE_FULL_ASSERT
  235. /**
  236. * @brief Reports the name of the source file and the source line number
  237. * where the assert_param error has occurred.
  238. * @param file: pointer to the source file name
  239. * @param line: assert_param error line source number
  240. * @retval None
  241. */
  242. void assert_failed(uint8_t *file, uint32_t line)
  243. {
  244. /* USER CODE BEGIN 6 */
  245. /* User can add his own implementation to report the file name and line number,
  246. ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  247. /* USER CODE END 6 */
  248. }
  249. #endif /* USE_FULL_ASSERT */

3.4 配置問題記錄

3.4.1 CubeMx生成代碼bug

測試發現,使用CubeMx當前最新版本:V6.8.0版本,生成代碼會存在以下問題:

  • SD卡/SDnand 卡片信息讀取成功,但是讀寫測試失敗

經過仔細分析代碼后發現,出現的問題在 MX_SDIO_SD_Init() 此初始化函數內的配置項錯誤導致,具體分析如下:

  1. 我們在CubeMx里面配置的時候選擇的是4線寬度模式 SD 4bit Wide bus
  2. v6.8.0版本CubeMx生成的 MX_SDIO_SD_Init() SD初始化函數內,hsd.Init.BusWide = SDIO_BUS_WIDE_4B;
  3. 看上去沒有什么問題,配置4線模式,對應的初始化項也使用4線模式,但是不然,我們繼續分析 MX_SDIO_SD_Init() 此初始配置的調用
  4. MX_SDIO_SD_Init() 此函數在main函數內初始化的時候調用,此函數只配置了 hsd 結構體,并未配置給SDIO硬件寄存器
  5. 之后調用 SD_Driver.disk_initialize(0); 函數的時候才真正開始進行SDIO外設配置

BSP_SD_Init()

??->HAL_SD_Init()

????->HAL_SD_InitCard()

在 HAL_SD_InitCard() 函數內使用Init結構體配置SDIO外設,總線寬度1bit,時鐘速度<400k,以進行卡片的初始化識別。

??????-> SD_InitCard()

????????-> SDIO_Init(hsd->Instance, hsd->Init)

??????-> SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE)

· 在 SD_InitCard() 函數內實現SD卡的初始化識別,之后調用 SDIO_Init() 將 MX_SDIO_SD_Init() 內對 hsd 的配置配置給SDIO外設,此處的作用主要是提升SDIO外設時鐘速率為我們配置的速率;

· v6.8.0版本的代碼此時hsd.Init.BusWide = SDIO_BUS_WIDE_4B; ,因此v6.8.0版本代碼后續SDIO外設使用4線通訊;

· 之后調用 SDMMC_CmdBlockLength() 設置塊大小,由于SDIO外設已切換到4線模式,而SD卡/SDnand此時仍然處于1線模式,因此配置會出錯

?? -> HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B)

根據前面獲取到的SD卡SCR寄存器值,判斷是否支持4線模式,如果支持則發送配置命令通知SD卡/SDnand進入4線模式,之后修改SDIO外設總線寬度為4線模式

6.通過以上分析可知,MX_SDIO_SD_Init() 函數內對 hsd.Init.BusWide = SDIO_BUS_WIDE_4B; 的配置會導致對SD卡塊大小的配置失敗,從而導致后續讀寫時失敗,報錯為塊大小設置失敗!

7.綜上,針對當前最新版本 V6.8.0 版本CubeMx的處理方法是:手動修改此 hsd.Init.BusWide 配置為 SDIO_BUS_WIDE_1B 或更換低版本CubeMx,本人更換V6.6.1版本后無此bug。

3.4.2 SD插入檢測引腳配置

使用CubeMx配置FATFS 選擇 SD Card 之后,有一個配置參數,用來配置SD Card的輸入檢測引腳。如果我們在硬件上有設計SD卡的卡槽插入檢測引腳插入連接到了MCU的IO,則可配置對應IO為輸入模式,并設置對應IO為輸入檢測引腳,比如,我們設置PD12為輸入檢測引腳,則配置如下:

對應代碼如下,輸入檢測 IO 低電平有效!

image.php?url=YD_cnt_77_01Mx088b2Vk2

?

image.php?url=YD_cnt_77_01Mx08Ds3I5r

?

如果硬件上,沒有此插入檢測引腳,則可以在CubeMx內不進行配置,只是在生成代碼的時候會提示警報而已,可以不用關心,生成的代碼項會自動屏蔽插入檢測!

image.php?url=YD_cnt_77_01Mx08AGoLIZ

?

4. 結束語

  • 以上便是本文的全部內容了,歡迎大家評論區留言討論!
  • 使用CubeMx雖然能幫助我們快速生成驅動,但是對于SD卡/SD nand的驅動流程,我們還是需要有清晰的認識,推薦閱讀: SD Nand 與 SD卡 SDIO模式應用流程

————————————————

【本文轉載自CSDN,作者: 愛出名的狗腿子】

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • SD卡
    +關注

    關注

    2

    文章

    553

    瀏覽量

    63520
  • FATFS
    +關注

    關注

    0

    文章

    43

    瀏覽量

    18211
收藏 人收藏

    評論

    相關推薦

    貼片式SD功能介紹【MK SD NAND

    技術與傳統SD不同,SD NAND使用貼裝式封裝,允許直接焊接至電子設備的PCB上,提供一種內置的存儲功能。
    的頭像 發表于 07-05 17:03 ?435次閱讀
    貼片式<b class='flag-5'>SD</b><b class='flag-5'>卡</b>功能介紹【MK <b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>】

    STM32CubeMX+FreeRTOS+SD+FATFS碰到DMA FIFO溢出問題怎么解決?

    也可以掛載,但是多次新建文件打開和關閉后,fatfs返回FR_DISK_ERR;可能是由于SD無響應后超時導致。 然后我下載STM32CubeMX4.24和1.19.0庫文件,配置
    發表于 04-23 07:49

    請問使用STM32F1能實現USB和fatfs同時訪問SD嗎?

    使用STM32F1能實現USB和fatfs同時訪問SD嗎,想實現1S寫一次數據到
    發表于 04-23 07:48

    STM32F412使用SD,SDIO,FATFS系統,SD掛載文件系統失敗的原因?

    \", /* (3) The physical drive cannot work */ 原代碼從STM32F103RCT6上驗證過,F103 CUBEMX版本好像是5.0的,可以直接運行SD
    發表于 04-11 07:15

    關于stm32cubemx usb讀卡和fatfs兼容問題求解

    芯片使用STM32F411,使能SDIO,四線接SD 使用stm32cubemx直接生成USB device,大容量儲存設備,可以在電腦上看到U盤,使用
    發表于 04-01 06:09

    stm32 CubeMx 怎么實現SD/sd nand FATFS讀寫測試

    本實驗僅用于記錄和分享技術經驗若涉及侵權請聯系我刪除。   stm32 CubeMx 實現SD/sd
    發表于 01-09 17:37

    什么是SD NAND存儲芯片? SD NAND與TF的區別

    什么是SD NAND?它俗稱貼片式T,貼片式TF,貼片式SD,貼片式內存
    的頭像 發表于 01-06 14:35 ?1409次閱讀
    什么是<b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>存儲芯片? <b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>與TF<b class='flag-5'>卡</b>的區別

    什么是SD NAND存儲芯片?

    標準驅動代碼,省去了驅動代碼編程環節。支持TF啟動的SOC都可以用SD NAND,提供STM32參考例程及原廠技術支持,主流容量:128MB/512MB/2GB/4GB/8GB,比T
    發表于 01-05 17:54

    基于Zynq FPGA對雷龍SD NAND測試

    簡介??雷龍的SDNAND有很多型號,在測試中使用的是CSNP4GCR01-AWM與CSNP32GCR01-AOW。芯片是基于NANDFLASH和SD控制器實現
    的頭像 發表于 12-22 17:45 ?402次閱讀
    基于Zynq FPGA對雷龍<b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>的<b class='flag-5'>測試</b>

    基于Zynq FPGA對雷龍SD NAND測試

    版本:2018.3 ??文件系統:FATFS ??SD接口:SD2.0 3.1 測試流程 ??本次測試
    發表于 12-22 17:43

    基于RT-Thread快速上手SD NAND 虛擬文件系統

    操作系統,更是不需要編寫任何復雜的驅動代碼就可以SD NAND讀寫操作。   (文末提供,STM32驅動代碼下載連接,需要可以自行下載)   將
    發表于 12-15 17:29

    DSP+FPGA+FATFS+SD

    項目背景,在DSP上掛Fatfs文件系統,而SD是掛在FPGA上的,DSP需要通過FPGA與SD交互,大概就是會把數據存到FPGA的DD
    發表于 11-14 09:30

    基于NIOS II的SD讀寫控制設計

    電子發燒友網站提供《基于NIOS II的SD讀寫控制設計.pdf》資料免費下載
    發表于 11-06 10:06 ?7次下載
    基于NIOS II的<b class='flag-5'>SD</b><b class='flag-5'>卡</b><b class='flag-5'>讀寫</b>控制設計

    淺談STM32SD

    STM32SD
    的頭像 發表于 10-19 18:28 ?1494次閱讀
    淺談<b class='flag-5'>STM32</b>之<b class='flag-5'>SD</b><b class='flag-5'>卡</b>

    CS SD NANDSTM32精英V2開發板的測試-是時候將TF換為SD NAND

    非常不錯的選擇,正好一個項目在選擇NAND存儲方案, 恰巧論壇中聯系到雷龍公司申請到了兩片SD NAND,所以就進行一下測試評估。 SD
    發表于 09-26 17:40