soft_sdcard.c 23 KB

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