天天看点

cube sdio fatfs 初始化sd卡_【STM32】SD卡读写(五)-STM32CubeMX HAL库SPI操作 SD卡带FATFS...

1、添加SD卡SPI模式驱动

  1. static void MX_SPI1_Init(void)
  2. {
  3. hspi1.Instance = SPI1;
  4. hspi1.Init.Mode = SPI_MODE_MASTER;
  5. hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  6. hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  7. hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  8. hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  9. hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT;
  10. hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
  11. hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  12. hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  13. hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  14. hspi1.Init.CRCPolynomial = 10;
  15. if (HAL_SPI_Init(&hspi1) != HAL_OK)
  16. {
  17. Error_Handler();
  18. }
  19. }

编写SD卡SPI驱动 SDCard.c

  1. #include "main.h"
  2. #include "SDCard.h"
  3. #define Dummy_Byte 0xFF
  4. SPI_HandleTypeDef hspiflash;
  5. extern SPI_HandleTypeDef hspi1;
  6. u8 SD_Type=0;
  7. uint8_t SPI_FLASH_ReadByte(void)
  8. {
  9. uint8_t d_read,d_send=Dummy_Byte;
  10. if(HAL_SPI_TransmitReceive(&hspiflash,&d_send,&d_read,1,0xFFFFFF)!=HAL_OK)
  11. d_read=Dummy_Byte;
  12. return d_read;
  13. }
  14. void SPI_I2S_SendData(SPI_TypeDef* SPIx, u16 Data)
  15. {
  16. assert_param(IS_SPI_ALL_PERIPH(SPIx));
  17. SPIx->DR = Data;
  18. }
  19. u16 SPI_I2S_ReceiveData(SPI_TypeDef* SPIx)
  20. {
  21. assert_param(IS_SPI_ALL_PERIPH(SPIx));
  22. //assert_param(IS_SPI_DIRECTION_2LINES_OR_1LINE(hspi->Init.Direction));
  23. return SPIx->DR;
  24. }
  25. uint8_t SPI_FLASH_SendByte(uint8_t byte)
  26. {
  27. uint8_t d_read,d_send=byte;
  28. // if(HAL_SPI_TransmitReceive(&hspiflash,&d_send,&d_read,1,0xFFFFFF)!=HAL_OK)
  29. //{
  30. //d_read=Dummy_Byte;
  31. //}
  32. //等待发送缓冲区空
  33. // while(__HAL_SPI_GET_FLAG(&hspi1, SPI_FLAG_TXE));
  34. //发一个字节
  35. // SPI_I2S_SendData(SPI1, d_send);
  36. HAL_SPI_Transmit(&hspi1,&d_send,1,1000);
  37. //HAL_SPI_Receive(&hspi1,&d_read,1,1000);
  38. //等待数据接收
  39. while(__HAL_SPI_GET_FLAG(&hspi1, SPI_FLAG_RXNE));
  40. //取数据
  41. d_read = SPI_I2S_ReceiveData(SPI1);
  42. return d_read;
  43. }
  44. u8 SD_WaitReady(void)
  45. {
  46. u8 r1;
  47. u16 retry;
  48. retry = 0;
  49. do
  50. {
  51. r1 = SPI_FLASH_SendByte(0xFF);
  52. if(retry==0xfffe)
  53. {
  54. return 1;
  55. }
  56. }while(r1!=0xFF);
  57. return 0;
  58. }
  59. u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc)
  60. {
  61. unsigned char r1;
  62. unsigned char Retry = 0;
  63. //????????
  64. SPI_FLASH_SendByte(0xff);
  65. //片选端置低,选中SD卡
  66. FLASH_SPI_CS_ENABLE();
  67. //发送
  68. SPI_FLASH_SendByte(cmd | 0x40); //分别写入命令
  69. SPI_FLASH_SendByte(arg >> 24);
  70. SPI_FLASH_SendByte(arg >> 16);
  71. SPI_FLASH_SendByte(arg >> 8);
  72. SPI_FLASH_SendByte(arg);
  73. SPI_FLASH_SendByte(crc);
  74. //等待响应,或超时退出
  75. while((r1 = SPI_FLASH_SendByte(0xFF))==0xFF)
  76. {
  77. Retry++;
  78. if(Retry > 200)
  79. {
  80. break;
  81. }
  82. }
  83. //关闭片选
  84. FLASH_SPI_CS_DISABLE();
  85. //在总线上额外增加8个时钟,让SD卡完成剩下的工作
  86. SPI_FLASH_SendByte(0xFF);
  87. //返回状态值
  88. return r1;
  89. }
  90. u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc)
  91. {
  92. unsigned char r1;
  93. unsigned char Retry = 0;
  94. //????????
  95. SPI_FLASH_SendByte(0xff);
  96. //片选端置低,选中SD卡
  97. FLASH_SPI_CS_ENABLE();
  98. //发送
  99. SPI_FLASH_SendByte(cmd | 0x40); //分别写入命令
  100. SPI_FLASH_SendByte(arg >> 24);
  101. SPI_FLASH_SendByte(arg >> 16);
  102. SPI_FLASH_SendByte(arg >> 8);
  103. SPI_FLASH_SendByte(arg);
  104. SPI_FLASH_SendByte(crc);
  105. //等待响应,或超时退出
  106. while((r1 = SPI_FLASH_SendByte(0xFF))==0xFF)
  107. {
  108. Retry++;
  109. if(Retry > 200)
  110. {
  111. break;
  112. }
  113. }
  114. //返回响应值
  115. return r1;
  116. }
  117. void SPI_SetSpeed(u8 SpeedSet)
  118. {
  119. hspi1.Instance = SPI1;
  120. hspi1.Init.Mode = SPI_MODE_MASTER;
  121. hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  122. hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  123. hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  124. hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  125. hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT;
  126. //如果速度设置输入0,则低速模式,非0则高速模式
  127. if(SpeedSet==SPI_SPEED_LOW)
  128. {
  129. hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
  130. }
  131. else
  132. {
  133. hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  134. }
  135. hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  136. hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  137. hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  138. hspi1.Init.CRCPolynomial = 10;
  139. if (HAL_SPI_Init(&hspi1) != HAL_OK)
  140. {
  141. Error_Handler();
  142. }
  143. // if(SpeedSet==SPI_SPEED_LOW)
  144. //{
  145. // hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
  146. //}
  147. //else
  148. //{
  149. //hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  150. //}
  151. //HAL_SPI_Init(&hspi1);
  152. //moon.mp3: 4707774 Byte size 目标文件 设为buffer[512]
  153. //speed:实验测试数据,最大速度 392314 Byte/S,
  154. //Prescaler_128, 59592 Byte/S
  155. //Prescaler_64, 104617 Byte/S
  156. //Prescaler_32, 168134 Byte/S 162337 Byte/S
  157. //Prescaler_16, 261543 Byte/S 247777 Byte/S
  158. //Prescaler_8, 313851 Byte/S 336269 Byte/S
  159. //Prescaler_4, 392314 Byte/S 392314 Byte/S
  160. //Prescaler_2, 392314 Byte/S
  161. }
  162. u8 SD_Init(void)
  163. {
  164. u16 i; // 用来循环计数
  165. u8 r1; // 存放SD卡的返回值
  166. u16 retry; // 用来进行超时计数
  167. u8 buff[6];
  168. //如果没有检测到卡插入,直接退出,返回错误标志
  169. // if(!SD_DET())
  170. // {
  171. // //return 99;
  172. // return STA_NODISK; // FatFS错误标志:没有插入磁盘
  173. // }
  174. //SD卡上电
  175. //SD_PWR_ON();
  176. // 纯延时,等待SD卡上电完成
  177. //for(i=0;i<0xf00;i++);
  178. SPI_SetSpeed(0); //设置SPI速度为低速
  179. //先产生>74个脉冲,让SD卡自己初始化完成
  180. for(i=0;i<100;i++)
  181. {
  182. SPI_FLASH_SendByte(0xFF);
  183. }
  184. //-----------------SD卡复位到idle开始-----------------
  185. //循环连续发送CMD0,直到SD卡返回0x01,进入IDLE状态
  186. //超时则直接退出
  187. retry = 0;
  188. do
  189. {
  190. //发送CMD0,让SD卡进入IDLE状态
  191. r1 = SD_SendCommand(CMD0, 0, 0x95);
  192. retry++;
  193. }while((r1 != 0x01) && (retry<200));
  194. //跳出循环后,检查原因:初始化成功?or 重试超时?
  195. if(retry==200)
  196. {
  197. return 1; //超时返回1
  198. }
  199. //-----------------SD卡复位到idle结束-----------------
  200. //获取卡片的SD版本信息
  201. r1 = SD_SendCommand_NoDeassert(8, 0x1aa, 0x87);
  202. //如果卡片版本信息是v1.0版本的,即r1=0x05,则进行以下初始化
  203. if(r1 == 0x05)
  204. {
  205. printf(" SD卡版本信息:V1.0 ");
  206. //设置卡类型为SDV1.0,如果后面检测到为MMC卡,再修改为MMC
  207. SD_Type = SD_TYPE_V1;
  208. //如果是V1.0卡,CMD8指令后没有后续数据
  209. //片选置高,结束本次命令
  210. FLASH_SPI_CS_DISABLE();
  211. //多发8个CLK,让SD结束后续操作
  212. SPI_FLASH_SendByte(0xFF);
  213. //-----------------SD卡、MMC卡初始化开始-----------------
  214. //发卡初始化指令CMD55+ACMD41
  215. // 如果有应答,说明是SD卡,且初始化完成
  216. // 没有回应,说明是MMC卡,额外进行相应初始化
  217. retry = 0;
  218. do
  219. {
  220. //先发CMD55,应返回0x01;否则出错
  221. r1 = SD_SendCommand(CMD55, 0, 0);
  222. if(r1 != 0x01)
  223. {
  224. return r1;
  225. }
  226. //得到正确响应后,发ACMD41,应得到返回值0x00,否则重试200次
  227. r1 = SD_SendCommand(ACMD41, 0, 0);
  228. retry++;
  229. }while((r1!=0x00) && (retry<400));
  230. // 判断是超时还是得到正确回应
  231. // 若有回应:是SD卡;没有回应:是MMC卡
  232. //----------MMC卡额外初始化操作开始------------
  233. if(retry==400)
  234. {
  235. printf(" SD卡信息: MMC卡 ");
  236. retry = 0;
  237. //发送MMC卡初始化命令(没有测试)
  238. do
  239. {
  240. r1 = SD_SendCommand(1, 0, 0);
  241. retry++;
  242. }while((r1!=0x00)&& (retry<400));
  243. if(retry==400)
  244. {
  245. return 1; //MMC卡初始化超时
  246. }
  247. //写入卡类型
  248. SD_Type = SD_TYPE_MMC;
  249. }
  250. else
  251. {
  252. printf(" SD卡信息: SD卡 ");
  253. }
  254. //----------MMC卡额外初始化操作结束------------
  255. //设置SPI为高速模式
  256. SPI_SetSpeed(1);
  257. SPI_FLASH_SendByte(0xFF);
  258. //禁止CRC校验
  259. //设置Sector Size
  260. r1 = SD_SendCommand(CMD16, 512, 0xff);
  261. if(r1 != 0x00)
  262. {
  263. return r1; //命令错误,返回r1
  264. }
  265. //-----------------SD卡、MMC卡初始化结束-----------------
  266. }//SD卡为V1.0版本的初始化结束
  267. //下面是V2.0卡的初始化
  268. //其中需要读取OCR数据,判断是SD2.0还是SD2.0HC卡
  269. else if(r1 == 0x01)
  270. {
  271. printf(" SD卡版本信息:V2.0 ");
  272. //V2.0的卡,CMD8命令后会传回4字节的数据,要跳过再结束本命令
  273. buff[0] = SPI_FLASH_SendByte(0xFF); //should be 0x00
  274. buff[1] = SPI_FLASH_SendByte(0xFF); //should be 0x00
  275. buff[2] = SPI_FLASH_SendByte(0xFF); //should be 0x01
  276. buff[3] = SPI_FLASH_SendByte(0xFF); //should be 0xAA
  277. FLASH_SPI_CS_DISABLE();
  278. //the next 8 clocks
  279. SPI_FLASH_SendByte(0xFF);
  280. //判断该卡是否支持2.7V-3.6V的电压范围
  281. if(buff[2]==0x01 && buff[3]==0xAA)
  282. {
  283. //支持电压范围,可以操作
  284. retry = 0;
  285. //发卡初始化指令CMD55+ACMD41
  286. do
  287. {
  288. r1 = SD_SendCommand(CMD55, 0, 0);
  289. if(r1!=0x01)
  290. {
  291. return r1;
  292. }
  293. r1 = SD_SendCommand(ACMD41, 0x40000000, 0);
  294. if(retry>200)
  295. {
  296. return r1; //超时则返回r1状态
  297. }
  298. }while(r1!=0);
  299. //初始化指令发送完成,接下来获取OCR信息
  300. //-----------鉴别SD2.0卡版本开始-----------
  301. r1 = SD_SendCommand_NoDeassert(CMD58, 0, 0);
  302. if(r1!=0x00)
  303. {
  304. return r1; //如果命令没有返回正确应答,直接退出,返回应答
  305. }
  306. //读OCR指令发出后,紧接着是4字节的OCR信息
  307. buff[0] = SPI_FLASH_SendByte(0xFF);
  308. buff[1] = SPI_FLASH_SendByte(0xFF);
  309. buff[2] = SPI_FLASH_SendByte(0xFF);
  310. buff[3] = SPI_FLASH_SendByte(0xFF);
  311. //OCR接收完成,片选置高
  312. FLASH_SPI_CS_DISABLE();
  313. SPI_FLASH_SendByte(0xFF);
  314. //检查接收到的OCR中的bit30位(CCS),确定其为SD2.0还是SDHC
  315. //如果CCS=1:SDHC CCS=0:SD2.0
  316. if(buff[0]&0x40) //检查CCS
  317. {
  318. SD_Type = SD_TYPE_V2HC;
  319. printf(" SD卡信息: SDHC ");
  320. }
  321. else
  322. {
  323. SD_Type = SD_TYPE_V2;
  324. printf(" SD卡信息: SD2.0 ");
  325. }
  326. //-----------鉴别SD2.0卡版本结束-----------
  327. //设置SPI为高速模式
  328. SPI_SetSpeed(1);
  329. }
  330. }
  331. return r1;
  332. }
  333. u8 SD_ReceiveData(u8 *data, u16 len, u8 release)
  334. {
  335. u16 retry;
  336. u8 r1;
  337. // 启动一次传输
  338. FLASH_SPI_CS_ENABLE();
  339. //等待SD卡发回数据起始令牌0xFE
  340. retry = 0;
  341. do
  342. {
  343. r1 = SPI_FLASH_SendByte(0xFF);
  344. retry++;
  345. if(retry>2000) //2000次等待后没有应答,退出报错
  346. {
  347. FLASH_SPI_CS_DISABLE();
  348. return 1;
  349. }
  350. }while(r1 != 0xFE);
  351. //开始接收数据
  352. while(len--)
  353. {
  354. *data = SPI_FLASH_SendByte(0xFF);
  355. data++;
  356. }
  357. //下面是2个伪CRC(dummy CRC)
  358. SPI_FLASH_SendByte(0xFF);
  359. SPI_FLASH_SendByte(0xFF);
  360. //按需释放总线,将CS置高
  361. if(release == RELEASE)
  362. {
  363. //传输结束
  364. FLASH_SPI_CS_DISABLE();
  365. SPI_FLASH_SendByte(0xFF);
  366. }
  367. return 0;
  368. }
  369. u8 SD_GetCID(u8 *cid_data)
  370. {
  371. u8 r1;
  372. //发CMD10命令,读CID
  373. r1 = SD_SendCommand(CMD10, 0, 0xFF);
  374. if(r1 != 0x00)
  375. {
  376. return r1; //没返回正确应答,则退出,报错
  377. }
  378. //接收16个字节的数据
  379. SD_ReceiveData(cid_data, 16, RELEASE);
  380. return 0;
  381. }
  382. u8 SD_GetCSD(u8 *csd_data)
  383. {
  384. u8 r1;
  385. //发CMD9命令,读CSD
  386. r1 = SD_SendCommand(CMD9, 0, 0xFF);
  387. if(r1 != 0x00)
  388. {
  389. return r1; //没返回正确应答,则退出,报错
  390. }
  391. //接收16个字节的数据
  392. SD_ReceiveData(csd_data, 16, RELEASE);
  393. return 0;
  394. }
  395. u32 SD_GetCapacity(void)
  396. {
  397. u8 csd[16];
  398. u32 Capacity;
  399. u8 r1;
  400. u16 i;
  401. u16 temp;
  402. //取CSD信息,如果期间出错,返回0
  403. if(SD_GetCSD(csd)!=0)
  404. {
  405. return 0;
  406. }
  407. //如果为SDHC卡,按照下面方式计算
  408. if((csd[0]&0xC0)==0x40)
  409. {
  410. Capacity = ((((u32)csd[8])<<8) + (u32)csd[9] + 1)*(u32)1024;
  411. }
  412. else
  413. {
  414. //下面代码为网上版本
  415. formula of the capacity///
  416. //
  417. // memory capacity = BLOCKNR * BLOCK_LEN
  418. //
  419. //BLOCKNR = (C_SIZE + 1)* MULT
  420. //
  421. // C_SIZE_MULT+2
  422. //MULT = 2
  423. //
  424. // READ_BL_LEN
  425. //BLOCK_LEN = 2
  426. //C_SIZE
  427. i = csd[6]&0x03;
  428. i<<=8;
  429. i += csd[7];
  430. i<<=2;
  431. i += ((csd[8]&0xc0)>>6);
  432. //C_SIZE_MULT
  433. r1 = csd[9]&0x03;
  434. r1<<=1;
  435. r1 += ((csd[10]&0x80)>>7);
  436. //BLOCKNR
  437. r1+=2;
  438. temp = 1;
  439. while(r1)
  440. {
  441. temp*=2;
  442. r1--;
  443. }
  444. Capacity = ((u32)(i+1))*((u32)temp);
  445. // READ_BL_LEN
  446. i = csd[5]&0x0f;
  447. //BLOCK_LEN
  448. temp = 1;
  449. while(i)
  450. {
  451. temp*=2;
  452. i--;
  453. }
  454. //The final result
  455. Capacity *= (u32)temp;
  456. //Capacity /= 512;
  457. }
  458. return (u32)Capacity;
  459. }
  460. u8 SD_ReadSingleBlock(u32 sector, u8 *buffer)
  461. {
  462. u8 r1;
  463. //设置为高速模式
  464. SPI_SetSpeed(SPI_SPEED_HIGH);
  465. //如果不是SDHC,将sector地址转成byte地址
  466. //sector = sector<<9;
  467. r1 = SD_SendCommand(CMD17, sector, 0);//读命令
  468. if(r1 != 0x00)
  469. {
  470. return r1;
  471. }
  472. r1 = SD_ReceiveData(buffer, 512, RELEASE);
  473. if(r1 != 0)
  474. {
  475. return r1; //读数据出错!
  476. }
  477. else
  478. {
  479. return 0;
  480. }
  481. }
  482. u8 SD_WriteSingleBlock(u32 sector, const u8 *data)
  483. {
  484. u8 r1;
  485. u16 i;
  486. u16 retry;
  487. //设置为高速模式
  488. SPI_SetSpeed(SPI_SPEED_HIGH);
  489. //如果不是SDHC,给定的是sector地址,将其转换成byte地址
  490. // if(SD_Type!=SD_TYPE_V2HC)
  491. // {
  492. // sector = sector<<9;
  493. // }
  494. r1 = SD_SendCommand(CMD24, sector, 0x00);
  495. if(r1 != 0x00)
  496. {
  497. return r1; //应答不正确,直接返回
  498. }
  499. //开始准备数据传输
  500. FLASH_SPI_CS_ENABLE();
  501. //先放3个空数据,等待SD卡准备好
  502. SPI_FLASH_SendByte(0xff);
  503. SPI_FLASH_SendByte(0xff);
  504. SPI_FLASH_SendByte(0xff);
  505. //放起始令牌0xFE
  506. SPI_FLASH_SendByte(0xFE);
  507. //放一个sector的数据
  508. for(i=0;i<512;i++)
  509. {
  510. SPI_FLASH_SendByte(*data++);
  511. }
  512. //发2个Byte的dummy CRC
  513. SPI_FLASH_SendByte(0xff);
  514. SPI_FLASH_SendByte(0xff);
  515. //等待SD卡应答
  516. r1 = SPI_FLASH_SendByte(0xff);
  517. if((r1&0x1F)!=0x05)
  518. {
  519. FLASH_SPI_CS_DISABLE();
  520. return r1;
  521. }
  522. //等待操作完成
  523. retry = 0;
  524. while(!SPI_FLASH_SendByte(0xff))
  525. {
  526. retry++;
  527. if(retry>0xfffe) //如果长时间写入没有完成,报错退出
  528. {
  529. FLASH_SPI_CS_DISABLE();
  530. return 1; //写入超时返回1
  531. }
  532. }
  533. //写入完成,片选置1
  534. FLASH_SPI_CS_DISABLE();
  535. SPI_FLASH_SendByte(0xff);
  536. return 0;
  537. }
  538. u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count)
  539. {
  540. u8 r1;
  541. //设置为高速模式
  542. SPI_SetSpeed(SPI_SPEED_HIGH);
  543. //如果不是SDHC,将sector地址转成byte地址
  544. // sector = sector<<9;
  545. //SD_WaitReady();
  546. //发读多块命令
  547. r1 = SD_SendCommand(CMD18, sector, 0);//读命令
  548. if(r1 != 0x00)
  549. {
  550. return r1;
  551. }
  552. //开始接收数据
  553. do
  554. {
  555. if(SD_ReceiveData(buffer, 512, NO_RELEASE) != 0x00)
  556. {
  557. break;
  558. }
  559. buffer += 512;
  560. } while(--count);
  561. //全部传输完毕,发送停止命令
  562. SD_SendCommand(CMD12, 0, 0);
  563. //释放总线
  564. FLASH_SPI_CS_DISABLE();
  565. SPI_FLASH_SendByte(0xFF);
  566. if(count != 0)
  567. {
  568. return count; //如果没有传完,返回剩余个数
  569. }
  570. else
  571. {
  572. return 0;
  573. }
  574. }
  575. u8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count)
  576. {
  577. u8 r1;
  578. u16 i;
  579. //设置为高速模式
  580. SPI_SetSpeed(SPI_SPEED_HIGH);
  581. //如果不是SDHC,给定的是sector地址,将其转换成byte地址
  582. // if(SD_Type != SD_TYPE_V2HC)
  583. // {
  584. // sector = sector<<9;
  585. // }
  586. //如果目标卡不是MMC卡,启用ACMD23指令使能预擦除
  587. if(SD_Type != SD_TYPE_MMC)
  588. {
  589. r1 = SD_SendCommand(ACMD23, count, 0x00);
  590. }
  591. //发多块写入指令
  592. r1 = SD_SendCommand(CMD25, sector, 0x00);
  593. if(r1 != 0x00)
  594. {
  595. return r1; //应答不正确,直接返回
  596. }
  597. //开始准备数据传输
  598. FLASH_SPI_CS_ENABLE();
  599. //先放3个空数据,等待SD卡准备好
  600. SPI_FLASH_SendByte(0xff);
  601. SPI_FLASH_SendByte(0xff);
  602. //--------下面是N个sector写入的循环部分
  603. do
  604. {
  605. //放起始令牌0xFC 表明是多块写入
  606. SPI_FLASH_SendByte(0xFC);
  607. //放一个sector的数据
  608. for(i=0;i<512;i++)
  609. {
  610. SPI_FLASH_SendByte(*data++);
  611. }
  612. //发2个Byte的dummy CRC
  613. SPI_FLASH_SendByte(0xff);
  614. SPI_FLASH_SendByte(0xff);
  615. //等待SD卡应答
  616. r1 = SPI_FLASH_SendByte(0xff);
  617. if((r1&0x1F)!=0x05)
  618. {
  619. FLASH_SPI_CS_DISABLE(); //如果应答为报错,则带错误代码直接退出
  620. return r1;
  621. }
  622. //等待SD卡写入完成
  623. if(SD_WaitReady()==1)
  624. {
  625. FLASH_SPI_CS_DISABLE(); //等待SD卡写入完成超时,直接退出报错
  626. return 1;
  627. }
  628. //本sector数据传输完成
  629. }while(--count);
  630. //发结束传输令牌0xFD
  631. r1 = SPI_FLASH_SendByte(0xFD);
  632. if(r1==0x00)
  633. {
  634. count = 0xfe;
  635. }
  636. if(SD_WaitReady())
  637. {
  638. while(1)
  639. {
  640. }
  641. }
  642. //写入完成,片选置1
  643. FLASH_SPI_CS_DISABLE();
  644. SPI_FLASH_SendByte(0xff);
  645. return count; //返回count值,如果写完则count=0,否则count=1
  646. }

SDCard.h 根据YS-F1Pro SPI Flash 改写 SD

  1. #ifndef __SDCard_H
  2. #define __SDCard_H
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. #include "main.h"
  7. #include "stm32f1xx_hal.h"
  8. //#define SPI_FLASH_ID 0xEF3015 //W25X16 2MB
  9. //#define SPI_FLASH_ID 0xEF4015 //W25Q16 4MB
  10. //#define SPI_FLASH_ID 0XEF4017 //W25Q64 8MB
  11. #define SPI_FLASH_ID 0XEF4018 //W25Q128 16MB YS-F1Pro开发默认使用
  12. #define FLASH_SPIx SPI1
  13. #define FLASH_SPIx_RCC_CLK_ENABLE() __HAL_RCC_SPI1_CLK_ENABLE()
  14. #define FLASH_SPIx_RCC_CLK_DISABLE() __HAL_RCC_SPI1_CLK_DISABLE()
  15. #define FLASH_SPI_GPIO_ClK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
  16. #define FLASH_SPI_GPIO_PORT GPIOA
  17. #define FLASH_SPI_SCK_PIN GPIO_PIN_5
  18. #define FLASH_SPI_MISO_PIN GPIO_PIN_6
  19. #define FLASH_SPI_MOSI_PIN GPIO_PIN_7
  20. #define FLASH_SPI_CS_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
  21. #define FLASH_SPI_CS_PORT GPIOA
  22. #define FLASH_SPI_CS_PIN GPIO_PIN_4
  23. #define FLASH_SPI_CS_ENABLE() HAL_GPIO_WritePin(FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN, GPIO_PIN_RESET)
  24. #define FLASH_SPI_CS_DISABLE() HAL_GPIO_WritePin(FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN, GPIO_PIN_SET)
  25. extern SPI_HandleTypeDef hspiflash;
  26. #define u8 uint8_t
  27. #define u16 uint16_t
  28. #define u32 uint32_t
  29. #define SD_TYPE_MMC 0
  30. #define SD_TYPE_V1 1
  31. #define SD_TYPE_V2 2
  32. #define SD_TYPE_V2HC 4
  33. #define SPI_SPEED_LOW 0
  34. #define SPI_SPEED_HIGH 1
  35. #define NO_RELEASE 0
  36. #define RELEASE 1
  37. #define CMD0 0 //卡复位
  38. #define CMD9 9 //命令9 ,读CSD数据
  39. #define CMD10 10 //命令10,读CID数据
  40. #define CMD12 12 //命令12,停止数据传输
  41. #define CMD16 16 //命令16,设置SectorSize 应返回0x00
  42. #define CMD17 17 //命令17,读sector
  43. #define CMD18 18 //命令18,读Multi sector
  44. #define ACMD23 23 //命令23,设置多sector写入前预先擦除N个block
  45. #define CMD24 24 //命令24,写sector
  46. #define CMD25 25 //命令25,写Multi sector
  47. #define ACMD41 41 //命令41,应返回0x00
  48. #define CMD55 55 //命令55,应返回0x01
  49. #define CMD58 58 //命令58,读OCR信息
  50. #define CMD59 59 //命令59,使能/禁止CRC,应返回0x00
  51. //SD卡CS片选使能端操作:
  52. #define SD_CS_ENABLE() GPIO_ResetBits(GPIOA,GPIO_PIN_4) //选中SD卡
  53. #define SD_CS_DISABLE() GPIO_SetBits(GPIOA,GPIO_PIN_4) //不选中SD卡
  54. //#define SD_PWR_ON() GPIO_ResetBits(GPIOD,GPIO_Pin_10) //SD卡上电
  55. //#define SD_PWR_OFF() GPIO_SetBits(GPIOD,GPIO_Pin_10) //SD卡断电
  56. //#define SD_DET() !GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2) //检测有卡
  57. //1-有 0-无
  58. void SPI_Configuration(void);
  59. void SPI_SetSpeed(u8 SpeedSet);
  60. u8 SPI_ReadWriteByte(u8 TxData); //SPI总线读写一个字节
  61. u8 SD_WaitReady(void); //等待SD卡就绪
  62. u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc); //SD卡发送一个命令
  63. u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc);
  64. u8 SD_Init(void); //SD卡初始化
  65. //
  66. u8 SD_ReceiveData(u8 *data, u16 len, u8 release);//SD卡读数据
  67. u8 SD_GetCID(u8 *cid_data); //读SD卡CID
  68. u8 SD_GetCSD(u8 *csd_data); //读SD卡CSD
  69. u32 SD_GetCapacity(void); //取SD卡容量
  70. u8 SD_ReadSingleBlock(u32 sector, u8 *buffer); //读一个sector
  71. u8 SD_WriteSingleBlock(u32 sector, const u8 *buffer); //写一个sector
  72. u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count); //读多个sector
  73. u8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count); //写多个sector
  74. extern u8 SD_Init(void);
  75. #ifdef __cplusplus
  76. }
  77. #endif
  78. #endif

2、添加FATFS文件系统

cube sdio fatfs 初始化sd卡_【STM32】SD卡读写(五)-STM32CubeMX HAL库SPI操作 SD卡带FATFS...

3、修改FATFS文件系统SD卡驱动部分sdcard_diskio.c

  1. #include "main.h"
  2. #include
  3. #include "SDCard.h"
  4. #include "ff_gen_drv.h"
  5. #define BLOCK_SIZE 512
  6. static volatile DSTATUS Stat = STA_NOINIT;
  7. DSTATUS SD_initialize (BYTE);
  8. DSTATUS SD_status (BYTE);
  9. DRESULT SD_read (BYTE, BYTE*, DWORD, UINT);
  10. #if _USE_WRITE == 1 // 如果允许写操作
  11. DRESULT SD_write (BYTE, const BYTE*, DWORD, UINT);
  12. #endif
  13. #if _USE_IOCTL == 1 // 如果输入输出操作控制
  14. DRESULT SD_ioctl (BYTE, BYTE, void*);
  15. #endif
  16. const Diskio_drvTypeDef SD_Driver =
  17. {
  18. SD_initialize, // SD卡初始化
  19. SD_status, // SD卡状态获取
  20. SD_read, // SD卡读数据
  21. #if _USE_WRITE == 1
  22. SD_write, // SD卡写数据
  23. #endif
  24. #if _USE_IOCTL == 1
  25. SD_ioctl, // 获取SD卡信息
  26. #endif
  27. };
  28. //extern void MX_SPI1_Init(void);
  29. DSTATUS SD_initialize(BYTE lun)
  30. {
  31. Stat = STA_NOINIT;
  32. // MX_SPI1_Init();
  33. int result;
  34. result = SD_Init();
  35. // if(HAL_SD_GetStatus(&hsdcard)==SD_TRANSFER_OK)
  36. // {
  37. // Stat &= ~STA_NOINIT;
  38. // }
  39. if (result == 0)
  40. {
  41. Stat = RES_OK;
  42. }
  43. else
  44. {
  45. Stat = RES_ERROR;
  46. }
  47. return Stat;
  48. }
  49. DSTATUS SD_status(BYTE lun)
  50. {
  51. Stat = STA_NOINIT;
  52. // if(HAL_SD_GetStatus(&hsdcard) == SD_TRANSFER_OK)
  53. // {
  54. // Stat &= ~STA_NOINIT;
  55. // }
  56. Stat = RES_OK;
  57. return Stat;
  58. }
  59. DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
  60. {
  61. DRESULT res = RES_OK;
  62. // if((DWORD)buff&3)
  63. // {
  64. // DWORD scratch[BLOCK_SIZE/4];
  65. // while (count--)
  66. // {
  67. // res = SD_read(lun,(void *)scratch, sector++, 1);
  68. // if (res != RES_OK)
  69. // {
  70. // break;
  71. // }
  72. // memcpy(buff, scratch, BLOCK_SIZE);
  73. // buff += BLOCK_SIZE;
  74. // }
  75. // return res;
  76. // }
  77. //
  78. // if(HAL_SD_ReadBlocks_DMA(&hsdcard,(uint32_t*)buff,(uint64_t)(sector * BLOCK_SIZE),BLOCK_SIZE,count) != SD_OK)
  79. // {
  80. // res = RES_ERROR;
  81. // }
  82. // if(res==RES_OK)
  83. // {
  84. // if(HAL_SD_CheckReadOperation(&hsdcard, 0xFFFFFFFF) != SD_OK)
  85. // {
  86. // res = RES_ERROR;
  87. // }
  88. // }
  89. int result;
  90. if(count==1)
  91. {
  92. result=SD_ReadSingleBlock(sector,buff);
  93. }
  94. else
  95. {
  96. result = SD_ReadMultiBlock(sector, buff, count);
  97. }
  98. if (result == 0)
  99. {
  100. res = RES_OK;
  101. }
  102. else
  103. {
  104. res = RES_ERROR;
  105. }
  106. return res;
  107. }
  108. #if _USE_WRITE == 1
  109. DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
  110. {
  111. DRESULT res = RES_OK;
  112. // if((DWORD)buff&3)
  113. // {
  114. // DRESULT res = RES_OK;
  115. // DWORD scratch[BLOCK_SIZE / 4];
  116. // while (count--)
  117. // {
  118. // memcpy( scratch,buff,BLOCK_SIZE);
  119. // res = SD_write(lun,(void *)scratch, sector++, 1);
  120. // if (res != RES_OK)
  121. // {
  122. // break;
  123. // }
  124. // buff += BLOCK_SIZE;
  125. // }
  126. // return res;
  127. // }
  128. //
  129. // if(HAL_SD_WriteBlocks(&hsdcard,(uint32_t*)buff,(uint64_t)(sector * BLOCK_SIZE),BLOCK_SIZE, count) != SD_OK)
  130. // {
  131. // res = RES_ERROR;
  132. // }
  133. int result;
  134. if(count==1)
  135. {
  136. result=SD_WriteSingleBlock(sector, buff);
  137. }
  138. else
  139. {
  140. result = SD_WriteMultiBlock(sector, buff, count);
  141. }
  142. if (result == 0)
  143. {
  144. res = RES_OK;
  145. }
  146. else
  147. {
  148. res = RES_ERROR;
  149. }
  150. return res;
  151. }
  152. #endif
  153. #if _USE_IOCTL == 1
  154. DRESULT SD_ioctl(BYTE lun, BYTE cmd, void *buff)
  155. {
  156. DRESULT res = RES_ERROR;
  157. // if (Stat & STA_NOINIT) return RES_NOTRDY;
  158. //
  159. // switch (cmd)
  160. // {
  161. //
  162. // case CTRL_SYNC :
  163. //FLASH_SPI_CS_ENABLE();
  164. //if(SD_WaitReady()==0)
  165. //{
  166. //res = RES_OK;
  167. //}
  168. //else
  169. //{
  170. //res = RES_ERROR;
  171. //}
  172. FLASH_SPI_CSDISABLE();
  173. // break;
  174. //
  175. //
  176. // case GET_SECTOR_COUNT :
  177. /
  178. // case GET_SECTOR_SIZE :
  179. /
  180. // case GET_BLOCK_SIZE :
  181. // *(DWORD*)buff = BLOCK_SIZE;
  182. // break;
  183. //
  184. // default:
  185. // res = RES_PARERR;
  186. // }
  187. uint8_t CSD[16] = {0};
  188. uint8_t csddata[16] = {0};
  189. uint32_t csize;
  190. uint32_t Capacity;
  191. switch (cmd)
  192. {
  193. case CTRL_SYNC:
  194. res = RES_OK;
  195. break;
  196. case GET_SECTOR_COUNT:
  197. SD_GetCID(CSD);
  198. SD_GetCSD(csddata);
  199. //SDGetCIDCSD(CSD, csddata);
  200. csize = csddata[9] + ((uint32_t)csddata[8] << 8) + ((uint32_t)(csddata[7] & 0x3f) << 16) + 1;
  201. Capacity = csize << 9;
  202. *((DWORD *)buff) = Capacity;
  203. res = RES_OK;
  204. break;
  205. case GET_SECTOR_SIZE:
  206. *(WORD *)buff = 512; //spi flash的扇区大小是 512 Bytes
  207. return RES_OK;
  208. case GET_BLOCK_SIZE:
  209. *((DWORD *)buff) = 4096;
  210. res = RES_OK;
  211. break;
  212. default:
  213. res = RES_PARERR;
  214. break;
  215. }
  216. return res;
  217. }
  218. #endif

4、在Main.c文件中添加 测试应用程序

  1. char SPIFLASHPath[4];
  2. char SDPath[4];
  3. FATFS fs;
  4. FIL file;
  5. FRESULT f_res;
  6. UINT fnum;
  7. BYTE ReadBuffer[1024]={0};
  8. BYTE WriteBuffer[]= "欢迎使用硬石STM32开发板 今天是个好日子,新建文件系统测试文件";
  9. extern Diskio_drvTypeDef SD_Driver;

添加文件系统操作结果处理

  1. static void printf_fatfs_error(FRESULT fresult)
  2. {
  3. switch(fresult)
  4. {
  5. case FR_OK: //(0)
  6. printf("》操作成功。");
  7. break;
  8. case FR_DISK_ERR: //(1)
  9. printf("!!硬件输入输出驱动出错。");
  10. break;
  11. case FR_INT_ERR: //(2)
  12. printf("!!断言错误。");
  13. break;
  14. case FR_NOT_READY: //(3)
  15. printf("!!物理设备无法工作。");
  16. break;
  17. case FR_NO_FILE: //(4)
  18. printf("!!无法找到文件。");
  19. break;
  20. case FR_NO_PATH: //(5)
  21. printf("!!无法找到路径。");
  22. break;
  23. case FR_INVALID_NAME: //(6)
  24. printf("!!无效的路径名。");
  25. break;
  26. case FR_DENIED: //(7)
  27. case FR_EXIST: //(8)
  28. printf("!!拒绝访问。");
  29. break;
  30. case FR_INVALID_OBJECT: //(9)
  31. printf("!!无效的文件或路径。");
  32. break;
  33. case FR_WRITE_PROTECTED: //(10)
  34. printf("!!逻辑设备写保护。");
  35. break;
  36. case FR_INVALID_DRIVE: //(11)
  37. printf("!!无效的逻辑设备。");
  38. break;
  39. case FR_NOT_ENABLED: //(12)
  40. printf("!!无效的工作区。");
  41. break;
  42. case FR_NO_FILESYSTEM: //(13)
  43. printf("!!无效的文件系统。");
  44. break;
  45. case FR_MKFS_ABORTED: //(14)
  46. printf("!!因函数参数问题导致f_mkfs函数操作失败。");
  47. break;
  48. case FR_TIMEOUT: //(15)
  49. printf("!!操作超时。");
  50. break;
  51. case FR_LOCKED: //(16)
  52. printf("!!文件被保护。");
  53. break;
  54. case FR_NOT_ENOUGH_CORE: //(17)
  55. printf("!!长文件名支持获取堆空间失败。");
  56. break;
  57. case FR_TOO_MANY_OPEN_FILES: //(18)
  58. printf("!!打开太多文件。");
  59. break;
  60. case FR_INVALID_PARAMETER: // (19)
  61. printf("!!参数无效。");
  62. break;
  63. }
  64. }

添加测试程序:

  1. if(FATFS_LinkDriver(&SD_Driver, SDPath) == 0)
  2. {
  3. //在SD卡挂载文件系统,文件系统挂载时会对SD卡初始化
  4. f_res = f_mount(&fs,(TCHAR const*)SDPath,1);
  5. printf_fatfs_error(f_res);
  6. if(f_res == FR_NO_FILESYSTEM)
  7. {
  8. printf("》SD卡还没有文件系统,即将进行格式化...");
  9. f_res=f_mkfs((TCHAR const*)SDPath,0,0);
  10. if(f_res == FR_OK)
  11. {
  12. printf("》SD卡已成功格式化文件系统。");
  13. f_res = f_mount(NULL,(TCHAR const*)SDPath,1);
  14. f_res = f_mount(&fs,(TCHAR const*)SDPath,1);
  15. }
  16. else
  17. {
  18. printf("《《格式化失败。》》");
  19. while(1);
  20. }
  21. }
  22. else if(f_res!=FR_OK)
  23. {
  24. printf("!!SD卡挂载文件系统失败。(%d)",f_res);
  25. printf_fatfs_error(f_res);
  26. while(1);
  27. }
  28. else
  29. {
  30. printf("》文件系统挂载成功,可以进行读写测试");
  31. }
  32. printf("****** 即将进行文件写入测试... ******");
  33. f_res = f_open(&file, "FatFs读写测试文件.txt",FA_CREATE_ALWAYS | FA_WRITE );
  34. if ( f_res == FR_OK )
  35. {
  36. printf("》打开/创建FatFs读写测试文件.txt文件成功,向文件写入数据。");
  37. f_res=f_write(&file,WriteBuffer,sizeof(WriteBuffer),&fnum);
  38. if(f_res==FR_OK)
  39. {
  40. printf("》文件写入成功,写入字节数据:%d",fnum);
  41. printf("》向文件写入的数据为:%s",WriteBuffer);
  42. }
  43. else
  44. {
  45. printf("!!文件写入失败:(%d)",f_res);
  46. }
  47. f_close(&file);
  48. }
  49. else
  50. {
  51. printf("!!打开/创建文件失败。");
  52. }
  53. printf("****** 即将进行文件读取测试... ******");
  54. f_res = f_open(&file, "FatFs读写测试文件.txt", FA_OPEN_EXISTING | FA_READ);
  55. if(f_res == FR_OK)
  56. {
  57. printf("》打开文件成功。");
  58. f_res = f_read(&file, ReadBuffer, sizeof(ReadBuffer), &fnum);
  59. if(f_res==FR_OK)
  60. {
  61. printf("》文件读取成功,读到字节数据:%d",fnum);
  62. printf("》读取得的文件数据为:%s ", ReadBuffer);
  63. }
  64. else
  65. {
  66. printf("!!文件读取失败:(%d)",f_res);
  67. }
  68. }
  69. else
  70. {
  71. printf("!!打开文件失败。");
  72. }
  73. f_close(&file);
  74. f_res = f_mount(NULL,(TCHAR const*)SDPath,1);
  75. }
  76. FATFS_UnLinkDriver(SDPath);

3、使用串口查看测试结果

cube sdio fatfs 初始化sd卡_【STM32】SD卡读写(五)-STM32CubeMX HAL库SPI操作 SD卡带FATFS...

继续阅读