|
Nor Flash與Nand flash的不同之處在于Nor Flash的地址和數據線是不共用的,所以Nor Flash比較象ROM,是可以按地址自由讀的,這樣就非常適合存儲代碼,在開機時從Nor Flash中取代碼來執行。在我的板子上有16M的Intel的Nor Flash E28F128J3A150,以此為例來研究一下Nor Flash的一些常用操作。E28F128J3A150每個sector是128k,擦除是按扇區操作了。
首先來看下E28F128J3A150與s3c2410的接口吧。
一般情況下ROM與s3c2410的接口我們可以在s3c2410的手冊上看到,如下圖所示

仔細看下16位和8位數據接口在地址線連接上的區別吧,16位的地址線是要移位的,A1接到A0上,這當然是比較容易理解的,位寬大了一倍,地址就少了一條。對于E28F128J3A150其實也是這樣,不過又有點不一樣,仔細看看E28F128J3A150的手冊吧。下面給出接線圖。

不同之處E28F128J3A150貌似并沒有移位,其實只是因為E28F128J3A150的A1就相對于別的16位ROM的A0,其A0就相當于他們的A(-1)是用來指示8位地址的,所以還是一樣的。
來看看Flash操作的命令集吧

以幾個比較重要的操作來說明比較容易懂
首先就是Read Identifier Codes
先給定我們的flash開始的地址吧,flash_addr=ioremap(0x0,0x1000000);
物理地址從0x0開始的0x1000000(16M)地址空間,這樣得到了可訪問的虛擬地址flash_addr
很簡單,看命令表,先寫一個命令 writew(0x90,flash_addr);
然后把Manufacture Code讀回來 readw(flash_addr);
接著再讀Device Code readw(flash_addr+2);
細節部分還是參考手冊吧
其實內核已經MTD驅動完全支持Nor Flash的操作,所以不必要自己再寫了。
不過在JTAG燒寫flash的程序中可以加入對我們自己的flash的支持。
來看看其中對E28F128J3A150的燒寫代碼,分析一下。
int Strata_CheckID(int targetAddr) //返回Manufacture Code
{
_WR(targetAddr, 0x0090);
return _RD(targetAddr); //_WR和_RD都是半字操作
}
int Strata_CheckDevice(int targetAddr) //返回Device Code
{
_WR(targetAddr, 0x0090);
return _RD(targetAddr+0x2);
}
看著Block Erase Flowchart再對照著Block Erase的函數看就比較能完全看懂了

void Strata_EraseSector(int targetAddress)
{
unsigned long ReadStatus;
unsigned long bSR5;
unsigned long bSR7;
_WR(targetAddress, 0x0020); //擦除命令first cycle
_WR(targetAddress, 0x00d0); //擦除命令second cycle
_WR(targetAddress, 0x0070); //讀狀態寄存器命令
ReadStatus=_RD(targetAddress); //讀狀態寄存器
bSR7=ReadStatus & (1<<7);
while(!bSR7 ) //需要判斷狀態寄存器的第7位
{
_WR(targetAddress, 0x0070);
ReadStatus=_RD(targetAddress);
bSR7=ReadStatus & (1<<7);
}
_WR(targetAddress, 0x0070);
ReadStatus=_RD(targetAddress);
bSR5=ReadStatus & (1<<5);
if (bSR5==0)
{
printf("Block @%xh Erase O.K. "n",targetAddress);
}
else
{
_WR(targetAddress, 0x0050); //// Clear Status Register
error_erase=1;
}
_RESET(); //就相當于_WR(targetAddress, 0x00ff),回到Read Array的狀態。
}
很清晰的流程吧。
Byte/Word Program Flowchart

共兩種Program方式可以把數據寫到Flash中,一般也只用到這種就可以了
int Strata_ProgFlash(U32 realAddr,U16 data)
{
unsigned long ReadStatus;
unsigned long bSR4;
unsigned long bSR7;
_WR(realAddr, 0x0040);
_WR(realAddr, data);
_WR(realAddr, 0x0070);
ReadStatus=_RD(realAddr);
bSR7=ReadStatus & (1<<7);
while(!bSR7)
{
_WR(realAddr, 0x0070);
ReadStatus=_RD(realAddr);
bSR7=ReadStatus & (1<<7);
}
_WR(realAddr, 0x0070);
ReadStatus=_RD(realAddr);
bSR4=ReadStatus & (1<<4);
if (bSR4==0)
{
//printf("Successful Program!!"n");
}
else
{
_WR(realAddr, 0x0050); // Clear Status Register
error_program=1;
}
_RESET();
return 0;
}
以上這種寫會很慢,以致于JTAG燒寫相當得慢。

int Strata_unprotect_sector(int targetAddr) //去除sector的寫保護
{
int SR7,SR3,SR4,SR5,ReadStatus;
int res=0;
_WR(targetAddr,0x0050); //Clear Status Register
_WR(targetAddr,0x0060); //First bus cycle
_WR(targetAddr,0x00D0); //Second bus cycle
_WR(targetAddr,0x0070);
ReadStatus=_RD(targetAddr);
SR7=ReadStatus & (1<<7);
while(!SR7)
{
_WR(targetAddr,0x0070);
ReadStatus=_RD(targetAddr);
SR7=ReadStatus & (1<<7);
}
_WR(targetAddr,0x0070);
ReadStatus=_RD(targetAddr);
SR3=ReadStatus & (1<<3);
SR4=ReadStatus & (1<<4);
SR5=ReadStatus & (1<<5);
if(SR3) {printf("Voltage Range Error"); res=-1;}
if(SR4 && SR5) {printf("Command Sequence Error"); res=-2;}
if(SR5) {printf("Clear Block Lock-Bits Error"); res=-3;}
_RESET();
return res;
}
另外按照write to buffer的流程自己寫了一個函數,沒有test,不想再去燒寫了,太煩了,就這樣好了。
void Strata_buffer_program(int blockAddress,int tagetAddress,U16* buf)
{
unsigned long ReadStatus;
unsigned long bSR4;
unsigned long bSR7;
int i;
do {
_WR(blockAddress, 0x00E8);
_WR(blockAddress, 0x0070);
ReadStatus=_RD(blockAddress);
bSR7=ReadStatus & (1<<7);
} while(!bSR7);
_WR(blockAddress, 0x001F);
for(i=0;i<=0x1F;i++)
_WR(targetAddress+2*i, *(buf+i));
_WR(blockAddress, 0x00D0);
do {
_WR(blockAddress, 0x0070);
ReadStatus=_RD(blockAddress);
bSR7=ReadStatus & (1<<7);
} while(!bSR7);
_WR(blockAddress, 0x0070);
ReadStatus=_RD(blockAddress);
bSR4=ReadStatus & (1<<4);
if (bSR4==0)
{
//printf("Successful Program!!"n");
}
else
{
_WR(blockAddress, 0x0050);
error_program=1;
}
_RESET();
}
|
|