xref: /nrf52832-nimble/rt-thread/components/drivers/spi/spi_flash_sfud.c (revision 104654410c56c573564690304ae786df310c91fc)
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 
11 #include <stdint.h>
12 #include <rtdevice.h>
13 #include "spi_flash.h"
14 #include "spi_flash_sfud.h"
15 
16 #ifdef RT_USING_SFUD
17 
18 #ifdef RT_DEBUG_SFUD
19 #define DEBUG_TRACE         rt_kprintf("[SFUD] "); rt_kprintf
20 #else
21 #define DEBUG_TRACE(...)
22 #endif /* RT_DEBUG_SFUD */
23 
24 #ifndef RT_SFUD_DEFAULT_SPI_CFG
25 /* read the JEDEC SFDP command must run at 50 MHz or less */
26 #define RT_SFUD_DEFAULT_SPI_CFG                  \
27 {                                                \
28     .mode = RT_SPI_MODE_0 | RT_SPI_MSB,          \
29     .data_width = 8,                             \
30     .max_hz = 50 * 1000 * 1000,                  \
31 }
32 #endif
33 
34 #ifdef SFUD_USING_QSPI
35 #define RT_SFUD_DEFAULT_QSPI_CFG                 \
36 {                                                \
37     RT_SFUD_DEFAULT_SPI_CFG,                     \
38     .medium_size = 0x800000,                     \
39     .ddr_mode = 0,                               \
40     .qspi_dl_width = 4,                          \
41 }
42 #endif
43 
44 static char log_buf[RT_CONSOLEBUF_SIZE];
45 
46 void sfud_log_debug(const char *file, const long line, const char *format, ...);
47 
rt_sfud_control(rt_device_t dev,int cmd,void * args)48 static rt_err_t rt_sfud_control(rt_device_t dev, int cmd, void *args) {
49     RT_ASSERT(dev != RT_NULL);
50 
51     switch (cmd) {
52     case RT_DEVICE_CTRL_BLK_GETGEOME: {
53         struct rt_device_blk_geometry *geometry = (struct rt_device_blk_geometry *) args;
54         struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
55 
56         if (rtt_dev == RT_NULL || geometry == RT_NULL) {
57             return -RT_ERROR;
58         }
59 
60         geometry->bytes_per_sector = rtt_dev->geometry.bytes_per_sector;
61         geometry->sector_count = rtt_dev->geometry.sector_count;
62         geometry->block_size = rtt_dev->geometry.block_size;
63         break;
64     }
65     case RT_DEVICE_CTRL_BLK_ERASE: {
66         rt_uint32_t *addrs = (rt_uint32_t *) args, start_addr = addrs[0], end_addr = addrs[1], phy_start_addr;
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         rt_size_t phy_size;
70 
71         if (addrs == RT_NULL || start_addr > end_addr || rtt_dev == RT_NULL || sfud_dev == RT_NULL) {
72             return -RT_ERROR;
73         }
74 
75         if (end_addr == start_addr) {
76             end_addr ++;
77         }
78 
79         phy_start_addr = start_addr * rtt_dev->geometry.bytes_per_sector;
80         phy_size = (end_addr - start_addr) * rtt_dev->geometry.bytes_per_sector;
81 
82         if (sfud_erase(sfud_dev, phy_start_addr, phy_size) != SFUD_SUCCESS) {
83             return -RT_ERROR;
84         }
85         break;
86     }
87     }
88 
89     return RT_EOK;
90 }
91 
92 
rt_sfud_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)93 static rt_size_t rt_sfud_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) {
94     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
95     sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
96     /* change the block device's logic address to physical address */
97     rt_off_t phy_pos = pos * rtt_dev->geometry.bytes_per_sector;
98     rt_size_t phy_size = size * rtt_dev->geometry.bytes_per_sector;
99 
100     if (sfud_read(sfud_dev, phy_pos, phy_size, buffer) != SFUD_SUCCESS) {
101         return 0;
102     } else {
103         return size;
104     }
105 }
106 
rt_sfud_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)107 static rt_size_t rt_sfud_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) {
108     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
109     sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
110     /* change the block device's logic address to physical address */
111     rt_off_t phy_pos = pos * rtt_dev->geometry.bytes_per_sector;
112     rt_size_t phy_size = size * rtt_dev->geometry.bytes_per_sector;
113 
114     if (sfud_erase_write(sfud_dev, phy_pos, phy_size, buffer) != SFUD_SUCCESS) {
115         return 0;
116     } else {
117         return size;
118     }
119 }
120 
121 /**
122  * SPI write data then read data
123  */
spi_write_read(const sfud_spi * spi,const uint8_t * write_buf,size_t write_size,uint8_t * read_buf,size_t read_size)124 static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
125         size_t read_size) {
126     sfud_err result = SFUD_SUCCESS;
127     sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
128     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
129 #ifdef SFUD_USING_QSPI
130     struct rt_qspi_device *qspi_dev = RT_NULL;
131 #endif
132     if (write_size) {
133         RT_ASSERT(write_buf);
134     }
135     if (read_size) {
136         RT_ASSERT(read_buf);
137     }
138 #ifdef SFUD_USING_QSPI
139     if(rtt_dev->rt_spi_device->bus->mode & RT_SPI_BUS_MODE_QSPI) {
140         qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
141         if (write_size && read_size) {
142             if (rt_qspi_send_then_recv(qspi_dev, write_buf, write_size, read_buf, read_size) == 0) {
143                 result = SFUD_ERR_TIMEOUT;
144             }
145         } else if (write_size) {
146             if (rt_qspi_send(qspi_dev, write_buf, write_size) == 0) {
147                 result = SFUD_ERR_TIMEOUT;
148             }
149         }
150     }
151     else
152 #endif
153     {
154         if (write_size && read_size) {
155             if (rt_spi_send_then_recv(rtt_dev->rt_spi_device, write_buf, write_size, read_buf, read_size) != RT_EOK) {
156                 result = SFUD_ERR_TIMEOUT;
157             }
158         } else if (write_size) {
159             if (rt_spi_send(rtt_dev->rt_spi_device, write_buf, write_size) == 0) {
160                 result = SFUD_ERR_TIMEOUT;
161             }
162         } else {
163             if (rt_spi_recv(rtt_dev->rt_spi_device, read_buf, read_size) == 0) {
164                 result = SFUD_ERR_TIMEOUT;
165             }
166         }
167     }
168 
169     return result;
170 }
171 
172 #ifdef SFUD_USING_QSPI
173 /**
174  * QSPI fast read data
175  */
qspi_read(const struct __sfud_spi * spi,uint32_t addr,sfud_qspi_read_cmd_format * qspi_read_cmd_format,uint8_t * read_buf,size_t read_size)176 static sfud_err qspi_read(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format, uint8_t *read_buf, size_t read_size) {
177     struct rt_qspi_message message;
178     sfud_err result = SFUD_SUCCESS;
179 
180     sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
181     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
182     struct rt_qspi_device *qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
183 
184     /* set message struct */
185     message.instruction.content = qspi_read_cmd_format->instruction;
186     message.instruction.qspi_lines = qspi_read_cmd_format->instruction_lines;
187 
188     message.address.content = addr;
189     message.address.size = qspi_read_cmd_format->address_size;
190     message.address.qspi_lines = qspi_read_cmd_format->address_lines;
191 
192     message.alternate_bytes.content = 0;
193     message.alternate_bytes.size = 0;
194     message.alternate_bytes.qspi_lines = 0;
195 
196     message.dummy_cycles = qspi_read_cmd_format->dummy_cycles;
197 
198     message.parent.send_buf = RT_NULL;
199     message.parent.recv_buf = read_buf;
200     message.parent.length = read_size;
201     message.parent.cs_release = 1;
202     message.parent.cs_take = 1;
203     message.qspi_data_lines = qspi_read_cmd_format->data_lines;
204 
205     if (rt_qspi_transfer_message(qspi_dev, &message) != read_size) {
206         result = SFUD_ERR_TIMEOUT;
207     }
208 
209     return result;
210 }
211 #endif
212 
spi_lock(const sfud_spi * spi)213 static void spi_lock(const sfud_spi *spi) {
214     sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
215     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
216 
217     rt_mutex_take(&(rtt_dev->lock), RT_WAITING_FOREVER);
218 }
219 
spi_unlock(const sfud_spi * spi)220 static void spi_unlock(const sfud_spi *spi) {
221     sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
222     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
223 
224     rt_mutex_release(&(rtt_dev->lock));
225 }
226 
retry_delay_100us(void)227 static void retry_delay_100us(void) {
228     /* 100 microsecond delay */
229     rt_thread_delay((RT_TICK_PER_SECOND * 1 + 9999) / 10000);
230 }
231 
232 /**
233  * This function is print debug info.
234  *
235  * @param file the file which has call this function
236  * @param line the line number which has call this function
237  * @param format output format
238  * @param ... args
239  */
sfud_log_debug(const char * file,const long line,const char * format,...)240 void sfud_log_debug(const char *file, const long line, const char *format, ...) {
241     va_list args;
242 
243     /* args point to the first variable parameter */
244     va_start(args, format);
245     rt_kprintf("[SFUD] (%s:%ld) ", file, line);
246     /* must use vprintf to print */
247     rt_vsnprintf(log_buf, sizeof(log_buf), format, args);
248     rt_kprintf("%s\n", log_buf);
249     va_end(args);
250 }
251 
252 /**
253  * This function is print routine info.
254  *
255  * @param format output format
256  * @param ... args
257  */
sfud_log_info(const char * format,...)258 void sfud_log_info(const char *format, ...) {
259     va_list args;
260 
261     /* args point to the first variable parameter */
262     va_start(args, format);
263     rt_kprintf("[SFUD] ");
264     /* must use vprintf to print */
265     rt_vsnprintf(log_buf, sizeof(log_buf), format, args);
266     rt_kprintf("%s\n", log_buf);
267     va_end(args);
268 }
269 
sfud_spi_port_init(sfud_flash * flash)270 sfud_err sfud_spi_port_init(sfud_flash *flash) {
271     sfud_err result = SFUD_SUCCESS;
272 
273     /* port SPI device interface */
274     flash->spi.wr = spi_write_read;
275 #ifdef SFUD_USING_QSPI
276     flash->spi.qspi_read = qspi_read;
277 #endif
278     flash->spi.lock = spi_lock;
279     flash->spi.unlock = spi_unlock;
280     flash->spi.user_data = flash;
281     if (RT_TICK_PER_SECOND < 1000) {
282         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);
283     }
284     /* 100 microsecond delay */
285     flash->retry.delay = retry_delay_100us;
286     /* 60 seconds timeout */
287     flash->retry.times = 60 * 10000;
288 
289     return result;
290 }
291 
292 #ifdef RT_USING_DEVICE_OPS
293 const static struct rt_device_ops flash_device_ops =
294 {
295     RT_NULL,
296     RT_NULL,
297     RT_NULL,
298     rt_sfud_read,
299     rt_sfud_write,
300     rt_sfud_control
301 };
302 #endif
303 
304 /**
305  * Probe SPI flash by SFUD(Serial Flash Universal Driver) driver library and though SPI device.
306  *
307  * @param spi_flash_dev_name the name which will create SPI flash device
308  * @param spi_dev_name using SPI device name
309  *
310  * @return probed SPI flash device, probe failed will return RT_NULL
311  */
rt_sfud_flash_probe(const char * spi_flash_dev_name,const char * spi_dev_name)312 rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const char *spi_dev_name) {
313     rt_spi_flash_device_t rtt_dev = RT_NULL;
314     sfud_flash *sfud_dev = RT_NULL;
315     char *spi_flash_dev_name_bak = RT_NULL, *spi_dev_name_bak = RT_NULL;
316     /* using default flash SPI configuration for initialize SPI Flash
317      * @note you also can change the SPI to other configuration after initialized finish */
318     struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG;
319     extern sfud_err sfud_device_init(sfud_flash *flash);
320 #ifdef SFUD_USING_QSPI
321     struct rt_qspi_configuration qspi_cfg = RT_SFUD_DEFAULT_QSPI_CFG;
322     struct rt_qspi_device *qspi_dev = RT_NULL;
323 #endif
324 
325     RT_ASSERT(spi_flash_dev_name);
326     RT_ASSERT(spi_dev_name);
327 
328     rtt_dev = (rt_spi_flash_device_t) rt_malloc(sizeof(struct spi_flash_device));
329     sfud_dev = (sfud_flash_t) rt_malloc(sizeof(sfud_flash));
330     spi_flash_dev_name_bak = (char *) rt_malloc(rt_strlen(spi_flash_dev_name) + 1);
331     spi_dev_name_bak = (char *) rt_malloc(rt_strlen(spi_dev_name) + 1);
332 
333     if (rtt_dev) {
334         rt_memset(rtt_dev, 0, sizeof(struct spi_flash_device));
335         /* initialize lock */
336         rt_mutex_init(&(rtt_dev->lock), spi_flash_dev_name, RT_IPC_FLAG_FIFO);
337     }
338 
339     if (rtt_dev && sfud_dev && spi_flash_dev_name_bak && spi_dev_name_bak) {
340         rt_memset(sfud_dev, 0, sizeof(sfud_flash));
341         rt_strncpy(spi_flash_dev_name_bak, spi_flash_dev_name, rt_strlen(spi_flash_dev_name));
342         rt_strncpy(spi_dev_name_bak, spi_dev_name, rt_strlen(spi_dev_name));
343         /* make string end sign */
344         spi_flash_dev_name_bak[rt_strlen(spi_flash_dev_name)] = '\0';
345         spi_dev_name_bak[rt_strlen(spi_dev_name)] = '\0';
346         /* SPI configure */
347         {
348             /* RT-Thread SPI device initialize */
349             rtt_dev->rt_spi_device = (struct rt_spi_device *) rt_device_find(spi_dev_name);
350             if (rtt_dev->rt_spi_device == RT_NULL || rtt_dev->rt_spi_device->parent.type != RT_Device_Class_SPIDevice) {
351                 rt_kprintf("ERROR: SPI device %s not found!\n", spi_dev_name);
352                 goto error;
353             }
354             sfud_dev->spi.name = spi_dev_name_bak;
355 
356 #ifdef SFUD_USING_QSPI
357             /* set the qspi line number and configure the QSPI bus */
358             if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
359                 qspi_dev = (struct rt_qspi_device *)rtt_dev->rt_spi_device;
360                 qspi_cfg.qspi_dl_width = qspi_dev->config.qspi_dl_width;
361                 rt_qspi_configure(qspi_dev, &qspi_cfg);
362             }
363             else
364 #endif
365                 rt_spi_configure(rtt_dev->rt_spi_device, &cfg);
366         }
367         /* SFUD flash device initialize */
368         {
369             sfud_dev->name = spi_flash_dev_name_bak;
370             /* accessed each other */
371             rtt_dev->user_data = sfud_dev;
372             rtt_dev->rt_spi_device->user_data = rtt_dev;
373             rtt_dev->flash_device.user_data = rtt_dev;
374             sfud_dev->user_data = rtt_dev;
375             /* initialize SFUD device */
376             if (sfud_device_init(sfud_dev) != SFUD_SUCCESS) {
377                 rt_kprintf("ERROR: SPI flash probe failed by SPI device %s.\n", spi_dev_name);
378                 goto error;
379             }
380             /* when initialize success, then copy SFUD flash device's geometry to RT-Thread SPI flash device */
381             rtt_dev->geometry.sector_count = sfud_dev->chip.capacity / sfud_dev->chip.erase_gran;
382             rtt_dev->geometry.bytes_per_sector = sfud_dev->chip.erase_gran;
383             rtt_dev->geometry.block_size = sfud_dev->chip.erase_gran;
384 #ifdef SFUD_USING_QSPI
385             /* reconfigure the QSPI bus for medium size */
386             if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
387                 qspi_cfg.medium_size = sfud_dev->chip.capacity;
388                 rt_qspi_configure(qspi_dev, &qspi_cfg);
389                 if(qspi_dev->enter_qspi_mode != RT_NULL)
390                     qspi_dev->enter_qspi_mode(qspi_dev);
391             }
392             /* set data lines width */
393             sfud_qspi_fast_read_enable(sfud_dev, qspi_dev->config.qspi_dl_width);
394 #endif /* SFUD_USING_QSPI */
395         }
396 
397         /* register device */
398         rtt_dev->flash_device.type = RT_Device_Class_Block;
399 #ifdef RT_USING_DEVICE_OPS
400         rtt_dev->flash_device.ops  = &flash_device_ops;
401 #else
402         rtt_dev->flash_device.init = RT_NULL;
403         rtt_dev->flash_device.open = RT_NULL;
404         rtt_dev->flash_device.close = RT_NULL;
405         rtt_dev->flash_device.read = rt_sfud_read;
406         rtt_dev->flash_device.write = rt_sfud_write;
407         rtt_dev->flash_device.control = rt_sfud_control;
408 #endif
409 
410         rt_device_register(&(rtt_dev->flash_device), spi_flash_dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
411 
412         DEBUG_TRACE("Probe SPI flash %s by SPI device %s success.\n",spi_flash_dev_name, spi_dev_name);
413         return rtt_dev;
414     } else {
415         rt_kprintf("ERROR: Low memory.\n");
416         goto error;
417     }
418 
419 error:
420 
421     if (rtt_dev) {
422         rt_mutex_detach(&(rtt_dev->lock));
423     }
424     /* may be one of objects memory was malloc success, so need free all */
425     rt_free(rtt_dev);
426     rt_free(sfud_dev);
427     rt_free(spi_flash_dev_name_bak);
428     rt_free(spi_dev_name_bak);
429 
430     return RT_NULL;
431 }
432 
433 /**
434  * Delete SPI flash device
435  *
436  * @param spi_flash_dev SPI flash device
437  *
438  * @return the operation status, RT_EOK on successful
439  */
rt_sfud_flash_delete(rt_spi_flash_device_t spi_flash_dev)440 rt_err_t rt_sfud_flash_delete(rt_spi_flash_device_t spi_flash_dev) {
441     sfud_flash *sfud_flash_dev = (sfud_flash *) (spi_flash_dev->user_data);
442 
443     RT_ASSERT(spi_flash_dev);
444     RT_ASSERT(sfud_flash_dev);
445 
446     rt_device_unregister(&(spi_flash_dev->flash_device));
447 
448     rt_mutex_detach(&(spi_flash_dev->lock));
449 
450     rt_free(sfud_flash_dev->spi.name);
451     rt_free(sfud_flash_dev->name);
452     rt_free(sfud_flash_dev);
453     rt_free(spi_flash_dev);
454 
455     return RT_EOK;
456 }
457 
rt_sfud_flash_find(const char * spi_dev_name)458 sfud_flash_t rt_sfud_flash_find(const char *spi_dev_name)
459 {
460     rt_spi_flash_device_t  rtt_dev       = RT_NULL;
461     struct rt_spi_device  *rt_spi_device = RT_NULL;
462     sfud_flash_t           sfud_dev      = RT_NULL;
463 
464     rt_spi_device = (struct rt_spi_device *) rt_device_find(spi_dev_name);
465     if (rt_spi_device == RT_NULL || rt_spi_device->parent.type != RT_Device_Class_SPIDevice)
466     {
467         rt_kprintf("ERROR: SPI device %s not found!\n", spi_dev_name);
468         goto error;
469     }
470 
471     rtt_dev = (rt_spi_flash_device_t)(rt_spi_device->user_data);
472     if (rtt_dev && rtt_dev->user_data)
473     {
474         sfud_dev = (sfud_flash_t)(rtt_dev->user_data);
475         return sfud_dev;
476     }
477     else
478     {
479         rt_kprintf("ERROR: SFUD flash device not found!\n");
480         goto error;
481     }
482 
483 error:
484     return RT_NULL;
485 }
486 
487 #if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH)
488 
489 #include <finsh.h>
490 
sf(uint8_t argc,char ** argv)491 static void sf(uint8_t argc, char **argv) {
492 
493 #define CMD_PROBE_INDEX               0
494 #define CMD_READ_INDEX                1
495 #define CMD_WRITE_INDEX               2
496 #define CMD_ERASE_INDEX               3
497 #define CMD_RW_STATUS_INDEX           4
498 #define CMD_BENCH_INDEX               5
499 
500     sfud_err result = SFUD_SUCCESS;
501     static const sfud_flash *sfud_dev = NULL;
502     static rt_spi_flash_device_t rtt_dev = NULL, rtt_dev_bak = NULL;
503     size_t i = 0;
504 
505     const char* sf_help_info[] = {
506             [CMD_PROBE_INDEX]     = "sf probe [spi_device]           - probe and init SPI flash by given 'spi_device'",
507             [CMD_READ_INDEX]      = "sf read addr size               - read 'size' bytes starting at 'addr'",
508             [CMD_WRITE_INDEX]     = "sf write addr data1 ... dataN   - write some bytes 'data' to flash starting at 'addr'",
509             [CMD_ERASE_INDEX]     = "sf erase addr size              - erase 'size' bytes starting at 'addr'",
510             [CMD_RW_STATUS_INDEX] = "sf status [<volatile> <status>] - read or write '1:volatile|0:non-volatile' 'status'",
511             [CMD_BENCH_INDEX]     = "sf bench                        - full chip benchmark. DANGER: It will erase full chip!",
512     };
513 
514     if (argc < 2) {
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     } else {
521         const char *operator = argv[1];
522         uint32_t addr, size;
523 
524         if (!strcmp(operator, "probe")) {
525             if (argc < 3) {
526                 rt_kprintf("Usage: %s.\n", sf_help_info[CMD_PROBE_INDEX]);
527             } else {
528                 char *spi_dev_name = argv[2];
529                 rtt_dev_bak = rtt_dev;
530 
531                 /* delete the old SPI flash device */
532                 if(rtt_dev_bak) {
533                     rt_sfud_flash_delete(rtt_dev_bak);
534                 }
535 
536                 rtt_dev = rt_sfud_flash_probe("sf_cmd", spi_dev_name);
537                 if (!rtt_dev) {
538                     return;
539                 }
540 
541                 sfud_dev = (sfud_flash_t)rtt_dev->user_data;
542                 if (sfud_dev->chip.capacity < 1024 * 1024) {
543                     rt_kprintf("%d KB %s is current selected device.\n", sfud_dev->chip.capacity / 1024, sfud_dev->name);
544                 } else {
545                     rt_kprintf("%d MB %s is current selected device.\n", sfud_dev->chip.capacity / 1024 / 1024,
546                             sfud_dev->name);
547                 }
548             }
549         } else {
550             if (!sfud_dev) {
551                 rt_kprintf("No flash device selected. Please run 'sf probe'.\n");
552                 return;
553             }
554             if (!rt_strcmp(operator, "read")) {
555                 if (argc < 4) {
556                     rt_kprintf("Usage: %s.\n", sf_help_info[CMD_READ_INDEX]);
557                     return;
558                 } else {
559                     addr = atol(argv[2]);
560                     size = atol(argv[3]);
561                     uint8_t *data = rt_malloc(size);
562                     if (data) {
563                         result = sfud_read(sfud_dev, addr, size, data);
564                         if (result == SFUD_SUCCESS) {
565                             rt_kprintf("Read the %s flash data success. Start from 0x%08X, size is %ld. The data is:\n",
566                                     sfud_dev->name, addr, size);
567                             rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
568                             for (i = 0; i < size; i++) {
569                                 if (i % 16 == 0) {
570                                     rt_kprintf("[%08X] ", addr + i);
571                                 }
572                                 rt_kprintf("%02X ", data[i]);
573                                 if (((i + 1) % 16 == 0) || i == size - 1) {
574                                     rt_kprintf("\n");
575                                 }
576                             }
577                             rt_kprintf("\n");
578                         }
579                         rt_free(data);
580                     } else {
581                         rt_kprintf("Low memory!\n");
582                     }
583                 }
584             } else if (!rt_strcmp(operator, "write")) {
585                 if (argc < 4) {
586                     rt_kprintf("Usage: %s.\n", sf_help_info[CMD_WRITE_INDEX]);
587                     return;
588                 } else {
589                     addr = atol(argv[2]);
590                     size = argc - 3;
591                     uint8_t *data = rt_malloc(size);
592                     if (data) {
593                         for (i = 0; i < size; i++) {
594                             data[i] = atoi(argv[3 + i]);
595                         }
596                         result = sfud_write(sfud_dev, addr, size, data);
597                         if (result == SFUD_SUCCESS) {
598                             rt_kprintf("Write the %s flash data success. Start from 0x%08X, size is %ld.\n",
599                                     sfud_dev->name, addr, size);
600                             rt_kprintf("Write data: ");
601                             for (i = 0; i < size; i++) {
602                                 rt_kprintf("%d ", data[i]);
603                             }
604                             rt_kprintf(".\n");
605                         }
606                         rt_free(data);
607                     } else {
608                         rt_kprintf("Low memory!\n");
609                     }
610                 }
611             } else if (!rt_strcmp(operator, "erase")) {
612                 if (argc < 4) {
613                     rt_kprintf("Usage: %s.\n", sf_help_info[CMD_ERASE_INDEX]);
614                     return;
615                 } else {
616                     addr = atol(argv[2]);
617                     size = atol(argv[3]);
618                     result = sfud_erase(sfud_dev, addr, size);
619                     if (result == SFUD_SUCCESS) {
620                         rt_kprintf("Erase the %s flash data success. Start from 0x%08X, size is %ld.\n", sfud_dev->name,
621                                 addr, size);
622                     }
623                 }
624             } else if (!rt_strcmp(operator, "status")) {
625                 if (argc < 3) {
626                     uint8_t status;
627                     result = sfud_read_status(sfud_dev, &status);
628                     if (result == SFUD_SUCCESS) {
629                         rt_kprintf("The %s flash status register current value is 0x%02X.\n", sfud_dev->name, status);
630                     }
631                 } else if (argc == 4) {
632                     bool is_volatile = atoi(argv[2]);
633                     uint8_t status = atoi(argv[3]);
634                     result = sfud_write_status(sfud_dev, is_volatile, status);
635                     if (result == SFUD_SUCCESS) {
636                         rt_kprintf("Write the %s flash status register to 0x%02X success.\n", sfud_dev->name, status);
637                     }
638                 } else {
639                     rt_kprintf("Usage: %s.\n", sf_help_info[CMD_RW_STATUS_INDEX]);
640                     return;
641                 }
642             } else if (!rt_strcmp(operator, "bench")) {
643                 if ((argc > 2 && rt_strcmp(argv[2], "yes")) || argc < 3) {
644                     rt_kprintf("DANGER: It will erase full chip! Please run 'sf bench yes'.\n");
645                     return;
646                 }
647                 /* full chip benchmark test */
648                 addr = 0;
649                 size = sfud_dev->chip.capacity;
650                 uint32_t start_time, time_cast;
651                 size_t write_size = SFUD_WRITE_MAX_PAGE_SIZE, read_size = SFUD_WRITE_MAX_PAGE_SIZE;
652                 uint8_t *write_data = rt_malloc(write_size), *read_data = rt_malloc(read_size);
653 
654                 if (write_data && read_data) {
655                     rt_memset(write_data, 0x55, write_size);
656                     /* benchmark testing */
657                     rt_kprintf("Erasing the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
658                     start_time = rt_tick_get();
659                     result = sfud_erase(sfud_dev, addr, size);
660                     if (result == SFUD_SUCCESS) {
661                         time_cast = rt_tick_get() - start_time;
662                         rt_kprintf("Erase benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
663                                 time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
664                     } else {
665                         rt_kprintf("Erase benchmark has an error. Error code: %d.\n", result);
666                     }
667                     /* write test */
668                     rt_kprintf("Writing the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
669                     start_time = rt_tick_get();
670                     for (i = 0; i < size; i += write_size) {
671                         result = sfud_write(sfud_dev, addr + i, write_size, write_data);
672                         if (result != SFUD_SUCCESS) {
673                             break;
674                         }
675                     }
676                     if (result == SFUD_SUCCESS) {
677                         time_cast = rt_tick_get() - start_time;
678                         rt_kprintf("Write benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
679                                 time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
680                     } else {
681                         rt_kprintf("Write benchmark has an error. Error code: %d.\n", result);
682                     }
683                     /* read test */
684                     rt_kprintf("Reading the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
685                     start_time = rt_tick_get();
686                     for (i = 0; i < size; i += read_size) {
687                         if (i + read_size <= size) {
688                             result = sfud_read(sfud_dev, addr + i, read_size, read_data);
689                         } else {
690                             result = sfud_read(sfud_dev, addr + i, size - i, read_data);
691                         }
692                         /* data check */
693                         if (memcmp(write_data, read_data, read_size))
694                         {
695                             rt_kprintf("Data check ERROR! Please check you flash by other command.\n");
696                             result = SFUD_ERR_READ;
697                         }
698 
699                         if (result != SFUD_SUCCESS) {
700                             break;
701                         }
702                     }
703                     if (result == SFUD_SUCCESS) {
704                         time_cast = rt_tick_get() - start_time;
705                         rt_kprintf("Read benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
706                                 time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
707                     } else {
708                         rt_kprintf("Read benchmark has an error. Error code: %d.\n", result);
709                     }
710                 } else {
711                     rt_kprintf("Low memory!\n");
712                 }
713                 rt_free(write_data);
714                 rt_free(read_data);
715             } else {
716                 rt_kprintf("Usage:\n");
717                 for (i = 0; i < sizeof(sf_help_info) / sizeof(char*); i++) {
718                     rt_kprintf("%s\n", sf_help_info[i]);
719                 }
720                 rt_kprintf("\n");
721                 return;
722             }
723             if (result != SFUD_SUCCESS) {
724                 rt_kprintf("This flash operate has an error. Error code: %d.\n", result);
725             }
726         }
727     }
728 }
729 MSH_CMD_EXPORT(sf, SPI Flash operate.);
730 #endif /* defined(RT_USING_FINSH) && defined(FINSH_USING_MSH) */
731 
732 #endif /* RT_USING_SFUD */
733