引脚说明
Read ID
读ID步骤:
1. 拉低CE# 选中芯片
2. 拉高CLE 说明发送的是控制信号
3. 拉低WE# 写使能
4. 发送0x90 表示要读取id
5. 拉高ALE 表示需要发送地址
6. 发送地址0x00
7. 拉低RE# 表示读使能
8. 读取id信息
uboot程序分析:
static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip, int busw, int *maf_id, int *dev_id, const struct nand_flash_dev *type)
{
int ret, maf_idx;
int tmp_id, tmp_manf;
/* Select the device */
/* 选中芯片 */
chip->select_chip(mtd, 0);
/*
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
* after power-up
*/
/* 发送0xff,复位芯片,有的芯片需要 */
chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
/* Send the command for reading device ID */
/* 发送0x90,地址是0x00 */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
*maf_id = chip->read_byte(mtd);
*dev_id = chip->read_byte(mtd);
/* Try again to make sure, as some systems the bus-hold or other
* interface concerns can cause random data which looks like a
* possibly credible NAND flash to appear. If the two results do
* not match, ignore the device completely.
*/
/* 重新读一次 */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */
tmp_manf = chip->read_byte(mtd);
tmp_id = chip->read_byte(mtd);
/* 比较两次读取的结果 */
if (tmp_manf != *maf_id || tmp_id != *dev_id)
{
printk(KERN_INFO "%s: second ID read did not match " "%02x,%02x against %02x,%02x\n", __func__, *maf_id,
*dev_id, tmp_manf, tmp_id);
return ERR_PTR(-ENODEV);
}
}
nand page read operation
读取数据步骤:
1. 拉低CE# 选中芯片
2. 拉高CLE 说明发送的是控制信号
3. 拉低WE# 写使能
4. 发送0x00
5. 拉高ALE 表示需要发送地址
6. 发送地址
7. 发送0x30
8. 等待R/B# 如果是高电平,说明数据已经准备好,如果是低电平,表示busy,正在搬运数据
9. 检测到R/B#变高,拉低RE# 读取数据
地址计算
S34ML08G101TF100
一共有8192个块,每个块内有64页,每个页是2K+64 Bytes
如果需要读取第7000块中的第64页的1208字节处的地址
物理地址
=块大小×块号 + 页大小×页号 + 页内地址
=128K×7000 + 2K×64 + 1208
=0x36B204B8
0x36B204B8 = 11 0110 1011 0010 0000 0100 1011 1000
但是不能这么算
实际上,表11中的A11,是比较特殊的,只有当我们访问页内地址处于oob的位置,即属于2048~2111的时候,A11才会其效果,才会用A0-A11用来表示对应的某个属于2048~2111的某个值,属于oob的某个位置。
页内地址
=1208
=0x4B8
页号
=块数×页数/块 + 块内的页号
= 7000×(128K/2K) + 64
= 7000×64 + 64
= 448064
=0x6D640
实际上是读取0x6D640页内的0x4B8地址
1st周期 | A7 ~ A0 | 1011 1000 = 0xB8 |
2nd周期 | A10~ A8 | 100 = 0x04 |
3rd周期 | A19~A12 | 010 0000 0 = 0x40 |
4th周期 | A27~A20 | 110 1011 0 = 0xD6 |
5th周期 | A30~A28 | 11 0 = 0x06 |
对应uboot中
drivers/mtd/nand/nand_base.c
static void nand_command_lp(struct mtd_info *mtd, unsigned int command, int column, int page_addr)
{
register struct nand_chip *chip = mtd->priv;
uint32_t rst_sts_cnt = CONFIG_SYS_NAND_RESET_CNT;
/* Emulate NAND_CMD_READOOB */
if (command == NAND_CMD_READOOB) {
column += mtd->writesize;
command = NAND_CMD_READ0;
}
/* Command latch cycle */
chip->cmd_ctrl(mtd, command & 0xff,
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
if (column != -1 || page_addr != -1) {
int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
/* Serially input address */
if (column != -1) {
/* Adjust columns for 16 bit buswidth */
if (chip->options & NAND_BUSWIDTH_16)
column >>= 1;
/* 发送column address1 @cpf */
chip->cmd_ctrl(mtd, column, ctrl);
ctrl &= ~NAND_CTRL_CHANGE;
/* 发送column address2 @cpf */
chip->cmd_ctrl(mtd, column >> 8, ctrl);
}
if (page_addr != -1) {
/* 发送row address1 @cpf */
chip->cmd_ctrl(mtd, page_addr, ctrl);
/* 发送row address2 @cpf */
chip->cmd_ctrl(mtd, page_addr >> 8,
NAND_NCE | NAND_ALE);
/* One more address cycle for devices > 128MiB */
if (chip->chipsize > (128 << 20))
/* 发送row address3 @cpf */
chip->cmd_ctrl(mtd, page_addr >> 16,
NAND_NCE | NAND_ALE);
}
}
chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
/*
* program and erase have their own busy handlers
* status, sequential in, and deplete1 need no delay
*/
switch (command) {
case NAND_CMD_CACHEDPROG:
case NAND_CMD_PAGEPROG:
case NAND_CMD_ERASE1:
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
case NAND_CMD_RNDIN:
case NAND_CMD_STATUS:
case NAND_CMD_DEPLETE1:
return;
/*
* read error status commands require only a short delay
*/
case NAND_CMD_STATUS_ERROR:
case NAND_CMD_STATUS_ERROR0:
case NAND_CMD_STATUS_ERROR1:
case NAND_CMD_STATUS_ERROR2:
case NAND_CMD_STATUS_ERROR3:
udelay(chip->chip_delay);
return;
case NAND_CMD_RESET:
if (chip->dev_ready)
break;
udelay(chip->chip_delay);
chip->cmd_ctrl(mtd, NAND_CMD_STATUS,
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
chip->cmd_ctrl(mtd, NAND_CMD_NONE,
NAND_NCE | NAND_CTRL_CHANGE);
while (!(chip->read_byte(mtd) & NAND_STATUS_READY) &&
(rst_sts_cnt--));
return;
case NAND_CMD_RNDOUT:
/* No ready / busy check necessary */
chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
chip->cmd_ctrl(mtd, NAND_CMD_NONE,
NAND_NCE | NAND_CTRL_CHANGE);
return;
case NAND_CMD_READ0:
/* 发送0x30 */
chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
chip->cmd_ctrl(mtd, NAND_CMD_NONE,
NAND_NCE | NAND_CTRL_CHANGE);
/* This applies to read commands */
default:
/*
* If we don't have access to the busy pin, we apply the given
* command delay
*/
if (!chip->dev_ready) {
udelay(chip->chip_delay);
return;
}
}
/* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine. */
ndelay(100);
nand_wait_ready(mtd);
}