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