野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 12837|回复: 9

FatFs 管理nand flash

[复制链接]
发表于 2016-5-9 13:08:33 | 显示全部楼层 |阅读模式
今天终于有时间将最近做的关于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;

}

回复

使用道具 举报

 楼主| 发表于 2016-5-9 13:09:11 | 显示全部楼层
#ifndef __NAND_IF_H
#define __NAND_IF_H

#define FREE_BLOCK         (1<<12)
#define BAD_BLOCK         (1<<13)
#define VALID_BLOCK  (1<<14)
#define USED_BLOCK         (1<<15)


#define MAX_PHY_BLOCK_PER_ZONE        1024
#define MAX_LOG_BLOCKS_PER_ZONE        1000

typedef struct __SPARE_AREA {
        uint16 LogicalIndex;
        uint16 DataStatus;
        uint16 BlockStatus;
}SPARE_AREA;

typedef enum {
        WRITE_IDLE = 0;
        POST_WRITE,
        PRE_WRITE,
        WRITE_CLEANUP,
        WRITE_ONGOING
}WRITE_STATE;

typedef enum {
        OLD_BLOCK = 0;
        UNUSED_BLOCK
}BLOCK_STATE;

#define WEAR_LEVELLING_SUPPORT
#define WEAR_DEPTH        10
#define PAGE_TO_WRITE                (Transfer_Length/NAND_PAGE_SIZE)

uint16 NAND_Init(void);
uint16 NAND_Write(uint32 Memory_Offset, uint32 *Writebuff, uint16 Transfer_Length);
uint16 NAND_Read(uint32 Memory_Offset, uint32 *Readbuff, uint16 Transfer_Length);
uint16 NAND_Format(void);

#endif
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-5-9 13:09:36 | 显示全部楼层
#ifndef __NAND_IF_H
#define __NAND_IF_H

#define FREE_BLOCK         (1<<12)
#define BAD_BLOCK         (1<<13)
#define VALID_BLOCK  (1<<14)
#define USED_BLOCK         (1<<15)


#define MAX_PHY_BLOCK_PER_ZONE        1024
#define MAX_LOG_BLOCKS_PER_ZONE        1000

typedef struct __SPARE_AREA {
        uint16 LogicalIndex;
        uint16 DataStatus;
        uint16 BlockStatus;
}SPARE_AREA;

typedef enum {
        WRITE_IDLE = 0;
        POST_WRITE,
        PRE_WRITE,
        WRITE_CLEANUP,
        WRITE_ONGOING
}WRITE_STATE;

typedef enum {
        OLD_BLOCK = 0;
        UNUSED_BLOCK
}BLOCK_STATE;

#define WEAR_LEVELLING_SUPPORT
#define WEAR_DEPTH        10
#define PAGE_TO_WRITE                (Transfer_Length/NAND_PAGE_SIZE)

uint16 NAND_Init(void);
uint16 NAND_Write(uint32 Memory_Offset, uint32 *Writebuff, uint16 Transfer_Length);
uint16 NAND_Read(uint32 Memory_Offset, uint32 *Readbuff, uint16 Transfer_Length);
uint16 NAND_Format(void);

#endif
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-5-9 13:10:06 | 显示全部楼层
nfjiang 发表于 2016-5-9 13:09
#ifndef __NAND_IF_H
#define __NAND_IF_H

#include "nand.c"

#define FSMC_Bank_NAND FSMC_Bank2_NAND
#define Bank_NAND_ADDR Bank2_NAND_ADDR
#define Bank2_NAND_ADDR ((uint32)0x70000000

void FSMC_NAND_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        FSMC_NANDInitTypeDef FSMC_NANDInitStructure;
        FSMC_NAND_PCCARDTimingInitTypeDef p;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE |
        RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG, ENABLE);
        /*-- GPIO Configuration ------------------------------------------------------*/
        /* CLE, ALE, D0->D3, NOE, NWE and NCE2 NAND pin configuration */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_14 | GPIO_Pin_15 |
        GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 |
        GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOD, &GPIO_InitStructure);
        /* D4->D7 NAND pin configuration */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;
        GPIO_Init(GPIOE, &GPIO_InitStructure);
        /* NWAIT NAND pin configuration */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_Init(GPIOD, &GPIO_InitStructure);
        /* INT2 NAND pin configuration */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
        GPIO_Init(GPIOG, &GPIO_InitStructure);
        /*-- FSMC Configuration ------------------------------------------------------*/
        p.FSMC_SetupTime = 0x1;
        p.FSMC_WaitSetupTime = 0x3;
        p.FSMC_HoldSetupTime = 0x2;
        p.FSMC_HiZSetupTime = 0x1;
        FSMC_NANDInitStructure.FSMC_Bank = FSMC_Bank2_NAND;
        FSMC_NANDInitStructure.FSMC_Waitfeature = FSMC_Waitfeature_Enable;
        FSMC_NANDInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_8b;
        FSMC_NANDInitStructure.FSMC_ECC = FSMC_ECC_Enable;
        FSMC_NANDInitStructure.FSMC_ECCPageSize = FSMC_ECCPageSize_512Bytes;
        FSMC_NANDInitStructure.FSMC_TCLRSetupTime = 0x00;
        FSMC_NANDInitStructure.FSMC_TARSetupTime = 0x00;
        FSMC_NANDInitStructure.FSMC_CommonSpaceTimingStruct = &p;
        FSMC_NANDInitStructure.FSMC_AttributeSpaceTimingStruct = &p;
        FSMC_NANDInit(&FSMC_NANDInitStructure);
        /* FSMC NAND Bank Cmd Test */
        FSMC_NANDCmd(FSMC_Bank2_NAND, ENABLE);
       
}
uint32 NAND_WriteLargePage(uint8 *pBuffer,NAND_ADDRESS Address, uint32 NumPageToWrite)
{
        uint32 index = 0x00, numpagewritten = 0x00,addressstatus = NAND_VALID_ADDRESS;
        uint32 status = NAND_READY,size = 0x00;
        uint32 data = 0xff;
        while((NumPageToWrite != 0x00) && (addressstatus == NAND_VALID_ADDRESS) && (status == NAND_READY))
        {
                /* Page write command and address */
                *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_WRITE0;
                *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = 0;
                *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = 0;
                *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = ROW_ADDRESS(Address)&0xff;
                *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = (ROW_ADDRESS(Address)&0xff00)>>8;
                /* Calculate the size */
                size = NAND_PAGE_SIZE + (NAND_PAGE_SIZE * numpagewritten);
                /* Write data */
                for(; index < size; index++)
                {
                        *(__IO uint8 *)(Bank_NAND_ADDR | DATA_AREA) = pBuffer[index];
                }
               
                *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_WRITE1;
               
                while( GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_6) == 0 );
               
                /* Check status for successful operation */
                status = NAND_GetStatus();
               
                data = *(__IO uint8 *)(Bank_NAND_ADDR | DATA_AREA);
               
                if(!(data&0x1))
                        status = NAND_READY;
               
                if(status == NAND_READY)
                {
                        // numpagewritten++;
                        // NumPageToWrite--;
                        // /* Calculate Next small page Address */
                        // if(PageAddress++ > (NAND_MAX_ZONE*NAND_ZONE_SIZE*NAND_BLOCK_SIZE))
                        // {
                                // addressstatus = NAND_INVALID_ADDRESS;
                        // }
                }
        }
        return (status | addressstatus);
}

uint32 NAND_CopyPage(NAND_ADDRESS SourceAddress, NAND_ADDRESS TargetAddress)
{
        uint32 status = NAND_READY ;
        uint32 data = 0xff;
        /* Page write command and address */
        *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_MOVE0;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = 0;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = 0;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = ROW_ADDRESS(SourceAddress)&0xFF;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = (ROW_ADDRESS(SourceAddress)&0xFF00)>>8;
        *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_MOVE1;
       
        while( GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_6) == 0 );
       
        *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_MOVE2;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = 0;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = 0;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = ROW_ADDRESS(TargetAddress)&0xFF;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = (ROW_ADDRESS(TargetAddress)&0xFF00)>>8;
        *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_MOVE3;
       
        while( GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_6) == 0 );
        /* Check status for successful operation */
        status = NAND_GetStatus();
       
        data = *(__IO uint8 *)(Bank_NAND_ADDR | DATA_AREA);
       
        if(!(data&0x1)) status = NAND_READY;
       
        return (status);
}

uint32 NAND_ReadLargePage(uint8 *pBuffer,NAND_ADDRESS Address, uint32 NumPageToRead)
{
        uint32 index = 0x00, numpageread = 0x00,addressstatus = NAND_VALID_ADDRESS;
        uint32 status = NAND_READY,size = 0x00;
       
        *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_READ1;
       
        while((NumPageToRead != 0x0) && (addressstatus == NAND_VALID_ADDRESS))
        {
                /* Page Read command and page address */
                *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = 0;
                *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = 0;
                *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = ROW_ADDRESS(Address)&0xff;
                *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = (ROW_ADDRESS(Address)&0xff00)>>8;
                *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_READ2;
               
                while( GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_6) == 0 );
                /* Calculate the size */
                size = NAND_PAGE_SIZE + (NAND_PAGE_SIZE * numpageread);
                /* Get Data into Buffer */
                for(; index < size; index++)
                {
                        pBuffer[index]= *(__IO uint8 *)(Bank_NAND_ADDR | DATA_AREA);
                }
               
                numpageread++;
                NumPageToRead--;
                /* Calculate page address */
                // if(PageAddress++ > (NAND_MAX_ZONE*NAND_ZONE_SIZE*NAND_BLOCK_SIZE))
                // {
                        // addressstatus = NAND_INVALID_ADDRESS;
                // }
        }
        status = NAND_GetStatus();
        return (status | addressstatus);
}
uint32 NAND_ReadSpareArea(uint8 *pBuffer,NAND_ADDRESS Address, uint32 NumPageToRead)
{
        uint32 index = 0x00;
        uint32 status = NAND_READY;
       
        *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_READ1;
       

                /* Page Read command and page address */
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = COLUMN_ADDRESS(Address)&0xff;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = (COLUMN_ADDRESS(Address)&0xff00)>>8;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = ROW_ADDRESS(Address)&0xff;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = (ROW_ADDRESS(Address)&0xff00)>>8;
               
        *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_READ2;
               
        while( GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_6) == 0 );

                /* Get Data into Buffer */
        for(; index < NumPageToRead; index++)
        {
                pBuffer[index]= *(__IO uint8 *)(Bank_NAND_ADDR | DATA_AREA);
        }
               
        status = NAND_GetStatus();
        return (status);
}
uint32 NAND_WriteSpareArea(uint8 *pBuffer,NAND_ADDRESS Address, uint32 NumPageToWrite)
{
        uint32 index = 0x00;
        uint32 status = NAND_READY;
       
        *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_WRITE0;
       

                /* Page Read command and page address */
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = COLUMN_ADDRESS(Address)&0xff;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = (COLUMN_ADDRESS(Address)&0xff00)>>8;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = ROW_ADDRESS(Address)&0xff;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = (ROW_ADDRESS(Address)&0xff00)>>8;
               
        *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_WRITE1;
               
        while( GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_6) == 0 );

                /* Get Data into Buffer */
        for(; index < NumPageToWrite; index++)
        {
                pBuffer[index]= *(__IO uint8 *)(Bank_NAND_ADDR | DATA_AREA);
        }
               
        status = NAND_GetStatus();
        return (status);
}
uint32 NAND_EraseBlock(NAND_ADDRESS Address)
{
        uint32 data = 0xff, status = NAND_ERROR;
        *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_ERASE0;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = ROW_ADDRESS(TargetAddress)&0xFF;
        *(__IO uint8 *)(Bank_NAND_ADDR | ADDR_AREA) = (ROW_ADDRESS(TargetAddress)&0xFF00)>>8;
        *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_ERASE1;
       
        while( GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_6) == 0 );
        /* Read status operation ------------------------------------ */
        NAND_GetStatus();
       
        data = *(__IO uint8 *)(Bank_NAND_ADDR | DATA_AREA);
       
        if(!(data&0x1))
                status = NAND_READY;
        return (status);
}

uint32 FSMC_NAND_Reset(void)
{
        *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_RESET;
        return (NAND_READY);
}

uint32 NAND_GetStatus(void)
{
        uint32 timeout = 0x1000000, status = NAND_READY;
        status = FSMC_NAND_ReadStatus();
        /* Wait for a NAND operation to complete or a TIMEOUT to occur */
        while ((status != NAND_READY) &&( timeout != 0x00))
        {
                status = FSMC_NAND_ReadStatus();
                timeout --;
        }
       
        if(timeout == 0x00)
        {
                status = NAND_TIMEOUT_ERROR;
        }
        /* Return the operation status */
        return (status);
}

uint32 NAND_ReadStatus(void)
{
        uint32 data = 0x00, status = NAND_BUSY;
        /* Read status operation ------------------------------------ */
        *(__IO uint8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_STATUS;
       
        data = *(__IO uint8 *)(Bank_NAND_ADDR);
       
        if((data & NAND_ERROR) == NAND_ERROR)
        {
                status = NAND_ERROR;
        }
        else if((data & NAND_READY) == NAND_READY)
        {
                status = NAND_READY;
        }
        else
        {
                status = NAND_BUSY;
        }
        return (status);
}
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-5-9 13:10:31 | 显示全部楼层
nfjiang 发表于 2016-5-9 13:10
#include "nand.c"

#define FSMC_Bank_NAND FSMC_Bank2_NAND

#ifndef __NAND_H
#define __NAND_H


#include "stm32f10x.h"
/* Exported types ------------------------------------------------------------*/
typedef struct
{
        uint8 Maker_ID;
        uint8 Device_ID;
        uint8 Third_ID;
        uint8 Fourth_ID;
}NAND_IDTypeDef;

typedef struct
{
        uint32 Block;
        uint32 Page;
        uint32 Chunk;
        uint32 SpareAreaAddr;
       
} NAND_ADDRESS;
/* Exported constants --------------------------------------------------------*/
/* NAND Area definition for STM3210E-EVAL Board RevD */
#define CMD_AREA (uint32)(1<<16) /* A16 = CLE high */
#define ADDR_AREA (uint32)(1<<17) /* A17 = ALE high */
#define DATA_AREA ((uint32)0x00000000)
/* FSMC NAND memory command */
#define NAND_CMD_READ1 ((uint8)0x00)
#define NAND_CMD_READ2 ((uint8)0x30)
#define NAND_CMD_WRITE0 ((uint8)0x80)
#define NAND_CMD_WRITE1 ((uint8)0x10)
#define NAND_CMD_MOVE0 ((uint8)0x00)
#define NAND_CMD_MOVE1 ((uint8)0x35)
#define NAND_CMD_MOVE2 ((uint8)0x85)
#define NAND_CMD_MOVE3 ((uint8)0x10)
#define NAND_CMD_ERASE0 ((uint8)0x60)
#define NAND_CMD_ERASE1 ((uint8)0xD0)
#define NAND_CMD_READID ((uint8)0x90)
#define NAND_CMD_IDADDR ((uint8)0x00)
#define NAND_CMD_STATUS ((uint8)0x70)
#define NAND_CMD_RESET ((uint8)0xFF)
/* NAND memory status */
#define NAND_VALID_ADDRESS ((uint32)0x00000100)
#define NAND_INVALID_ADDRESS ((uint32)0x00000200)
#define NAND_TIMEOUT_ERROR ((uint32)0x00000400)
#define NAND_BUSY ((uint32)0x00000000)
#define NAND_ERROR ((uint32)0x00000001)
#define NAND_READY ((uint32)0x00000040)
/* FSMC NAND memory parameters */
//#define NAND_PAGE_SIZE ((uint16)0x0200) /* 512 bytes per page w/o Spare Area */
//#define NAND_BLOCK_SIZE ((uint16)0x0020) /* 32x512 bytes pages per block */
//#define NAND_ZONE_SIZE ((uint16)0x0400) /* 1024 Block per zone */
//#define NAND_SPARE_AREA_SIZE ((uint16)0x0010) /* last 16 bytes as spare area */
//#define NAND_MAX_ZONE ((uint16)0x0004) /* 4 zones of 1024 block */
/* FSMC NAND memory HY27UF081G2A-TPCB parameters */
#define NAND_PAGE_SIZE ((uint16)0x0800) /* 2048 bytes per page w/o Spare Area */
#define NAND_BLOCK_SIZE ((uint16)0x0040) /* 64x2048 bytes pages per block */
#define NAND_ZONE_SIZE ((uint16)0x0200) /* 512 Block per zone */
#define NAND_SPARE_AREA_SIZE ((uint16)0x0040) /* last 64 bytes as spare area */
#define NAND_MAX_ZONE ((uint16)0x0002) /* 2 zones of 1024 block */
/* FSMC NAND memory data computation */
#define DATA_1st_CYCLE(DATA) (uint8)((DATA)& 0xFF) /* 1st data cycle */
#define DATA_2nd_CYCLE(DATA) (uint8)(((DATA)& 0xFF00) >> 8) /* 2nd data cycle */
#define DATA_3rd_CYCLE(DATA) (uint8)(((DATA)& 0xFF0000) >> 16) /* 3rd data cycle */
#define DATA_4th_CYCLE(DATA) (uint8)(((DATA)& 0xFF000000) >> 24) /* 4th data cycle */
/* FSMC NAND memory HY27UF081G2A-TPCB address computation */
#define ADDR_1st_CYCLE(PADDR) (uint8)(0x0) /* 1st addressing cycle */
#define ADDR_2nd_CYCLE(PADDR) (uint8)(0x0) /* 2nd addressing cycle */
#define ADDR_3rd_CYCLE(PADDR) (uint8)(PADDR & 0xFF) /* 3rd addressing cycle */
#define ADDR_4th_CYCLE(PADDR) (uint8)((PADDR>>8) & 0xFF) /* 4th addressing cycle */

#define COLUMN_ADDRESS(Address)                Address.SpareAreaAddr
#define ROW_ADDRESS(Address)                (Address.Page + Address.Block * NAND_BLOCK_SIZE)
#define SPARE_AREA_ADDRESS(Address)        (Address.Page*2 + Address.Block * NAND_BLOCK_SIZE)*NAND_PAGE_SIZE + Address.SpareAreaAddr
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void FSMC_NAND_Init(void);
uint32 NAND_WriteLargePage(uint8 *pBuffer,NAND_ADDRESS Address, uint32 NumPageToWrite);
uint32 NAND_CopyPage(NAND_ADDRESS SourceAddress, NAND_ADDRESS TargetAddress);
uint32 NAND_ReadLargePage(uint8 *pBuffer,NAND_ADDRESS Address, uint32 NumPageToRead);
uint32 NAND_ReadSpareArea(uint8 *pBuffer,NAND_ADDRESS Address, uint32 NumPageToRead);
uint32 NAND_WriteSpareArea(uint8 *pBuffer,NAND_ADDRESS Address, uint32 NumPageToWrite);
uint32 NAND_EraseBlock(uint32 Address);
uint32 NAND_Reset(void);
uint32 NAND_GetStatus(void);
uint32 NAND_ReadStatus(void);
//uint32 FSMC_NAND_AddressIncrement(NAND_ADDRESS* Address);



#endif
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-5-9 13:11:03 | 显示全部楼层
nfjiang 发表于 2016-5-9 13:10
#ifndef __NAND_H
#define __NAND_H

居然上传4次 才能上传完毕
回复 支持 反对

使用道具 举报

发表于 2016-5-10 09:10:08 | 显示全部楼层
额。。nftl是什么。还有是什么错误?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-5-10 11:31:45 | 显示全部楼层
NAND Flash Translation Layer(NAND Flash 转换层,NFTL),是一个文件系统和mtd之间一个转换层,它提供的写入均衡算法,均衡管理每个扇区的写入和擦除次数,大大增加了FLASH的使用寿命。
在fatfs 中的例程中,res_flash=f_mkfs("1:",0,4096);        其实是有问题的,应该是res_flash=f_mkfs("1:",1,4096)才行,不然使用f_mount会返回FR_NO_FILESYSTEM。因为在f_mkfs 中b_vol = (sfd) ? 0 : 63; 如果为0就偏移63个扇区,写入0xaa55,而f_mount是从0扇区去读取有没有0xaa55;
回复 支持 反对

使用道具 举报

发表于 2017-12-1 13:06:21 | 显示全部楼层
野火F429 挑战者 没有 NAND flash呀,管理啥 ?!
回复 支持 反对

使用道具 举报

发表于 2018-10-26 11:52:16 | 显示全部楼层
能不能上传个源文件?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-11-23 22:20 , Processed in 0.044601 second(s), 23 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表