大学生
最后登录1970-1-1
在线时间 小时
注册时间2015-12-5
|
今天终于有时间将最近做的关于nand flash 的项目的代码整理了一下,其实火哥写的FatFs 是有缺陷的,实际 应用中不能这么用,如果只是用来学习还不错。实际应用时,需要加上NFTL,这样才能使用FatFs管理nand flash,其实在火哥的FatFs例程中还有一个错误,如果大家看过FatFs源码就很快能发现这个错误。
这个论坛好像高手并不多,好了,不说了直接上添加了NFTL 的源码。
#include "nand_if.h"
#include "nand_flash.h"
uint32 NAND_BlkLen;
WRITE_STATE Write_State;
BLOCK_STATE Block_State;
NAND_ADDRESS wAddress, fAddress;
uint16 phBlock, LogAddress, Initial_Page, Initial_Chunk, CurrentZone = 0;
uint16 Written_Chunks = 0;
static volatile uint8 databuf[NAND_PAGE_SIZE];
volatile uint16 LUT[1024];
uint16 NAND_Init(void)
{
uint16 Status = NAND_OK;
FSMC_NAND_Init();
Status = NAND_BuildLUT(0);
Write_State = WRITE_IDLE;
return Status;
}
uint16 NAND_Write(uint32 Memory_Offset, uint32 *Writebuff, uint16 Transfer_Length)
{
NAND_ADDRESS phAddress;
wAddress = NAND_GetAddress(Memory_Offset);
phBlock = LUT[wAddress.Block];
if(Write_State == WRITE_IDLE)
{
if(phBlock & USED_BLOCK)
{
phAddress.Block = phBlock & ~(USED_BLOCK | VALID_BLOCK);
phAddress.Page = wAddress.Page;
Block_State = OLD_BLOCK;
fAddress.Block = NAND_GetFreeBlock();
Initial_Page = fAddress.Page = wAddress.Page;
Initial_Chunk = fAddress.Chunk = wAddress.Chunk;
NAND_ReadLargePage(databuf, phAddress, 1);
memcpy(databuf+wAddress.Chunk*512,Writebuff, 512);
NAND_WriteLargePage(databuf, fAddress, 1);
Written_Chunks++;
wAddress.Block = phBlock & 0x3FF;
if(Written_Chunks == NAND_BlkLen)
{
NAND_Write_Cleanup();
Written_Chunks = 0;
return NAND_OK;
}
else
{
if((wAddress.Page == (NAND_BLOCK_SIZE - 1)) && (wAddress.Chunk == (NAND_CHUNK_SIZE - 1)))
{
NAND_Write_Cleanup();
return NAND_OK;
}
Write_State = WRITE_ONGOING;
return NAND_OK;
}
}
}
else
{
Block_State = UNUSED_BLOCK;
wAddress.Block = phBlock & 0x3FF;
NAND_ReadLargePage(databuf, phAddress, 1);
memcpy(databuf+wAddress.Chunk*512,Writebuff, 512);
NAND_WriteLargePage(databuf, fAddress, 1);
Written_Chunks++;
if(Written_Chunks == NAND_BlkLen)
{
NAND_Write_Cleanup();
Written_Chunks = 0;
return NAND_OK;
}
else
{
Write_State = WRITE_ONGOING;
return NAND_OK;
}
}
if(Write_State == WRITE_ONGOING)
{
if(phBlock & USED_BLOCK)
{
wAddress.Block = phBlock & 0x3FF;
Block_State = OLD_BLOCK;
fAddress.Page = wAddress.Page;
fAddress.Chunk = wAddress.Chunk;
}
if((wAddress.Page == (NAND_BLOCK_SIZE - 1)) && (wAddress.Chunk == (NAND_CHUNK_SIZE - 1)))
{
NAND_ReadLargePage(databuf, phAddress, 1);
memcpy(databuf+wAddress.Chunk*512,Writebuff, 512);
NAND_WriteLargePage(databuf, fAddress, 1);
Written_Chunks++;
if(Written_Chunks == NAND_BlkLen)
Written_Chunks = 0;
NAND_Write_Cleanup();
Write_State = WRITE_IDLE;
return NAND_OK;
}
NAND_ReadLargePage(databuf, phAddress, 1);
memcpy(databuf+wAddress.Chunk*512,Writebuff, 512);
NAND_WriteLargePage(databuf, fAddress, 1);
Written_Chunks++;
if(Written_Chunks == NAND_BlkLen)
{
Written_Chunks = 0;
NAND_Write_Cleanup();
Write_State = WRITE_IDLE;
}
}
else
{
wAddress.Block = phBlock & 0x3FF;
if((wAddress.Page == (NAND_BLOCK_SIZE - 1)) && (wAddress.Chunk == (NAND_CHUNK_SIZE - 1)))
{
NAND_ReadLargePage(databuf, phAddress, 1);
memcpy(databuf+wAddress.Chunk*512,Writebuff, 512);
NAND_WriteLargePage(databuf, fAddress, 1);
Written_Chunks++;
if(Written_Chunks == NAND_BlkLen)
Written_Chunks = 0;
NAND_Write_Cleanup();
Write_State = WRITE_IDLE;
return NAND_OK;
}
NAND_ReadLargePage(databuf, phAddress, 1);
memcpy(databuf+wAddress.Chunk*512,Writebuff, 512);
NAND_WriteLargePage(databuf, fAddress, 1);
Written_Chunks++;
if(Written_Chunks == NAND_BlkLen)
{
Written_Chunks = 0;
NAND_Write_Cleanup();
Write_State = WRITE_IDLE;
}
}
return NAND_OK;
}
uint16 NAND_Read(uint32 Memory_Offset, uint32 *Readbuff, uint16 Transfer_Length)
{
NAND_ADDRESS phAddress;
phAddress = NAND_GetAddress(Memory_Offset);
if(LUT[phAddress.Block]&BAD_BLOCK)
return NAND_FAIL;
else
{
phAddress.Block = LUT[phAddress.Block] &~(USED_BLOCK | VALID_BLOCK);
NAND_ReadLargePage(databuf, phAddress, Transfer_Length);
memcpy(Readbuff, databuf + phAddress.Chunk*512, 512);
}
return NAND_OK;
}
static uint16 NAND_CleanLUT(uint8 ZoneNbr)
{
uint16 BlockIdx, LUT_Item;
NAND_BuildLUT(ZoneNbr);
BlockIdx = MAX_LOG_BLOCKS_PER_ZONE;
LUT_Item = LUT[BlockIdx];
for(BlockIdx= MAX_LOG_BLOCKS_PER_ZONE;BlockIdx < MAX_LOG_BLOCKS_PER_ZONE + WEAR_DEPTH; BlockIdx++)
{
LUT[BlockIdx] = LUT[BlockIdx + 1];
}
LUT[MAX_LOG_BLOCKS_PER_ZONE + WEAR_DEPTH - 1] = LUT_Item;
return NAND_OK;
}
static NAND_ADDRESS NAND_GetAddress(uint32 Address)
{
NAND_ADDRESS Address_t;
Address_t.Chunk = Address & (NAND_CHUNK_SIZE -1);
Address_t.Page = (Address/4) & (NAND_BLOCK_SIZE -1);
Address_t.Block = Address/NAND_BLOCK_SIZE*4;
while(Address_t.Block >= MAX_LOG_BLOCKS_PER_ZONE)
Address_t.Block -= MAX_LOG_BLOCKS_PER_ZONE;
return Address_t;
}
static uint16 NAND_GetFreeBlock(void)
{
return LUT[MAX_LOG_BLOCKS_PER_ZONE]&~(USED_BLOCK | VALID_BLOCK);
}
SPARE_AREA ReadSpareArea(uint32 address)
{
SPARE_AREA temp;
uint8 Buffer[6];
NAND_ADDRESS address_s;
address_s = NAND_ConvertPhyAddress(address);
address_s.SpareAreaAddr = 0x800;
NAND_ReadSpareArea(Buffer, address_s, 6);
temp = *(SPARE_AREA*)Buffer;
return temp;
}
static NAND_ADDRESS NAND_GetAddress(uint32 Address)
{
NAND_ADDRESS Address_t;
Address_t.Chunk = Address & (NAND_CHUNK_SIZE - 1);
Address_t.Page = (Address / 4) & (NAND_CHUNK_SIZE - 1);
Address_t.Block = Address / (NAND_BLOCK_SIZE*4);
while(Address_t.Block>=MAX_LOG_BLOCKS_PER_ZONE)
{
Address_t.Block -= MAX_LOG_BLOCKS_PER_ZONE;
}
return Address_t;
}
uint16 NAND_Format(void)
{
NAND_ADDRESS phAddress;
SPARE_AREA SpareArea;
uint32 BlockIndex;
for(BlockIndex = 0; BlockIndex < MAX_LOG_BLOCKS_PER_ZONE; BlockIndex++)
{
phAddress = NAND_ConvertPhyAddress(BlockIndex * NAND_BLOCK_SIZE * 4);
SpareArea = ReadSpareArea(BlockIndex * NAND_BLOCK_SIZE * 4);
if((SpareArea.DataStatus != 0)||(SpareArea.BlockStatus != 0 ))
{
NAND_EraseBlock(phAddress);
}
}
NAND_BuildLUT(0);
return NAND_OK;
}
uint16 NAND_Write_Cleanup(void)
{
uint16 tempSpareArea[8];
uint16 Page_Back,Chunk_Back;
if(Block_State == OLD_BLOCK)
{
if(Initial_Page !=0)
{
Page_Back = wAddress.Page;
fAddress.Page = wAddress.Page = 0;
NAND_Copy(wAddress,fAddress,Initial_Page);
wAddress.Page = Page_Back;
}
if(((NAND_BLOCK_SIZE - (wAddress.Page + 1)) != 0))
{
Page_Back = wAddress.Page;
NAND_AddressPageIncrement(&wAddress);
fAddress.Page = wAddress.Page ;
fAddress.Chunk = wAddress.Chunk ;
NAND_Copy(wAddress,fAddress,NAND_BLOCK_SIZE - wAddress.Page);
wAddress.Page = Page_Back;
}
tempSpareArea[0] = LogAddress | USED_BLOCK;
tempSpareArea[1] = 0xFFFF;
tempSpareArea[2] = 0xFFFF;
fAddress.Page = 0 ;
fAddress.SpareAreaAddr = 0x800;
NAND_WriteSpareArea(tempSpareArea,fAddress, 6);
NAND_EraseBlock(wAddress);
NAND_BuildLUT(0);
}
else
{
tempSpareArea[0] = LogAddress | USED_BLOCK;
tempSpareArea[1] = 0xFFFF;
tempSpareArea[2] = 0xFFFF;
fAddress.Page = 0 ;
fAddress.SpareAreaAddr = 0x800;
NAND_WriteSpareArea(tempSpareArea,fAddress, 6);
NAND_BuildLUT(0);
}
return NAND_OK;
}
NAND_ADDRESS NAND_ConvertPhyAddress(uint32 Address)
{
NAND_ADDRESS Address_t;
Address_t.Chunk = Address & (NAND_CHUNK_SIZE - 1);
Address_t.Page = (Address / 4) & (NAND_BLOCK_SIZE - 1);
Address_t.Block = Address / (NAND_BLOCK_SIZE*4);
while(Address_t.Block>=MAX_PHY_BLOCKS_PER_ZONE)
{
Address_t.Block -= MAX_PHY_BLOCKS_PER_ZONE;
}
return Address_t;
}
uint16 NAND_BuildLUT(uint8 ZoneNbr)
{
uint16 pBadBlock, pCurrentBlock, pFreeBlock;
SPARE_AREA SpareArea;
for(pCurrentBlock=0; pCurrentBlock < MAX_PHY_BLOCKS_PER_ZONE; pCurrentBlock++)
{
LUT[pCurrentBlock] = FREE_BLOCK;
}
pBadBlock = MAX_PHY_BLOCKS_PER_ZONE - 1;
pCurrentBlock = 0;
while(pCurrentBlock < MAX_PHY_BLOCKS_PER_ZONE)
{
SpareArea = ReadSpareArea(pCurrentBlock*NAND_BLOCK_SIZE*4)
if((SpareArea.DataStatus == 0)||(SpareArea.BlockStatus == 0))
{
LUT[pBadBlock--] |= pCurrentBlock | BAD_BLOCK;
LUT[pCurrentBlock] &= (~FREE_BLOCK);
if(pBadBlock == MAX_LOG_BLOCKS_PER_ZONE)
return NAND_FAIL;
}
else if(SpareArea.LogicalIndex != 0xFFFF)
{
LUT[SpareArea.LogicalIndex & 0x3FF] |= pCurrentBlock | VALID_BLOCK | USED_BLOCK;
LUT[pCurrentBlock] &= (~FREE_BLOCK);
}
pCurrentBlock++;
}
pFreeBlock = 0;
for(pCurrentBlock = 0;pCurrentBlock<MAX_PHY_BLOCKS_PER_ZONE;pCurrentBlock++)
{
if(!(LUT[pCurrentBlock]&USED_BLOCK) && !(LUT[pCurrentBlock]&BAD_BLOCK))
{
do
{
if(LUT[pFreeBlock] & FREE_BLOCK)
{
LUT[pCurrentBlock] |= pFreeBlock;
LUT[pFreeBlock] &= (~FREE_BLOCK);
break;
}
pFreeBlock++;
}while(pFreeBlock < MAX_PHY_BLOCKS_PER_ZONE);
}
}
return NAND_OK;
}
|
|