demo_nand_fatfs.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. /*
  2. *********************************************************************************************************
  3. *
  4. * 模块名称 : NAND Flash Fat文件系统演示模块。
  5. * 文件名称 : demo_nand_fatfs.c
  6. * 版 本 : V1.0
  7. * 说 明 : 该例程移植FatFS文件系统(版本 R0.09b),演示如何创建文件、读取文件、创建目录和删除文件
  8. * 并测试了文件读写速度。
  9. *
  10. * 修改记录 :
  11. * 版本号 日期 作者 说明
  12. * V1.0 2013-02-01 armfly 正式发布
  13. * V1.1 2013-06-20 armfly 正式发布
  14. *
  15. * Copyright (C), 2013-2014, 安富莱电子 www.armfly.com
  16. *
  17. *********************************************************************************************************
  18. */
  19. #include "bsp.h"
  20. #include "ff.h" /* FatFS文件系统模块*/
  21. #include "demo_nand_fatfs.h"
  22. /* 用于测试读写速度 */
  23. #define TEST_FILE_LEN (2*1024*1024) /* 用于测试的文件长度 */
  24. #define BUF_SIZE (4*1024) /* 每次读写SD卡的最大数据长度 */
  25. uint8_t g_TestBuf[BUF_SIZE];
  26. /* 仅允许本文件内调用的函数声明 */
  27. static void DispMenu(void);
  28. static void ViewRootDir(void);
  29. static void CreateNewFile(void);
  30. static void ReadFileData(void);
  31. static void CreateDir(void);
  32. static void DeleteDirFile(void);
  33. static void WriteFileTest(void);
  34. /*
  35. *********************************************************************************************************
  36. * 函 数 名: DemoFatFS
  37. * 功能说明: FatFS文件系统演示主程序
  38. * 形 参:无
  39. * 返 回 值: 无
  40. *********************************************************************************************************
  41. */
  42. void DemoFatFS(void)
  43. {
  44. uint8_t cmd;
  45. /* 打印命令列表,用户可以通过串口操作指令 */
  46. DispMenu();
  47. while(1)
  48. {
  49. bsp_Idle(); /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */
  50. //cmd = getchar(); /* 从串口读入一个字符 (阻塞方式) */
  51. if (1) /* 从串口读入一个字符(非阻塞方式) */
  52. {
  53. printf("\r\n------------------------------------------------\r\n");
  54. switch ('2')
  55. {
  56. case '1':
  57. printf("【1 - ViewRootDir】\r\n");
  58. ViewRootDir(); /* 显示根目录下的文件名 */
  59. break;
  60. case '2':
  61. printf("【2 - CreateNewFile】\r\n");
  62. CreateNewFile(); /* 创建一个新文件,写入一个字符串 */
  63. break;
  64. case '3':
  65. printf("【3 - ReadFileData】\r\n");
  66. ReadFileData(); /* 读取根目录下armfly.txt的内容 */
  67. break;
  68. case '4':
  69. printf("【4 - CreateDir】\r\n");
  70. CreateDir(); /* 创建目录 */
  71. break;
  72. case '5':
  73. printf("【5 - DeleteDirFile】\r\n");
  74. DeleteDirFile(); /* 删除目录和文件 */
  75. break;
  76. case '6':
  77. printf("【6 - TestSpeed】\r\n");
  78. WriteFileTest(); /* 速度测试 */
  79. break;
  80. case '0':
  81. printf("Start Format(Low Level) NAND Flash......\r\n");
  82. NAND_Format();
  83. printf("NAND Flash Format Ok\r\n");
  84. break;
  85. default:
  86. DispMenu();
  87. break;
  88. }
  89. }
  90. }
  91. }
  92. /*
  93. *********************************************************************************************************
  94. * 函 数 名: DispMenu
  95. * 功能说明: 显示操作提示菜单
  96. * 形 参:无
  97. * 返 回 值: 无
  98. *********************************************************************************************************
  99. */
  100. static void DispMenu(void)
  101. {
  102. printf("\r\n------------------------------------------------\r\n");
  103. printf("请选择操作命令:\r\n");
  104. printf("1 - 显示根目录下的文件列表\r\n");
  105. printf("2 - 创建一个新文件armfly.txt\r\n");
  106. printf("3 - 读armfly.txt文件的内容\r\n");
  107. printf("4 - 创建目录\r\n");
  108. printf("5 - 删除文件和目录\r\n");
  109. printf("6 - 读写文件速度测试\r\n");
  110. printf("0 - NAND Flash 低级格式化\r\n");
  111. }
  112. /*
  113. *********************************************************************************************************
  114. * 函 数 名: ViewRootDir
  115. * 功能说明: 显示SD卡根目录下的文件名
  116. * 形 参:无
  117. * 返 回 值: 无
  118. *********************************************************************************************************
  119. */
  120. static void ViewRootDir(void)
  121. {
  122. /* 本函数使用的局部变量占用较多,请修改启动文件,保证堆栈空间够用 */
  123. FRESULT result;
  124. FATFS fs;
  125. DIR DirInf;
  126. FILINFO FileInf;
  127. uint32_t cnt = 0;
  128. char lfname[256];
  129. /* 挂载文件系统 */
  130. result = f_mount(&fs, FS_VOLUME_NAND, 0); /* Mount a logical drive */
  131. if (result != FR_OK)
  132. {
  133. printf("挂载文件系统失败 (%d)\r\n", result);
  134. }
  135. /* 打开根文件夹 */
  136. result = f_opendir(&DirInf, "0:/"); /* 1: 表示盘符 */
  137. if (result != FR_OK)
  138. {
  139. printf("打开根目录失败 (%d)\r\n", result);
  140. return;
  141. }
  142. /* 读取当前文件夹下的文件和目录 */
  143. FileInf.lfname = lfname;
  144. FileInf.lfsize = 256;
  145. printf("属性 | 文件大小 | 短文件名 | 长文件名\r\n");
  146. for (cnt = 0; ;cnt++)
  147. {
  148. result = f_readdir(&DirInf,&FileInf); /* 读取目录项,索引会自动下移 */
  149. if (result != FR_OK || FileInf.fname[0] == 0)
  150. {
  151. break;
  152. }
  153. if (FileInf.fname[0] == '.')
  154. {
  155. continue;
  156. }
  157. /* 判断是文件还是子目录 */
  158. if (FileInf.fattrib & AM_DIR)
  159. {
  160. printf("(0x%02d)目录 ", FileInf.fattrib);
  161. }
  162. else
  163. {
  164. printf("(0x%02d)文件 ", FileInf.fattrib);
  165. }
  166. /* 打印文件大小, 最大4G */
  167. printf(" %10d", FileInf.fsize);
  168. printf(" %s |", FileInf.fname); /* 短文件名 */
  169. printf(" %s\r\n", (char *)FileInf.lfname); /* 长文件名 */
  170. }
  171. /* 卸载文件系统 */
  172. f_mount(NULL, FS_VOLUME_NAND, 0);
  173. }
  174. /*
  175. *********************************************************************************************************
  176. * 函 数 名: CreateNewFile
  177. * 功能说明: 在SD卡创建一个新文件,文件内容填写“www.armfly.com”
  178. * 形 参:无
  179. * 返 回 值: 无
  180. *********************************************************************************************************
  181. */
  182. static void CreateNewFile(void)
  183. {
  184. /* 本函数使用的局部变量占用较多,请修改启动文件,保证堆栈空间够用 */
  185. FRESULT result;
  186. FATFS fs;
  187. FIL file;
  188. DIR DirInf;
  189. uint32_t bw;
  190. /* 挂载文件系统 */
  191. result = f_mount(&fs, FS_VOLUME_NAND, 0); /* Mount a logical drive */
  192. if (result != FR_OK)
  193. {
  194. printf("挂载文件系统失败 (%d)\r\n", result);
  195. }
  196. /* 打开根文件夹 */
  197. result = f_opendir(&DirInf, "0:/"); /* 1: 表示盘符 */
  198. if(result==FR_NO_FILESYSTEM) //如果返回值为无filesystem则创建文件系统
  199. {
  200. f_mkfs("0:",0,0);
  201. }
  202. if (result != FR_OK)
  203. {
  204. printf("打开根目录失败 (%d)\r\n", result);
  205. return;
  206. }
  207. /* 打开文件 */
  208. result = f_open(&file, "0:/armfly.txt", FA_CREATE_ALWAYS | FA_WRITE);
  209. /* 写一串数据 */
  210. result = f_write(&file, "FatFS Write Demo \r\n www.armfly.com \r\n", 34, &bw);
  211. if (result == FR_OK)
  212. {
  213. printf("armfly.txt 文件写入成功\r\n");
  214. }
  215. else
  216. {
  217. printf("armfly.txt 文件写入失败\r\n");
  218. }
  219. /* 关闭文件*/
  220. f_close(&file);
  221. /* 卸载文件系统 */
  222. f_mount(NULL, FS_VOLUME_NAND, 0);
  223. }
  224. /*
  225. *********************************************************************************************************
  226. * 函 数 名: ReadFileData
  227. * 功能说明: 读取文件armfly.txt前128个字符,并打印到串口
  228. * 形 参:无
  229. * 返 回 值: 无
  230. *********************************************************************************************************
  231. */
  232. static void ReadFileData(void)
  233. {
  234. /* 本函数使用的局部变量占用较多,请修改启动文件,保证堆栈空间够用 */
  235. FRESULT result;
  236. FATFS fs;
  237. FIL file;
  238. DIR DirInf;
  239. uint32_t bw;
  240. char buf[128];
  241. /* 挂载文件系统 */
  242. result = f_mount(&fs, FS_VOLUME_NAND, 0); /* Mount a logical drive */
  243. if (result != FR_OK)
  244. {
  245. printf("挂载文件系统失败(%d)\r\n", result);
  246. }
  247. /* 打开根文件夹 */
  248. result = f_opendir(&DirInf, "0:/"); /* 1: 表示盘符 */
  249. if (result != FR_OK)
  250. {
  251. printf("打开根目录失败(%d)\r\n", result);
  252. return;
  253. }
  254. /* 打开文件 */
  255. result = f_open(&file, "0:/armfly.txt", FA_OPEN_EXISTING | FA_READ);
  256. if (result != FR_OK)
  257. {
  258. printf("Don't Find File : armfly.txt\r\n");
  259. return;
  260. }
  261. /* 读取文件 */
  262. result = f_read(&file, &buf, sizeof(buf) - 1, &bw);
  263. if (bw > 0)
  264. {
  265. buf[bw] = 0;
  266. printf("\r\narmfly.txt 文件内容 : \r\n%s\r\n", buf);
  267. }
  268. else
  269. {
  270. printf("\r\narmfly.txt 文件内容 : \r\n");
  271. }
  272. /* 关闭文件*/
  273. f_close(&file);
  274. /* 卸载文件系统 */
  275. f_mount(NULL, FS_VOLUME_NAND, 0);
  276. }
  277. /*
  278. *********************************************************************************************************
  279. * 函 数 名: CreateDir
  280. * 功能说明: 在SD卡根目录创建Dir1和Dir2目录,在Dir1目录下创建子目录Dir1_1
  281. * 形 参:无
  282. * 返 回 值: 无
  283. *********************************************************************************************************
  284. */
  285. static void CreateDir(void)
  286. {
  287. /* 本函数使用的局部变量占用较多,请修改启动文件,保证堆栈空间够用 */
  288. FRESULT result;
  289. FATFS fs;
  290. /* 挂载文件系统 */
  291. result = f_mount(&fs, FS_VOLUME_NAND, 0); /* Mount a logical drive */
  292. if (result != FR_OK)
  293. {
  294. printf("挂载文件系统失败 (%d)\r\n", result);
  295. }
  296. /* 创建目录/Dir1 */
  297. result = f_mkdir("0:/Dir1");
  298. if (result == FR_OK)
  299. {
  300. printf("f_mkdir Dir1 Ok\r\n");
  301. }
  302. else if (result == FR_EXIST)
  303. {
  304. printf("Dir1 目录已经存在(%d)\r\n", result);
  305. }
  306. else
  307. {
  308. printf("f_mkdir Dir1 失败 (%d)\r\n", result);
  309. return;
  310. }
  311. /* 创建目录/Dir2 */
  312. result = f_mkdir("0:/Dir2");
  313. if (result == FR_OK)
  314. {
  315. printf("f_mkdir Dir2 Ok\r\n");
  316. }
  317. else if (result == FR_EXIST)
  318. {
  319. printf("Dir2 目录已经存在(%d)\r\n", result);
  320. }
  321. else
  322. {
  323. printf("f_mkdir Dir2 失败 (%d)\r\n", result);
  324. return;
  325. }
  326. /* 创建子目录 /Dir1/Dir1_1 注意:创建子目录Dir1_1时,必须先创建好Dir1 */
  327. result = f_mkdir("0:/Dir1/Dir1_1"); /* */
  328. if (result == FR_OK)
  329. {
  330. printf("f_mkdir Dir1_1 成功\r\n");
  331. }
  332. else if (result == FR_EXIST)
  333. {
  334. printf("Dir1_1 目录已经存在 (%d)\r\n", result);
  335. }
  336. else
  337. {
  338. printf("f_mkdir Dir1_1 失败 (%d)\r\n", result);
  339. return;
  340. }
  341. /* 卸载文件系统 */
  342. f_mount(NULL, FS_VOLUME_NAND, 0);
  343. }
  344. /*
  345. *********************************************************************************************************
  346. * 函 数 名: DeleteDirFile
  347. * 功能说明: 删除SD卡根目录下的 armfly.txt 文件和 Dir1,Dir2 目录
  348. * 形 参:无
  349. * 返 回 值: 无
  350. *********************************************************************************************************
  351. */
  352. static void DeleteDirFile(void)
  353. {
  354. /* 本函数使用的局部变量占用较多,请修改启动文件,保证堆栈空间够用 */
  355. FRESULT result;
  356. FATFS fs;
  357. char FileName[13];
  358. uint8_t i;
  359. /* 挂载文件系统 */
  360. result = f_mount(&fs, FS_VOLUME_NAND, 0); /* Mount a logical drive */
  361. if (result != FR_OK)
  362. {
  363. printf("挂载文件系统失败 (%d)\r\n", result);
  364. }
  365. #if 0
  366. /* 打开根文件夹 */
  367. result = f_opendir(&DirInf, "0:/"); /* 如果不带参数,则从当前目录开始 */
  368. if (result != FR_OK)
  369. {
  370. printf("打开根目录失败(%d)\r\n", result);
  371. return;
  372. }
  373. #endif
  374. /* 删除目录/Dir1 【因为还存在目录非空(存在子目录),所以这次删除会失败】*/
  375. result = f_unlink("0:/Dir1");
  376. if (result == FR_OK)
  377. {
  378. printf("删除目录Dir1成功\r\n");
  379. }
  380. else if (result == FR_NO_FILE)
  381. {
  382. printf("没有发现文件或目录 :%s\r\n", "/Dir1");
  383. }
  384. else
  385. {
  386. printf("删除Dir1失败(错误代码 = %d) 文件只读或目录非空\r\n", result);
  387. }
  388. /* 先删除目录/Dir1/Dir1_1 */
  389. result = f_unlink("0:/Dir1/Dir1_1");
  390. if (result == FR_OK)
  391. {
  392. printf("删除子目录/Dir1/Dir1_1成功\r\n");
  393. }
  394. else if ((result == FR_NO_FILE) || (result == FR_NO_PATH))
  395. {
  396. printf("没有发现文件或目录 :%s\r\n", "/Dir1/Dir1_1");
  397. }
  398. else
  399. {
  400. printf("删除子目录/Dir1/Dir1_1失败(错误代码 = %d) 文件只读或目录非空\r\n", result);
  401. }
  402. /* 先删除目录/Dir1 */
  403. result = f_unlink("0:/Dir1");
  404. if (result == FR_OK)
  405. {
  406. printf("删除目录Dir1成功\r\n");
  407. }
  408. else if (result == FR_NO_FILE)
  409. {
  410. printf("没有发现文件或目录 :%s\r\n", "/Dir1");
  411. }
  412. else
  413. {
  414. printf("删除Dir1失败(错误代码 = %d) 文件只读或目录非空\r\n", result);
  415. }
  416. /* 删除目录/Dir2 */
  417. result = f_unlink("0:/Dir2");
  418. if (result == FR_OK)
  419. {
  420. printf("删除目录 Dir2 成功\r\n");
  421. }
  422. else if (result == FR_NO_FILE)
  423. {
  424. printf("没有发现文件或目录 :%s\r\n", "/Dir2");
  425. }
  426. else
  427. {
  428. printf("删除Dir2 失败(错误代码 = %d) 文件只读或目录非空\r\n", result);
  429. }
  430. /* 删除文件 armfly.txt */
  431. result = f_unlink("0:/armfly.txt");
  432. if (result == FR_OK)
  433. {
  434. printf("删除文件 armfly.txt 成功\r\n");
  435. }
  436. else if (result == FR_NO_FILE)
  437. {
  438. printf("没有发现文件或目录 :%s\r\n", "armfly.txt");
  439. }
  440. else
  441. {
  442. printf("删除armfly.txt失败(错误代码 = %d) 文件只读或目录非空\r\n", result);
  443. }
  444. /* 删除文件 speed1.txt */
  445. for (i = 0; i < 20; i++)
  446. {
  447. sprintf(FileName, "0:/Speed%02d.txt", i); /* 每写1次,序号递增 */
  448. result = f_unlink(FileName);
  449. if (result == FR_OK)
  450. {
  451. printf("删除文件%s成功\r\n", FileName);
  452. }
  453. else if (result == FR_NO_FILE)
  454. {
  455. printf("没有发现文件:%s\r\n", FileName);
  456. }
  457. else
  458. {
  459. printf("删除%s文件失败(错误代码 = %d) 文件只读或目录非空\r\n", FileName, result);
  460. }
  461. }
  462. /* 卸载文件系统 */
  463. f_mount(NULL, FS_VOLUME_NAND, 0);
  464. }
  465. /*
  466. *********************************************************************************************************
  467. * 函 数 名: WriteFileTest
  468. * 功能说明: 测试文件读写速度
  469. * 形 参:无
  470. * 返 回 值: 无
  471. *********************************************************************************************************
  472. */
  473. static void WriteFileTest(void)
  474. {
  475. /* 本函数使用的局部变量占用较多,请修改启动文件,保证堆栈空间够用 */
  476. FRESULT result;
  477. FATFS fs;
  478. FIL file;
  479. DIR DirInf;
  480. uint32_t bw;
  481. uint32_t i,k;
  482. uint32_t runtime1,runtime2,timelen;
  483. uint8_t err = 0;
  484. char TestFileName[13];
  485. static uint8_t s_ucTestSn = 0;
  486. for (i = 0; i < sizeof(g_TestBuf); i++)
  487. {
  488. g_TestBuf[i] = (i / 512) + '0';
  489. }
  490. /* 挂载文件系统 */
  491. result = f_mount(&fs, FS_VOLUME_NAND, 0); /* Mount a logical drive */
  492. if (result != FR_OK)
  493. {
  494. printf("挂载文件系统失败 (%d)\r\n", result);
  495. }
  496. /* 打开根文件夹 */
  497. result = f_opendir(&DirInf, "0:/"); /* 如果不带参数,则从当前目录开始 */
  498. if (result != FR_OK)
  499. {
  500. printf("打开根目录失败 (%d)\r\n", result);
  501. return;
  502. }
  503. /* 打开文件 */
  504. sprintf(TestFileName, "0:/Speed%02d.txt", s_ucTestSn++); /* 每写1次,序号递增 */
  505. result = f_open(&file, TestFileName, FA_CREATE_ALWAYS | FA_WRITE);
  506. /* 写一串数据 */
  507. printf("开始写文件%s %dKB ...\r\n", TestFileName, TEST_FILE_LEN / 1024);
  508. runtime1 = 10; /* 读取系统运行时间 */
  509. for (i = 0; i < TEST_FILE_LEN / BUF_SIZE; i++)
  510. {
  511. result = f_write(&file, g_TestBuf, sizeof(g_TestBuf), &bw);
  512. if (result == FR_OK)
  513. {
  514. if (((i + 1) % 8) == 0)
  515. {
  516. printf(".");
  517. }
  518. }
  519. else
  520. {
  521. err = 1;
  522. printf("%s文件写失败\r\n", TestFileName);
  523. break;
  524. }
  525. }
  526. runtime2 =100; /* 读取系统运行时间 */
  527. if (err == 0)
  528. {
  529. timelen = (runtime2 - runtime1);
  530. printf("\r\n 写耗时 : %dms 平均写速度 : %dB/S (%dKB/S)\r\n",
  531. timelen,
  532. (TEST_FILE_LEN * 1000) / timelen,
  533. ((TEST_FILE_LEN / 1024) * 1000) / timelen);
  534. }
  535. f_close(&file); /* 关闭文件*/
  536. /* 开始读文件测试 */
  537. result = f_open(&file, TestFileName, FA_OPEN_EXISTING | FA_READ);
  538. if (result != FR_OK)
  539. {
  540. printf("没有找到文件: %s\r\n", TestFileName);
  541. return;
  542. }
  543. printf("开始读文件 %dKB ...\r\n", TEST_FILE_LEN / 1024);
  544. runtime1 = 10; /* 读取系统运行时间 */
  545. for (i = 0; i < TEST_FILE_LEN / BUF_SIZE; i++)
  546. {
  547. result = f_read(&file, g_TestBuf, sizeof(g_TestBuf), &bw);
  548. if (result == FR_OK)
  549. {
  550. if (((i + 1) % 8) == 0)
  551. {
  552. printf(".");
  553. }
  554. /* 比较写入的数据是否正确,此语句会导致读卡速度结果降低到 3.5MBytes/S */
  555. for (k = 0; k < sizeof(g_TestBuf); k++)
  556. {
  557. if (g_TestBuf[k] != (k / 512) + '0')
  558. {
  559. err = 1;
  560. printf("Speed1.txt 文件读成功,但是数据出错\r\n");
  561. break;
  562. }
  563. }
  564. if (err == 1)
  565. {
  566. break;
  567. }
  568. }
  569. else
  570. {
  571. err = 1;
  572. printf("Speed1.txt 文件读失败\r\n");
  573. break;
  574. }
  575. }
  576. runtime2 = 100; /* 读取系统运行时间 */
  577. if (err == 0)
  578. {
  579. timelen = (runtime2 - runtime1);
  580. printf("\r\n 读耗时 : %dms 平均读速度 : %dB/S (%dKB/S)\r\n", timelen,
  581. (TEST_FILE_LEN * 1000) / timelen, ((TEST_FILE_LEN / 1024) * 1000) / timelen);
  582. }
  583. /* 关闭文件*/
  584. f_close(&file);
  585. /* 卸载文件系统 */
  586. f_mount(NULL, FS_VOLUME_NAND, 0);
  587. }
  588. /***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/