soft_sdcard.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. #include "board.h"
  2. #include "soft_sdcard.h"
  3. #include "ff.h"
  4. #include "hard_sdio_sd.h"
  5. #include "my_math.h"
  6. #include "soft_delay.h"
  7. #include "soft_time.h"
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include "test.h"
  12. // 掉hpm的sd fatfs库
  13. /*
  14. //==========================连续写入测试=============================
  15. WriteBuffer字节 写入速度 写固定字节数 写大数据块
  16. 512 475kb 写512字节用时1052us 写2*1024*1024字节用时4310us
  17. 1024 563kb 写1024字节用时1775us 写2*1024*1024字节用时3637us
  18. 2048 1280kb 写2048字节用时1562us 写2*1024*1024字节用时1600us
  19. 4096 2528KB 写4096字节用时1582us 写2*1024*1024字节用时810us
  20. /////////////=============实际测试==非连续写入==写512字节用时平均4500us========问题出在哪里????
  21. 实际测试
  22. 正常记录过程中拔掉TF卡不会造成死机。f_write之前会检查系统,如果CARD_ERR会直接返回。且不耗时间,直接返回。
  23. 不连续记录时,每次写512字节用时4000us。写5120字节用时5000us。。。所以猜测写操作的时间主要浪费在了数据发送完成后的写入环节。。
  24. */
  25. /**
  26. ******************************************************************************
  27. * 定义变量
  28. ******************************************************************************
  29. */
  30. FATFS fs; /* FatFs文件系统对象 */
  31. FIL fnew_data, fnew_log; /* 文件对象 */
  32. FRESULT res_sd; /* 文件操作结果 */
  33. UINT frnum; /* 文件成功读数量 */
  34. UINT fwnum; /* 文件成功写数量 */
  35. // BYTE ReadBuffer[_MAX_SS] = {0}; /* 读缓冲区 */
  36. // BYTE WriteBuffer[_MAX_SS] = {0}; /* 写缓冲区*/
  37. BYTE work[FF_MAX_SS] = {0}; /* 工作区 (larger is better for processing time) */
  38. DIR logdir;
  39. DIR posdir;
  40. FILINFO fno;
  41. int file_num = 0;
  42. const TCHAR driver_num_buf[3] = { DEV_SD + '0', ':', '/' };
  43. // FATFS文件名不区分大小写。默认大写。
  44. const char *logpath = "LOG";
  45. const char *pospath = "POS";
  46. static uint8_t _sd_init_ok = 0;
  47. const char *show_error_string(FRESULT fresult);
  48. static FRESULT sd_mount_fs(void);
  49. static FRESULT sd_mkfs(void);
  50. uint8_t sdcard_initok(void)
  51. {
  52. return _sd_init_ok;
  53. }
  54. static FRESULT sd_mount_fs(void)
  55. {
  56. FRESULT fresult = f_mount(&fs, driver_num_buf, 1);
  57. if (fresult == FR_OK) {
  58. printf("SD card has been mounted successfully\n");
  59. } else {
  60. printf("Failed to mount SD card, cause: %s\n", show_error_string(fresult));
  61. }
  62. fresult = f_chdrive(driver_num_buf);
  63. return fresult;
  64. }
  65. static FRESULT sd_mkfs(void)
  66. {
  67. printf("Formatting the SD card, depending on the SD card capacity, the formatting process may take a long time\n");
  68. FRESULT fresult = f_mkfs(driver_num_buf, NULL, work, sizeof(work));
  69. if (fresult != FR_OK) {
  70. printf("Making File system failed, cause: %s\n", show_error_string(fresult));
  71. } else {
  72. printf("Making file system is successful\n");
  73. }
  74. return fresult;
  75. }
  76. const char *show_error_string(FRESULT fresult)
  77. {
  78. const char *result_str;
  79. switch (fresult) {
  80. case FR_OK:
  81. result_str = "succeeded";
  82. break;
  83. case FR_DISK_ERR:
  84. result_str = "A hard error occurred in the low level disk I/O level";
  85. break;
  86. case FR_INT_ERR:
  87. result_str = "Assertion failed";
  88. break;
  89. case FR_NOT_READY:
  90. result_str = "The physical drive cannot work";
  91. break;
  92. case FR_NO_FILE:
  93. result_str = "Could not find the file";
  94. break;
  95. case FR_NO_PATH:
  96. result_str = "Could not find the path";
  97. break;
  98. case FR_INVALID_NAME:
  99. result_str = "Tha path name format is invalid";
  100. break;
  101. case FR_DENIED:
  102. result_str = "Access denied due to prohibited access or directory full";
  103. break;
  104. case FR_EXIST:
  105. result_str = "Access denied due to prohibited access";
  106. break;
  107. case FR_INVALID_OBJECT:
  108. result_str = "The file/directory object is invalid";
  109. break;
  110. case FR_WRITE_PROTECTED:
  111. result_str = "The physical drive is write protected";
  112. break;
  113. case FR_INVALID_DRIVE:
  114. result_str = "The logical driver number is invalid";
  115. break;
  116. case FR_NOT_ENABLED:
  117. result_str = "The volume has no work area";
  118. break;
  119. case FR_NO_FILESYSTEM:
  120. result_str = "There is no valid FAT volume";
  121. break;
  122. case FR_MKFS_ABORTED:
  123. result_str = "THe f_mkfs() aborted due to any problem";
  124. break;
  125. case FR_TIMEOUT:
  126. result_str = "Could not get a grant to access the volume within defined period";
  127. break;
  128. case FR_LOCKED:
  129. result_str = "The operation is rejected according to the file sharing policy";
  130. break;
  131. case FR_NOT_ENOUGH_CORE:
  132. result_str = "LFN working buffer could not be allocated";
  133. break;
  134. case FR_TOO_MANY_OPEN_FILES:
  135. result_str = "Number of open files > FF_FS_LOCK";
  136. break;
  137. case FR_INVALID_PARAMETER:
  138. result_str = "Given parameter is invalid";
  139. break;
  140. default:
  141. result_str = "Unknown error";
  142. break;
  143. }
  144. return result_str;
  145. }
  146. /**
  147. * @brief 初始化 SD 卡
  148. * @param init_type
  149. * @arg 0 初始化 SD 卡, 1 格式化 SD 卡
  150. */
  151. void sdcard_inital(uint8_t init_type)
  152. {
  153. bool need_init_filesystem = true;
  154. DSTATUS dstatus = disk_status(DEV_SD);
  155. printf("sd state is %d\r\n", dstatus); // 找到SD卡
  156. if (dstatus == STA_NODISK) {
  157. printf("No disk in the SD slot, please insert an SD card...\n");
  158. do {
  159. dstatus = disk_status(DEV_SD);
  160. } while (dstatus == STA_NODISK);
  161. board_delay_ms(100);
  162. printf("Detected SD card, re-initialize the filesystem...\n");
  163. need_init_filesystem = true;
  164. }
  165. dstatus = disk_initialize(DEV_SD);
  166. if (dstatus != RES_OK) {
  167. printf("Failed to initialize SD disk\n");
  168. }
  169. if (need_init_filesystem) {
  170. res_sd = sd_mount_fs();
  171. if (res_sd == FR_NO_FILESYSTEM || init_type == 1) {
  172. printf("There is no File system available, making file system...\n");
  173. res_sd = sd_mkfs();
  174. if (res_sd != FR_OK) {
  175. printf("Failed to make filesystem, cause:%s\n", show_error_string(res_sd));
  176. } else {
  177. need_init_filesystem = false;
  178. }
  179. }
  180. }
  181. // 创建文件夹
  182. res_sd = f_mkdir(logpath);
  183. if (res_sd != FR_OK && res_sd != FR_EXIST) {
  184. printf("Failed to create LOG directory, cause: %d\n", res_sd);
  185. }
  186. res_sd = f_mkdir(pospath);
  187. if (res_sd != FR_OK && res_sd != FR_EXIST) {
  188. printf("Failed to create POS directory, cause: %d\n", res_sd);
  189. }
  190. // 检查是否存在LOG文件
  191. res_sd = f_open(&fnew_data, "LOG/LOG_FLY.DAT", FA_CREATE_NEW);
  192. if (res_sd == FR_OK) {
  193. f_close(&fnew_data);
  194. printf("LOG_FLY.DAT file created\n");
  195. } else if (res_sd == FR_EXIST) {
  196. printf("LOG_FLY.DAT file already exists\n");
  197. } else {
  198. printf("Failed to create LOG_FLY.DAT, cause: %d\n", res_sd);
  199. }
  200. DWORD nclst;
  201. unsigned long free_size = 0;
  202. FATFS *fs_p = &fs;
  203. // 检查剩余容量
  204. res_sd = f_getfree(driver_num_buf, &nclst, &fs_p);
  205. if (res_sd == FR_OK) {
  206. free_size = nclst * fs_p->csize / 2; /* 单位:KB */
  207. printf("Free space: %lu KB\n", free_size);
  208. } else {
  209. printf("Failed to get free space, cause: %d\n", res_sd);
  210. }
  211. // 打开log文件夹, 读下一个的文件
  212. res_sd = f_opendir(&logdir, logpath);
  213. if (res_sd == FR_OK) {
  214. res_sd = f_readdir(&logdir, &fno);
  215. // 如果剩余容量小于96MB, 删除部分数据文件, 防止写满
  216. while (free_size < 96 * 1024 && res_sd == FR_OK && fno.fname[0] != 0)
  217. {
  218. // 跳过目录和LOG_FLY.DAT文件
  219. if (fno.fname[0] != 'L' && !(fno.fattrib & AM_DIR))
  220. {
  221. char datafile_path[50] = {0};
  222. // 拼接文件路径
  223. strcat(datafile_path, logpath);
  224. strcat(datafile_path, "/");
  225. strcat(datafile_path, fno.fname);
  226. // 删除一个文件
  227. printf("Deleting old file: %s\n", datafile_path);
  228. f_unlink(datafile_path);
  229. // 再读一下剩余的容量是否够用
  230. res_sd = f_getfree("", &nclst, &fs_p);
  231. if (res_sd == FR_OK) {
  232. free_size = nclst * fs_p->csize / 2;
  233. printf("Free space now: %lu KB\n", free_size);
  234. }
  235. }
  236. // 读下一个文件
  237. res_sd = f_readdir(&logdir, &fno);
  238. }
  239. // 关闭文件夹
  240. res_sd = f_closedir(&logdir);
  241. } else {
  242. printf("Failed to open LOG directory, cause: %d\n", res_sd);
  243. }
  244. _sd_init_ok = 1;
  245. printf("SD card initialization completed!\n");
  246. }
  247. #ifdef SOFT_SD_TEST
  248. // 测试代码 - 注意:这里不再重复包含头文件,因为上面已经包含了
  249. // 测试配置
  250. #define TEST_FILE_NAME "test_speed.bin"
  251. #define TEST_BUFFER_SIZE 4096 // 测试缓冲区大小
  252. #define TEST_DATA_SIZE (2 * 1024 * 1024) // 测试数据大小 2MB
  253. #define TEST_ITERATIONS 10 // 测试次数
  254. // 测试结果结构体
  255. typedef struct {
  256. uint32_t buffer_size; // 缓冲区大小
  257. uint32_t total_bytes; // 总写入字节数
  258. uint32_t total_time_us; // 总耗时(微秒)
  259. uint32_t avg_time_per_write_us; // 平均每次写入耗时
  260. float speed_kb_per_sec; // 写入速度(KB/s)
  261. } test_result_t;
  262. // 函数声明
  263. void sd_speed_test(void);
  264. void sd_continuous_write_test(void);
  265. void sd_random_write_test(void);
  266. void sd_large_block_test(void);
  267. void sd_integrity_test(void);
  268. void sd_run_tests(void);
  269. int sd_write_data(const char *filename, const uint8_t *data, uint32_t size);
  270. void main_test_demo(void);
  271. /**
  272. * @brief 测试SD卡写入速度
  273. */
  274. void sd_speed_test(void)
  275. {
  276. if (!sdcard_initok()) {
  277. printf("SD card not initialized!\n");
  278. return;
  279. }
  280. printf("\n========== SD Card Speed Test ==========\n");
  281. // 测试1: 连续写入测试
  282. sd_continuous_write_test();
  283. // 测试2: 随机写入测试(模拟实际记录场景)
  284. sd_random_write_test();
  285. // 测试3: 不同缓冲区大小测试
  286. sd_large_block_test();
  287. }
  288. /**
  289. * @brief 连续写入测试
  290. */
  291. void sd_continuous_write_test(void)
  292. {
  293. test_result_t result;
  294. FIL test_file;
  295. UINT bytes_written;
  296. uint32_t start_time, end_time;
  297. uint8_t *buffer;
  298. printf("\n--- Continuous Write Test ---\n");
  299. // 分配测试缓冲区
  300. buffer = (uint8_t *)malloc(TEST_BUFFER_SIZE);
  301. if (buffer == NULL) {
  302. printf("Failed to allocate buffer!\n");
  303. return;
  304. }
  305. // 填充测试数据
  306. for (uint32_t i = 0; i < TEST_BUFFER_SIZE; i++) {
  307. buffer[i] = i & 0xFF;
  308. }
  309. // 创建测试文件
  310. FRESULT res = f_open(&test_file, TEST_FILE_NAME, FA_WRITE | FA_CREATE_ALWAYS);
  311. if (res != FR_OK) {
  312. printf("Failed to create test file! Error: %d\n", res);
  313. free(buffer);
  314. return;
  315. }
  316. // 开始测试
  317. start_time = micros();
  318. uint32_t remaining = TEST_DATA_SIZE;
  319. uint32_t write_count = 0;
  320. while (remaining > 0) {
  321. uint32_t write_size = (remaining > TEST_BUFFER_SIZE) ? TEST_BUFFER_SIZE : remaining;
  322. res = f_write(&test_file, buffer, write_size, &bytes_written);
  323. if (res != FR_OK || bytes_written != write_size) {
  324. printf("Write failed! Error: %d, Written: %d\n", res, bytes_written);
  325. break;
  326. }
  327. remaining -= bytes_written;
  328. write_count++;
  329. }
  330. end_time = micros();
  331. // 关闭文件
  332. f_close(&test_file);
  333. // 计算结果
  334. result.buffer_size = TEST_BUFFER_SIZE;
  335. result.total_bytes = TEST_DATA_SIZE;
  336. result.total_time_us = end_time - start_time;
  337. result.avg_time_per_write_us = result.total_time_us / write_count;
  338. result.speed_kb_per_sec = (float)(TEST_DATA_SIZE) / 1024.0f / (result.total_time_us / 1000000.0f);
  339. printf("Continuous Write Test Results:\n");
  340. printf(" Buffer size: %d bytes\n", result.buffer_size);
  341. printf(" Total data: %d bytes (%.2f MB)\n", result.total_bytes, result.total_bytes / (1024.0f * 1024.0f));
  342. printf(" Write count: %d\n", write_count);
  343. printf(" Total time: %d us (%.2f ms)\n", result.total_time_us, result.total_time_us / 1000.0f);
  344. printf(" Avg time per write: %d us\n", result.avg_time_per_write_us);
  345. printf(" Speed: %.2f KB/s (%.2f MB/s)\n", result.speed_kb_per_sec, result.speed_kb_per_sec / 1024.0f);
  346. free(buffer);
  347. }
  348. /**
  349. * @brief 随机写入测试(模拟实际记录场景)
  350. */
  351. void sd_random_write_test(void)
  352. {
  353. test_result_t result;
  354. FIL test_file;
  355. UINT bytes_written;
  356. uint32_t start_time, end_time;
  357. uint8_t *buffer;
  358. printf("\n--- Random Write Test (Simulating Real Recording) ---\n");
  359. // 分配测试缓冲区
  360. buffer = (uint8_t *)malloc(512); // 模拟实际记录时的512字节数据包
  361. if (buffer == NULL) {
  362. printf("Failed to allocate buffer!\n");
  363. return;
  364. }
  365. // 填充测试数据
  366. for (uint32_t i = 0; i < 512; i++) {
  367. buffer[i] = i & 0xFF;
  368. }
  369. // 创建测试文件
  370. FRESULT res = f_open(&test_file, "random_test.bin", FA_WRITE | FA_CREATE_ALWAYS);
  371. if (res != FR_OK) {
  372. printf("Failed to create test file! Error: %d\n", res);
  373. free(buffer);
  374. return;
  375. }
  376. // 测试不同写入大小的性能
  377. uint32_t test_sizes[] = {512, 1024, 2048, 4096};
  378. int test_count = sizeof(test_sizes) / sizeof(test_sizes[0]);
  379. for (int t = 0; t < test_count; t++) {
  380. uint32_t write_size = test_sizes[t];
  381. uint32_t total_data = 2 * 1024 * 1024; // 2MB
  382. uint32_t write_count = total_data / write_size;
  383. printf("\n Testing write size: %d bytes\n", write_size);
  384. // 重新定位文件开头
  385. f_lseek(&test_file, 0);
  386. start_time = micros();
  387. for (uint32_t i = 0; i < write_count; i++) {
  388. res = f_write(&test_file, buffer, write_size, &bytes_written);
  389. if (res != FR_OK || bytes_written != write_size) {
  390. printf(" Write failed at %d! Error: %d\n", i, res);
  391. break;
  392. }
  393. }
  394. end_time = micros();
  395. result.buffer_size = write_size;
  396. result.total_bytes = total_data;
  397. result.total_time_us = end_time - start_time;
  398. result.avg_time_per_write_us = result.total_time_us / write_count;
  399. result.speed_kb_per_sec = (float)(total_data) / 1024.0f / (result.total_time_us / 1000000.0f);
  400. printf(" Total time: %d us (%.2f ms)\n", result.total_time_us, result.total_time_us / 1000.0f);
  401. printf(" Avg time per write: %d us\n", result.avg_time_per_write_us);
  402. printf(" Speed: %.2f KB/s (%.2f MB/s)\n", result.speed_kb_per_sec, result.speed_kb_per_sec / 1024.0f);
  403. }
  404. // 关闭文件
  405. f_close(&test_file);
  406. free(buffer);
  407. }
  408. /**
  409. * @brief 大数据块写入测试
  410. */
  411. void sd_large_block_test(void)
  412. {
  413. FIL test_file;
  414. UINT bytes_written;
  415. uint32_t start_time, end_time;
  416. uint8_t *buffer;
  417. printf("\n--- Large Block Write Test ---\n");
  418. // 测试不同缓冲区大小
  419. uint32_t buffer_sizes[] = {512, 1024, 2048, 4096, 8192};
  420. int test_count = sizeof(buffer_sizes) / sizeof(buffer_sizes[0]);
  421. for (int t = 0; t < test_count; t++) {
  422. uint32_t buffer_size = buffer_sizes[t];
  423. // 分配测试缓冲区
  424. buffer = (uint8_t *)malloc(buffer_size);
  425. if (buffer == NULL) {
  426. printf("Failed to allocate buffer size %d!\n", buffer_size);
  427. continue;
  428. }
  429. // 填充测试数据
  430. for (uint32_t i = 0; i < buffer_size; i++) {
  431. buffer[i] = i & 0xFF;
  432. }
  433. // 创建测试文件
  434. FRESULT res = f_open(&test_file, "large_block_test.bin", FA_WRITE | FA_CREATE_ALWAYS);
  435. if (res != FR_OK) {
  436. printf("Failed to create test file! Error: %d\n", res);
  437. free(buffer);
  438. continue;
  439. }
  440. uint32_t total_data = 2 * 1024 * 1024; // 2MB
  441. uint32_t write_count = total_data / buffer_size;
  442. start_time = micros();
  443. for (uint32_t i = 0; i < write_count; i++) {
  444. res = f_write(&test_file, buffer, buffer_size, &bytes_written);
  445. if (res != FR_OK || bytes_written != buffer_size) {
  446. printf(" Write failed at %d! Error: %d\n", i, res);
  447. break;
  448. }
  449. }
  450. end_time = micros();
  451. // 关闭文件
  452. f_close(&test_file);
  453. uint32_t total_time_us = end_time - start_time;
  454. float speed_kb_per_sec = (float)(total_data) / 1024.0f / (total_time_us / 1000000.0f);
  455. printf(" Buffer size: %5d bytes -> Total time: %6d us (%.2f ms) -> Speed: %.2f KB/s (%.2f MB/s)\n",
  456. buffer_size, total_time_us, total_time_us / 1000.0f,
  457. speed_kb_per_sec, speed_kb_per_sec / 1024.0f);
  458. free(buffer);
  459. // 删除测试文件
  460. f_unlink("large_block_test.bin");
  461. }
  462. }
  463. /**
  464. * @brief 测试文件写入并验证数据完整性
  465. */
  466. void sd_integrity_test(void)
  467. {
  468. FIL test_file;
  469. UINT bytes_written, bytes_read;
  470. uint32_t start_time, end_time;
  471. uint8_t *write_buffer, *read_buffer;
  472. uint32_t test_size = 1024 ; // 1MB测试数据
  473. printf("\n--- Data Integrity Test ---\n");
  474. if (!sdcard_initok()) {
  475. printf("SD card not initialized!\n");
  476. return;
  477. }
  478. // 分配缓冲区
  479. write_buffer = (uint8_t *)malloc(test_size);
  480. read_buffer = (uint8_t *)malloc(test_size);
  481. if (write_buffer == NULL || read_buffer == NULL) {
  482. printf("Failed to allocate buffers!\n");
  483. if (write_buffer) free(write_buffer);
  484. if (read_buffer) free(read_buffer);
  485. return;
  486. }
  487. // 填充测试数据(使用特定的模式)
  488. for (uint32_t i = 0; i < test_size; i++) {
  489. write_buffer[i] = i & 0xFF;
  490. }
  491. // 写入测试
  492. FRESULT res = f_open(&test_file, "integrity_test.bin", FA_WRITE | FA_CREATE_ALWAYS);
  493. if (res != FR_OK) {
  494. printf("Failed to create test file! Error: %d\n", res);
  495. goto cleanup;
  496. }
  497. start_time = micros();
  498. res = f_write(&test_file, write_buffer, test_size, &bytes_written);
  499. end_time = micros();
  500. if (res != FR_OK || bytes_written != test_size) {
  501. printf("Write failed! Error: %d, Written: %d\n", res, bytes_written);
  502. f_close(&test_file);
  503. goto cleanup;
  504. }
  505. printf("Write completed: %d bytes in %d us (%.2f KB/s)\n",
  506. bytes_written, end_time - start_time,
  507. (float)bytes_written / 1024.0f / ((end_time - start_time) / 1000000.0f));
  508. f_close(&test_file);
  509. // 读取测试
  510. res = f_open(&test_file, "integrity_test.bin", FA_READ);
  511. if (res != FR_OK) {
  512. printf("Failed to open test file for reading! Error: %d\n", res);
  513. goto cleanup;
  514. }
  515. start_time = micros();
  516. res = f_read(&test_file, read_buffer, test_size, &bytes_read);
  517. end_time = micros();
  518. if (res != FR_OK || bytes_read != test_size) {
  519. printf("Read failed! Error: %d, Read: %d\n", res, bytes_read);
  520. f_close(&test_file);
  521. goto cleanup;
  522. }
  523. printf("Read completed: %d bytes in %d us (%.2f KB/s)\n",
  524. bytes_read, end_time - start_time,
  525. (float)bytes_read / 1024.0f / ((end_time - start_time) / 1000000.0f));
  526. f_close(&test_file);
  527. // 验证数据完整性
  528. printf("Verifying data integrity...\n");
  529. int error_count = 0;
  530. for (uint32_t i = 0; i < test_size; i++) {
  531. if (write_buffer[i] != read_buffer[i]) {
  532. if (error_count < 10) { // 只显示前10个错误
  533. printf("Data mismatch at offset %d: expected 0x%02X, got 0x%02X\n",
  534. i, write_buffer[i], read_buffer[i]);
  535. }
  536. error_count++;
  537. }
  538. }
  539. if (error_count == 0) {
  540. printf("Data integrity test PASSED! All %d bytes verified.\n", test_size);
  541. } else {
  542. printf("Data integrity test FAILED! %d errors found.\n", error_count);
  543. }
  544. // 删除测试文件
  545. f_unlink("integrity_test.bin");
  546. cleanup:
  547. free(write_buffer);
  548. free(read_buffer);
  549. }
  550. /**
  551. * @brief 主测试函数,可以在主循环中调用
  552. */
  553. void sd_run_tests(void)
  554. {
  555. printf("\n");
  556. printf("****************************************\n");
  557. printf("* SD Card Performance Test *\n");
  558. printf("****************************************\n");
  559. // 运行各种测试
  560. sd_speed_test();
  561. sd_integrity_test();
  562. printf("\n========== All Tests Completed ==========\n");
  563. }
  564. /**
  565. * @brief 简单的文件写入测试(用于实际应用)
  566. * @param filename 文件名
  567. * @param data 数据指针
  568. * @param size 数据大小
  569. * @return 0:成功, -1:失败
  570. */
  571. int sd_write_data(const char *filename, const uint8_t *data, uint32_t size)
  572. {
  573. FIL file;
  574. UINT bytes_written;
  575. uint32_t start_time, end_time;
  576. if (!sdcard_initok()) {
  577. printf("SD card not ready!\n");
  578. return -1;
  579. }
  580. // 打开或创建文件
  581. FRESULT res = f_open(&file, filename, FA_WRITE | FA_OPEN_ALWAYS);
  582. if (res != FR_OK) {
  583. printf("Failed to open file %s! Error: %d\n", filename, res);
  584. return -1;
  585. }
  586. // 移动到文件末尾
  587. f_lseek(&file, f_size(&file));
  588. // 写入数据
  589. start_time = micros();
  590. res = f_write(&file, data, size, &bytes_written);
  591. end_time = micros();
  592. if (res != FR_OK || bytes_written != size) {
  593. printf("Write failed! Error: %d, Written: %d\n", res, bytes_written);
  594. f_close(&file);
  595. return -1;
  596. }
  597. printf("Written %d bytes to %s in %d us (%.2f KB/s)\n",
  598. bytes_written, filename, end_time - start_time,
  599. (float)bytes_written / 1024.0f / ((end_time - start_time) / 1000000.0f));
  600. f_close(&file);
  601. return 0;
  602. }
  603. #include "hard_system_delay.h"
  604. /**
  605. * @brief 测试主函数
  606. */
  607. void sd_test_demo(void)
  608. {
  609. // 先初始化SD卡
  610. sdcard_inital(0);
  611. system_time_initial();
  612. if (sdcard_initok()) {
  613. // 运行性能测试
  614. sd_run_tests();
  615. // 示例:写入实际数据
  616. uint8_t test_data[512];
  617. for (int i = 0; i < 512; i++) {
  618. test_data[i] = i & 0xFF;
  619. }
  620. // 写入到LOG目录下的测试文件
  621. sd_write_data("LOG/test_data.dat", test_data, sizeof(test_data));
  622. printf("\nAll tests completed. You can now use the SD card for your application.\n");
  623. } else {
  624. printf("SD card initialization failed!\n");
  625. }
  626. }
  627. #endif /* SOFT_SD_TEST */