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