【STM32】SD卡讀寫(五)-STM32CubeMX HAL庫SPI操作 SD卡帶FATFS

1、添加SD卡SPI模式驅動

  1. /**
  2. * @brief SPI1 Initialization Function
  3. * @param None
  4. * @retval None
  5. */
  6. static void MX_SPI1_Init(void)
  7. {
  8. /* USER CODE BEGIN SPI1_Init 0 */
  9. /* USER CODE END SPI1_Init 0 */
  10. /* USER CODE BEGIN SPI1_Init 1 */
  11. /* USER CODE END SPI1_Init 1 */
  12. /* SPI1 parameter configuration*/
  13. hspi1.Instance = SPI1;
  14. hspi1.Init.Mode = SPI_MODE_MASTER;
  15. hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  16. hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  17. hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  18. hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  19. hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT;
  20. hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
  21. hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  22. hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  23. hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  24. hspi1.Init.CRCPolynomial = 10;
  25. if (HAL_SPI_Init(&hspi1) != HAL_OK)
  26. {
  27. Error_Handler();
  28. }
  29. /* USER CODE BEGIN SPI1_Init 2 */
  30. /* USER CODE END SPI1_Init 2 */
  31. }

編寫SD卡SPI驅動 SDCard.c

  1. #include "main.h"
  2. #include "SDCard.h"
  3. /* USER CODE BEGIN 0 */
  4. /* USER CODE END 0 */
  5. /* USART1 init function */
  6. /**************************************************************************/
  7. #define Dummy_Byte 0xFF
  8. /* 私有變量 ------------------------------------------------------------------*/
  9. SPI_HandleTypeDef hspiflash;
  10. extern SPI_HandleTypeDef hspi1;
  11. u8 SD_Type=0;
  12. /* function ------------------------------------------------------------------*/
  13. /**
  14. * 函數功能: 從串行Flash讀取一個字節數據
  15. * 輸入參數: 無
  16. * 返 回 值: uint8_t:讀取到的數據
  17. * 說 明:This function must be used only if the Start_Read_Sequence
  18. * function has been previously called.
  19. */
  20. uint8_t SPI_FLASH_ReadByte(void)
  21. {
  22. uint8_t d_read,d_send=Dummy_Byte;
  23. if(HAL_SPI_TransmitReceive(&hspiflash,&d_send,&d_read,1,0xFFFFFF)!=HAL_OK)
  24. d_read=Dummy_Byte;
  25. return d_read;
  26. }
  27. void SPI_I2S_SendData(SPI_TypeDef* SPIx, u16 Data)
  28. {
  29. /* Check the parameters */
  30. assert_param(IS_SPI_ALL_PERIPH(SPIx));
  31. /* Write in the DR register the data to be sent */
  32. SPIx->DR = Data;
  33. }
  34. u16 SPI_I2S_ReceiveData(SPI_TypeDef* SPIx)
  35. {
  36. /* Check the parameters */
  37. assert_param(IS_SPI_ALL_PERIPH(SPIx));
  38. //assert_param(IS_SPI_DIRECTION_2LINES_OR_1LINE(hspi->Init.Direction));
  39. /* Return the data in the DR register */
  40. return SPIx->DR;
  41. }
  42. /**
  43. * 函數功能: 往串行Flash讀取寫入一個字節數據並接收一個字節數據
  44. * 輸入參數: byte:待發送數據
  45. * 返 回 值: uint8_t:接收到的數據
  46. * 說 明:無
  47. */
  48. uint8_t SPI_FLASH_SendByte(uint8_t byte)
  49. {
  50. uint8_t d_read,d_send=byte;
  51. // if(HAL_SPI_TransmitReceive(&hspiflash,&d_send,&d_read,1,0xFFFFFF)!=HAL_OK)
  52. //{
  53. //d_read=Dummy_Byte;
  54. //}
  55. //等待發送緩衝區空
  56. // while(__HAL_SPI_GET_FLAG(&hspi1, SPI_FLAG_TXE));
  57. //發一個字節
  58. // SPI_I2S_SendData(SPI1, d_send);
  59. HAL_SPI_Transmit(&hspi1,&d_send,1,1000);
  60. //HAL_SPI_Receive(&hspi1,&d_read,1,1000);
  61. //等待數據接收
  62. while(__HAL_SPI_GET_FLAG(&hspi1, SPI_FLAG_RXNE));
  63. //取數據
  64. d_read = SPI_I2S_ReceiveData(SPI1);
  65. return d_read;
  66. }
  67. /*******************************************************************************
  68. * Function Name : SD_WaitReady
  69. * Description : 等待SD卡Ready
  70. * Input : None
  71. * Output : None
  72. * Return : u8
  73. * 0: 成功
  74. * other:失敗
  75. *******************************************************************************/
  76. u8 SD_WaitReady(void)
  77. {
  78. u8 r1;
  79. u16 retry;
  80. retry = 0;
  81. do
  82. {
  83. r1 = SPI_FLASH_SendByte(0xFF);
  84. if(retry==0xfffe)
  85. {
  86. return 1;
  87. }
  88. }while(r1!=0xFF);
  89. return 0;
  90. }
  91. /*******************************************************************************
  92. * Function Name : SD_SendCommand
  93. * Description : 向SD卡發送一個命令
  94. * Input : u8 cmd 命令
  95. * u32 arg 命令參數
  96. * u8 crc crc校驗值
  97. * Output : None
  98. * Return : u8 r1 SD卡返回的響應
  99. *******************************************************************************/
  100. u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc)
  101. {
  102. unsigned char r1;
  103. unsigned char Retry = 0;
  104. //????????
  105. SPI_FLASH_SendByte(0xff);
  106. //片選端置低,選中SD卡
  107. FLASH_SPI_CS_ENABLE();
  108. //發送
  109. SPI_FLASH_SendByte(cmd | 0x40); //分別寫入命令
  110. SPI_FLASH_SendByte(arg >> 24);
  111. SPI_FLASH_SendByte(arg >> 16);
  112. SPI_FLASH_SendByte(arg >> 8);
  113. SPI_FLASH_SendByte(arg);
  114. SPI_FLASH_SendByte(crc);
  115. //等待響應,或超時退出
  116. while((r1 = SPI_FLASH_SendByte(0xFF))==0xFF)
  117. {
  118. Retry++;
  119. if(Retry > 200)
  120. {
  121. break;
  122. }
  123. }
  124. //關閉片選
  125. FLASH_SPI_CS_DISABLE();
  126. //在總線上額外增加8個時鐘,讓SD卡完成剩下的工作
  127. SPI_FLASH_SendByte(0xFF);
  128. //返回狀態值
  129. return r1;
  130. }
  131. /*******************************************************************************
  132. * Function Name : SD_SendCommand_NoDeassert
  133. * Description : 向SD卡發送一個命令(結束是不失能片選,還有後續數據傳來)
  134. * Input : u8 cmd 命令
  135. * u32 arg 命令參數
  136. * u8 crc crc校驗值
  137. * Output : None
  138. * Return : u8 r1 SD卡返回的響應
  139. *******************************************************************************/
  140. u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc)
  141. {
  142. unsigned char r1;
  143. unsigned char Retry = 0;
  144. //????????
  145. SPI_FLASH_SendByte(0xff);
  146. //片選端置低,選中SD卡
  147. FLASH_SPI_CS_ENABLE();
  148. //發送
  149. SPI_FLASH_SendByte(cmd | 0x40); //分別寫入命令
  150. SPI_FLASH_SendByte(arg >> 24);
  151. SPI_FLASH_SendByte(arg >> 16);
  152. SPI_FLASH_SendByte(arg >> 8);
  153. SPI_FLASH_SendByte(arg);
  154. SPI_FLASH_SendByte(crc);
  155. //等待響應,或超時退出
  156. while((r1 = SPI_FLASH_SendByte(0xFF))==0xFF)
  157. {
  158. Retry++;
  159. if(Retry > 200)
  160. {
  161. break;
  162. }
  163. }
  164. //返回響應值
  165. return r1;
  166. }
  167. void SPI_SetSpeed(u8 SpeedSet)
  168. {
  169. hspi1.Instance = SPI1;
  170. hspi1.Init.Mode = SPI_MODE_MASTER;
  171. hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  172. hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  173. hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  174. hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  175. hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT;
  176. //如果速度設置輸入0,則低速模式,非0則高速模式
  177. if(SpeedSet==SPI_SPEED_LOW)
  178. {
  179. hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
  180. }
  181. else
  182. {
  183. hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  184. }
  185. hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  186. hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  187. hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  188. hspi1.Init.CRCPolynomial = 10;
  189. if (HAL_SPI_Init(&hspi1) != HAL_OK)
  190. {
  191. Error_Handler();
  192. }
  193. // if(SpeedSet==SPI_SPEED_LOW)
  194. //{
  195. // hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
  196. //}
  197. //else
  198. //{
  199. //hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  200. //}
  201. //HAL_SPI_Init(&hspi1);
  202. //moon.mp3: 4707774 Byte size 目標文件 設為buffer[512]
  203. //speed:實驗測試數據,最大速度 392314 Byte/S,
  204. //Prescaler_128, 59592 Byte/S
  205. //Prescaler_64, 104617 Byte/S
  206. //Prescaler_32, 168134 Byte/S 162337 Byte/S
  207. //Prescaler_16, 261543 Byte/S 247777 Byte/S
  208. //Prescaler_8, 313851 Byte/S 336269 Byte/S
  209. //Prescaler_4, 392314 Byte/S 392314 Byte/S
  210. //Prescaler_2, 392314 Byte/S
  211. }
  212. /*******************************************************************************
  213. * Function Name : SD_Init
  214. * Description : 初始化SD卡
  215. * Input : None
  216. * Output : None
  217. * Return : u8
  218. * 0:NO_ERR
  219. * 1:TIME_OUT
  220. * 99:NO_CARD
  221. *******************************************************************************/
  222. u8 SD_Init(void)
  223. {
  224. u16 i; // 用來循環計數
  225. u8 r1; // 存放SD卡的返回值
  226. u16 retry; // 用來進行超時計數
  227. u8 buff[6];
  228. //如果沒有檢測到卡插入,直接退出,返回錯誤標誌
  229. // if(!SD_DET())
  230. // {
  231. // //return 99;
  232. // return STA_NODISK; // FatFS錯誤標誌:沒有插入磁盤
  233. // }
  234. //SD卡上電
  235. //SD_PWR_ON();
  236. // 純延時,等待SD卡上電完成
  237. //for(i=0;i<0xf00;i++);
  238. /*******************************************************
  239. //這個地方要加一句,設置SPI速度為低速。
  240. //為什麼有的卡可以呢?因為SPI初始化時是低速的,SD卡初始化
  241. //完成後設置為高速,有的卡只要初始化一次就行,程序就ok;
  242. //但有的卡需要多次復位,呵呵,這個地方差這一句,
  243. //這種卡就用不成咯!
  244. *******************************************************/
  245. SPI_SetSpeed(0); //設置SPI速度為低速
  246. //先產生>74個脈衝,讓SD卡自己初始化完成
  247. for(i=0;i<100;i++)
  248. {
  249. SPI_FLASH_SendByte(0xFF);
  250. }
  251. //-----------------SD卡復位到idle開始-----------------
  252. //循環連續發送CMD0,直到SD卡返回0x01,進入IDLE狀態
  253. //超時則直接退出
  254. retry = 0;
  255. do
  256. {
  257. //發送CMD0,讓SD卡進入IDLE狀態
  258. r1 = SD_SendCommand(CMD0, 0, 0x95);
  259. retry++;
  260. }while((r1 != 0x01) && (retry<200));
  261. //跳出循環後,檢查原因:初始化成功?or 重試超時?
  262. if(retry==200)
  263. {
  264. return 1; //超時返回1
  265. }
  266. //-----------------SD卡復位到idle結束-----------------
  267. //獲取卡片的SD版本信息
  268. r1 = SD_SendCommand_NoDeassert(8, 0x1aa, 0x87);
  269. //如果卡片版本信息是v1.0版本的,即r1=0x05,則進行以下初始化
  270. if(r1 == 0x05)
  271. {
  272. printf("\\r\\n SD卡版本信息:V1.0 \\r\\n");
  273. //設置卡類型為SDV1.0,如果後面檢測到為MMC卡,再修改為MMC
  274. SD_Type = SD_TYPE_V1;
  275. //如果是V1.0卡,CMD8指令後沒有後續數據
  276. //片選置高,結束本次命令
  277. FLASH_SPI_CS_DISABLE();
  278. //多發8個CLK,讓SD結束後續操作
  279. SPI_FLASH_SendByte(0xFF);
  280. //-----------------SD卡、MMC卡初始化開始-----------------
  281. //髮卡初始化指令CMD55+ACMD41
  282. // 如果有應答,說明是SD卡,且初始化完成
  283. // 沒有回應,說明是MMC卡,額外進行相應初始化
  284. retry = 0;
  285. do
  286. {
  287. //先發CMD55,應返回0x01;否則出錯
  288. r1 = SD_SendCommand(CMD55, 0, 0);
  289. if(r1 != 0x01)
  290. {
  291. return r1;
  292. }
  293. //得到正確響應後,發ACMD41,應得到返回值0x00,否則重試200次
  294. r1 = SD_SendCommand(ACMD41, 0, 0);
  295. retry++;
  296. }while((r1!=0x00) && (retry<400));
  297. // 判斷是超時還是得到正確回應
  298. // 若有回應:是SD卡;沒有回應:是MMC卡
  299. //----------MMC卡額外初始化操作開始------------
  300. if(retry==400)
  301. {
  302. printf("\\r\\n SD卡信息: MMC卡 \\r\\n");
  303. retry = 0;
  304. //發送MMC卡初始化命令(沒有測試)
  305. do
  306. {
  307. r1 = SD_SendCommand(1, 0, 0);
  308. retry++;
  309. }while((r1!=0x00)&& (retry<400));
  310. if(retry==400)
  311. {
  312. return 1; //MMC卡初始化超時
  313. }
  314. //寫入卡類型
  315. SD_Type = SD_TYPE_MMC;
  316. }
  317. else
  318. {
  319. printf("\\r\\n SD卡信息: SD卡 \\r\\n");
  320. }
  321. //----------MMC卡額外初始化操作結束------------
  322. //設置SPI為高速模式
  323. SPI_SetSpeed(1);
  324. SPI_FLASH_SendByte(0xFF);
  325. //禁止CRC校驗
  326. /*
  327. r1 = SD_SendCommand(CMD59, 0, 0x01);
  328. if(r1 != 0x00)
  329. {
  330. return r1; //命令錯誤,返回r1
  331. }
  332. */
  333. //設置Sector Size
  334. r1 = SD_SendCommand(CMD16, 512, 0xff);
  335. if(r1 != 0x00)
  336. {
  337. return r1; //命令錯誤,返回r1
  338. }
  339. //-----------------SD卡、MMC卡初始化結束-----------------
  340. }//SD卡為V1.0版本的初始化結束
  341. //下面是V2.0卡的初始化
  342. //其中需要讀取OCR數據,判斷是SD2.0還是SD2.0HC卡
  343. else if(r1 == 0x01)
  344. {
  345. printf("\\r\\n SD卡版本信息:V2.0 \\r\\n");
  346. //V2.0的卡,CMD8命令後會傳回4字節的數據,要跳過再結束本命令
  347. buff[0] = SPI_FLASH_SendByte(0xFF); //should be 0x00
  348. buff[1] = SPI_FLASH_SendByte(0xFF); //should be 0x00
  349. buff[2] = SPI_FLASH_SendByte(0xFF); //should be 0x01
  350. buff[3] = SPI_FLASH_SendByte(0xFF); //should be 0xAA
  351. FLASH_SPI_CS_DISABLE();
  352. //the next 8 clocks
  353. SPI_FLASH_SendByte(0xFF);
  354. //判斷該卡是否支持2.7V-3.6V的電壓範圍
  355. if(buff[2]==0x01 && buff[3]==0xAA)
  356. {
  357. //支持電壓範圍,可以操作
  358. retry = 0;
  359. //髮卡初始化指令CMD55+ACMD41
  360. do
  361. {
  362. r1 = SD_SendCommand(CMD55, 0, 0);
  363. if(r1!=0x01)
  364. {
  365. return r1;
  366. }
  367. r1 = SD_SendCommand(ACMD41, 0x40000000, 0);
  368. if(retry>200)
  369. {
  370. return r1; //超時則返回r1狀態
  371. }
  372. }while(r1!=0);
  373. //初始化指令發送完成,接下來獲取OCR信息
  374. //-----------鑑別SD2.0卡版本開始-----------
  375. r1 = SD_SendCommand_NoDeassert(CMD58, 0, 0);
  376. if(r1!=0x00)
  377. {
  378. return r1; //如果命令沒有返回正確應答,直接退出,返回應答
  379. }
  380. //讀OCR指令發出後,緊接著是4字節的OCR信息
  381. buff[0] = SPI_FLASH_SendByte(0xFF);
  382. buff[1] = SPI_FLASH_SendByte(0xFF);
  383. buff[2] = SPI_FLASH_SendByte(0xFF);
  384. buff[3] = SPI_FLASH_SendByte(0xFF);
  385. //OCR接收完成,片選置高
  386. FLASH_SPI_CS_DISABLE();
  387. SPI_FLASH_SendByte(0xFF);
  388. //檢查接收到的OCR中的bit30位(CCS),確定其為SD2.0還是SDHC
  389. //如果CCS=1:SDHC CCS=0:SD2.0
  390. if(buff[0]&0x40) //檢查CCS
  391. {
  392. SD_Type = SD_TYPE_V2HC;
  393. printf("\\r\\n SD卡信息: SDHC \\r\\n");
  394. }
  395. else
  396. {
  397. SD_Type = SD_TYPE_V2;
  398. printf("\\r\\n SD卡信息: SD2.0 \\r\\n");
  399. }
  400. //-----------鑑別SD2.0卡版本結束-----------
  401. //設置SPI為高速模式
  402. SPI_SetSpeed(1);
  403. }
  404. }
  405. return r1;
  406. }
  407. /*******************************************************************************
  408. * Function Name : SD_ReceiveData
  409. * Description : 從SD卡中讀回指定長度的數據,放置在給定位置
  410. * Input : u8 *data(存放讀回數據的內存>len)
  411. * u16 len(數據長度)
  412. * u8 release(傳輸完成後是否釋放總線CS置高 0:不釋放 1:釋放)
  413. * Output : None
  414. * Return : u8
  415. * 0:NO_ERR
  416. * other:錯誤信息
  417. *******************************************************************************/
  418. u8 SD_ReceiveData(u8 *data, u16 len, u8 release)
  419. {
  420. u16 retry;
  421. u8 r1;
  422. // 啟動一次傳輸
  423. FLASH_SPI_CS_ENABLE();
  424. //等待SD卡發回數據起始令牌0xFE
  425. retry = 0;
  426. do
  427. {
  428. r1 = SPI_FLASH_SendByte(0xFF);
  429. retry++;
  430. if(retry>2000) //2000次等待後沒有應答,退出報錯
  431. {
  432. FLASH_SPI_CS_DISABLE();
  433. return 1;
  434. }
  435. }while(r1 != 0xFE);
  436. //開始接收數據
  437. while(len--)
  438. {
  439. *data = SPI_FLASH_SendByte(0xFF);
  440. data++;
  441. }
  442. //下面是2個偽CRC(dummy CRC)
  443. SPI_FLASH_SendByte(0xFF);
  444. SPI_FLASH_SendByte(0xFF);
  445. //按需釋放總線,將CS置高
  446. if(release == RELEASE)
  447. {
  448. //傳輸結束
  449. FLASH_SPI_CS_DISABLE();
  450. SPI_FLASH_SendByte(0xFF);
  451. }
  452. return 0;
  453. }
  454. /*******************************************************************************
  455. * Function Name : SD_GetCID
  456. * Description : 獲取SD卡的CID信息,包括製造商信息
  457. * Input : u8 *cid_data(存放CID的內存,至少16Byte)
  458. * Output : None
  459. * Return : u8
  460. * 0:NO_ERR
  461. * 1:TIME_OUT
  462. * other:錯誤信息
  463. *******************************************************************************/
  464. u8 SD_GetCID(u8 *cid_data)
  465. {
  466. u8 r1;
  467. //發CMD10命令,讀CID
  468. r1 = SD_SendCommand(CMD10, 0, 0xFF);
  469. if(r1 != 0x00)
  470. {
  471. return r1; //沒返回正確應答,則退出,報錯
  472. }
  473. //接收16個字節的數據
  474. SD_ReceiveData(cid_data, 16, RELEASE);
  475. return 0;
  476. }
  477. /*******************************************************************************
  478. * Function Name : SD_GetCSD
  479. * Description : 獲取SD卡的CSD信息,包括容量和速度信息
  480. * Input : u8 *cid_data(存放CID的內存,至少16Byte)
  481. * Output : None
  482. * Return : u8
  483. * 0:NO_ERR
  484. * 1:TIME_OUT
  485. * other:錯誤信息
  486. *******************************************************************************/
  487. u8 SD_GetCSD(u8 *csd_data)
  488. {
  489. u8 r1;
  490. //發CMD9命令,讀CSD
  491. r1 = SD_SendCommand(CMD9, 0, 0xFF);
  492. if(r1 != 0x00)
  493. {
  494. return r1; //沒返回正確應答,則退出,報錯
  495. }
  496. //接收16個字節的數據
  497. SD_ReceiveData(csd_data, 16, RELEASE);
  498. return 0;
  499. }
  500. /*******************************************************************************
  501. * Function Name : SD_GetCapacity
  502. * Description : 獲取SD卡的容量
  503. * Input : None
  504. * Output : None
  505. * Return : u32 capacity
  506. * 0: 取容量出錯
  507. *******************************************************************************/
  508. u32 SD_GetCapacity(void)
  509. {
  510. u8 csd[16];
  511. u32 Capacity;
  512. u8 r1;
  513. u16 i;
  514. u16 temp;
  515. //取CSD信息,如果期間出錯,返回0
  516. if(SD_GetCSD(csd)!=0)
  517. {
  518. return 0;
  519. }
  520. //如果為SDHC卡,按照下面方式計算
  521. if((csd[0]&0xC0)==0x40)
  522. {
  523. Capacity = ((((u32)csd[8])<<8) + (u32)csd[9] + 1)*(u32)1024;
  524. }
  525. else
  526. {
  527. //下面代碼為網上版本
  528. ////////////formula of the capacity///////////////
  529. //
  530. // memory capacity = BLOCKNR * BLOCK_LEN
  531. //
  532. //BLOCKNR = (C_SIZE + 1)* MULT
  533. //
  534. // C_SIZE_MULT+2
  535. //MULT = 2
  536. //
  537. // READ_BL_LEN
  538. //BLOCK_LEN = 2
  539. /**********************************************/
  540. //C_SIZE
  541. i = csd[6]&0x03;
  542. i<<=8;
  543. i += csd[7];
  544. i<<=2;
  545. i += ((csd[8]&0xc0)>>6);
  546. //C_SIZE_MULT
  547. r1 = csd[9]&0x03;
  548. r1<<=1;
  549. r1 += ((csd[10]&0x80)>>7);
  550. //BLOCKNR
  551. r1+=2;
  552. temp = 1;
  553. while(r1)
  554. {
  555. temp*=2;
  556. r1--;
  557. }
  558. Capacity = ((u32)(i+1))*((u32)temp);
  559. // READ_BL_LEN
  560. i = csd[5]&0x0f;
  561. //BLOCK_LEN
  562. temp = 1;
  563. while(i)
  564. {
  565. temp*=2;
  566. i--;
  567. }
  568. //The final result
  569. Capacity *= (u32)temp;
  570. //Capacity /= 512;
  571. }
  572. return (u32)Capacity;
  573. }
  574. /*******************************************************************************
  575. * Function Name : SD_ReadSingleBlock
  576. * Description : 讀SD卡的一個block
  577. * Input : u32 sector 取地址(sector值,非物理地址)
  578. * u8 *buffer 數據存儲地址(大小至少512byte)
  579. * Output : None
  580. * Return : u8 r1
  581. * 0: 成功
  582. * other:失敗
  583. *******************************************************************************/
  584. u8 SD_ReadSingleBlock(u32 sector, u8 *buffer)
  585. {
  586. u8 r1;
  587. //設置為高速模式
  588. SPI_SetSpeed(SPI_SPEED_HIGH);
  589. //如果不是SDHC,將sector地址轉成byte地址
  590. //sector = sector<<9;
  591. r1 = SD_SendCommand(CMD17, sector, 0);//讀命令
  592. if(r1 != 0x00)
  593. {
  594. return r1;
  595. }
  596. r1 = SD_ReceiveData(buffer, 512, RELEASE);
  597. if(r1 != 0)
  598. {
  599. return r1; //讀數據出錯!
  600. }
  601. else
  602. {
  603. return 0;
  604. }
  605. }
  606. /*******************************************************************************
  607. * Function Name : SD_WriteSingleBlock
  608. * Description : 寫入SD卡的一個block
  609. * Input : u32 sector 扇區地址(sector值,非物理地址)
  610. * u8 *buffer 數據存儲地址(大小至少512byte)
  611. * Output : None
  612. * Return : u8 r1
  613. * 0: 成功
  614. * other:失敗
  615. *******************************************************************************/
  616. u8 SD_WriteSingleBlock(u32 sector, const u8 *data)
  617. {
  618. u8 r1;
  619. u16 i;
  620. u16 retry;
  621. //設置為高速模式
  622. SPI_SetSpeed(SPI_SPEED_HIGH);
  623. //如果不是SDHC,給定的是sector地址,將其轉換成byte地址
  624. // if(SD_Type!=SD_TYPE_V2HC)
  625. // {
  626. // sector = sector<<9;
  627. // }
  628. r1 = SD_SendCommand(CMD24, sector, 0x00);
  629. if(r1 != 0x00)
  630. {
  631. return r1; //應答不正確,直接返回
  632. }
  633. //開始準備數據傳輸
  634. FLASH_SPI_CS_ENABLE();
  635. //先放3個空數據,等待SD卡準備好
  636. SPI_FLASH_SendByte(0xff);
  637. SPI_FLASH_SendByte(0xff);
  638. SPI_FLASH_SendByte(0xff);
  639. //放起始令牌0xFE
  640. SPI_FLASH_SendByte(0xFE);
  641. //放一個sector的數據
  642. for(i=0;i<512;i++)
  643. {
  644. SPI_FLASH_SendByte(*data++);
  645. }
  646. //發2個Byte的dummy CRC
  647. SPI_FLASH_SendByte(0xff);
  648. SPI_FLASH_SendByte(0xff);
  649. //等待SD卡應答
  650. r1 = SPI_FLASH_SendByte(0xff);
  651. if((r1&0x1F)!=0x05)
  652. {
  653. FLASH_SPI_CS_DISABLE();
  654. return r1;
  655. }
  656. //等待操作完成
  657. retry = 0;
  658. while(!SPI_FLASH_SendByte(0xff))
  659. {
  660. retry++;
  661. if(retry>0xfffe) //如果長時間寫入沒有完成,報錯退出
  662. {
  663. FLASH_SPI_CS_DISABLE();
  664. return 1; //寫入超時返回1
  665. }
  666. }
  667. //寫入完成,片選置1
  668. FLASH_SPI_CS_DISABLE();
  669. SPI_FLASH_SendByte(0xff);
  670. return 0;
  671. }
  672. /*******************************************************************************
  673. * Function Name : SD_ReadMultiBlock
  674. * Description : 讀SD卡的多個block
  675. * Input : u32 sector 取地址(sector值,非物理地址)
  676. * u8 *buffer 數據存儲地址(大小至少512byte)
  677. * u8 count 連續讀count個block
  678. * Output : None
  679. * Return : u8 r1
  680. * 0: 成功
  681. * other:失敗
  682. *******************************************************************************/
  683. u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count)
  684. {
  685. u8 r1;
  686. //設置為高速模式
  687. SPI_SetSpeed(SPI_SPEED_HIGH);
  688. //如果不是SDHC,將sector地址轉成byte地址
  689. // sector = sector<<9;
  690. //SD_WaitReady();
  691. //發讀多塊命令
  692. r1 = SD_SendCommand(CMD18, sector, 0);//讀命令
  693. if(r1 != 0x00)
  694. {
  695. return r1;
  696. }
  697. //開始接收數據
  698. do
  699. {
  700. if(SD_ReceiveData(buffer, 512, NO_RELEASE) != 0x00)
  701. {
  702. break;
  703. }
  704. buffer += 512;
  705. } while(--count);
  706. //全部傳輸完畢,發送停止命令
  707. SD_SendCommand(CMD12, 0, 0);
  708. //釋放總線
  709. FLASH_SPI_CS_DISABLE();
  710. SPI_FLASH_SendByte(0xFF);
  711. if(count != 0)
  712. {
  713. return count; //如果沒有傳完,返回剩餘個數
  714. }
  715. else
  716. {
  717. return 0;
  718. }
  719. }
  720. /*******************************************************************************
  721. * Function Name : SD_WriteMultiBlock
  722. * Description : 寫入SD卡的N個block
  723. * Input : u32 sector 扇區地址(sector值,非物理地址)
  724. * u8 *buffer 數據存儲地址(大小至少512byte)
  725. * u8 count 寫入的block數目
  726. * Output : None
  727. * Return : u8 r1
  728. * 0: 成功
  729. * other:失敗
  730. *******************************************************************************/
  731. u8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count)
  732. {
  733. u8 r1;
  734. u16 i;
  735. //設置為高速模式
  736. SPI_SetSpeed(SPI_SPEED_HIGH);
  737. //如果不是SDHC,給定的是sector地址,將其轉換成byte地址
  738. // if(SD_Type != SD_TYPE_V2HC)
  739. // {
  740. // sector = sector<<9;
  741. // }
  742. //如果目標卡不是MMC卡,啟用ACMD23指令使能預擦除
  743. if(SD_Type != SD_TYPE_MMC)
  744. {
  745. r1 = SD_SendCommand(ACMD23, count, 0x00);
  746. }
  747. //發多塊寫入指令
  748. r1 = SD_SendCommand(CMD25, sector, 0x00);
  749. if(r1 != 0x00)
  750. {
  751. return r1; //應答不正確,直接返回
  752. }
  753. //開始準備數據傳輸
  754. FLASH_SPI_CS_ENABLE();
  755. //先放3個空數據,等待SD卡準備好
  756. SPI_FLASH_SendByte(0xff);
  757. SPI_FLASH_SendByte(0xff);
  758. //--------下面是N個sector寫入的循環部分
  759. do
  760. {
  761. //放起始令牌0xFC 表明是多塊寫入
  762. SPI_FLASH_SendByte(0xFC);
  763. //放一個sector的數據
  764. for(i=0;i<512;i++)
  765. {
  766. SPI_FLASH_SendByte(*data++);
  767. }
  768. //發2個Byte的dummy CRC
  769. SPI_FLASH_SendByte(0xff);
  770. SPI_FLASH_SendByte(0xff);
  771. //等待SD卡應答
  772. r1 = SPI_FLASH_SendByte(0xff);
  773. if((r1&0x1F)!=0x05)
  774. {
  775. FLASH_SPI_CS_DISABLE(); //如果應答為報錯,則帶錯誤代碼直接退出
  776. return r1;
  777. }
  778. //等待SD卡寫入完成
  779. if(SD_WaitReady()==1)
  780. {
  781. FLASH_SPI_CS_DISABLE(); //等待SD卡寫入完成超時,直接退出報錯
  782. return 1;
  783. }
  784. //本sector數據傳輸完成
  785. }while(--count);
  786. //髮結束傳輸令牌0xFD
  787. r1 = SPI_FLASH_SendByte(0xFD);
  788. if(r1==0x00)
  789. {
  790. count = 0xfe;
  791. }
  792. if(SD_WaitReady())
  793. {
  794. while(1)
  795. {
  796. }
  797. }
  798. //寫入完成,片選置1
  799. FLASH_SPI_CS_DISABLE();
  800. SPI_FLASH_SendByte(0xff);
  801. return count; //返回count值,如果寫完則count=0,否則count=1
  802. }
  803. /* USER CODE END 1 */

SDCard.h 根據YS-F1Pro SPI Flash 改寫 SD

  1. /* Define to prevent recursive inclusion -------------------------------------*/
  2. #ifndef __SDCard_H
  3. #define __SDCard_H
  4. #ifdef __cplusplus
  5. extern "C" {
  6. #endif
  7. /* Includes ------------------------------------------------------------------*/
  8. #include "main.h"
  9. /* USER CODE BEGIN Includes */
  10. /* 包含頭文件 ----------------------------------------------------------------*/
  11. #include "stm32f1xx_hal.h"
  12. /* USER CODE END Includes */
  13. /* 類型定義 ------------------------------------------------------------------*/
  14. /* 宏定義 --------------------------------------------------------------------*/
  15. //#define SPI_FLASH_ID 0xEF3015 //W25X16 2MB
  16. //#define SPI_FLASH_ID 0xEF4015 //W25Q16 4MB
  17. //#define SPI_FLASH_ID 0XEF4017 //W25Q64 8MB
  18. #define SPI_FLASH_ID 0XEF4018 //W25Q128 16MB YS-F1Pro開發默認使用
  19. #define FLASH_SPIx SPI1
  20. #define FLASH_SPIx_RCC_CLK_ENABLE() __HAL_RCC_SPI1_CLK_ENABLE()
  21. #define FLASH_SPIx_RCC_CLK_DISABLE() __HAL_RCC_SPI1_CLK_DISABLE()
  22. #define FLASH_SPI_GPIO_ClK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
  23. #define FLASH_SPI_GPIO_PORT GPIOA
  24. #define FLASH_SPI_SCK_PIN GPIO_PIN_5
  25. #define FLASH_SPI_MISO_PIN GPIO_PIN_6
  26. #define FLASH_SPI_MOSI_PIN GPIO_PIN_7
  27. #define FLASH_SPI_CS_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
  28. #define FLASH_SPI_CS_PORT GPIOA
  29. #define FLASH_SPI_CS_PIN GPIO_PIN_4
  30. #define FLASH_SPI_CS_ENABLE() HAL_GPIO_WritePin(FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN, GPIO_PIN_RESET)
  31. #define FLASH_SPI_CS_DISABLE() HAL_GPIO_WritePin(FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN, GPIO_PIN_SET)
  32. /* 擴展變量 ------------------------------------------------------------------*/
  33. extern SPI_HandleTypeDef hspiflash;
  34. /* 函數聲明 ------------------------------------------------------------------*/
  35. /* USER CODE BEGIN Private defines */
  36. /* USER CODE END Private defines */
  37. #define u8 uint8_t
  38. #define u16 uint16_t
  39. #define u32 uint32_t
  40. /* Private define ------------------------------------------------------------*/
  41. /* SD卡類型定義 */
  42. #define SD_TYPE_MMC 0
  43. #define SD_TYPE_V1 1
  44. #define SD_TYPE_V2 2
  45. #define SD_TYPE_V2HC 4
  46. /* SPI總線速度設置*/
  47. #define SPI_SPEED_LOW 0
  48. #define SPI_SPEED_HIGH 1
  49. /* SD傳輸數據結束後是否釋放總線宏定義 */
  50. #define NO_RELEASE 0
  51. #define RELEASE 1
  52. /* SD卡指令表 */
  53. #define CMD0 0 //卡復位
  54. #define CMD9 9 //命令9 ,讀CSD數據
  55. #define CMD10 10 //命令10,讀CID數據
  56. #define CMD12 12 //命令12,停止數據傳輸
  57. #define CMD16 16 //命令16,設置SectorSize 應返回0x00
  58. #define CMD17 17 //命令17,讀sector
  59. #define CMD18 18 //命令18,讀Multi sector
  60. #define ACMD23 23 //命令23,設置多sector寫入前預先擦除N個block
  61. #define CMD24 24 //命令24,寫sector
  62. #define CMD25 25 //命令25,寫Multi sector
  63. #define ACMD41 41 //命令41,應返回0x00
  64. #define CMD55 55 //命令55,應返回0x01
  65. #define CMD58 58 //命令58,讀OCR信息
  66. #define CMD59 59 //命令59,使能/禁止CRC,應返回0x00
  67. /* Private macro -------------------------------------------------------------*/
  68. //SD卡CS片選使能端操作:
  69. #define SD_CS_ENABLE() GPIO_ResetBits(GPIOA,GPIO_PIN_4) //選中SD卡
  70. #define SD_CS_DISABLE() GPIO_SetBits(GPIOA,GPIO_PIN_4) //不選中SD卡
  71. //#define SD_PWR_ON() GPIO_ResetBits(GPIOD,GPIO_Pin_10) //SD卡上電
  72. //#define SD_PWR_OFF() GPIO_SetBits(GPIOD,GPIO_Pin_10) //SD卡斷電
  73. //#define SD_DET() !GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2) //檢測有卡
  74. //1-有 0-無
  75. /* Private function prototypes -----------------------------------------------*/
  76. void SPI_Configuration(void);
  77. void SPI_SetSpeed(u8 SpeedSet);
  78. u8 SPI_ReadWriteByte(u8 TxData); //SPI總線讀寫一個字節
  79. u8 SD_WaitReady(void); //等待SD卡就緒
  80. u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc); //SD卡發送一個命令
  81. u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc);
  82. u8 SD_Init(void); //SD卡初始化
  83. //
  84. u8 SD_ReceiveData(u8 *data, u16 len, u8 release);//SD卡讀數據
  85. u8 SD_GetCID(u8 *cid_data); //讀SD卡CID
  86. u8 SD_GetCSD(u8 *csd_data); //讀SD卡CSD
  87. u32 SD_GetCapacity(void); //取SD卡容量
  88. u8 SD_ReadSingleBlock(u32 sector, u8 *buffer); //讀一個sector
  89. u8 SD_WriteSingleBlock(u32 sector, const u8 *buffer); //寫一個sector
  90. u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count); //讀多個sector
  91. u8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count); //寫多個sector
  92. /* USER CODE BEGIN Prototypes */
  93. extern u8 SD_Init(void);
  94. /* USER CODE END Prototypes */
  95. #ifdef __cplusplus
  96. }
  97. #endif
  98. #endif /*__ usart_H */

2、添加FATFS文件系統


【STM32】SD卡讀寫(五)-STM32CubeMX HAL庫SPI操作 SD卡帶FATFS

3、修改FATFS文件系統SD卡驅動部分sdcard_diskio.c

  1. /* 包含頭文件 ----------------------------------------------------------------*/
  2. #include "main.h"
  3. #include <string.h>
  4. #include "SDCard.h"
  5. #include "ff_gen_drv.h"
  6. /* 私有類型定義 --------------------------------------------------------------*/
  7. /* 私有宏定義 ----------------------------------------------------------------*/
  8. #define BLOCK_SIZE 512
  9. /* 私有變量 ------------------------------------------------------------------*/
  10. static volatile DSTATUS Stat = STA_NOINIT;
  11. /* 擴展變量 ------------------------------------------------------------------*/
  12. /* 私有函數原形 --------------------------------------------------------------*/
  13. DSTATUS SD_initialize (BYTE);
  14. DSTATUS SD_status (BYTE);
  15. DRESULT SD_read (BYTE, BYTE*, DWORD, UINT);
  16. #if _USE_WRITE == 1 // 如果允許寫操作
  17. DRESULT SD_write (BYTE, const BYTE*, DWORD, UINT);
  18. #endif /* _USE_WRITE == 1 */
  19. #if _USE_IOCTL == 1 // 如果輸入輸出操作控制
  20. DRESULT SD_ioctl (BYTE, BYTE, void*);
  21. #endif /* _USE_IOCTL == 1 */
  22. /* 定義SD卡接口函數 */
  23. const Diskio_drvTypeDef SD_Driver =
  24. {
  25. SD_initialize, // SD卡初始化
  26. SD_status, // SD卡狀態獲取
  27. SD_read, // SD卡讀數據
  28. #if _USE_WRITE == 1
  29. SD_write, // SD卡寫數據
  30. #endif /* _USE_WRITE == 1 */
  31. #if _USE_IOCTL == 1
  32. SD_ioctl, // 獲取SD卡信息
  33. #endif /* _USE_IOCTL == 1 */
  34. };
  35. /* 函數體 --------------------------------------------------------------------*/
  36. /**
  37. * 函數功能: SD卡初始化配置
  38. * 輸入參數: 無
  39. * 返 回 值: 無
  40. * 說 明: 無
  41. */
  42. //extern void MX_SPI1_Init(void);
  43. DSTATUS SD_initialize(BYTE lun)
  44. {
  45. Stat = STA_NOINIT;
  46. /* 初始化SDIO外設 */
  47. // MX_SPI1_Init();
  48. /* 獲取SD卡狀態 */
  49. int result;
  50. result = SD_Init();
  51. // if(HAL_SD_GetStatus(&hsdcard)==SD_TRANSFER_OK)
  52. // {
  53. // Stat &= ~STA_NOINIT;
  54. // }
  55. if (result == 0)
  56. {
  57. Stat = RES_OK;
  58. }
  59. else
  60. {
  61. Stat = RES_ERROR;
  62. }
  63. return Stat;
  64. }
  65. /**
  66. * 函數功能: SD卡狀態獲取
  67. * 輸入參數: lun : 不用
  68. * 返 回 值: DSTATUS:SD卡狀態返回值
  69. * 說 明: 無
  70. */
  71. DSTATUS SD_status(BYTE lun)
  72. {
  73. Stat = STA_NOINIT;
  74. // if(HAL_SD_GetStatus(&hsdcard) == SD_TRANSFER_OK)
  75. // {
  76. // Stat &= ~STA_NOINIT;
  77. // }
  78. Stat = RES_OK;
  79. return Stat;
  80. }
  81. /**
  82. * 函數功能: 從SD卡讀取數據到緩衝區
  83. * 輸入參數: lun : 不用
  84. * buff:存放讀取到數據緩衝區指針
  85. * sector:扇區地址(LBA)
  86. * count:扇區數目
  87. * 返 回 值: DSTATUS:操作結果
  88. * 說 明: SD卡讀操作使用DMA傳輸
  89. */
  90. DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
  91. {
  92. DRESULT res = RES_OK;
  93. // if((DWORD)buff&3)
  94. // {
  95. // DWORD scratch[BLOCK_SIZE/4];
  96. // while (count--)
  97. // {
  98. // res = SD_read(lun,(void *)scratch, sector++, 1);
  99. // if (res != RES_OK)
  100. // {
  101. // break;
  102. // }
  103. // memcpy(buff, scratch, BLOCK_SIZE);
  104. // buff += BLOCK_SIZE;
  105. // }
  106. // return res;
  107. // }
  108. //
  109. // if(HAL_SD_ReadBlocks_DMA(&hsdcard,(uint32_t*)buff,(uint64_t)(sector * BLOCK_SIZE),BLOCK_SIZE,count) != SD_OK)
  110. // {
  111. // res = RES_ERROR;
  112. // }
  113. // if(res==RES_OK)
  114. // {
  115. // if(HAL_SD_CheckReadOperation(&hsdcard, 0xFFFFFFFF) != SD_OK)
  116. // {
  117. // res = RES_ERROR;
  118. // }
  119. // }
  120. int result;
  121. if(count==1)
  122. {
  123. result=SD_ReadSingleBlock(sector,buff);
  124. }
  125. else
  126. {
  127. result = SD_ReadMultiBlock(sector, buff, count);
  128. }
  129. if (result == 0)
  130. {
  131. res = RES_OK;
  132. }
  133. else
  134. {
  135. res = RES_ERROR;
  136. }
  137. return res;
  138. }
  139. /**
  140. * 函數功能: 將緩衝區數據寫入到SD卡內
  141. * 輸入參數: lun : 不用
  142. * buff:存放待寫入數據的緩衝區指針
  143. * sector:扇區地址(LBA)
  144. * count:扇區數目
  145. * 返 回 值: DSTATUS:操作結果
  146. * 說 明: SD卡寫操作沒有使用DMA傳輸
  147. */
  148. #if _USE_WRITE == 1
  149. DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
  150. {
  151. DRESULT res = RES_OK;
  152. // if((DWORD)buff&3)
  153. // {
  154. // DRESULT res = RES_OK;
  155. // DWORD scratch[BLOCK_SIZE / 4];
  156. // while (count--)
  157. // {
  158. // memcpy( scratch,buff,BLOCK_SIZE);
  159. // res = SD_write(lun,(void *)scratch, sector++, 1);
  160. // if (res != RES_OK)
  161. // {
  162. // break;
  163. // }
  164. // buff += BLOCK_SIZE;
  165. // }
  166. // return res;
  167. // }
  168. //
  169. // if(HAL_SD_WriteBlocks(&hsdcard,(uint32_t*)buff,(uint64_t)(sector * BLOCK_SIZE),BLOCK_SIZE, count) != SD_OK)
  170. // {
  171. // res = RES_ERROR;
  172. // }
  173. int result;
  174. if(count==1)
  175. {
  176. result=SD_WriteSingleBlock(sector, buff);
  177. }
  178. else
  179. {
  180. result = SD_WriteMultiBlock(sector, buff, count);
  181. }
  182. if (result == 0)
  183. {
  184. res = RES_OK;
  185. }
  186. else
  187. {
  188. res = RES_ERROR;
  189. }
  190. return res;
  191. }
  192. #endif /* _USE_WRITE == 1 */
  193. /**
  194. * 函數功能: 輸入輸出控制操作(I/O control operation)
  195. * 輸入參數: lun : 不用
  196. * cmd:控制命令
  197. * buff:存放待寫入或者讀取數據的緩衝區指針
  198. * 返 回 值: DSTATUS:操作結果
  199. * 說 明: 無
  200. */
  201. #if _USE_IOCTL == 1
  202. DRESULT SD_ioctl(BYTE lun, BYTE cmd, void *buff)
  203. {
  204. DRESULT res = RES_ERROR;
  205. // if (Stat & STA_NOINIT) return RES_NOTRDY;
  206. //
  207. // switch (cmd)
  208. // {
  209. // /* Make sure that no pending write process */
  210. // case CTRL_SYNC :
  211. //FLASH_SPI_CS_ENABLE();
  212. //if(SD_WaitReady()==0)
  213. //{
  214. //res = RES_OK;
  215. //}
  216. //else
  217. //{
  218. //res = RES_ERROR;
  219. //}
  220. ////FLASH_SPI_CSDISABLE();
  221. // break;
  222. //
  223. // /* 獲取SD卡總扇區數目(DWORD) */
  224. // case GET_SECTOR_COUNT :
  225. //*(WORD*)buff = 512;
  226. //res = RES_OK;
  227. // break;
  228. //
  229. // /* 獲取讀寫扇區大小(WORD) */
  230. // case GET_SECTOR_SIZE :
  231. //*(DWORD*)buff = SD_GetCapacity();
  232. //res = RES_OK;
  233. // break;
  234. //
  235. // /* 獲取擦除塊大小(DWORD) */
  236. // case GET_BLOCK_SIZE :
  237. // *(DWORD*)buff = BLOCK_SIZE;
  238. // break;
  239. //
  240. // default:
  241. // res = RES_PARERR;
  242. // }
  243. uint8_t CSD[16] = {0};
  244. uint8_t csddata[16] = {0};
  245. uint32_t csize;
  246. uint32_t Capacity;
  247. switch (cmd)
  248. {
  249. case CTRL_SYNC:
  250. res = RES_OK;
  251. break;
  252. case GET_SECTOR_COUNT:
  253. SD_GetCID(CSD);
  254. SD_GetCSD(csddata);
  255. //SDGetCIDCSD(CSD, csddata);
  256. csize = csddata[9] + ((uint32_t)csddata[8] << 8) + ((uint32_t)(csddata[7] & 0x3f) << 16) + 1;
  257. Capacity = csize << 9;
  258. *((DWORD *)buff) = Capacity;
  259. res = RES_OK;
  260. break;
  261. case GET_SECTOR_SIZE:
  262. *(WORD *)buff = 512; //spi flash的扇區大小是 512 Bytes
  263. return RES_OK;
  264. case GET_BLOCK_SIZE:
  265. *((DWORD *)buff) = 4096;
  266. res = RES_OK;
  267. break;
  268. default:
  269. res = RES_PARERR;
  270. break;
  271. }
  272. return res;
  273. }
  274. #endif /* _USE_IOCTL == 1 */

4、在Main.c文件中添加 測試應用程序

  1. char SPIFLASHPath[4]; /* 串行Flash邏輯設備路徑 */
  2. char SDPath[4]; /* SD卡邏輯設備路徑 */
  3. FATFS fs;/* FatFs文件系統對象 */
  4. FIL file;/* 文件對象 */
  5. FRESULT f_res; /* 文件操作結果 */
  6. UINT fnum; /* 文件成功讀寫數量 */
  7. BYTE ReadBuffer[1024]={0}; /* 讀緩衝區 */
  8. BYTE WriteBuffer[]= "歡迎使用硬石STM32開發板 今天是個好日子,新建文件系統測試文件\\n";/* 寫緩衝區*/
  9. extern Diskio_drvTypeDef SD_Driver;

添加文件系統操作結果處理

  1. /**
  2. * 函數功能: FatFS文件系統操作結果信息處理.
  3. * 輸入參數: FatFS文件系統操作結果:FRESULT
  4. * 返 回 值: 無
  5. * 說 明: 無
  6. */
  7. static void printf_fatfs_error(FRESULT fresult)
  8. {
  9. switch(fresult)
  10. {
  11. case FR_OK: //(0)
  12. printf("》操作成功。\\n");
  13. break;
  14. case FR_DISK_ERR: //(1)
  15. printf("!!硬件輸入輸出驅動出錯。\\n");
  16. break;
  17. case FR_INT_ERR: //(2)
  18. printf("!!斷言錯誤。\\n");
  19. break;
  20. case FR_NOT_READY: //(3)
  21. printf("!!物理設備無法工作。\\n");
  22. break;
  23. case FR_NO_FILE: //(4)
  24. printf("!!無法找到文件。\\n");
  25. break;
  26. case FR_NO_PATH: //(5)
  27. printf("!!無法找到路徑。\\n");
  28. break;
  29. case FR_INVALID_NAME: //(6)
  30. printf("!!無效的路徑名。\\n");
  31. break;
  32. case FR_DENIED: //(7)
  33. case FR_EXIST: //(8)
  34. printf("!!拒絕訪問。\\n");
  35. break;
  36. case FR_INVALID_OBJECT: //(9)
  37. printf("!!無效的文件或路徑。\\n");
  38. break;
  39. case FR_WRITE_PROTECTED: //(10)
  40. printf("!!邏輯設備寫保護。\\n");
  41. break;
  42. case FR_INVALID_DRIVE: //(11)
  43. printf("!!無效的邏輯設備。\\n");
  44. break;
  45. case FR_NOT_ENABLED: //(12)
  46. printf("!!無效的工作區。\\n");
  47. break;
  48. case FR_NO_FILESYSTEM: //(13)
  49. printf("!!無效的文件系統。\\n");
  50. break;
  51. case FR_MKFS_ABORTED: //(14)
  52. printf("!!因函數參數問題導致f_mkfs函數操作失敗。\\n");
  53. break;
  54. case FR_TIMEOUT: //(15)
  55. printf("!!操作超時。\\n");
  56. break;
  57. case FR_LOCKED: //(16)
  58. printf("!!文件被保護。\\n");
  59. break;
  60. case FR_NOT_ENOUGH_CORE: //(17)
  61. printf("!!長文件名支持獲取堆空間失敗。\\n");
  62. break;
  63. case FR_TOO_MANY_OPEN_FILES: //(18)
  64. printf("!!打開太多文件。\\n");
  65. break;
  66. case FR_INVALID_PARAMETER: // (19)
  67. printf("!!參數無效。\\n");
  68. break;
  69. }
  70. }

添加測試程序:

  1. /* 註冊一個FatFS設備:SD卡 */
  2. if(FATFS_LinkDriver(&SD_Driver, SDPath) == 0)
  3. {
  4. //在SD卡掛載文件系統,文件系統掛載時會對SD卡初始化
  5. f_res = f_mount(&fs,(TCHAR const*)SDPath,1);
  6. printf_fatfs_error(f_res);
  7. /*----------------------- 格式化測試 ---------------------------*/
  8. /* 如果沒有文件系統就格式化創建創建文件系統 */
  9. if(f_res == FR_NO_FILESYSTEM)
  10. {
  11. printf("》SD卡還沒有文件系統,即將進行格式化...\\n");
  12. /* 格式化 */
  13. f_res=f_mkfs((TCHAR const*)SDPath,0,0);
  14. if(f_res == FR_OK)
  15. {
  16. printf("》SD卡已成功格式化文件系統。\\n");
  17. /* 格式化後,先取消掛載 */
  18. f_res = f_mount(NULL,(TCHAR const*)SDPath,1);
  19. /* 重新掛載*/
  20. f_res = f_mount(&fs,(TCHAR const*)SDPath,1);
  21. }
  22. else
  23. {
  24. printf("《《格式化失敗。》》\\n");
  25. while(1);
  26. }
  27. }
  28. else if(f_res!=FR_OK)
  29. {
  30. printf("!!SD卡掛載文件系統失敗。(%d)\\n",f_res);
  31. printf_fatfs_error(f_res);
  32. while(1);
  33. }
  34. else
  35. {
  36. printf("》文件系統掛載成功,可以進行讀寫測試\\n");
  37. }
  38. /*----------------------- 文件系統測試:寫測試 -----------------------------*/
  39. /* 打開文件,如果文件不存在則創建它 */
  40. printf("****** 即將進行文件寫入測試... ******\\n");
  41. f_res = f_open(&file, "FatFs讀寫測試文件.txt",FA_CREATE_ALWAYS | FA_WRITE );
  42. if ( f_res == FR_OK )
  43. {
  44. printf("》打開/創建FatFs讀寫測試文件.txt文件成功,向文件寫入數據。\\n");
  45. /* 將指定存儲區內容寫入到文件內 */
  46. f_res=f_write(&file,WriteBuffer,sizeof(WriteBuffer),&fnum);
  47. if(f_res==FR_OK)
  48. {
  49. printf("》文件寫入成功,寫入字節數據:%d\\n",fnum);
  50. printf("》向文件寫入的數據為:\\n%s\\n",WriteBuffer);
  51. }
  52. else
  53. {
  54. printf("!!文件寫入失敗:(%d)\\n",f_res);
  55. }
  56. /* 不再讀寫,關閉文件 */
  57. f_close(&file);
  58. }
  59. else
  60. {
  61. printf("!!打開/創建文件失敗。\\n");
  62. }
  63. /*------------------- 文件系統測試:讀測試 ------------------------------------*/
  64. printf("****** 即將進行文件讀取測試... ******\\n");
  65. f_res = f_open(&file, "FatFs讀寫測試文件.txt", FA_OPEN_EXISTING | FA_READ);
  66. if(f_res == FR_OK)
  67. {
  68. printf("》打開文件成功。\\n");
  69. f_res = f_read(&file, ReadBuffer, sizeof(ReadBuffer), &fnum);
  70. if(f_res==FR_OK)
  71. {
  72. printf("》文件讀取成功,讀到字節數據:%d\\n",fnum);
  73. printf("》讀取得的文件數據為:\\n%s \\n", ReadBuffer);
  74. }
  75. else
  76. {
  77. printf("!!文件讀取失敗:(%d)\\n",f_res);
  78. }
  79. }
  80. else
  81. {
  82. printf("!!打開文件失敗。\\n");
  83. }
  84. /* 不再讀寫,關閉文件 */
  85. f_close(&file);
  86. /* 不再使用,取消掛載 */
  87. f_res = f_mount(NULL,(TCHAR const*)SDPath,1);
  88. }
  89. /* 註銷一個FatFS設備:SD卡 */
  90. FATFS_UnLinkDriver(SDPath);

3、使用串口查看測試結果


【STM32】SD卡讀寫(五)-STM32CubeMX HAL庫SPI操作 SD卡帶FATFS


分享到:


相關文章: