1
0

spi_flash_sfud.c 24 KB

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