rt-thread-official/bsp/stm32f429-apollo/drivers/drv_nand.c

614 lines
20 KiB
C
Raw Normal View History

/*
2018-10-16 13:00:37 +08:00
* Copyright (c) 2006-2018, RT-Thread Development Team
*
2018-10-16 13:00:37 +08:00
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-04-10 lizhen9880 the first version
*/
#include "drv_nand.h"
#include <rtdevice.h>
#include <string.h>
#ifdef RT_USING_NFTL
#include <nftl.h>
#endif
#define NAND_DEBUG rt_kprintf
/* nandflash confg */
#define PAGES_PER_BLOCK 64
#define PAGE_DATA_SIZE 2048
#define PAGE_OOB_SIZE 64
#define ECC_SIZE 4
#define SET_NAND_CMD(_c) do{*(volatile rt_uint8_t*)(NAND_ADDRESS|NAND_CMD) = _c;}while(0)
#define SET_NAND_ADD(_a) do{*(volatile rt_uint8_t*)(NAND_ADDRESS|NAND_ADDR) = _a;}while(0)
#define SET_NAND_DAT(_d) do{*(volatile rt_uint8_t*)NAND_ADDRESS = _d;}while(0)
#define GET_NAND_DAT(_d) do{_d = *(volatile rt_uint8_t*)NAND_ADDRESS;}while(0)
static struct stm32f4_nand _device;
static rt_bool_t read_status(rt_uint8_t cmd);
NAND_HandleTypeDef NAND_Handler; //NAND FLASH<53><48><EFBFBD><EFBFBD>
//NAND<4E><44>ʱ
void NAND_Delay(volatile rt_uint32_t i)
{
while(i>0)i--;
}
//<2F>ȴ<EFBFBD>RB<52>ź<EFBFBD>Ϊij<CEAA><C4B3><EFBFBD><EFBFBD>ƽ
//rb:0,<2C>ȴ<EFBFBD>RB==0
// 1,<2C>ȴ<EFBFBD>RB==1
//<2F><><EFBFBD><EFBFBD>ֵ:0,<2C>ɹ<EFBFBD>
// 1,<2C><>ʱ
rt_uint8_t NAND_WaitRB(volatile rt_uint8_t rb)
{
volatile rt_uint16_t time=0;
while(time<10000)
{
time++;
if(NAND_RB==rb)
{
// NAND_DEBUG("time:%d/%d R/B:%d\n",time,10000,rb);
return 0;
}
}
// NAND_DEBUG("timeOUT\n");
return 1;
}
//<2F><>NAND״̬
//<2F><><EFBFBD><EFBFBD>ֵ:NAND״ֵ̬
//bit0:0,<2C>ɹ<EFBFBD>;1,<2C><><EFBFBD><EFBFBD>(<28><><EFBFBD><EFBFBD>/<2F><><EFBFBD><EFBFBD>/READ)
//bit6:0,Busy;1,Ready
rt_uint8_t NAND_ReadStatus(void)
{
volatile rt_uint8_t data=0;
SET_NAND_CMD(NAND_READSTA);//<2F><><EFBFBD>Ͷ<EFBFBD>״̬<D7B4><CCAC><EFBFBD><EFBFBD>
data++;data++;data++;data++;data++; //<2F><><EFBFBD><EFBFBD>ʱ,<2C><>ֹ-O2<4F>Ż<EFBFBD>,<2C><><EFBFBD>µĴ<C2B5><C4B4><EFBFBD>.
data=*(volatile rt_uint8_t*)NAND_ADDRESS; //<2F><>ȡ״ֵ̬
return data;
}
//<2F>ȴ<EFBFBD>NAND׼<44><D7BC><EFBFBD><EFBFBD>
//<2F><><EFBFBD><EFBFBD>ֵ:NSTA_TIMEOUT <20>ȴ<EFBFBD><C8B4><EFBFBD>ʱ<EFBFBD><CAB1>
// NSTA_READY <20>Ѿ<EFBFBD>׼<EFBFBD><D7BC><EFBFBD><EFBFBD>
static rt_uint8_t wait_for_ready(void)
{
rt_uint8_t status=0;
volatile rt_uint32_t time=0;
while(1) //<2F>ȴ<EFBFBD>ready
{
status=NAND_ReadStatus(); //<2F><>ȡ״ֵ̬
if(status&NSTA_READY)break;
time++;
if(time>=0X1FFFF)return NSTA_TIMEOUT;//<2F><>ʱ
}
return NSTA_READY;//׼<><D7BC><EFBFBD><EFBFBD>
}
//<2F><>λNAND
//<2F><><EFBFBD><EFBFBD>ֵ:0,<2C>ɹ<EFBFBD>;
// <20><><EFBFBD><EFBFBD><><CAA7>
static rt_uint8_t nand_reset(void)
{
SET_NAND_CMD(NAND_RESET);//<2F><>λNAND
if(wait_for_ready()==NSTA_READY)return 0;//<2F><>λ<EFBFBD>ɹ<EFBFBD>
else return 1; //<2F><>λʧ<CEBB><CAA7>
}
//<2F><>ȡNAND FLASH<53><48>ID
//<2F><><EFBFBD><EFBFBD>ֵ:0,<2C>ɹ<EFBFBD>;
// <20><><EFBFBD><EFBFBD><><CAA7>
rt_uint8_t NAND_ModeSet(rt_uint8_t mode)
{
SET_NAND_CMD(NAND_FEATURE);
SET_NAND_ADD(0X01);
SET_NAND_DAT(mode);
SET_NAND_DAT(0);
SET_NAND_DAT(0);
SET_NAND_DAT(0);
if(wait_for_ready()==NSTA_READY)return 0;//<2F>ɹ<EFBFBD>
else return 1; //ʧ<><CAA7>
}
//<2F><>ʼ<EFBFBD><CABC>NAND FLASH
void NAND_Init(void)
{
FMC_NAND_PCC_TimingTypeDef ComSpaceTiming,AttSpaceTiming;
NAND_Handler.Instance=FMC_NAND_DEVICE;
NAND_Handler.Init.NandBank=FMC_NAND_BANK3; //NAND<4E><44><EFBFBD><EFBFBD>BANK3<4B><33>
NAND_Handler.Init.Waitfeature=FMC_NAND_PCC_WAIT_FEATURE_DISABLE; //<2F>رյȴ<D5B5><C8B4><EFBFBD><EFBFBD><EFBFBD>
NAND_Handler.Init.MemoryDataWidth=FMC_NAND_PCC_MEM_BUS_WIDTH_8; //8λ<38><CEBB><EFBFBD>ݿ<EFBFBD><DDBF><EFBFBD>
NAND_Handler.Init.EccComputation=FMC_NAND_ECC_DISABLE; //<2F><>ʹ<EFBFBD><CAB9>ECC
NAND_Handler.Init.ECCPageSize=FMC_NAND_ECC_PAGE_SIZE_2048BYTE; //ECCҳ<43><D2B3>СΪ2k
NAND_Handler.Init.TCLRSetupTime=0; //<2F><><EFBFBD><EFBFBD>TCLR(tCLR=CLE<4C><45>RE<52><45><EFBFBD><EFBFBD>ʱ)=(TCLR+TSET+2)*THCLK,THCLK=1/180M=5.5ns
NAND_Handler.Init.TARSetupTime=1; //<2F><><EFBFBD><EFBFBD>TAR(tAR=ALE<4C><45>RE<52><45><EFBFBD><EFBFBD>ʱ)=(TAR+TSET+2)*THCLK,THCLK=1/180M=5.5n<EFBFBD><EFBFBD>
ComSpaceTiming.SetupTime=2; //<2F><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
ComSpaceTiming.WaitSetupTime=3; //<2F>ȴ<EFBFBD>ʱ<EFBFBD><CAB1>
ComSpaceTiming.HoldSetupTime=2; //<2F><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
ComSpaceTiming.HiZSetupTime=1; //<2F><><EFBFBD><EFBFBD>̬ʱ<CCAC><CAB1>
AttSpaceTiming.SetupTime=2; //<2F><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
AttSpaceTiming.WaitSetupTime=3; //<2F>ȴ<EFBFBD>ʱ<EFBFBD><CAB1>
AttSpaceTiming.HoldSetupTime=2; //<2F><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
AttSpaceTiming.HiZSetupTime=1; //<2F><><EFBFBD><EFBFBD>̬ʱ<CCAC><CAB1>
HAL_NAND_Init(&NAND_Handler,&ComSpaceTiming,&AttSpaceTiming);
nand_reset(); //<2F><>λNAND
// delay_ms(100);
wait_for_ready();
NAND_ModeSet(4); //<2F><><EFBFBD><EFBFBD>ΪMODE4,<2C><><EFBFBD><EFBFBD>ģʽ
}
//NAND FALSH<53>ײ<EFBFBD><D7B2><EFBFBD><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD>ʱ<EFBFBD><CAB1>ʹ<EFBFBD><CAB9>
//<2F>˺<EFBFBD><CBBA><EFBFBD><EFBFBD>ᱻHAL_NAND_Init()<29><><EFBFBD><EFBFBD>
void HAL_NAND_MspInit(NAND_HandleTypeDef *hnand)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_FMC_CLK_ENABLE(); //ʹ<><CAB9>FMCʱ<43><CAB1>
__HAL_RCC_GPIOD_CLK_ENABLE(); //ʹ<><CAB9>GPIODʱ<44><CAB1>
__HAL_RCC_GPIOE_CLK_ENABLE(); //ʹ<><CAB9>GPIOEʱ<45><CAB1>
__HAL_RCC_GPIOG_CLK_ENABLE(); //ʹ<><CAB9>GPIOGʱ<47><CAB1>
//<2F><>ʼ<EFBFBD><CABC>PD6 R/B<><42><EFBFBD><EFBFBD>
GPIO_Initure.Pin=GPIO_PIN_6;
GPIO_Initure.Mode=GPIO_MODE_INPUT; //<2F><><EFBFBD><EFBFBD>
GPIO_Initure.Pull=GPIO_PULLUP; //<2F><><EFBFBD><EFBFBD>
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //<2F><><EFBFBD><EFBFBD>
HAL_GPIO_Init(GPIOD,&GPIO_Initure);
//<2F><>ʼ<EFBFBD><CABC>PG9 NCE3<45><33><EFBFBD><EFBFBD>
GPIO_Initure.Pin=GPIO_PIN_9;
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //<2F><><EFBFBD><EFBFBD>
GPIO_Initure.Pull=GPIO_NOPULL; //<2F><><EFBFBD><EFBFBD>
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //<2F><><EFBFBD><EFBFBD>
GPIO_Initure.Alternate=GPIO_AF12_FMC; //<2F><><EFBFBD><EFBFBD>ΪFMC
HAL_GPIO_Init(GPIOG,&GPIO_Initure);
//<2F><>ʼ<EFBFBD><CABC>PD0,1,4,5,11,12,14,15
GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5|\
GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_14|GPIO_PIN_15;
GPIO_Initure.Pull=GPIO_NOPULL;
HAL_GPIO_Init(GPIOD,&GPIO_Initure);
//<2F><>ʼ<EFBFBD><CABC>PE7,8,9,10
GPIO_Initure.Pin=GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10;
HAL_GPIO_Init(GPIOE,&GPIO_Initure);
}
//<2F><>NAND״̬
//<2F><><EFBFBD><EFBFBD>ֵ:NAND״ֵ̬
//bit0:0,<2C>ɹ<EFBFBD>;1,<2C><><EFBFBD><EFBFBD>(<28><><EFBFBD><EFBFBD>/<2F><><EFBFBD><EFBFBD>/READ)
//bit6:0,Busy;1,Ready
static rt_bool_t read_status(rt_uint8_t cmd)
{
volatile rt_uint8_t value=0;
SET_NAND_CMD(NAND_READSTA);//<2F><><EFBFBD>Ͷ<EFBFBD>״̬<D7B4><CCAC><EFBFBD><EFBFBD>
value++;value++;value++;value++;value++; //<2F><><EFBFBD><EFBFBD>ʱ,<2C><>ֹ-O2<4F>Ż<EFBFBD>,<2C><><EFBFBD>µĴ<C2B5><C4B4><EFBFBD>.
value=*(volatile rt_uint8_t*)NAND_ADDRESS; //<2F><>ȡ״ֵ̬
switch (cmd)
{
case NAND_WRITE0:
case NAND_ERASE1:
if (value & 0x01) /* Erase/Program failure(1) or pass(0) */
return (RT_FALSE);
else
return (RT_TRUE);
case NAND_AREA_TRUE1: /* bit 5 and 6, Read busy(0) or ready(1) */
return (RT_TRUE);
default:
break;
}
return (RT_FALSE);
}
static rt_err_t nand_MT29F4G08_readid(struct rt_mtd_nand_device *device)
{
rt_uint32_t id;
SET_NAND_CMD(NAND_READID); //<2F><><EFBFBD>Ͷ<EFBFBD>ȡID<49><44><EFBFBD><EFBFBD>
SET_NAND_ADD(0X00);
GET_NAND_DAT(_device.id[0]);//IDһ<44><D2BB><EFBFBD><EFBFBD>5<EFBFBD><35><EFBFBD>ֽ<EFBFBD>
GET_NAND_DAT(_device.id[1]);
GET_NAND_DAT(_device.id[2]);
GET_NAND_DAT(_device.id[3]);
GET_NAND_DAT(_device.id[4]);
//þ<><C3BE><EFBFBD><EFBFBD>NAND FLASH<53><48>IDһ<44><D2BB>5<EFBFBD><35><EFBFBD>ֽڣ<D6BD><DAA3><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>˷<EFBFBD><CBB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֻȡ4<C8A1><34><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>32λ<32><CEBB>IDֵ
//<2F><><EFBFBD><EFBFBD>NAND FLASH<53><48><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֲᣬֻҪ<D6BB><D2AA>þ<EFBFBD><C3BE><EFBFBD><EFBFBD>NAND FLASH<53><48><EFBFBD><EFBFBD>ôһ<C3B4><D2BB><EFBFBD>ֽ<EFBFBD>ID<49>ĵ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ֽڶ<D6BD><DAB6><EFBFBD>0X2C
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǾͿ<C7BE><CDBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0X2C<32><43>ֻȡ<D6BB><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽڵ<D6BD>IDֵ<44><D6B5>
id=((rt_uint32_t)_device.id[1])<<24|((rt_uint32_t)_device.id[2])<<16|((rt_uint32_t)_device.id[3])<<8|_device.id[4];
rt_kprintf("\nNAND ID: 0x%08X\n", id);
return RT_EOK;
}
static rt_err_t nand_datacorrect(uint32_t generatedEcc, uint32_t readEcc, uint8_t *data)
{
#define ECC_MASK28 0x0FFFFFFF /* 28 valid ECC parity bits. */
#define ECC_MASK 0x05555555 /* 14 ECC parity bits. */
rt_uint32_t count, bitNum, byteAddr;
rt_uint32_t mask;
rt_uint32_t syndrome;
rt_uint32_t eccP; /* 14 even ECC parity bits. */
rt_uint32_t eccPn; /* 14 odd ECC parity bits. */
syndrome = (generatedEcc ^ readEcc) & ECC_MASK28;
if (syndrome == 0)
return (RT_MTD_EOK); /* No errors in data. */
eccPn = syndrome & ECC_MASK; /* Get 14 odd parity bits. */
eccP = (syndrome >> 1) & ECC_MASK; /* Get 14 even parity bits. */
if ((eccPn ^ eccP) == ECC_MASK) /* 1-bit correctable error ? */
{
bitNum = (eccP & 0x01) |
((eccP >> 1) & 0x02) |
((eccP >> 2) & 0x04);
NAND_DEBUG("ECC bit %d\n",bitNum);
byteAddr = ((eccP >> 6) & 0x001) |
((eccP >> 7) & 0x002) |
((eccP >> 8) & 0x004) |
((eccP >> 9) & 0x008) |
((eccP >> 10) & 0x010) |
((eccP >> 11) & 0x020) |
((eccP >> 12) & 0x040) |
((eccP >> 13) & 0x080) |
((eccP >> 14) & 0x100) |
((eccP >> 15) & 0x200) |
((eccP >> 16) & 0x400) ;
data[ byteAddr ] ^= 1 << bitNum;
return RT_MTD_EOK;
}
/* Count number of one's in the syndrome. */
count = 0;
mask = 0x00800000;
while (mask)
{
if (syndrome & mask)
count++;
mask >>= 1;
}
if (count == 1) /* Error in the ECC itself. */
return RT_MTD_EECC;
return -RT_MTD_EECC; /* Unable to correct data. */
#undef ECC_MASK
#undef ECC_MASK24
}
static rt_err_t nand_MT29F4G08_readpage(struct rt_mtd_nand_device *device,
rt_off_t page,
rt_uint8_t *data,
rt_uint32_t data_len,
rt_uint8_t *spare,
rt_uint32_t spare_len)
{
rt_uint32_t index;
rt_uint32_t gecc, recc;
rt_uint8_t tmp[4];
rt_err_t result;
rt_uint32_t i;
page = page + device->block_start * device->pages_per_block;
if (page/device->pages_per_block > device->block_end)
{
return -RT_MTD_EIO;
}
result = RT_MTD_EOK;
rt_mutex_take(&_device.lock, RT_WAITING_FOREVER);
if (data && data_len)
{
SET_NAND_CMD(NAND_AREA_A); //<2F><><EFBFBD>͵<EFBFBD>ַ
SET_NAND_ADD((rt_uint8_t)(0&0xFF));
SET_NAND_ADD((rt_uint8_t)(0>>8));
SET_NAND_ADD((rt_uint8_t)(page & 0xFF));
SET_NAND_ADD((rt_uint8_t)(page >> 8));
SET_NAND_ADD((rt_uint8_t)(page >> 16));
SET_NAND_CMD(NAND_AREA_TRUE1);
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD>ǵȴ<C7B5>R/B<><42><EFBFBD>ű<EFBFBD>Ϊ<EFBFBD>͵<EFBFBD>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>õģ<C3B5><C4A3>ȴ<EFBFBD>NAND<4E><44><EFBFBD><EFBFBD>R/B<><42><EFBFBD>š<EFBFBD><C5A1><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8>
//<2F><>STM32<33><32>NWAIT<49><54><EFBFBD><EFBFBD>(NAND<4E><44>R/B<><42><EFBFBD><EFBFBD>)<29><><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>ͨIO<49><4F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD>ȡNWAIT<49><54><EFBFBD>ŵĵ<C5B5>ƽ<EFBFBD><C6BD><EFBFBD>ж<EFBFBD>NAND<4E>Ƿ<EFBFBD>׼<EFBFBD><D7BC>
//<2F><><EFBFBD><EFBFBD><EFBFBD>ġ<EFBFBD><C4A1><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD>ķ<EFBFBD><C4B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٶȺܿ<C8BA><DCBF><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>п<EFBFBD><D0BF><EFBFBD>NAND<4E><44>û<EFBFBD><C3BB><EFBFBD>ü<EFBFBD><C3BC><EFBFBD><EFBFBD><EFBFBD>R/B<><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾNAND<4E><44>æ
//<2F><>״̬<D7B4><CCAC><EFBFBD>Ͷ<EFBFBD>ȡ<EFBFBD><C8A1>R/B<><42><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>϶<EFBFBD><CFB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD>ʵ<EFBFBD><CAB5>ȷʵ<C8B7>ǻ<EFBFBD><C7BB><EFBFBD><EFBFBD><EFBFBD>!
NAND_WaitRB(0); //<2F>ȴ<EFBFBD>RB=0
//<2F><><EFBFBD><EFBFBD>2<EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>NAND<4E>Ƿ<EFBFBD>׼<EFBFBD><D7BC><EFBFBD>õ<EFBFBD>
NAND_WaitRB(1); //<2F>ȴ<EFBFBD>RB=1
FMC_NAND_ECC_Enable(NAND_Handler.Instance,FMC_NAND_BANK3);
for (i = 0; i < data_len; i ++)
{
GET_NAND_DAT(data[i]);
}
gecc = FMC_NAND_GetECC(NAND_Handler.Instance,(uint32_t*)&gecc,FMC_NAND_BANK3,10);
if (data_len == PAGE_DATA_SIZE)
{
for (index = 0; index < ECC_SIZE; index ++)
{
GET_NAND_DAT(tmp[index]);
}
if (spare && spare_len)
{
for (i = ECC_SIZE; i < spare_len; i ++)
{
GET_NAND_DAT(spare[i]);
}
rt_memcpy(spare, tmp , ECC_SIZE);
}
recc = (tmp[3] << 24) | (tmp[2] << 16) | (tmp[1] << 8) | tmp[0];
if (recc != 0xFFFFFFFF && gecc != 0)
result = nand_datacorrect(gecc, recc, data);
if (result != RT_MTD_EOK)
NAND_DEBUG("page: %d, gecc %X, recc %X>",page, gecc, recc);
goto _exit;
}
}
if (spare && spare_len)
{
SET_NAND_CMD(NAND_AREA_A); //<2F><><EFBFBD>͵<EFBFBD>ַ
SET_NAND_ADD((rt_uint8_t)(PAGE_DATA_SIZE&0xFF));
SET_NAND_ADD((rt_uint8_t)(PAGE_DATA_SIZE>>8));
SET_NAND_ADD((rt_uint8_t)(page & 0xFF));
SET_NAND_ADD((rt_uint8_t)(page >> 8));
SET_NAND_ADD((rt_uint8_t)(page >> 16));
SET_NAND_CMD(NAND_AREA_TRUE1);
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD>ǵȴ<C7B5>R/B<><42><EFBFBD>ű<EFBFBD>Ϊ<EFBFBD>͵<EFBFBD>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>õģ<C3B5><C4A3>ȴ<EFBFBD>NAND<4E><44><EFBFBD><EFBFBD>R/B<><42><EFBFBD>š<EFBFBD><C5A1><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8>
//<2F><>STM32<33><32>NWAIT<49><54><EFBFBD><EFBFBD>(NAND<4E><44>R/B<><42><EFBFBD><EFBFBD>)<29><><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>ͨIO<49><4F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD>ȡNWAIT<49><54><EFBFBD>ŵĵ<C5B5>ƽ<EFBFBD><C6BD><EFBFBD>ж<EFBFBD>NAND<4E>Ƿ<EFBFBD>׼<EFBFBD><D7BC>
//<2F><><EFBFBD><EFBFBD><EFBFBD>ġ<EFBFBD><C4A1><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD>ķ<EFBFBD><C4B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٶȺܿ<C8BA><DCBF><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>п<EFBFBD><D0BF><EFBFBD>NAND<4E><44>û<EFBFBD><C3BB><EFBFBD>ü<EFBFBD><C3BC><EFBFBD><EFBFBD><EFBFBD>R/B<><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾNAND<4E><44>æ
//<2F><>״̬<D7B4><CCAC><EFBFBD>Ͷ<EFBFBD>ȡ<EFBFBD><C8A1>R/B<><42><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>϶<EFBFBD><CFB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD>ʵ<EFBFBD><CAB5>ȷʵ<C8B7>ǻ<EFBFBD><C7BB><EFBFBD><EFBFBD><EFBFBD>!
NAND_WaitRB(0); //<2F>ȴ<EFBFBD>RB=0
//<2F><><EFBFBD><EFBFBD>2<EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>NAND<4E>Ƿ<EFBFBD>׼<EFBFBD><D7BC><EFBFBD>õ<EFBFBD>
NAND_WaitRB(1); //<2F>ȴ<EFBFBD>RB=1
for (i = 0; i < spare_len; i ++)
{
GET_NAND_DAT(spare[i]);
}
}
_exit:
rt_mutex_release(&_device.lock);
return (result);
}
static rt_err_t nand_MT29F4G08_writepage(struct rt_mtd_nand_device *device,
rt_off_t page,
const rt_uint8_t *data,
rt_uint32_t data_len,
const rt_uint8_t *spare,
rt_uint32_t spare_len)
{
rt_err_t result;
rt_uint32_t gecc;
rt_uint32_t i;
page = page + device->block_start * device->pages_per_block;
if (page/device->pages_per_block > device->block_end)
{
return -RT_MTD_EIO;
}
result = RT_MTD_EOK;
rt_mutex_take(&_device.lock, RT_WAITING_FOREVER);
if (data && data_len)
{
SET_NAND_CMD(NAND_WRITE0); //<2F><><EFBFBD>͵<EFBFBD>ַ
SET_NAND_ADD((rt_uint8_t)(0&0xFF));
SET_NAND_ADD((rt_uint8_t)(0>>8));
SET_NAND_ADD((rt_uint8_t)(page & 0xFF));
SET_NAND_ADD((rt_uint8_t)(page >> 8));
SET_NAND_ADD((rt_uint8_t)(page >> 16));
FMC_NAND_ECC_Enable(NAND_Handler.Instance,FMC_NAND_BANK3);
for (i = 0; i < data_len; i ++)
{
SET_NAND_DAT(data[i]);
}
gecc = FMC_NAND_GetECC(NAND_Handler.Instance,(uint32_t*)&gecc,FMC_NAND_BANK3,10);
FMC_NAND_ECC_Disable(NAND_Handler.Instance,FMC_NAND_BANK3);
if (data_len == PAGE_DATA_SIZE)
{
SET_NAND_DAT((uint8_t)gecc);
SET_NAND_DAT((uint8_t)(gecc >> 8));
SET_NAND_DAT((uint8_t)(gecc >> 16));
SET_NAND_DAT((uint8_t)(gecc >> 24));
if (spare && spare_len)
{
for (i = ECC_SIZE; i < spare_len; i ++)
{
SET_NAND_DAT(spare[i]);
}
}
}
SET_NAND_CMD(NAND_WRITE_TURE1);
if(wait_for_ready()!=NSTA_READY)
{
nand_reset();
result = -RT_MTD_EIO;//ʧ<><CAA7>
}
goto _exit;
}
if (spare && spare_len)
{
SET_NAND_CMD(NAND_WRITE0); //<2F><><EFBFBD>͵<EFBFBD>ַ
SET_NAND_ADD((rt_uint8_t)(PAGE_DATA_SIZE&0xFF));
SET_NAND_ADD((rt_uint8_t)(PAGE_DATA_SIZE>>8));
SET_NAND_ADD((rt_uint8_t)(page & 0xFF));
SET_NAND_ADD((rt_uint8_t)(page >> 8));
SET_NAND_ADD((rt_uint8_t)(page >> 16));
if (spare && spare_len)
for (i = ECC_SIZE; i < spare_len; i ++)
{
SET_NAND_DAT(spare[i]);
}
SET_NAND_CMD(NAND_WRITE_TURE1);
if(wait_for_ready()!=NSTA_READY)
{
nand_reset();
result = -RT_MTD_EIO;//ʧ<><CAA7>
}
}
_exit:
rt_mutex_release(&_device.lock);
return (result);
}
static rt_err_t nand_MT29F4G08_eraseblock(struct rt_mtd_nand_device *device,
rt_uint32_t block)
{
unsigned int blockPage;
rt_err_t result;
/* add the start blocks */
block = block + device->block_start;
blockPage = (block << 6);
result = RT_MTD_EOK;
rt_mutex_take(&_device.lock, RT_WAITING_FOREVER);
SET_NAND_CMD(NAND_ERASE0); //<2F><><EFBFBD>͵<EFBFBD>ַ
SET_NAND_ADD((rt_uint8_t)blockPage);
SET_NAND_ADD((rt_uint8_t)(blockPage>>8));
SET_NAND_ADD((rt_uint8_t)(blockPage>>16));
SET_NAND_CMD(NAND_ERASE1);
if(wait_for_ready()!=NSTA_READY)
{
nand_reset();
result = -RT_MTD_EIO;//ʧ<><CAA7>
}
rt_mutex_release(&_device.lock);
return result;
}
static rt_err_t nand_MT29F4G08_pagecopy(struct rt_mtd_nand_device *device,
rt_off_t src_page,
rt_off_t dst_page)
{
rt_err_t result = RT_MTD_EOK;
rt_uint32_t source_block=0,dest_block=0;
src_page = src_page + device->block_start * device->pages_per_block;
dst_page = dst_page + device->block_start * device->pages_per_block;
//<2F>ж<EFBFBD>Դҳ<D4B4><D2B3>Ŀ<EFBFBD><C4BF>ҳ<EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>ͬһ<CDAC><D2BB>plane<6E><65>
source_block=src_page/device->pages_per_block;
dest_block=dst_page/device->pages_per_block;
if((source_block%2)!=(dest_block%2))return RT_MTD_ESRC; //<2F><><EFBFBD><EFBFBD>ͬһ<CDAC><D2BB>plane<6E><65>
SET_NAND_CMD(NAND_MOVEDATA_CMD0);//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0X00
SET_NAND_ADD((rt_uint8_t)(0&0xFF)); //<2F><><EFBFBD><EFBFBD>Դҳ<D4B4><D2B3>ַ
SET_NAND_ADD((rt_uint8_t)(0>>8));
SET_NAND_ADD((rt_uint8_t)(src_page & 0xFF));
SET_NAND_ADD((rt_uint8_t)(src_page >> 8));
SET_NAND_ADD((rt_uint8_t)(src_page >> 16));
SET_NAND_CMD(NAND_MOVEDATA_CMD1);//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0X35
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD>ǵȴ<C7B5>R/B<><42><EFBFBD>ű<EFBFBD>Ϊ<EFBFBD>͵<EFBFBD>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>õģ<C3B5><C4A3>ȴ<EFBFBD>NAND<4E><44><EFBFBD><EFBFBD>R/B<><42><EFBFBD>š<EFBFBD><C5A1><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8>
//<2F><>STM32<33><32>NWAIT<49><54><EFBFBD><EFBFBD>(NAND<4E><44>R/B<><42><EFBFBD><EFBFBD>)<29><><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>ͨIO<49><4F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD>ȡNWAIT<49><54><EFBFBD>ŵĵ<C5B5>ƽ<EFBFBD><C6BD><EFBFBD>ж<EFBFBD>NAND<4E>Ƿ<EFBFBD>׼<EFBFBD><D7BC>
//<2F><><EFBFBD><EFBFBD><EFBFBD>ġ<EFBFBD><C4A1><EFBFBD><EFBFBD><EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD>ķ<EFBFBD><C4B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٶȺܿ<C8BA><DCBF><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>п<EFBFBD><D0BF><EFBFBD>NAND<4E><44>û<EFBFBD><C3BB><EFBFBD>ü<EFBFBD><C3BC><EFBFBD><EFBFBD><EFBFBD>R/B<><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾNAND<4E><44>æ
//<2F><>״̬<D7B4><CCAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǾͶ<C7BE>ȡ<EFBFBD><C8A1>R/B<><42><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>϶<EFBFBD><CFB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD>ʵ<EFBFBD><CAB5>ȷʵ<C8B7>ǻ<EFBFBD><C7BB><EFBFBD><EFBFBD><EFBFBD>!<21><><EFBFBD><EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD>Խ<EFBFBD><D4BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//<2F><><EFBFBD><EFBFBD><EBBBBB><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><><D6BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>Ч<EFBFBD><D0A7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
result=NAND_WaitRB(0); //<2F>ȴ<EFBFBD>RB=0
if(result)return -RT_MTD_EIO; //<2F><>ʱ<EFBFBD>˳<EFBFBD>
//<2F><><EFBFBD><EFBFBD>2<EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>NAND<4E>Ƿ<EFBFBD>׼<EFBFBD><D7BC><EFBFBD>õ<EFBFBD>
result=NAND_WaitRB(1); //<2F>ȴ<EFBFBD>RB=1
if(result)return -RT_MTD_EIO; //<2F><>ʱ<EFBFBD>˳<EFBFBD>
SET_NAND_CMD(NAND_MOVEDATA_CMD2);//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0X85
SET_NAND_ADD((rt_uint8_t)(0&0xFF)); //<2F><><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF>ҳ<EFBFBD><D2B3>ַ
SET_NAND_ADD((rt_uint8_t)(0>>8));
SET_NAND_ADD((rt_uint8_t)(dst_page & 0xFF));
SET_NAND_ADD((rt_uint8_t)(dst_page >> 8));
SET_NAND_ADD((rt_uint8_t)(dst_page >> 16));
SET_NAND_CMD(NAND_MOVEDATA_CMD3);//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0X10
if(wait_for_ready()!=NSTA_READY)
{
nand_reset();
return -RT_MTD_EIO;//ʧ<><CAA7>
}
return RT_MTD_EOK;
}
static rt_err_t nand_MT29F4G08_checkblock(struct rt_mtd_nand_device* device, rt_uint32_t block)
{
return (RT_MTD_EOK);
}
static rt_err_t nand_MT29F4G08_markbad(struct rt_mtd_nand_device* device, rt_uint32_t block)
{
return (RT_MTD_EOK);
}
static const struct rt_mtd_nand_driver_ops ops =
{
nand_MT29F4G08_readid,
nand_MT29F4G08_readpage,
nand_MT29F4G08_writepage,
nand_MT29F4G08_pagecopy,
nand_MT29F4G08_eraseblock,
nand_MT29F4G08_checkblock,
nand_MT29F4G08_markbad,
};
static struct rt_mtd_nand_device _partition[1];
int nand_MT29F4G08_hw_init(void)
{
NAND_Init();
rt_mutex_init(&_device.lock, "nand", RT_IPC_FLAG_FIFO);
/* register nand0 */
_partition[0].page_size = PAGE_DATA_SIZE;
_partition[0].pages_per_block = PAGES_PER_BLOCK;
_partition[0].plane_num = 2;
_partition[0].oob_size = PAGE_OOB_SIZE;
_partition[0].oob_free = PAGE_OOB_SIZE - ((PAGE_DATA_SIZE) * 3 / 256);
_partition[0].block_start = 0;
_partition[0].block_end = 4095;
_partition[0].block_total = _partition[0].block_end - _partition[0].block_start;
_partition[0].ops = &ops;
rt_mtd_nand_register_device("nand0", &_partition[0]);
nand_MT29F4G08_readid(&_partition[0]);
return RT_EOK;
}
INIT_BOARD_EXPORT(nand_MT29F4G08_hw_init);