首先查看芯片文档,s3c2410 用户手册.需要了解的资料有:
1.用户手册中关于NAND FLASH 操作的一章,详细相关寄存器的作用。
2.芯片文档:命令,地址,读写流程等。用户手册上的寄存器的使用并不列出。这里根据学习目的,列出部分的芯片文档中的流程图。
下面是芯片操作的命令
通过在命令引脚上写命令来操作芯片。
写数据也称为编程数据。流程图如下:
乘热看下编程函数的代码:这里注意在编程前应该先擦出原有位置的数据,而擦除操作一次根据具体的芯片而定。
/* * NAND write */ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { int i, page, col, cnt, status; struct nand_chip *this = mtd->priv; /* Do not allow write past end of page */ if ((to + len) > mtd->size) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Attempted write past end of device\n"); return -EINVAL; } /* Shift to get page */ page = ((int)to) >> this->page_shift; /* Get the starting column */ col = to & (mtd->oobblock - 1); /* Initialize return length value */ *retlen = 0; /* Select the NAND device */ nand_select(); /* Check the WP bit */ nand_command(mtd, NAND_CMD_STATUS, -1, -1); this->wait_for_ready(); if (!(this->read_data() & SMC_STAT_NOT_WP)) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Device is write protected!!!\n"); i = -EPERM; goto nand_write_exit; } /* Loop until all data is written */ while (*retlen < len) { /* Write data into buffer */ if ((col + len) >= mtd->oobblock) for (i = col, cnt = 0; i < mtd->oobblock; i++, cnt++) this->data_buf[i] = buf[(*retlen + cnt)]; else for (i = col, cnt = 0; cnt < (len - *retlen); i++, cnt++) this->data_buf[i] = buf[(*retlen + cnt)]; /* Write ones for partial page programming */ for (i = mtd->oobblock; i < (mtd->oobblock + mtd->oobsize); i++) this->data_buf[i] = 0xff; /* Write pre-padding bytes into buffer */ for (i = 0; i < col; i++) this->data_buf[i] = 0xff; /* Write post-padding bytes into buffer */ if ((col + (len - *retlen)) < mtd->oobblock) { for (i = (col + cnt); i < mtd->oobblock; i++) this->data_buf[i] = 0xff; } /* Send command to begin auto page programming这个地方其实就是写地址,也就是第一步。一次写的是一页。
*/ nand_command(mtd, NAND_CMD_SEQIN, 0x00, page); /* Write out complete page of data */ this->hwcontrol(NAND_CTL_DAT_OUT); for (i = 0; i < (mtd->oobblock + mtd->oobsize); i++) this->write_data(this->data_buf[i]); this->hwcontrol(NAND_CTL_DAT_IN); /* Send command to actually program the data */ nand_command(mtd, NAND_CMD_PAGEPROG, -1, -1); this->wait_for_ready(); /* * Wait for program operation to complete. This could * take up to 3000us (3ms) on some devices. so we try * and exit as quickly as possible. */ status = 0; for (i = 0; i < 24; i++) { /* Delay for 125us */ udelay(125); /* Check for status */ nand_command(mtd, NAND_CMD_STATUS, -1, -1); status = (int)this->read_data(); if (status & SMC_STAT_READY) break; } /* See if device thinks it succeeded */ if (status & SMC_STAT_WRITE_ERR) { DEBUG(MTD_DEBUG_LEVEL0, __FUNCTION__"(): Failed write, page 0x%08x, " \ "%6i bytes were sucesful\n", page, *retlen); i = -EIO; goto nand_write_exit; } if (col) col = 0x00; /* Update written bytes count */ *retlen += cnt; /* Increment page address */ page++; } /* Return happy */ *retlen = len; i = 0; nand_write_exit: /* De-select the NAND device */ nand_deselect(); return i; }
关键部分在于while循环,注意一次写可能大于512个字节,每次只能写一个页,这也是为什么在写后需要填充前后空隙的原因。
nand_command(mtd, NAND_CMD_PAGEPROG, -1, -1); 这个就是就是写10到命令引脚,强制写入FLASH。属于流程图中的第三步。其中的ECC校验的部分被我省略了,主要想一步一步来。这个基本的读写完成了,再去考虑校验部分。