色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

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

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

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

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

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

文章目錄

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

1. 前言

2. 環(huán)境介紹

2.1 軟硬件說明

2.2 外設(shè)原理圖

3. 工程搭建

3.1 CubeMx 配置

3.2 SDIO時(shí)鐘配置說明

3.2 讀寫測(cè)試

3.2.1 添加讀寫測(cè)試代碼

3.3 FATFS文件操作

3.3.1 修改讀寫測(cè)試代碼

3.4 配置問題記錄

3.4.1 CubeMx生成代碼bug

3.4.2 SD插入檢測(cè)引腳配置

4. 結(jié)束語

1. 前言

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

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

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

2. 環(huán)境介紹

2.1 軟硬件說明

硬件環(huán)境:

主控:stm32f103vet6

SD nand: CSNP1GCR01-AOW【樣品CS創(chuàng)世SD NAND由深圳市雷龍發(fā)展有限公司免費(fèi)提供的,感興趣的可到雷龍官網(wǎng)申請(qǐ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.搜索對(duì)應(yīng)的芯片型號(hào),在對(duì)應(yīng)列表下方選擇對(duì)應(yīng)芯片
  2. 3.配置時(shí)鐘方案,采用外部高速時(shí)鐘,無源晶振方案
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線寬度,因此如果你實(shí)在不知道你的SD卡支持幾線寬度,你可以直接選擇1線寬度!4線和1線寬度的差別也就在于速度上相差了4倍!
  2. (注意這里暫時(shí)不需要對(duì)SDIO的參數(shù)進(jìn)行配置,后面我們?cè)倩貋砼渲茫?
image.php?url=YD_cnt_77_01Mx08Trm7ST

?

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

?

  1. 7.
  2. 修改SDIO參數(shù)配置,主要是修改SDIOCLK的分頻
  • 由于我們上述配置的SDIO時(shí)鐘為 72M,而SD卡支持的通訊速率在0MHz至25MHz之間,因此我們需要分頻,配置 SDIO Clock divider bypass 為 Disable
  • 此處設(shè)置 SDIOCLK clock divide factor CLKDIV分頻系數(shù)為 8,這個(gè)受限于具體的SD卡支持的最大速度。如果設(shè)置值較小,可能由于SDIO_CK速度過高,SD卡/SDnand不支持,導(dǎo)致通訊失敗,因此建議先將此值設(shè)大點(diǎn)(或查看SD卡/SDnand手冊(cè),或先設(shè)一個(gè)較大值,軟件完成SD信息讀取后再配置)
  • 注意這個(gè)配置的時(shí)鐘是用于SD讀寫通訊時(shí)候的時(shí)鐘,而不是SD卡信息識(shí)別過程時(shí)的速度!
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卡檢測(cè)引腳,有以下兩種方案

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

編輯

?

  • 方案二:不配置輸入IO,最后生成代碼的時(shí)候無視警報(bào)即可,生成的代碼會(huì)自動(dòng)取消輸入檢測(cè)判斷
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)改大一點(diǎn),怕不夠用
image.php?url=YD_cnt_77_01Mx08NTJ89o

編輯

?

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

image.php?url=YD_cnt_77_01Mx08LoQemv

編輯

?

13.生成代碼

image.php?url=YD_cnt_77_01Mx08LBLxXn

編輯

?

3.2 SDIO時(shí)鐘配置說明

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

image.php?url=YD_cnt_77_01Mx08KVSMts

編輯

?

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

image.php?url=YD_cnt_77_01Mx08JPVVjB

?

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

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

image.php?url=YD_cnt_77_01Mx08IWsorx

?

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

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

image.php?url=YD_cnt_77_01Mx08HKsQvu

?

image.php?url=YD_cnt_77_01Mx08H2hi40

?

3.2 讀寫測(cè)試

3.2.1 添加讀寫測(cè)試代碼

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

?

2.修改編碼規(guī)則為 UTF-8,這是由于我們CubeMx中配置的FATFS的編碼格式為 UTF-8導(dǎo)致,如果不修改為 UTF-8 則部分中文會(huì)亂碼! //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); //計(jì)算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)); //卡版本號(hào)
  24. printf("Class: %d \r\n",(uint32_t)(SDCardInfo.Class)); //SD卡類別
  25. printf("Card RCA(RelCardAdd):%d \r\n",SDCardInfo.RelCardAdd); //卡相對(duì)地址
  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.添加初始化及讀寫測(cè)試代碼,注意此處我們沒有直接使用FATFS的讀寫接口,我們先測(cè)試生成的SD驅(qū)動(dòng)函數(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. /* ...省略若干自動(dòng)生成代碼... */
  8. /* USER CODE BEGIN 2 */
  9. SD_Driver.disk_initialize(0);
  10. printf_sdcard_info();
  11. printf("\r\n\r\n********** 英文讀寫測(cè)試 **********\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********** 中文讀寫測(cè)試 **********\r\n");
  23. ret = SD_Driver.disk_write(0,
  24. (BYTE *)"開發(fā)者社區(qū)的明天需要大家一同開源共創(chuàng),期待下一次你的分享,讓我們一同攜手共進(jìn),推動(dòng)人類科技的發(fā)展!!!\r\n\
  25. 創(chuàng)作不易,轉(zhuǎn)載請(qǐng)注明出處~\r\n\
  26. 更多文章敬請(qǐng)關(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.修改燒錄器配置,配置為燒錄后自動(dòng)運(yùn)行

image.php?url=YD_cnt_77_01Mx08M2ko1H

?

7.下載測(cè)試,這里由于我們采用UTF-8編碼,所以使用的串口上位機(jī)也需要支持UTF-8解析,我們這里使用Mobaxterm上位機(jī),測(cè)試結(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); //計(jì)算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)); //卡版本號(hào)
  70. printf("Class: %d \r\n",(uint32_t)(SDCardInfo.Class)); //SD卡類別
  71. printf("Card RCA(RelCardAdd):%d \r\n",SDCardInfo.RelCardAdd); //卡相對(duì)地址
  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********** 英文讀寫測(cè)試 **********\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********** 中文讀寫測(cè)試 **********\r\n");
  123. ret = SD_Driver.disk_write(0,
  124. (BYTE *)"開發(fā)者社區(qū)的明天需要大家一同開源共創(chuàng),期待下一次你的分享,讓我們一同攜手共進(jìn),推動(dòng)人類科技的發(fā)展!!!\r\n\
  125. 創(chuàng)作不易,轉(zhuǎn)載請(qǐng)注明出處~\r\n\
  126. 更多文章敬請(qǐng)關(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 修改讀寫測(cè)試代碼

修改3.2.1章節(jié)所使用的讀寫測(cè)試代碼,此處我們直接使用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),推動(dòng)人類科技的發(fā)展!!!\r\n\
  9. 創(chuàng)作不易,轉(zhuǎn)載請(qǐng)注明出處~\r\n\
  10. 更多文章敬請(qǐng)關(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),掛載的時(shí)候會(huì)完成對(duì)應(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) { /* 檢測(cè)是否存在文件系統(tǒng),如果沒有則進(jìn)行格式化 */
  24. printf("未檢測(cè)到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. /* 讀寫測(cè)試 */
  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初始化的時(shí)候鏈接的根目錄為 0:/ ,所以掛載的文件系統(tǒng)需要在此目錄下,當(dāng)然也可以是此目錄下的路徑,如0:/hello,但不能是其他目錄,如 1:/

image.php?url=YD_cnt_77_01Mx08CWe7Ji

?

測(cè)試結(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); //計(jì)算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)); //卡版本號(hào)
  71. printf("Class: %d \r\n",(uint32_t)(SDCardInfo.Class)); //SD卡類劌
  72. printf("Card RCA(RelCardAdd):%d \r\n",SDCardInfo.RelCardAdd); //卡相對(duì)地坿
  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),推動(dòng)人類科技的發(fā)展!!!\r\n\
  96. 創(chuàng)作不易,轉(zhuǎn)載請(qǐng)注明出處~\r\n\
  97. 更多文章敬請(qǐng)關(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),掛載的時(shí)候會(huì)完成對(duì)應(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) { /* 檢測(cè)是否存在文件系統(tǒng),如果沒有則進(jìn)行格式化 */
  124. printf("未檢測(cè)到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. /* 讀寫測(cè)試 */
  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

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

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

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

  1. 我們?cè)贑ubeMx里面配置的時(shí)候選擇的是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線模式,對(duì)應(yīng)的初始化項(xiàng)也使用4線模式,但是不然,我們繼續(xù)分析 MX_SDIO_SD_Init() 此初始配置的調(diào)用
  4. MX_SDIO_SD_Init() 此函數(shù)在main函數(shù)內(nèi)初始化的時(shí)候調(diào)用,此函數(shù)只配置了 hsd 結(jié)構(gòu)體,并未配置給SDIO硬件寄存器
  5. 之后調(diào)用 SD_Driver.disk_initialize(0); 函數(shù)的時(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,時(shí)鐘速度<400k,以進(jìn)行卡片的初始化識(shí)別。

??????-> SD_InitCard()

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

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

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

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

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

?? -> 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)對(duì) hsd.Init.BusWide = SDIO_BUS_WIDE_4B; 的配置會(huì)導(dǎo)致對(duì)SD卡塊大小的配置失敗,從而導(dǎo)致后續(xù)讀寫時(shí)失敗,報(bào)錯(cuò)為塊大小設(shè)置失敗!

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

3.4.2 SD插入檢測(cè)引腳配置

使用CubeMx配置FATFS 選擇 SD Card 之后,有一個(gè)配置參數(shù),用來配置SD Card的輸入檢測(cè)引腳。如果我們?cè)谟布嫌性O(shè)計(jì)SD卡的卡槽插入檢測(cè)引腳插入連接到了MCU的IO,則可配置對(duì)應(yīng)IO為輸入模式,并設(shè)置對(duì)應(yīng)IO為輸入檢測(cè)引腳,比如,我們?cè)O(shè)置PD12為輸入檢測(cè)引腳,則配置如下:

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

image.php?url=YD_cnt_77_01Mx088b2Vk2

?

image.php?url=YD_cnt_77_01Mx08Ds3I5r

?

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

image.php?url=YD_cnt_77_01Mx08AGoLIZ

?

4. 結(jié)束語

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

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

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

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

    關(guān)注

    2

    文章

    566

    瀏覽量

    63980
  • FATFS
    +關(guān)注

    關(guān)注

    0

    文章

    44

    瀏覽量

    18319
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    關(guān)于SD NAND 的概述

    SD NAND是一種小型、可表面貼裝的存儲(chǔ)解決方案,適用于各種嵌入式系統(tǒng)和便攜式設(shè)備。SD NAND技術(shù)是近年來在存儲(chǔ)領(lǐng)域內(nèi)的一項(xiàng)創(chuàng)新,它結(jié)合了傳統(tǒng)
    發(fā)表于 12-06 11:22

    SD NAND 概述

    SD NAND是一種小型、可表面貼裝的存儲(chǔ)解決方案,適用于各種嵌入式系統(tǒng)和便攜式設(shè)備。SD NAND技術(shù)是近年來在存儲(chǔ)領(lǐng)域內(nèi)的一項(xiàng)創(chuàng)新,它結(jié)合了傳統(tǒng)
    的頭像 發(fā)表于 12-06 11:21 ?209次閱讀

    SD NAND技術(shù)簡介

    SD NAND是一種基于NAND Flash技術(shù)的嵌入式存儲(chǔ)解決方案,具備SD協(xié)議兼容性。它結(jié)合了NA
    的頭像 發(fā)表于 12-05 15:32 ?203次閱讀
    <b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>技術(shù)簡介

    雷龍CS SD NAND:貼片式TF體驗(yàn)與性能測(cè)試

    最近有幸獲得了雷龍發(fā)展提供的貼片式TF樣品,收到的快遞中包含兩片 CS SD NAND 芯片和一個(gè)轉(zhuǎn)接板。以下是芯片和轉(zhuǎn)接板的實(shí)物照片: 產(chǎn)品簡介 此次測(cè)試的芯片型號(hào)
    發(fā)表于 11-26 10:04

    Arduino程序:實(shí)現(xiàn)SD NAND(貼片sd)的讀寫功能

      單片機(jī)上傳程序的時(shí)候,有時(shí)候感覺它的rom和 ram有時(shí)直接限制了他的使用,之前使用eeprom,和sd模塊. []()   然后最近看到了出的SD NAND 就是下面這個(gè)
    發(fā)表于 11-07 17:45

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

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

    請(qǐng)問如何用STM32芯片讀寫SD

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

    SD、MicroSDSD NAND的性能與應(yīng)用對(duì)比

    在當(dāng)前豐富多元的存儲(chǔ)解決方案領(lǐng)域,SD、MicroSD以及SD NAND憑借其各自的獨(dú)特優(yōu)勢(shì)和特定的使用情景,贏得了市場(chǎng)的廣泛認(rèn)可。每種
    的頭像 發(fā)表于 06-14 15:48 ?923次閱讀
    <b class='flag-5'>SD</b><b class='flag-5'>卡</b>、MicroSD<b class='flag-5'>卡</b>和<b class='flag-5'>SD</b> <b class='flag-5'>NAND</b>的性能與應(yīng)用對(duì)比

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

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

    SD NAND 簡介

    SD NAND是一種創(chuàng)新的存儲(chǔ)芯片,可直接貼片,又名貼片式TF、貼片式T、貼片式SD、貼片
    的頭像 發(fā)表于 05-29 16:34 ?1257次閱讀
    <b class='flag-5'>SD</b> <b class='flag-5'>NAND</b> 簡介

    NAND Flash(貼片式TF)存儲(chǔ)新突破,基礎(chǔ)示例

    F407ZG;   STM32CubeMX;   Keil;   SD NAND:芯片型號(hào) CSNP4GCR01-AMW;芯片轉(zhuǎn)接板(將芯片引腳引出為TF )  ** 硬件設(shè)備及電
    發(fā)表于 05-21 17:13

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

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

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

    使用STM32F1能實(shí)現(xiàn)USB和fatfs同時(shí)訪問SD嗎,想實(shí)現(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上驗(yàn)證過,F(xiàn)103 CUBEMX版本好像是5.0的,可以直接運(yùn)行SD
    發(fā)表于 04-11 07:15

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

    芯片使用STM32F411,使能SDIO,四線接SD 使用stm32cubemx直接生成USB device,大容量儲(chǔ)存設(shè)備,可以在電腦上看到U盤,使用
    發(fā)表于 04-01 06:09
    主站蜘蛛池模板: 99热久久这里只精品国产WWW| 久久精品国产免费播放| 久久大综合| 丁香成人网址| 久久国产主播福利在线| 色拍拍噜噜噜久久蜜桃| 69国产精品人妻无码免费| 国产精品.XX视频.XXTV| 麻豆免费高清完整版| 亚洲高清国产品国语在线观看| 99国产精品人妻无码免费| 亚洲精品免播放器在线观看| 成人性生交大片免费看4| 久久视频这里只精品99re8久| 偷尝禁果H1V1幸运的山熊| wwwzzz日本| 美女露出乳胸扒开尿口| 亚洲综合国产精品| 国产成人啪精视频精东传媒网站| 蜜桃人妻无码AV天堂三区| 妖精视频在线观看高清| 国产精品永久免费视频| 日韩1区1区产品乱码芒果榴莲| 97草碰在线视频免费| 久久一级片| 在线亚洲中文精品第1页| 精品久久久久中文字幕日本 | 动漫美女喷水| 美国69xxxx59| 在线播放午夜理论片| 娇女的呻吟亲女禁忌h16| 亚洲AV无码一区二区三区乱子伦| 国产v综合v亚洲欧美大片| 日本人bbwbbwbbwbbw| tobu中国日本高清| 欧美日韩在线成人看片a| music radio在线收听| 桥本有菜黑丝| 俄罗斯12一15处交| 极品少妇伦理一区二区| 快穿做妓女好爽H|