spi_flash_sfud.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. /*
  2. * File : spi_flash_sfud.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2016, RT-Thread Development Team
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. *
  20. * Change Logs:
  21. * Date Author Notes
  22. * 2016-09-28 armink first version.
  23. */
  24. #include <stdint.h>
  25. #include <rtdevice.h>
  26. #include "spi_flash.h"
  27. #include "spi_flash_sfud.h"
  28. #ifdef RT_USING_SFUD
  29. #if RT_DEBUG_SFUD
  30. #define DEBUG_TRACE rt_kprintf("[SFUD] "); rt_kprintf
  31. #else
  32. #define DEBUG_TRACE(...)
  33. #endif /* RT_DEBUG_SFUD */
  34. #ifndef RT_SFUD_DEFAULT_SPI_CFG
  35. /* read the JEDEC SFDP command must run at 50 MHz or less */
  36. #define RT_SFUD_DEFAULT_SPI_CFG \
  37. { \
  38. .mode = RT_SPI_MODE_0 | RT_SPI_MSB, \
  39. .data_width = 8, \
  40. .max_hz = 50 * 1000 * 1000, \
  41. }
  42. #endif
  43. static char log_buf[RT_CONSOLEBUF_SIZE];
  44. void sfud_log_debug(const char *file, const long line, const char *format, ...);
  45. static rt_err_t rt_sfud_control(rt_device_t dev, rt_uint8_t cmd, void *args) {
  46. RT_ASSERT(dev != RT_NULL);
  47. switch (cmd) {
  48. case RT_DEVICE_CTRL_BLK_GETGEOME: {
  49. struct rt_device_blk_geometry *geometry = (struct rt_device_blk_geometry *) args;
  50. struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
  51. if (rtt_dev == RT_NULL || geometry == RT_NULL) {
  52. return -RT_ERROR;
  53. }
  54. geometry->bytes_per_sector = rtt_dev->geometry.bytes_per_sector;
  55. geometry->sector_count = rtt_dev->geometry.sector_count;
  56. geometry->block_size = rtt_dev->geometry.block_size;
  57. break;
  58. }
  59. case RT_DEVICE_CTRL_BLK_ERASE: {
  60. rt_uint32_t *addrs = (rt_uint32_t *) args, start_addr = addrs[0], end_addr = addrs[1], phy_start_addr;
  61. struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
  62. sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
  63. rt_size_t phy_size;
  64. if (addrs == RT_NULL || start_addr > end_addr || rtt_dev == RT_NULL || sfud_dev == RT_NULL) {
  65. return -RT_ERROR;
  66. }
  67. phy_start_addr = start_addr * rtt_dev->geometry.bytes_per_sector;
  68. phy_size = (end_addr - start_addr) * rtt_dev->geometry.bytes_per_sector;
  69. if (sfud_erase(sfud_dev, phy_start_addr, phy_size) != SFUD_SUCCESS) {
  70. return -RT_ERROR;
  71. }
  72. break;
  73. }
  74. }
  75. return RT_EOK;
  76. }
  77. static rt_size_t rt_sfud_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) {
  78. struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
  79. sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
  80. /* change the block device¡¯s logic address to physical address */
  81. rt_off_t phy_pos = pos * rtt_dev->geometry.bytes_per_sector;
  82. rt_size_t phy_size = size * rtt_dev->geometry.bytes_per_sector;
  83. if (sfud_read(sfud_dev, phy_pos, phy_size, buffer) != SFUD_SUCCESS) {
  84. return 0;
  85. } else {
  86. return size;
  87. }
  88. }
  89. static rt_size_t rt_sfud_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) {
  90. struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
  91. sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
  92. /* change the block device¡¯s logic address to physical address */
  93. rt_off_t phy_pos = pos * rtt_dev->geometry.bytes_per_sector;
  94. rt_size_t phy_size = size * rtt_dev->geometry.bytes_per_sector;
  95. if (sfud_erase_write(sfud_dev, phy_pos, phy_size, buffer) != SFUD_SUCCESS) {
  96. return 0;
  97. } else {
  98. return size;
  99. }
  100. }
  101. /**
  102. * SPI write data then read data
  103. */
  104. static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
  105. size_t read_size) {
  106. sfud_err result = SFUD_SUCCESS;
  107. sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
  108. struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
  109. if (write_size) {
  110. RT_ASSERT(write_buf);
  111. }
  112. if (read_size) {
  113. RT_ASSERT(read_buf);
  114. }
  115. if (write_size && read_size) {
  116. if (rt_spi_send_then_recv(rtt_dev->rt_spi_device, write_buf, write_size, read_buf, read_size) != RT_EOK) {
  117. result = SFUD_ERR_TIMEOUT;
  118. }
  119. } else if (write_size) {
  120. if (rt_spi_send(rtt_dev->rt_spi_device, write_buf, write_size) == 0) {
  121. result = SFUD_ERR_TIMEOUT;
  122. }
  123. } else {
  124. if (rt_spi_recv(rtt_dev->rt_spi_device, read_buf, read_size) == 0) {
  125. result = SFUD_ERR_TIMEOUT;
  126. }
  127. }
  128. return result;
  129. }
  130. static void spi_lock(const sfud_spi *spi) {
  131. sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
  132. struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
  133. rt_mutex_take(&(rtt_dev->lock), RT_WAITING_FOREVER);
  134. }
  135. static void spi_unlock(const sfud_spi *spi) {
  136. sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
  137. struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
  138. rt_mutex_release(&(rtt_dev->lock));
  139. }
  140. static void retry_delay_ms(void) {
  141. /* millisecond delay */
  142. rt_tick_from_millisecond(1);
  143. }
  144. static void retry_delay_100us(void) {
  145. /* 100 microsecond delay */
  146. rt_thread_delay((RT_TICK_PER_SECOND * 1 + 9999) / 10000);
  147. }
  148. /**
  149. * This function is print debug info.
  150. *
  151. * @param file the file which has call this function
  152. * @param line the line number which has call this function
  153. * @param format output format
  154. * @param ... args
  155. */
  156. void sfud_log_debug(const char *file, const long line, const char *format, ...) {
  157. va_list args;
  158. /* args point to the first variable parameter */
  159. va_start(args, format);
  160. rt_kprintf("[SFUD](%s:%ld) ", file, line);
  161. /* must use vprintf to print */
  162. vsnprintf(log_buf, sizeof(log_buf), format, args);
  163. rt_kprintf("%s\n", log_buf);
  164. va_end(args);
  165. }
  166. /**
  167. * This function is print routine info.
  168. *
  169. * @param format output format
  170. * @param ... args
  171. */
  172. void sfud_log_info(const char *format, ...) {
  173. va_list args;
  174. /* args point to the first variable parameter */
  175. va_start(args, format);
  176. rt_kprintf("[SFUD]");
  177. /* must use vprintf to print */
  178. vsnprintf(log_buf, sizeof(log_buf), format, args);
  179. rt_kprintf("%s\n", log_buf);
  180. va_end(args);
  181. }
  182. sfud_err sfud_spi_port_init(sfud_flash *flash) {
  183. sfud_err result = SFUD_SUCCESS;
  184. /* port SPI device interface */
  185. flash->spi.wr = spi_write_read;
  186. flash->spi.lock = spi_lock;
  187. flash->spi.unlock = spi_unlock;
  188. flash->spi.user_data = flash;
  189. /* 100 microsecond delay */
  190. flash->retry.delay = retry_delay_100us;
  191. /* 60 seconds timeout */
  192. flash->retry.times = 60 * 10000;
  193. return result;
  194. }
  195. /**
  196. * Probe SPI flash by SFUD(Serial Flash Universal Driver) driver library and though SPI device.
  197. *
  198. * @param spi_flash_dev_name the name which will create SPI flash device
  199. * @param spi_dev_name using SPI device name
  200. *
  201. * @return probed SPI flash device, probe failed will return RT_NULL
  202. */
  203. rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const char *spi_dev_name) {
  204. rt_spi_flash_device_t rtt_dev = RT_NULL;
  205. sfud_flash *sfud_dev = RT_NULL;
  206. char *spi_flash_dev_name_bak = RT_NULL, *spi_dev_name_bak = RT_NULL;
  207. extern sfud_err sfud_device_init(sfud_flash *flash);
  208. RT_ASSERT(spi_flash_dev_name);
  209. RT_ASSERT(spi_dev_name);
  210. rtt_dev = (rt_spi_flash_device_t) rt_malloc(sizeof(struct spi_flash_device));
  211. sfud_dev = (sfud_flash_t) rt_malloc(sizeof(sfud_flash));
  212. spi_flash_dev_name_bak = (char *) rt_malloc(rt_strlen(spi_flash_dev_name) + 1);
  213. spi_dev_name_bak = (char *) rt_malloc(rt_strlen(spi_dev_name) + 1);
  214. if (rtt_dev && sfud_dev && spi_flash_dev_name_bak && spi_dev_name_bak) {
  215. rt_memset(rtt_dev, 0, sizeof(struct spi_flash_device));
  216. rt_memset(sfud_dev, 0, sizeof(sfud_flash));
  217. rt_strncpy(spi_flash_dev_name_bak, spi_flash_dev_name, rt_strlen(spi_flash_dev_name));
  218. rt_strncpy(spi_dev_name_bak, spi_dev_name, rt_strlen(spi_dev_name));
  219. /* make string end sign */
  220. spi_flash_dev_name_bak[rt_strlen(spi_flash_dev_name)] = '\0';
  221. spi_dev_name_bak[rt_strlen(spi_dev_name)] = '\0';
  222. /* SPI configure */
  223. {
  224. /* RT-Thread SPI device initialize */
  225. rtt_dev->rt_spi_device = (struct rt_spi_device *) rt_device_find(spi_dev_name);
  226. if (rtt_dev->rt_spi_device == RT_NULL) {
  227. rt_kprintf("ERROR: SPI device %s not found!\n", spi_dev_name);
  228. goto error;
  229. }
  230. sfud_dev->spi.name = spi_dev_name_bak;
  231. /* using default flash SPI configuration for initialize SPI Flash
  232. * @note you also can change the SPI to other configuration after initialized finish */
  233. struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG;
  234. rt_spi_configure(rtt_dev->rt_spi_device, &cfg);
  235. /* initialize lock */
  236. rt_mutex_init(&(rtt_dev->lock), spi_flash_dev_name, RT_IPC_FLAG_FIFO);
  237. }
  238. /* SFUD flash device initialize */
  239. {
  240. sfud_dev->name = spi_flash_dev_name_bak;
  241. /* accessed each other */
  242. rtt_dev->user_data = sfud_dev;
  243. rtt_dev->flash_device.user_data = rtt_dev;
  244. sfud_dev->user_data = rtt_dev;
  245. /* initialize SFUD device */
  246. if (sfud_device_init(sfud_dev) != SFUD_SUCCESS) {
  247. rt_kprintf("ERROR: SPI flash probe failed by SPI device %s.\n", spi_dev_name);
  248. goto error;
  249. }
  250. /* when initialize success, then copy SFUD flash device's geometry to RT-Thread SPI flash device */
  251. rtt_dev->geometry.sector_count = sfud_dev->chip.capacity / sfud_dev->chip.erase_gran;
  252. rtt_dev->geometry.bytes_per_sector = sfud_dev->chip.erase_gran;
  253. rtt_dev->geometry.block_size = sfud_dev->chip.erase_gran;
  254. }
  255. /* register device */
  256. rtt_dev->flash_device.type = RT_Device_Class_Block;
  257. rtt_dev->flash_device.init = RT_NULL;
  258. rtt_dev->flash_device.open = RT_NULL;
  259. rtt_dev->flash_device.close = RT_NULL;
  260. rtt_dev->flash_device.read = rt_sfud_read;
  261. rtt_dev->flash_device.write = rt_sfud_write;
  262. rtt_dev->flash_device.control = rt_sfud_control;
  263. rt_device_register(&(rtt_dev->flash_device), spi_flash_dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
  264. DEBUG_TRACE("Probe SPI flash %s by SPI device %s success.\n",spi_flash_dev_name, spi_dev_name);
  265. return rtt_dev;
  266. } else {
  267. rt_kprintf("ERROR: Low memory.\n");
  268. goto error;
  269. }
  270. error:
  271. /* may be one of objects memory was malloc success, so need free all */
  272. rt_free(rtt_dev);
  273. rt_free(sfud_dev);
  274. rt_free(spi_flash_dev_name_bak);
  275. rt_free(spi_dev_name_bak);
  276. return RT_NULL;
  277. }
  278. /**
  279. * Delete SPI flash device
  280. *
  281. * @param spi_flash_dev SPI flash device
  282. *
  283. * @return the operation status, RT_EOK on successful
  284. */
  285. rt_err_t rt_sfud_flash_delete(rt_spi_flash_device_t spi_flash_dev) {
  286. sfud_flash *sfud_flash_dev = (sfud_flash *) (spi_flash_dev->user_data);
  287. RT_ASSERT(spi_flash_dev);
  288. RT_ASSERT(sfud_flash_dev);
  289. rt_device_unregister(&(spi_flash_dev->flash_device));
  290. rt_mutex_detach(&(spi_flash_dev->lock));
  291. rt_free(sfud_flash_dev->spi.name);
  292. rt_free(sfud_flash_dev->name);
  293. rt_free(sfud_flash_dev);
  294. rt_free(spi_flash_dev);
  295. return RT_EOK;
  296. }
  297. #if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH)
  298. #include <finsh.h>
  299. static void sf(uint8_t argc, char **argv) {
  300. #define CMD_SETECT_INDEX 0
  301. #define CMD_READ_INDEX 1
  302. #define CMD_WRITE_INDEX 2
  303. #define CMD_ERASE_INDEX 3
  304. #define CMD_RW_STATUS_INDEX 4
  305. #define CMD_BENCH_INDEX 5
  306. sfud_err result = SFUD_SUCCESS;
  307. static const sfud_flash *sfud_dev = NULL;
  308. static rt_spi_flash_device_t rtt_dev = NULL, rtt_dev_bak = NULL;
  309. size_t i = 0;
  310. const char* sf_help_info[] = {
  311. [CMD_SETECT_INDEX] = "sf probe [spi_device] - probe and init SPI flash by given 'spi_device'",
  312. [CMD_READ_INDEX] = "sf read addr size - read 'size' bytes starting at 'addr'",
  313. [CMD_WRITE_INDEX] = "sf write addr data1 ... dataN - write some bytes 'data' to flash starting at 'addr'",
  314. [CMD_ERASE_INDEX] = "sf erase addr size - erase 'size' bytes starting at 'addr'",
  315. [CMD_RW_STATUS_INDEX] = "sf status [<volatile> <status>] - read or write '1:volatile|0:non-volatile' 'status'",
  316. [CMD_BENCH_INDEX] = "sf bench - full chip benchmark. DANGER: It will erase full chip!",
  317. };
  318. if (argc < 2) {
  319. rt_kprintf("Usage:\n");
  320. for (i = 0; i < sizeof(sf_help_info) / sizeof(char*); i++) {
  321. rt_kprintf("%s\n", sf_help_info[i]);
  322. }
  323. rt_kprintf("\n");
  324. } else {
  325. const char *operator = argv[1];
  326. uint32_t addr, size;
  327. if (!strcmp(operator, "probe")) {
  328. if (argc < 3) {
  329. rt_kprintf("Usage: %s.\n", sf_help_info[CMD_SETECT_INDEX]);
  330. } else {
  331. char *spi_dev_name = argv[2];
  332. rtt_dev_bak = rtt_dev;
  333. rtt_dev = rt_sfud_flash_probe("sf_cmd", spi_dev_name);
  334. if (!rtt_dev) {
  335. return;
  336. }
  337. /* already probe then delete the old SPI flash device */
  338. if(rtt_dev_bak) {
  339. rt_sfud_flash_delete(rtt_dev_bak);
  340. }
  341. sfud_dev = (sfud_flash_t)rtt_dev->user_data;
  342. if (sfud_dev->chip.capacity < 1024 * 1024) {
  343. rt_kprintf("%d KB %s is current selected device.\n", sfud_dev->chip.capacity / 1024, sfud_dev->name);
  344. } else {
  345. rt_kprintf("%d MB %s is current selected device.\n", sfud_dev->chip.capacity / 1024 / 1024,
  346. sfud_dev->name);
  347. }
  348. }
  349. } else {
  350. if (!sfud_dev) {
  351. rt_kprintf("No flash device selected. Please run 'sf probe'.\n");
  352. return;
  353. }
  354. if (!rt_strcmp(operator, "read")) {
  355. if (argc < 4) {
  356. rt_kprintf("Usage: %s.\n", sf_help_info[CMD_READ_INDEX]);
  357. return;
  358. } else {
  359. addr = atol(argv[2]);
  360. size = atol(argv[3]);
  361. uint8_t *data = rt_malloc(size);
  362. if (data) {
  363. result = sfud_read(sfud_dev, addr, size, data);
  364. if (result == SFUD_SUCCESS) {
  365. rt_kprintf("Read the %s flash data success. Start from 0x%08X, size is %ld. The data is:\n",
  366. sfud_dev->name, addr, size);
  367. rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
  368. for (i = 0; i < size; i++) {
  369. if (i % 16 == 0) {
  370. rt_kprintf("[%08X] ", addr + i);
  371. }
  372. rt_kprintf("%02X ", data[i]);
  373. if (((i + 1) % 16 == 0) || i == size - 1) {
  374. rt_kprintf("\n");
  375. }
  376. }
  377. rt_kprintf("\n");
  378. }
  379. rt_free(data);
  380. } else {
  381. rt_kprintf("Low memory!\n");
  382. }
  383. }
  384. } else if (!rt_strcmp(operator, "write")) {
  385. if (argc < 4) {
  386. rt_kprintf("Usage: %s.\n", sf_help_info[CMD_WRITE_INDEX]);
  387. return;
  388. } else {
  389. addr = atol(argv[2]);
  390. size = argc - 3;
  391. uint8_t *data = rt_malloc(size);
  392. if (data) {
  393. for (i = 0; i < size; i++) {
  394. data[i] = atoi(argv[3 + i]);
  395. }
  396. result = sfud_write(sfud_dev, addr, size, data);
  397. if (result == SFUD_SUCCESS) {
  398. rt_kprintf("Write the %s flash data success. Start from 0x%08X, size is %ld.\n",
  399. sfud_dev->name, addr, size);
  400. rt_kprintf("Write data: ");
  401. for (i = 0; i < size; i++) {
  402. rt_kprintf("%d ", data[i]);
  403. }
  404. rt_kprintf(".\n");
  405. }
  406. rt_free(data);
  407. } else {
  408. rt_kprintf("Low memory!\n");
  409. }
  410. }
  411. } else if (!rt_strcmp(operator, "erase")) {
  412. if (argc < 4) {
  413. rt_kprintf("Usage: %s.\n", sf_help_info[CMD_ERASE_INDEX]);
  414. return;
  415. } else {
  416. addr = atol(argv[2]);
  417. size = atol(argv[3]);
  418. result = sfud_erase(sfud_dev, addr, size);
  419. if (result == SFUD_SUCCESS) {
  420. rt_kprintf("Erase the %s flash data success. Start from 0x%08X, size is %ld.\n", sfud_dev->name,
  421. addr, size);
  422. }
  423. }
  424. } else if (!rt_strcmp(operator, "status")) {
  425. if (argc < 3) {
  426. uint8_t status;
  427. result = sfud_read_status(sfud_dev, &status);
  428. if (result == SFUD_SUCCESS) {
  429. rt_kprintf("The %s flash status register current value is 0x%02X.\n", sfud_dev->name, status);
  430. }
  431. } else if (argc == 4) {
  432. bool is_volatile = atoi(argv[2]);
  433. uint8_t status = atoi(argv[3]);
  434. result = sfud_write_status(sfud_dev, is_volatile, status);
  435. if (result == SFUD_SUCCESS) {
  436. rt_kprintf("Write the %s flash status register to 0x%02X success.\n", sfud_dev->name, status);
  437. }
  438. } else {
  439. rt_kprintf("Usage: %s.\n", sf_help_info[CMD_RW_STATUS_INDEX]);
  440. return;
  441. }
  442. } else if (!rt_strcmp(operator, "bench")) {
  443. if ((argc > 2 && rt_strcmp(argv[2], "yes")) || argc < 3) {
  444. rt_kprintf("DANGER: It will erase full chip! Please run 'sf bench yes'.\n");
  445. return;
  446. }
  447. /* full chip benchmark test */
  448. addr = 0;
  449. size = sfud_dev->chip.capacity;
  450. uint32_t start_time, time_cast;
  451. rt_uint32_t total_mem, used_mem, max_uesd_mem;
  452. rt_memory_info(&total_mem, &used_mem, &max_uesd_mem);
  453. size_t write_size = SFUD_WRITE_MAX_PAGE_SIZE, read_size;
  454. if ((total_mem - used_mem) / 2 < size) {
  455. read_size = (total_mem - used_mem) / 2;
  456. } else {
  457. read_size = size;
  458. }
  459. uint8_t *write_data = rt_malloc(write_size), *read_data = rt_malloc(read_size);
  460. if (write_data && read_data) {
  461. rt_memset(write_data, 0x55, write_size);
  462. /* benchmark testing */
  463. rt_kprintf("Erasing the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
  464. start_time = rt_tick_get();
  465. result = sfud_erase(sfud_dev, addr, size);
  466. if (result == SFUD_SUCCESS) {
  467. time_cast = rt_tick_get() - start_time;
  468. rt_kprintf("Erase benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
  469. time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
  470. } else {
  471. rt_kprintf("Erase benchmark has an error. Error code: %d.\n", result);
  472. }
  473. /* write test */
  474. rt_kprintf("Writing the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
  475. start_time = rt_tick_get();
  476. for (i = 0; i < size; i += write_size) {
  477. result = sfud_write(sfud_dev, addr + i, write_size, write_data);
  478. if (result != SFUD_SUCCESS) {
  479. break;
  480. }
  481. }
  482. if (result == SFUD_SUCCESS) {
  483. time_cast = rt_tick_get() - start_time;
  484. rt_kprintf("Write benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
  485. time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
  486. } else {
  487. rt_kprintf("Write benchmark has an error. Error code: %d.\n", result);
  488. }
  489. /* read test */
  490. rt_kprintf("Reading the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
  491. start_time = rt_tick_get();
  492. for (i = 0; i < size; i += read_size) {
  493. if (i + read_size <= size) {
  494. result = sfud_read(sfud_dev, addr + i, read_size, read_data);
  495. } else {
  496. result = sfud_read(sfud_dev, addr + i, size - i, read_data);
  497. }
  498. if (result != SFUD_SUCCESS) {
  499. break;
  500. }
  501. }
  502. if (result == SFUD_SUCCESS) {
  503. time_cast = rt_tick_get() - start_time;
  504. rt_kprintf("Read benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
  505. time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
  506. } else {
  507. rt_kprintf("Read benchmark has an error. Error code: %d.\n", result);
  508. }
  509. } else {
  510. rt_kprintf("Low memory!\n");
  511. }
  512. rt_free(write_data);
  513. rt_free(read_data);
  514. } else {
  515. rt_kprintf("Usage:\n");
  516. for (i = 0; i < sizeof(sf_help_info) / sizeof(char*); i++) {
  517. rt_kprintf("%s\n", sf_help_info[i]);
  518. }
  519. rt_kprintf("\n");
  520. return;
  521. }
  522. if (result != SFUD_SUCCESS) {
  523. rt_kprintf("This flash operate has an error. Error code: %d.\n", result);
  524. }
  525. }
  526. }
  527. }
  528. MSH_CMD_EXPORT(sf, SPI Flash operate.);
  529. #endif /* defined(RT_USING_FINSH) && defined(FINSH_USING_MSH) */
  530. #endif /* RT_USING_SFUD */