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