0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

stm32 CubeMx 實現(xiàn)SD卡/sd nand FATFS讀寫測試

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

文章目錄

stm32 CubeMx 實現(xiàn)SD卡/SD nand FATFS讀寫測試

1. 前言

2. 環(huán)境介紹

2.1 軟硬件說明

2.2 外設(shè)原理圖

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. 結(jié)束語

1. 前言

SD卡/SD nand是嵌入式開發(fā)中常為使用的大容量存儲設(shè)備,SD nand雖然當(dāng)前價格比SD卡高,但勝在價格、封裝以及穩(wěn)定性上有優(yōu)勢,實際操作和SD卡沒什么區(qū)別。

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

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

2. 環(huán)境介紹

2.1 軟硬件說明

硬件環(huán)境:

主控:stm32f103vet6

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

軟件環(huán)境:

CubeMx版本:Version 6.6.1

注意:當(dāng)前最新版本 V6.8.0,生成的工程配置存在bug,具體細(xì)節(jié)在后文描述

2.2 外設(shè)原理圖

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.搜索對應(yīng)的芯片型號,在對應(yīng)列表下方選擇對應(yīng)芯片
  2. 3.配置時鐘方案,采用外部高速時鐘,無源晶振方案
image.php?url=YD_cnt_77_01Mx08VaagmX

?

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

?

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

?

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

?

  1. 7.
  2. 修改SDIO參數(shù)配置,主要是修改SDIOCLK的分頻
  • 由于我們上述配置的SDIO時鐘為 72M,而SD卡支持的通訊速率在0MHz至25MHz之間,因此我們需要分頻,配置 SDIO Clock divider bypass 為 Disable
  • 此處設(shè)置 SDIOCLK clock divide factor CLKDIV分頻系數(shù)為 8,這個受限于具體的SD卡支持的最大速度。如果設(shè)置值較小,可能由于SDIO_CK速度過高,SD卡/SDnand不支持,導(dǎo)致通訊失敗,因此建議先將此值設(shè)大點(或查看SD卡/SDnand手冊,或先設(shè)一個較大值,軟件完成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,作為觸發(fā)引腳
image.php?url=YD_cnt_77_01Mx08PfCgh3

編輯

?

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

編輯

?

10.配置調(diào)試串口,用來打印信息,此處我選擇USART1,大家可根據(jù)自己硬件環(huán)境自行選擇

image.php?url=YD_cnt_77_01Mx08OFrG9X

編輯

?

11.配置工程信息

  • 配置工程名
  • 選擇工程路徑
  • 配置應(yīng)用程序結(jié)構(gòu),我習(xí)慣選擇 Basic 結(jié)構(gòu)
  • 選擇IDE工具及版本
  • 修改堆棧大小,適當(dāng)改大一點,怕不夠用
image.php?url=YD_cnt_77_01Mx08NTJ89o

編輯

?

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

image.php?url=YD_cnt_77_01Mx08LoQemv

編輯

?

13.生成代碼

image.php?url=YD_cnt_77_01Mx08LBLxXn

編輯

?

3.2 SDIO時鐘配置說明

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

image.php?url=YD_cnt_77_01Mx08KVSMts

編輯

?

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

image.php?url=YD_cnt_77_01Mx08JPVVjB

?

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

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

image.php?url=YD_cnt_77_01Mx08IWsorx

?

關(guān)于AHB總線接口及SDIO適配器更多細(xì)節(jié),大家可自行閱讀參考手冊部分章節(jié)內(nèi)容,此處不做贅述。

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

image.php?url=YD_cnt_77_01Mx08HKsQvu

?

image.php?url=YD_cnt_77_01Mx08H2hi40

?

3.2 讀寫測試

3.2.1 添加讀寫測試代碼

  1. 1.使能 MicroLIB 微庫,否則調(diào)用 printf 函數(shù)會卡住
image.php?url=YD_cnt_77_01Mx08G9BZVO

?

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

image.php?url=YD_cnt_77_01Mx08FO8oOv

?

image.php?url=YD_cnt_77_01Mx08EYFRKS

?

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

  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 信息打印函數(shù),查看卡片信息

  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); //塊數(shù)量
  27. printf("Card BlockSize: %d \r\n",SDCardInfo.BlockSize); //塊大小
  28. printf("LogBlockNbr: %d \r\n",(uint32_t)(SDCardInfo.LogBlockNbr)); //邏輯塊數(shù)量
  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驅(qū)動函數(shù)接口

  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 *)"開發(fā)者社區(qū)的明天需要大家一同開源共創(chuàng),期待下一次你的分享,讓我們一同攜手共進(jìn),推動人類科技的發(fā)展!?。r\n\
  25. 創(chuàng)作不易,轉(zhuǎn)載請注明出處~\r\n\
  26. 更多文章敬請關(guān)注:愛出名的狗腿子\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上位機,測試結(jié)果如下:

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); //塊數(shù)量
  73. printf("Card BlockSize: %d \r\n",SDCardInfo.BlockSize); //塊大小
  74. printf("LogBlockNbr: %d \r\n",(uint32_t)(SDCardInfo.LogBlockNbr)); //邏輯塊數(shù)量
  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 *)"開發(fā)者社區(qū)的明天需要大家一同開源共創(chuàng),期待下一次你的分享,讓我們一同攜手共進(jìn),推動人類科技的發(fā)展?。?!\r\n\
  125. 創(chuàng)作不易,轉(zhuǎn)載請注明出處~\r\n\
  126. 更多文章敬請關(guān)注:愛出名的狗腿子\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,當(dāng)然也就可以只用通用的文件系統(tǒng)操作函數(shù)完成文件的讀寫,通用的文件系統(tǒng)操作API 在 ff.c 文件內(nèi),聲明在 ff.h 文件內(nèi),主要使用的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 */

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

3.3.1 修改讀寫測試代碼

修改3.2.1章節(jié)所使用的讀寫測試代碼,此處我們直接使用FATFS文件系統(tǒng)的讀寫函數(shù)接口,修改主函數(shù)如下,注意需要包含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. 開發(fā)者社區(qū)的明天需要大家一同開源共創(chuàng),期待下一次你的分享,讓我們一同攜手共進(jìn),推動人類科技的發(fā)展?。?!\r\n\
  9. 創(chuàng)作不易,轉(zhuǎn)載請注明出處~\r\n\
  10. 更多文章敬請關(guān)注:愛出名的狗腿子\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. /* 掛載文件系統(tǒng),掛載的時候會完成對應(yīng)硬件設(shè)備(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) { /* 檢測是否存在文件系統(tǒng),如果沒有則進(jìn)行格式化 */
  24. printf("未檢測到FATFS文件系統(tǒng),執(zhí)行格式化...\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:/ ,所以掛載的文件系統(tǒng)需要在此目錄下,當(dāng)然也可以是此目錄下的路徑,如0:/hello,但不能是其他目錄,如 1:/

image.php?url=YD_cnt_77_01Mx08CWe7Ji

?

測試結(jié)果如下:

image.php?url=YD_cnt_77_01Mx08BWSRPJ

?

main.c完整內(nèi)容如下:

  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); //塊數(shù)釿
  74. printf("Card BlockSize: %d \r\n",SDCardInfo.BlockSize); //塊大尿
  75. printf("LogBlockNbr: %d \r\n",(uint32_t)(SDCardInfo.LogBlockNbr)); //邏輯塊數(shù)釿
  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. 開發(fā)者社區(qū)的明天需要大家一同開源共創(chuàng),期待下一次你的分享,讓我們一同攜手共進(jìn),推動人類科技的發(fā)展!?。r\n\
  96. 創(chuàng)作不易,轉(zhuǎn)載請注明出處~\r\n\
  97. 更多文章敬請關(guān)注:愛出名的狗腿子\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. /* 掛載文件系統(tǒng),掛載的時候會完成對應(yīng)硬件設(shè)備(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) { /* 檢測是否存在文件系統(tǒng),如果沒有則進(jìn)行格式化 */
  124. printf("未檢測到FATFS文件系統(tǒng),執(zhí)行格式化...\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

測試發(fā)現(xiàn),使用CubeMx當(dāng)前最新版本:V6.8.0版本,生成代碼會存在以下問題:

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

經(jīng)過仔細(xì)分析代碼后發(fā)現(xiàn),出現(xiàn)的問題在 MX_SDIO_SD_Init() 此初始化函數(shù)內(nèi)的配置項錯誤導(dǎo)致,具體分析如下:

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

BSP_SD_Init()

??->HAL_SD_Init()

????->HAL_SD_InitCard()

在 HAL_SD_InitCard() 函數(shù)內(nèi)使用Init結(jié)構(gòu)體配置SDIO外設(shè),總線寬度1bit,時鐘速度<400k,以進(jìn)行卡片的初始化識別。

??????-> SD_InitCard()

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

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

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

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

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

?? -> HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B)

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

6.通過以上分析可知,MX_SDIO_SD_Init() 函數(shù)內(nèi)對 hsd.Init.BusWide = SDIO_BUS_WIDE_4B; 的配置會導(dǎo)致對SD卡塊大小的配置失敗,從而導(dǎo)致后續(xù)讀寫時失敗,報錯為塊大小設(shè)置失?。?/p>

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

3.4.2 SD插入檢測引腳配置

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

對應(yīng)代碼如下,輸入檢測 IO 低電平有效!

image.php?url=YD_cnt_77_01Mx088b2Vk2

?

image.php?url=YD_cnt_77_01Mx08Ds3I5r

?

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

image.php?url=YD_cnt_77_01Mx08AGoLIZ

?

4. 結(jié)束語

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

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

【本文轉(zhuǎn)載自CSDN,作者: 愛出名的狗腿子】

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • SD卡
    +關(guān)注

    關(guān)注

    2

    文章

    554

    瀏覽量

    63683
  • FATFS
    +關(guān)注

    關(guān)注

    0

    文章

    44

    瀏覽量

    18233
收藏 人收藏

    評論

    相關(guān)推薦

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

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

    請問如何用STM32芯片讀寫SD?

    如何用STM32芯片讀寫SD
    發(fā)表于 07-03 07:08

    SD NAND和SPI NAND的區(qū)別

    SD NAND和SPI NAND各有優(yōu)缺點,適用于不同的應(yīng)用場景。SD NAND提供更高的讀寫
    的頭像 發(fā)表于 06-04 14:26 ?1567次閱讀

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

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

    請問使用STM32F1能實現(xiàn)USB和fatfs同時訪問SD嗎?

    使用STM32F1能實現(xiàn)USB和fatfs同時訪問SD嗎,想實現(xiàn)1S寫一次數(shù)據(jù)到
    發(fā)表于 04-23 07:48

    STM32F412使用SD,SDIO,FATFS系統(tǒng),SD掛載文件系統(tǒng)失敗的原因?

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

    關(guān)于stm32cubemx usb讀卡和fatfs兼容問題求解

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

    stm32 CubeMx 怎么實現(xiàn)SD/sd nand FATFS讀寫測試

    本實驗僅用于記錄和分享技術(shù)經(jīng)驗若涉及侵權(quán)請聯(lián)系我刪除。   stm32 CubeMx 實現(xiàn)SD/sd
    發(fā)表于 01-09 17:37

    什么是SD NAND存儲芯片? SD NAND與TF的區(qū)別

    什么是SD NAND?它俗稱貼片式T,貼片式TF,貼片式SD,貼片式內(nèi)存
    的頭像 發(fā)表于 01-06 14:35 ?1534次閱讀
    什么是<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>的區(qū)別

    什么是SD NAND存儲芯片?

    標(biāo)準(zhǔn)驅(qū)動代碼,省去了驅(qū)動代碼編程環(huán)節(jié)。支持TF啟動的SOC都可以用SD NAND,提供STM32參考例程及原廠技術(shù)支持,主流容量:128MB/512MB/2GB/4GB/8GB,比T
    發(fā)表于 01-05 17:54

    基于Zynq FPGA對雷龍SD NAND測試

    簡介??雷龍的SDNAND有很多型號,在測試中使用的是CSNP4GCR01-AWM與CSNP32GCR01-AOW。芯片是基于NANDFLASH和SD控制器實現(xiàn)
    的頭像 發(fā)表于 12-22 17:45 ?468次閱讀
    基于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 ??文件系統(tǒng):FATFS ??SD接口:SD2.0 3.1 測試流程 ??本次測試
    發(fā)表于 12-22 17:43

    基于RT-Thread快速上手SD NAND 虛擬文件系統(tǒng)

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

    DSP+FPGA+FATFS+SD

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

    基于NIOS II的SD讀寫控制設(shè)計

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