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 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 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 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 */ 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 */ 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 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 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 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 */ 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 */ 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 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 */ 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 */ 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 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 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