nand读过程

引脚说明

 

 

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);

}

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值