这款芯片一页有(2048+64)个字节,一块有64页
原理图如下:
引脚介绍:
RnB: 就绪或者忙 FALE:地址锁存器
nFRE: 读使能 FCLE:命令所存器
nFCE: 片选使能 FWE:写使能
2416nand控制器时序图:
K92G08时序
查芯片手册得到TCS=20ns,Tch=5ns,twp=12ns,
所以
TACLS=tcs-twp=20-12=8;
TWRPH0=12ns:
TWRPH1=5ns;
初始化代码如下:
void nand_Init(void)
{
rGPACON = (rGPACON &~(0x3f<<17)) | (0x3f<<17);
// 配置K9F2G08U0B timing(HCLK@133M)
//1秒/133约为7纳秒
// TACLS=1, (tALS或tCLS-tWP=0)(ALE或CLE有效后需保持才能发出写脉冲)
// TWRPH0=2,tWP=12ns(最小写脉冲宽度)
// TWRPH1=1,tALH或tCLH=5ns(写脉冲后ALE或CLE需保持有效时间)
// 1-bit ECC
rNFCONF = (1<<12)|(2<<8)|(1<<4)|(1<<1)|(0<<0);
// 上升沿检查nand准备好信号线
rNFCONT = (0<<12)|(0<<10)|(0<<9)|(0<<8)
|(0x3<<6)|(0x3<<4)|(0x3<<1)|(1<<0);
}
芯片的读操纵:
static int Nand_ReadPage(unsigned int Block, unsigned int Page,unsigned char *Buffer)
{
unsigned int i;
unsigned int MECC, SECC;
if (Buffer == (unsigned char *)0) {
return 1; // 缓冲区为空,参数错误
}
Page &= (64-1); // 64 page in one block
Page += (Block << 6); // Block转换为页数
NF_INIT_MECC(); // main区ECC清空
NF_INIT_SECC(); // spare区ECC清空
NF_MECC_UNLOCK(); // main区ECC解锁,开始ECC计算
NF_CE_ENABLE(); // 使能片选
NF_CLEAR_RB(); // 清数据传输标志
NF_CMD(NAND_CMD_READ0); // page read cycle 1
NF_ADDR(0); // column address
NF_ADDR(0); // columu address
NF_ADDR(Page & 0xff); // 写入3字节的页地址
NF_ADDR((Page>>8) & 0xff);
NF_ADDR((Page>>16) & 0xff);
NF_CMD(NAND_CMD_READSTART); // page read cycle 2
NF_WAIT_READY(); // 等待命令完成
for (i=0; i<2048; i++) { // 读取main区数据
Buffer[i] = NF_READ_BYTE();
}
NF_MECC_LOCK(); // 锁定main ECC
NF_SECC_UNLOCK(); // 解锁spare ECC
MECC = NF_READ_WORD(); // spare区前4字节为main区ECC
// main区的ECC放入到NFMECCD0/1中相应的位中
rNFMECCD0=((MECC&0xff00)<<8) | (MECC&0xff);
rNFMECCD1=((MECC&0xff000000)>>8) | ((MECC&0xff0000)>>16);
NF_SECC_LOCK(); // 锁定spare ECC
// spare区第5,6这两字节为spare区ECC,剩下部分未使用
SECC = NF_READ_WORD();
// spare区的ECC放入到NFMECCD0/1中相应的位中
rNFSECCD=((SECC&0xff00)<<8)|(SECC&0xff);
NF_CE_DISABLE();
// check whether spare/main area bit fail error occurred
if ((rNFECCERR0 & 0xf) == 0) {
return 0; // 数据读取正确
} else {
return 2; // ECC检验不一致,数据读取有误
}
}
写操作也类是,只不过命令不一样
static int Nand_WritePage(unsigned int Block, unsigned int Page, unsigned char *Buffer)
{
unsigned int i;
unsigned char State;
unsigned int MECC, SECC;
if (Buffer == (unsigned char *)0) {
return 1; // 数据缓存参数错误
}
if (Nand_IsBadBlock(Block)) {
return 2; // 是坏块,返回坏块错误码
}
Page &= (64-1); // 1 block最大64页
Page += (Block << 6); // block转换成页
NF_INIT_MECC(); // main区ECC清空
NF_INIT_SECC(); // spare区ECC清空
NF_MECC_UNLOCK(); // main区ECC解锁,开始ECC计算
NF_CE_ENABLE(); // 使能片选
NF_CLEAR_RB(); // 清数据传输标志
NF_CMD(NAND_CMD_SEQIN); // page program cycle 1
NF_ADDR(0); // column address
NF_ADDR(0); // columu address
NF_ADDR(Page & 0xff); // 写入3字节页地址
NF_ADDR((Page>>8) & 0xff);
NF_ADDR((Page>>16) & 0xff);
for (i=0; i<2048; i++) { // 写入2k数据到main区
NF_WRITE_BYTE(Buffer[i]);
}
NF_MECC_LOCK(); // 锁定main ECC
MECC = rNFMECC0; // 4字节写main区数据的ECC
NF_SECC_UNLOCK(); // 解锁spare ECC
NF_WRITE_BYTE(MECC&0xff);// 写4字节main ECC到spare区
NF_WRITE_BYTE((MECC>>8) & 0xff);
NF_WRITE_BYTE((MECC>>16) & 0xff);
NF_WRITE_BYTE((MECC>>24) & 0xff);
NF_SECC_LOCK(); // 锁定spare ECC
SECC = rNFSECC; // 2字节的spare写数据ECC
NF_WRITE_BYTE(SECC & 0xff); // 继续写入SECC
NF_WRITE_BYTE((SECC>>8) & 0xff);
NF_CMD(NAND_CMD_PAGEPROG); // page program cycle 2
NF_WAIT_READY(); // 等待写完
NF_CMD(NAND_CMD_STATUS); // 发送命令读取状态
do {
State = NF_READ_BYTE();
} while(!(State & (1<<6))); // 等待状态变成Ready
NF_CE_DISABLE();
// 是否写成功,第0位为0则pass,不然fail
if (State & (1<<0)) {
if (Nand_MarkBadBlock(Block)) { // 标志坏块
return 3; // 写不成功并且坏块标记不成功
} else {
return 4; // 写不成功坏块标记成功
}
}
return 0;
}
nandflash 8位ECC码写操作,如果2416的自动方式采用IROM启动的话,在将nandflash的8k数据复制到SRAM的过程中会进行校验,否则芯片是无法启动的
int32_t NandBoot_WritePage_8Bit(uint32_t Block, uint32_t Page, uint8_t *Buffer)
{
uint8_t oob[64];
uint8_t i;
uint8_t State;
uint8_t *poob;
int32_t j;
uint32_t eccprgecc0, eccprgecc1, eccprgecc2, eccprgecc3;
Page &= (64-1); // 1 block最大64页
Page += (Block << 6); // block转换成页
NF_CE_ENABLE(); // 使能片选
NF_CLEAR_RB(); // 清数据传输标志
NF_CMD(NAND_CMD_SEQIN); // page program cycle 1
NF_ADDR(0); // column address
NF_ADDR(0); // columu address
NF_ADDR(Page & 0xff); // 写入3字节页地址
NF_ADDR((Page>>8) & 0xff);
NF_ADDR((Page>>16) & 0xff);
poob = oob;
rNFCONF = (rNFCONF & ~(3<<23)) | (1<<23);
for (i=0; i<4; i++) {
// clear illegal access status bit
rNFSTAT = rNFSTAT | ((1<<4)|(1<<5)|(1<<6)|(1<<7));
rNFCONT |= (1<<18) | (1<<11); // Encoding 8-bit ECC
NF_MECC_UNLOCK(); // main区ECC解锁,开始ECC计算
NF_INIT_MECC(); // main区ECC清空
// Write buffer to main area
for (j=0; j<512; j++) {
NF_WRITE_BYTE(*Buffer++);
}
// 锁住校验码
NF_MECC_LOCK();
//等待校验码完成
while (!(rNFSTAT & (1<<6))) {
}
// clear 8bit ecc encode done
rNFSTAT |= (1<<6);
eccprgecc0 = rNFM8ECC0;
eccprgecc1 = rNFM8ECC1;
eccprgecc2 = rNFM8ECC2;
eccprgecc3 = rNFM8ECC3;
*poob++ = eccprgecc0 & 0xff;
*poob++ = (eccprgecc0 >> 8) & 0xff;
*poob++ = (eccprgecc0 >> 16) & 0xff;
*poob++ = (eccprgecc0 >> 24) & 0xff;
*poob++ = eccprgecc1 & 0xff;
*poob++ = (eccprgecc1 >> 8) & 0xff;
*poob++ = (eccprgecc1 >> 16) & 0xff;
*poob++ = (eccprgecc1 >> 24) & 0xff;
*poob++ = eccprgecc2 & 0xff;
*poob++ = (eccprgecc2 >> 8) & 0xff;
*poob++ = (eccprgecc2 >> 16) & 0xff;
*poob++ = (eccprgecc2 >> 24) & 0xff;
*poob++ = eccprgecc3 & 0xff;
}
// Reserved for OS(12 byte)
*poob++ = 0xff;
*poob++ = 0xff;
*poob++ = 0xff;
*poob++ = 0xff;
*poob++ = 0xff;
*poob++ = 0xff;
*poob++ = 0xff;
*poob++ = 0xff;
*poob++ = 0xff;
*poob++ = 0xff;
*poob++ = 0xff;
*poob++ = 0xff;
// 写完主数据区的数据之后,在写入ECC码
for (j=0; j<64; j++) {
NF_WRITE_BYTE(oob[j]);
}
NF_CMD(NAND_CMD_PAGEPROG); // page program cycle 2
NF_WAIT_READY(); // 等待写完
NF_CMD(NAND_CMD_STATUS); // 读取nand状态
do {
State = NF_READ_BYTE();
} while(!(State & (1<<6))); // 等待状态变成Ready
NF_CE_DISABLE();
// 是否写成功,第0位为0则pass,不然fail
if (State & (1<<0)) {
return -1; // 写不成功
}
return 0;
}
其他操作也一样,主要记住