Nios II 中Flash的使用

admin @ 2014-03-26 , reply:0

   在嵌入式系統中,Flash是最常用組件之一。許多使用過flash的朋友都了解,Flash的特點是“讀來容易寫來難”。通常,可以直接讀出Flash的內容;但如果要寫入數據,就要發送一長串命令,比如像:555 ,AA,2AA,55,555,A0 ,PA,PD就表示對PA地址寫入數據PD,實際情況還要複雜一點,因為通常還要包含許多查詢操作。
    哎呀,這真是好繁瑣呀,有沒有省力的方法呢?現在好了,NiosII的開發環境提供了對符合CFI標準的Flash的支持,使用幾個簡單的函數,就可以操作Flash,真是方便了許多。
   在這裡,我粗略得介紹一下nios 中flash的使用;更加詳細的幫助信息請您參考Altera公司提供的文檔。如果本文能對您有一點點幫助,我都會感到非常高興。

1 準備工作:
    在使用Flash之前,有幾個準備工作要做:

  1. 開發板上至少要有一片符合CFI標準的Flash。
  2. 設計好對應目標板的Flash編程器(Flash Programmer)。

    下面我以本站設計的開發板ezNiosDKC6B為目標板,來介紹如何使用Flash,你可以舉一反三,在自己的系統中使用Flash.

2 為SOPC系統中添加Flash介面:

  1. 雙擊在Memory中的Flash Memory(Common Flash Interface),即可為系統添加Flash介面。
  2. 對於ezNiosDK的用戶,Address Width可以選擇 20 Bits,Data Width 可以選擇 16 Bits,這樣總的容量是2M Bytes
     
  3. Timing選項卡中,可以如下添寫:
     
       完成後,選擇Finish,即可為系統添加Flash介面。
  4. 增加三態匯流排橋。Flash 介面必須通過三態匯流排橋接到實際的晶元上。雙擊Bridges下的Avalon Tri-State Bridge,請按照下圖設置,為系統增加三態匯流排橋。  
     
  5. 為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 在Nios IDE中使用Flash編程器:
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, &regions, &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<stdio.h>
#include<errno.h>
#include<string.h>
#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<sizeof(data_written)/2;i++)
data_written[i] = j*0x15;
for(i=sizeof(data_written)/2;i<sizeof(data_written);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, &regions, &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<number_of_regions;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<number_of_regions;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, &regions, &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<number_of_regions;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<number_of_regions;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, &regions, &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<number_of_regions;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;
}




[admin via 研發互助社區 ] Nios II 中Flash的使用已經有2345次圍觀

http://cocdig.com/docs/show-post-43121.html