在嵌入式系统中,Flash是最常用组件之一。许多使用过flash的朋友都了解,Flash的特点是“读来容易写来难”。通常,可以直接读出Flash的内容;但如果要写入数据,就要发送一长串命令,比如像:555 ,AA,2AA,55,555,A0 ,PA,PD就表示对PA地址写入数据PD,实际情况还要复杂一点,因为通常还要包含许多查询操作。
哎呀,这真是好繁琐呀,有没有省力的方法呢?现在好了,NiosII的开发环境提供了对符合CFI标准的Flash的支持,使用几个简单的函数,就可以操作Flash,真是方便了许多。
在这里,我粗略得介绍一下nios 中flash的使用;更加详细的帮助信息请您参考Altera公司提供的文档。如果本文能对您有一点点帮助,我都会感到非常高兴。
在使用Flash之前,有几个准备工作要做:
下面我以本站设计的开发板ezNiosDKC6B为目标板,来介绍如何使用Flash,你可以举一反三,在自己的系统中使用Flash.
完成后,选择Finish,即可为系统添加Flash接口。
注意,如果Data Width是16Bits,那么tri_state_bridge_0_address[0]不必接到Flash上,tri_state_bridge_0_address[1]对应Flash的A[0],tri_state_bridge_0_address[2]对应Flash的A[1],以此类推。
3-1 配置Component/Kit Library Search Path。
目的是在系统中增加本站设计的Flash编程器目录,请把光盘CD1上的/Example/ezNiosC6 拷贝到您的电脑的硬盘上。比如,我把他放在h:/DB2005/project/niosDK/CD/CD1/Example/中,然后在Altera SOPC Builder中,选择File -> SOPC Builder Setup,增加如下搜索路径:+h:/DB2005/project/niosDK/CD/CD1/Example/ezNiosC6
ezNiosC3的用户如下操作:请把光盘CD1上的/Example/ezNiosC3 拷贝到您的电脑的硬盘上。比如,我把他放在h:/DB2005/project/niosDK/CD/CD1/Example/中,然后在Altera SOPC Builder中,选择File -> SOPC Builder Setup,增加如下搜索路径:+h:/DB2005/project/niosDK/CD/CD1/Example/ezNiosC3
并顺便检察Modelsim Directory是否正确:比如,我的是 g:/w2k/eda/fpga/altera/modeltech_6.0/win32
然后,你需要关闭Altera SOPC Builder,然后再重新通过QuartusII的Tools ->SOPC Builder来开启SOPC Builder,这样上述修改才能生效。
常见错误:有许多朋友往往在设置路径的时候,犯与下图类似的错误。错误在于第一个路径前面是不需要 + 号的!要去掉第一个路径前面的 + 号
3-2:使用Flash编程器。
我使用项目:ezC6Be_StdF50_zip_filesystem_0(在CD1ExampleezNiosC6BezC6Be_StdF50softwareezC6Be_StdF50_zip_filesystem_0下,请使用Nios IDE中的File-Import来导入这个项目),来说明如何使用Flash编程器。
首先为系统上电,并连接好下载电缆。
选择Tools -> Flash Programmer,启动 Flash 编程器
选择New,可以看到增加了一个名为 ezC6Be_StdF50_zip_filesystem_0 programmer的flash 编程器
选择Program software project into flash memory,然后选择Apply,在选择Program Flash,就启动了Flash 编程器!如果顺利的话,可以看到如下的提示:
如果看到如上提示,OK,小功告成,我们已经可以正常使用Flash编程器啦!
下面我来介绍如何在程序中引用Flash。
使用NiosII提供的系统函数,可以方便得使用Flash,免除了通常操作Flash 的繁琐,这对用户来说,真是方便多了。
Altera 提供了两种类型的函数,提供给客户:Simple Flash Access(简单的Flash访问),以及Fine-Grained Flash Access(细粒度Flash访问)。
一般情况下,我还是推荐使用Fine-Grained Flash Access(细粒度Flash访问)函数,比Simple Flash Access也复杂不了多少,但可以避免通常的跨块擦除问题。因为Flash是按照Block组织起来的,通常一次擦除一整个块。如果写Flash的地址于Flash块的组织结构不吻合,比如跨越了Flash块的边缘,那么可能会擦除掉其余的数据。比如,即使要写入1Byte,也要擦除掉4Kbyte,也许这4Kbyte里面还有许多有用的数据,就会被抹掉。
我们下面介绍几个常用的函数,关于更详细的内容,请参考Altera提供的文档。
首先介绍第一步:打开Flash,就像c程序打开硬盘中的数据文件一样,使用之前要打开Flash.我们使用alt_flash_open_dev()打开Flash,它返回一个句柄。比如,下面是使用这个函数的片断:
alt_flash_fd* fd;
fd = alt_flash_open_dev(EXT_FLASH_NAME);
其中,EXT_FLASH_NAME是预先定义的Flash的名字(#defineEXT_FLASH_NAME"/dev/ext_flash"),接下来的操作,都是通过该句柄:fd,来访问Flash的。
读出Flash使用函数:alt_read_flash,原型如下:
int alt_read_flash( alt_flash_fd* fd,
int offset,
void* dest_addr,
int length )
使用完了,也别忘记关闭该Flash,就象读写完硬盘中的数据文件后要关闭一样。其原型如下:
void alt_flash_close_dev(alt_flash_fd* fd )
Fine-Grained Flash Access机制提供了如下几个函数:alt_get_flash_info(), alt_erase_flash_block(), alt_write_flash_block()。
alt_get_flash_info()可以提取Flash的信息,比如包含几个区域,每个区域有几个块,每个块的大小等等。它的原型如下:
int alt_get_flash_info( alt_flash_fd* fd,flash_region** info,int* number_of_regions)
比如,如下就是一个调用该函数的程序片断:
intret_code = 0;
intnumber_of_regions=0;
flash_region* regions;
ret_code = alt_get_flash_info(fd, ®ions, &number_of_regions
这里涉及到一个结构:flash_region,原型如下:
typedef struct flash_region
{int offset;/* Offset of this region from start of the flash */
int region_size;/* Size of this erase region */
int number_of_blocks;/* Number of blocks in this region */
int block_size;/* Size of each block in this erase region */
}flash_region;
擦除一个块使用函数:alt_flash_fd,函数原型如下:
int alt_erase_flash_block( alt_flash_fd* fd,int offset,int length)
写入一个块使用函数:alt_write_flash_block,函数原型如下:
int alt_write_flash_block( alt_flash_fd* fd,
int block_offset,
int data_offset,
const void *data,
int length)
罗罗嗦嗦说了这么多,下面我们来看一个实际的范例;这个范例是我使用来测试flash的,相信大家可以从中获益良多。
#include
#include
#include
#include"alt_types.h"
#include"sys/alt_flash.h"
#include"sys/alt_flash_dev.h"
#defineNUM_BYTES_TO_WRITE 512
//#define NUM_BYTES_TO_WRITE 64
/*
* test_programming() is called by main to test a range of flash by
* writing incrementing patterns, then reading them back and comparing
* the result
* The start of the range to be tested is defined by test_offset, and
* the size of the range to be tested is defined by NUM_BYTES_TO_WRITE
*/
inttest_programming( alt_flash_fd* fd,inttest_offset)
{
inti,j;
alt_u8 data_written[NUM_BYTES_TO_WRITE];
alt_u8 data_read[NUM_BYTES_TO_WRITE];
intret_code = 0;
inttest_length =sizeof(data_written);
/*
* 30 iterations takes about 60 seconds
*/
for(j=0;j<7;j++)
{
for(i=0;i data_written[i] = j*0x15; for(i=sizeof(data_written)/2;i data_written[i] = (j*0x15)+1; ret_code = alt_write_flash(fd, test_offset, data_written, test_length); if(!ret_code) { ret_code = alt_read_flash(fd, test_offset, data_read, test_length); if(!ret_code) { if(memcmp(data_written, data_read, test_length)) { printf("
ERROR: compare failed sector offset %#x iteration%#x
", test_offset, j); returnret_code; } } } printf("*"); if(ret_code) { printf("
ERROR: function alt_write_flash failed. ret_code %d
", ret_code); returnret_code; } } returnret_code; } inttest_flash_erase( alt_flash_fd* fd) { intret_code = 0; intnumber_of_regions=0; flash_region* regions; inti,j,k; inttest_offset; inttest_length; alt_u8 read_data[200] ; ret_code = alt_get_flash_info(fd, ®ions, &number_of_regions); if(ret_code) { printf("
ERROR: function alt_get_flash_info failed. ret_code %d
", ret_code); } /* * If this is the development board check the number of regions etc. */ printf("
This is AMD29LV160DB
"); printf("Flash name %s
",fd->name); printf("This flash has %d erase regions
", number_of_regions); for(i=0;i { printf("Start 0x%8x End 0x%8x Number of Blocks %3d Block Size 0x%8x
", (regions+i)->offset, (regions+i)->region_size+(regions+i)->offset, (regions+i)->number_of_blocks, (regions+i)->block_size); } for(j=0;j { for(i=0;i<((regions+j)->number_of_blocks);i++) { test_offset = (regions+j)->offset + i*(regions+j)->block_size; test_length = (regions+j)->block_size; printf(" ---Testing flash block erase...@ 0x%8x length= 0x%8x ",test_offset,test_length); ret_code = alt_erase_flash_block(fd, (regions+j)->offset + i*(regions+j)- >block_size, (regions+j)->block_size); if(ret_code) { printf("
ERROR: function alt_erase_flash_block failed. ret_code %d
", ret_code); break; } else { ret_code = alt_read_flash(fd, test_offset, read_data, 100); for(k=0;k<100;k++) { if(read_data[k] != 0xff) { printf("
ERROR: erase compare failed. %d %#x
", k, read_data[k]); break; } } } }//@for(i=1 }//@for(j=1) printf(" passed.
"); returnret_code; } inttest_flash_write( alt_flash_fd* fd) { intret_code = 0; intnumber_of_regions=0; flash_region* regions; inti,j,k; inttest_offset; inttest_length; alt_u8 read_data[200] ; alt_u8 write_data[200]; ret_code = alt_get_flash_info(fd, ®ions, &number_of_regions); if(ret_code) { printf("
ERROR: function alt_get_flash_info failed. ret_code %d
", ret_code); } /* * If this is the development board check the number of regions etc. */ printf("
This is AMD29LV160DB
"); printf("Flash name %s
",fd->name); printf("This flash has %d erase regions
", number_of_regions); for(i=0;i { printf("Start 0x%8x End 0x%8x Number of Blocks %3d Block Size 0x%8x
", (regions+i)->offset, (regions+i)->region_size+(regions+i)->offset, (regions+i)->number_of_blocks, (regions+i)->block_size); } for(j=0;j { for(i=0;i<((regions+j)->number_of_blocks);i++) { test_offset = (regions+j)->offset + i*(regions+j)->block_size; test_length = (regions+j)->block_size; printf(" ---Testing flash block erase...@ 0x%8x length= 0x%8x ",test_offset,test_length); ret_code = alt_erase_flash_block(fd, (regions+j)->offset + i*(regions+j)- >block_size, (regions+j)->block_size); if(ret_code) { printf("
ERROR: function alt_erase_flash_block failed. ret_code %d
", ret_code); break; } else { ret_code = alt_read_flash(fd, test_offset, read_data, 100); for(k=0;k<100;k++) { if(read_data[k] != 0xff) { printf("
ERROR: erase compare failed. %d %#x
", k, read_data[k]); break; } }//@for (k=0) printf(" -----------Now Testing flash block write...@ 0x%8x
",test_offset); for(k=0;k<100;k++) write_data[k] = k; ret_code = alt_write_flash_block( fd, (regions+j)->offset + i*(regions+j)- >block_size, test_offset + i, write_data, 100); if(ret_code) { printf("
ERROR: function aXlt_write_flash_block failed. ret_code %d
", ret_code); break; } else { ret_code = alt_read_flash(fd, test_offset + i, read_data, 100); for(k=0;k<100;k++) { if(read_data[k] != write_data[k]) {printf("
ERROR: compare failed, expected %#x read %#x
",write_data[i], read_data[i]); break; } } }//@ else } }//@for(i=1 }//@for(j=1) printf(" passed.
"); returnret_code; } /* * test_get_info() is called by main to test that the regions, sector * size, block size and number of blocks can be correctly read from * the flash */ inttest_get_info( alt_flash_fd* fd) { intret_code = 0; intnumber_of_regions=0; flash_region* regions; inti; ret_code = alt_get_flash_info(fd, ®ions, &number_of_regions); if(ret_code) { printf("
ERROR: function alt_get_flash_info failed. ret_code %d
", ret_code); } /* * If this is the development board check the number of regions etc. */ if(0) { } else { printf("
This is not the standard reference design
"); printf("Flash name %s
",fd->name); printf("This flash has %d erase regions
", number_of_regions); for(i=0;i { printf("Start 0x%8x End 0x%8x Number of Blocks %3d Block Size 0x%8x
", (regions+i)->offset, (regions+i)->region_size+(regions+i)->offset, (regions+i)->number_of_blocks, (regions+i)->block_size); } } returnret_code; } /* * Run various tests on a small section of the system flash. */ intmain (void) { intret_code; inttest_offset; alt_flash_fd* fd; alt_u8 write_data[100]; alt_u8 read_data[100]; inti,j; fd = alt_flash_open_dev(EXT_FLASH_NAME); if(fd) { printf("
<----> Running Flash Tests <---->
"); printf("This will take approximately 1 minute
"); printf("-Testing flash info retrieval..."); ret_code = test_get_info(fd); if(ret_code) { printf("
ERROR: function test_get_info failed. ret_code %d
", ret_code); gotofinished; } printf(" passed.
"); printf("-Testing flash block erase,write...
"); ret_code = test_flash_write(fd); if(ret_code) { printf("
ERROR: test_flash_erase failed. ret_code %d
", ret_code); gotofinished; } printf(" passed.
"); printf("-Testing flash write...
"); test_offset = 0x0; printf("
test_offset=0x%8x ",test_offset); ret_code = test_programming(fd, test_offset); if(ret_code) gotofinished; printf(" passed.
"); test_offset = 0x4000; printf("
test_offset=0x%8x ",test_offset); ret_code = test_programming(fd, test_offset); if(ret_code) gotofinished; printf(" passed.
"); test_offset = 0x6000; printf("
test_offset=0x%8x ",test_offset); ret_code = test_programming(fd, test_offset); if(ret_code) gotofinished; printf(" passed.
"); test_offset = 0x8000; printf("
test_offset=0x%8x ",test_offset); ret_code = test_programming(fd, test_offset); if(ret_code) gotofinished; printf(" passed.
"); for(j=1;j<=31;j++) {test_offset = 0x10000*j; printf("
test_offset=0x%8x ",test_offset); ret_code = test_programming(fd, test_offset); if(ret_code) gotofinished; } printf(" passed.
"); printf(" 0x10ff00: "); test_offset = 0x10ff00; ret_code = test_programming(fd, test_offset); if(ret_code) gotofinished; printf(" passed.
"); printf(" 0x100100: "); test_offset = 0x100100; ret_code = test_programming(fd, test_offset); if(ret_code) gotofinished; printf(" passed.
"); printf("-Testing flash block erase...
"); ret_code = test_flash_erase(fd); if(ret_code) { printf("
ERROR: test_flash_erase failed. ret_code %d
", ret_code); gotofinished; } printf(" passed.
"); test_offset = 0x10000; printf(" ---Testing flash block write...@ 0x%8x
",test_offset); for(i=0;i<100;i++) write_data[i] = i; ret_code = alt_write_flash_block( fd, 0x10000, test_offset, write_data, 100); if(ret_code) { printf("
ERROR: function alt_write_flash_block failed. ret_code %d
", ret_code); gotofinished; } else { ret_code = alt_read_flash(fd, test_offset, read_data, 100); for(i=0;i<100;i++) { if(read_data[i] != write_data[i]) { printf("
ERROR: compare failed, expected %#x read %#x
", write_data[i], read_data[i]); gotofinished; } } } printf(" passed.
"); test_offset = 0x10010; printf("-Testing unaligned writes....."); alt_erase_flash_block(fd, 0x10000, 0x100000); ret_code = alt_write_flash_block( fd, 0x10000, test_offset, write_data,100); if(ret_code) { printf("
ERROR: function alt_write_flash_block failed. ret_code %d
", ret_code); gotofinished; } else { ret_code = alt_read_flash(fd, test_offset, read_data, 100); for(i=0;i<100;i++) { if(read_data[i] != write_data[i]) { printf("
ERROR: compare failed, expected %#x read %#x
", write_data[i], read_data[i]); gotofinished; } } } printf(" passed.
"); printf("-Testing flash block erase...
"); ret_code = test_flash_erase(fd); if(ret_code) { printf("
ERROR: test_flash_erase failed. ret_code %d
", ret_code); gotofinished; } printf(" passed.
"); printf("All Tests Passed!
"); } else { printf("Can't open the flash device
"); } finished: alt_flash_close_dev(fd); printf("Exiting Flash Tests
"); return0; }