1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2011-01-01 aozima the first version.
9 * 2012-02-11 aozima add multiple sector speed test.
10 * 2012-05-27 aozima use rt_deice API.
11 */
12
13 #include <rtthread.h>
14
15 /* calculate speed */
calculate_speed_print(rt_uint32_t speed)16 static void calculate_speed_print(rt_uint32_t speed)
17 {
18 rt_uint32_t k,m;
19
20 k = speed/1024UL;
21 if( k )
22 {
23 m = k/1024UL;
24 if( m )
25 {
26 rt_kprintf("%d.%dMbyte/s",m,k%1024UL*100/1024UL);
27 }
28 else
29 {
30 rt_kprintf("%d.%dKbyte/s",k,speed%1024UL*100/1024UL);
31 }
32 }
33 else
34 {
35 rt_kprintf("%dbyte/s",speed);
36 }
37 }
38
_block_device_test(rt_device_t device)39 static rt_err_t _block_device_test(rt_device_t device)
40 {
41 rt_err_t result;
42 struct rt_device_blk_geometry geometry;
43 rt_uint8_t * read_buffer = RT_NULL;
44 rt_uint8_t * write_buffer = RT_NULL;
45
46 rt_kprintf("\r\n");
47
48 if( (device->flag & RT_DEVICE_FLAG_RDWR) == RT_DEVICE_FLAG_RDWR )
49 {
50 // device can read and write.
51 // step 1: open device
52 result = rt_device_open(device,RT_DEVICE_FLAG_RDWR);
53 if( result != RT_EOK )
54 {
55 return result;
56 }
57
58 // step 2: get device info
59 rt_memset(&geometry, 0, sizeof(geometry));
60 result = rt_device_control(device,
61 RT_DEVICE_CTRL_BLK_GETGEOME,
62 &geometry);
63 if( result != RT_EOK )
64 {
65 rt_kprintf("device : %s cmd RT_DEVICE_CTRL_BLK_GETGEOME failed.\r\n");
66 return result;
67 }
68 rt_kprintf("device info:\r\n");
69 rt_kprintf("sector size : %d byte\r\n", geometry.bytes_per_sector);
70 rt_kprintf("sector count : %d \r\n", geometry.sector_count);
71 rt_kprintf("block size : %d byte\r\n", geometry.block_size);
72
73 rt_kprintf("\r\n");
74 read_buffer = rt_malloc(geometry.bytes_per_sector);
75 if( read_buffer == RT_NULL )
76 {
77 rt_kprintf("no memory for read_buffer!\r\n");
78 goto __return;
79 }
80 write_buffer = rt_malloc(geometry.bytes_per_sector);
81 if( write_buffer == RT_NULL )
82 {
83 rt_kprintf("no memory for write_buffer!\r\n");
84 goto __return;
85 }
86
87 /* step 3: R/W test */
88 {
89 rt_uint32_t i, err_count, sector_no;
90 rt_uint8_t * data_point;
91
92 i = rt_device_read(device, 0, read_buffer, 1);
93 if(i != 1)
94 {
95 rt_kprintf("read device :%s ", device->parent.name);
96 rt_kprintf("the first sector failed.\r\n");
97 goto __return;
98 }
99
100 data_point = write_buffer;
101 for(i=0; i<geometry.bytes_per_sector; i++)
102 {
103 *data_point++ = (rt_uint8_t)i;
104 }
105
106 /* write first sector */
107 sector_no = 0;
108 data_point = write_buffer;
109 *data_point++ = (rt_uint8_t)sector_no;
110 i = rt_device_write(device, sector_no, write_buffer,1);
111 if( i != 1 )
112 {
113 rt_kprintf("read the first sector success!\r\n");
114 rt_kprintf("but write device :%s ", device->parent.name);
115 rt_kprintf("the first sector failed.\r\n");
116 rt_kprintf("maybe readonly!\r\n");
117 goto __return;
118 }
119
120 /* write the second sector */
121 sector_no = 1;
122 data_point = write_buffer;
123 *data_point++ = (rt_uint8_t)sector_no;
124 i = rt_device_write(device,sector_no,write_buffer,1);
125 if( i != 1 )
126 {
127 rt_kprintf("write device :%s ",device->parent.name);
128 rt_kprintf("the second sector failed.\r\n");
129 goto __return;
130 }
131
132 /* write the end sector */
133 sector_no = geometry.sector_count-1;
134 data_point = write_buffer;
135 *data_point++ = (rt_uint8_t)sector_no;
136 i = rt_device_write(device,sector_no,write_buffer,1);
137 if( i != 1 )
138 {
139 rt_kprintf("write device :%s ",device->parent.name);
140 rt_kprintf("the end sector failed.\r\n");
141 goto __return;
142 }
143
144 /* verify first sector */
145 sector_no = 0;
146 i = rt_device_read(device,sector_no,read_buffer,1);
147 if( i != 1 )
148 {
149 rt_kprintf("read device :%s ",device->parent.name);
150 rt_kprintf("the first sector failed.\r\n");
151 goto __return;
152 }
153 err_count = 0;
154 data_point = read_buffer;
155 if( (*data_point++) != (rt_uint8_t)sector_no)
156 {
157 err_count++;
158 }
159 for(i=1; i<geometry.bytes_per_sector; i++)
160 {
161 if( (*data_point++) != (rt_uint8_t)i )
162 {
163 err_count++;
164 }
165 }
166 if( err_count > 0 )
167 {
168 rt_kprintf("verify device :%s ",device->parent.name);
169 rt_kprintf("the first sector failed.\r\n");
170 goto __return;
171 }
172
173 /* verify sector sector */
174 sector_no = 1;
175 i = rt_device_read(device,sector_no,read_buffer,1);
176 if( i != 1 )
177 {
178 rt_kprintf("read device :%s ",device->parent.name);
179 rt_kprintf("the second sector failed.\r\n");
180 goto __return;
181 }
182 err_count = 0;
183 data_point = read_buffer;
184 if( (*data_point++) != (rt_uint8_t)sector_no)
185 {
186 err_count++;
187 }
188 for(i=1; i<geometry.bytes_per_sector; i++)
189 {
190 if( (*data_point++) != (rt_uint8_t)i )
191 {
192 err_count++;
193 }
194 }
195 if( err_count > 0 )
196 {
197 rt_kprintf("verify device :%s ",device->parent.name);
198 rt_kprintf("the second sector failed.\r\n");
199 goto __return;
200 }
201
202 /* verify the end sector */
203 sector_no = geometry.sector_count-1;
204 i = rt_device_read(device,sector_no,read_buffer,1);
205 if( i != 1 )
206 {
207 rt_kprintf("read device :%s ",device->parent.name);
208 rt_kprintf("the end sector failed.\r\n");
209 goto __return;
210 }
211 err_count = 0;
212 data_point = read_buffer;
213 if( (*data_point++) != (rt_uint8_t)sector_no)
214 {
215 err_count++;
216 }
217 for(i=1; i<geometry.bytes_per_sector; i++)
218 {
219 if( (*data_point++) != (rt_uint8_t)i )
220 {
221 err_count++;
222 }
223 }
224 if( err_count > 0 )
225 {
226 rt_kprintf("verify device :%s ",device->parent.name);
227 rt_kprintf("the end sector failed.\r\n");
228 goto __return;
229 }
230 rt_kprintf("device R/W test pass!\r\n");
231
232 } /* step 3: I/O R/W test */
233
234 rt_kprintf("\r\nRT_TICK_PER_SECOND:%d\r\n", RT_TICK_PER_SECOND);
235
236 // step 4: continuous single sector speed test
237 {
238 rt_uint32_t tick_start,tick_end;
239 rt_uint32_t i;
240
241 rt_kprintf("\r\ncontinuous single sector speed test:\r\n");
242
243 if( geometry.sector_count < 10 )
244 {
245 rt_kprintf("device sector_count < 10, speed test abort!\r\n");
246 }
247 else
248 {
249 unsigned int sector;
250
251 // sign sector write
252 rt_kprintf("write: ");
253 sector = 0;
254 tick_start = rt_tick_get();
255 for(i=0; i<200; i++)
256 {
257 sector += rt_device_write(device, i, read_buffer, 1);
258 if((i != 0) && ((i%4) == 0) )
259 {
260 if(sector < 4)
261 {
262 rt_kprintf("#");
263 }
264 else
265 {
266 rt_kprintf("<");
267 }
268 sector = 0;
269 }
270 }
271 tick_end = rt_tick_get();
272 rt_kprintf("\r\nwrite 200 sector from %d to %d, ",tick_start,tick_end);
273 calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) );
274 rt_kprintf("\r\n");
275
276 // sign sector read
277 rt_kprintf("read : ");
278 sector = 0;
279 tick_start = rt_tick_get();
280 for(i=0; i<200; i++)
281 {
282 sector += rt_device_read(device, i, read_buffer, 1);
283 if((i != 0) && ((i%4) == 0) )
284 {
285 if(sector < 4)
286 {
287 rt_kprintf("#");
288 }
289 else
290 {
291 rt_kprintf(">");
292 }
293 sector = 0;
294 }
295 }
296 tick_end = rt_tick_get();
297 rt_kprintf("\r\nread 200 sector from %d to %d, ",tick_start,tick_end);
298 calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) );
299 rt_kprintf("\r\n");
300 }
301 }// step 4: speed test
302
303 // step 5: random single sector speed test
304 {
305 rt_uint32_t tick_start,tick_end;
306 rt_uint32_t i;
307
308 rt_kprintf("\r\nrandom single sector speed test:\r\n");
309
310 if( geometry.sector_count < 10 )
311 {
312 rt_kprintf("device sector_count < 10, speed test abort!\r\n");
313 }
314 else
315 {
316 unsigned int sector;
317
318 // sign sector write
319 rt_kprintf("write: ");
320 sector = 0;
321 tick_start = rt_tick_get();
322 for(i=0; i<200; i++)
323 {
324 sector += rt_device_write(device, (geometry.sector_count / 10) * (i%10) + (i%10), read_buffer, 1);
325 if((i != 0) && ((i%4) == 0) )
326 {
327 if(sector < 4)
328 {
329 rt_kprintf("#");
330 }
331 else
332 {
333 rt_kprintf("<");
334 }
335 sector = 0;
336 }
337 }
338 tick_end = rt_tick_get();
339 rt_kprintf("\r\nwrite 200 sector from %d to %d, ",tick_start,tick_end);
340 calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) );
341 rt_kprintf("\r\n");
342
343 // sign sector read
344 rt_kprintf("read : ");
345 sector = 0;
346 tick_start = rt_tick_get();
347 for(i=0; i<200; i++)
348 {
349 sector += rt_device_read(device, (geometry.sector_count / 10) * (i%10) + (i%10), read_buffer, 1);
350 if((i != 0) && ((i%4) == 0) )
351 {
352 if(sector < 4)
353 {
354 rt_kprintf("#");
355 }
356 else
357 {
358 rt_kprintf(">");
359 }
360 sector = 0;
361 }
362 }
363 tick_end = rt_tick_get();
364 rt_kprintf("\r\nread 200 sector from %d to %d, ",tick_start,tick_end);
365 calculate_speed_print( (geometry.bytes_per_sector*200UL*RT_TICK_PER_SECOND)/(tick_end-tick_start) );
366 rt_kprintf("\r\n");
367 }
368 }// step 4: speed test
369
370 /* step 6: multiple sector speed test */
371 {
372 rt_uint8_t * multiple_buffer;
373 rt_uint8_t * ptr;
374 rt_uint32_t tick_start,tick_end;
375 rt_uint32_t sector,i;
376
377 rt_kprintf("\r\nmultiple sector speed test\r\n");
378
379 for(sector=2; sector<256; sector=sector*2)
380 {
381 multiple_buffer = rt_malloc(geometry.bytes_per_sector * sector);
382
383 if(multiple_buffer == RT_NULL)
384 {
385 rt_kprintf("no memory for %d sector! multiple sector speed test abort!\r\n", sector);
386 break;
387 }
388
389 rt_memset(multiple_buffer, sector, geometry.bytes_per_sector * sector);
390 rt_kprintf("write: ");
391 tick_start = rt_tick_get();
392 for(i=0; i<10; i++)
393 {
394 rt_size_t n;
395 n = rt_device_write(device, 50, multiple_buffer, sector);
396 if(n == sector)
397 {
398 rt_kprintf("<");
399 }
400 else
401 {
402 rt_kprintf("#");
403 }
404 }
405 tick_end = rt_tick_get();
406 rt_kprintf("\r\n");
407 rt_kprintf("multiple write %d sector speed : ", sector);
408 calculate_speed_print( (geometry.bytes_per_sector * sector * 10 * RT_TICK_PER_SECOND)/(tick_end-tick_start) );
409 rt_kprintf("\r\n");
410
411 rt_memset(multiple_buffer, ~sector, geometry.bytes_per_sector * sector);
412 rt_kprintf("read : ");
413 tick_start = rt_tick_get();
414 for(i=0; i<10; i++)
415 {
416 rt_size_t n;
417 n = rt_device_read(device, 50, multiple_buffer, sector);
418 if(n == sector)
419 {
420 rt_kprintf(">");
421 }
422 else
423 {
424 rt_kprintf("#");
425 }
426 }
427 tick_end = rt_tick_get();
428 rt_kprintf("\r\n");
429 rt_kprintf("multiple read %d sector speed : ", sector);
430 calculate_speed_print( (geometry.bytes_per_sector * sector * 10 * RT_TICK_PER_SECOND)/(tick_end-tick_start) );
431
432 ptr = multiple_buffer;
433 for(i=0; i<geometry.bytes_per_sector * sector; i++)
434 {
435 if(*ptr != sector)
436 {
437 rt_kprintf(" but data verify fail!");
438 break;
439 }
440 ptr++;
441 }
442 rt_kprintf("\r\n\r\n");
443
444 rt_free(multiple_buffer);
445 }
446 } /* step 5: multiple sector speed test */
447
448 rt_device_close(device);
449 return RT_EOK;
450 }// device can read and write.
451 else
452 {
453 // device read only
454 rt_device_close(device);
455 return RT_EOK;
456 }// device read only
457
458 __return:
459 if( read_buffer != RT_NULL )
460 {
461 rt_free(read_buffer);
462 }
463 if( write_buffer != RT_NULL )
464 {
465 rt_free(write_buffer);
466 }
467 rt_device_close(device);
468 return -RT_ERROR;
469 }
470
device_test(const char * device_name)471 int device_test(const char * device_name)
472 {
473 rt_device_t device = RT_NULL;
474
475 // step 1:find device
476 device = rt_device_find(device_name);
477 if( device == RT_NULL)
478 {
479 rt_kprintf("device %s: not found!\r\n", device_name);
480 return -RT_ERROR;
481 }
482
483 // step 2:init device
484 if (!(device->flag & RT_DEVICE_FLAG_ACTIVATED))
485 {
486 rt_err_t result;
487 result = rt_device_init(device);
488 if (result != RT_EOK)
489 {
490 rt_kprintf("To initialize device:%s failed. The error code is %d\r\n",
491 device->parent.name, result);
492 return result;
493 }
494 else
495 {
496 device->flag |= RT_DEVICE_FLAG_ACTIVATED;
497 }
498 }
499
500 // step 3: device test
501 switch( device->type )
502 {
503 case RT_Device_Class_Block :
504 rt_kprintf("block device!\r\n");
505 return _block_device_test(device);
506 default:
507 rt_kprintf("unkown device type : %02X",device->type);
508 return -RT_ERROR;
509 }
510 }
511
512 #ifdef RT_USING_FINSH
513 #include <finsh.h>
514 FINSH_FUNCTION_EXPORT(device_test, e.g: device_test("sd0"));
515 #endif
516
517