打印

关于NAND FLASH写入错误

[复制链接]
5110|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hao01222|  楼主 | 2008-7-18 21:18 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
这几天用SAM9260写nandflsh的底层驱动,已经能实现读FLASH ID,读和擦写,但是写就是实现不了。
每次我进行写一页,读取状态时,是显示正确的(返回0xc0),但是读的时候读的数据总是1,不知道各位有没有遇到过这种情况
我用的NAND FLASH的芯片是三星的K9F1208U0B,读写命令我均是按照官方手册上的时序说明进行

相关帖子

沙发
香水城| | 2008-7-18 22:43 | 只看该作者

如果写完一页后,第一次读出的状态时显示就绪,基本表示

用示波器看看吧。

使用特权

评论回复
板凳
hao01222|  楼主 | 2008-7-19 09:42 | 只看该作者

手头没有示波器啊,有没有其它方法

使用特权

评论回复
地板
香水城| | 2008-7-19 12:05 | 只看该作者

做这样的底层驱动一定要有相应的仪器设备

这样才能保证正确的时序和最优的效率。

使用特权

评论回复
5
hao01222|  楼主 | 2008-7-21 10:55 | 只看该作者

问下,有没有可能是我的程序有问题

程序只是用来实验的,所以一些地方不规范, wait()是延时5个指令周期
写页之前已经将所在块擦除,返回信息是0xC0,但读出来的信息是全部为0x01


AT91F_NandWriteSector(unsigned int uSectorAddr, char *pOutBuffer)
{
    unsigned int i;
    unsigned char bRet=1;

    NAND_ENABLE_CE();
    WRITE_NAND_COMMAND(CMD_WRITE_1);
         wait();

         WRITE_NAND_ADDRESS(0x00);
    WRITE_NAND_ADDRESS((uSectorAddr >>  0) & 0xFF);
    WRITE_NAND_ADDRESS((uSectorAddr >>  8) & 0xFF);
    WRITE_NAND_ADDRESS((uSectorAddr >> 16) & 0xFF);

    wait();
    for(i=0; i<512; i++)
    {
        WRITE_NAND(*(pOutBuffer++));
    }
         wait();

    WRITE_NAND_COMMAND(CMD_WRITE_2);
    NAND_WAIT_READY();
    NAND_WAIT_READY();
    WRITE_NAND_COMMAND(CMD_STATUS);
    wait();
    NAND_WAIT_READY();
    NAND_WAIT_READY();
    bRet=READ_NAND();

    NAND_DISABLE_CE();
    return(bRet);
}

使用特权

评论回复
6
lomeisi_99| | 2008-7-21 11:18 | 只看该作者

时序问题

感觉是时序问题,板子主频是多少?你如何配置时序的?

使用特权

评论回复
7
hao01222|  楼主 | 2008-7-21 15:17 | 只看该作者

应该不是时序问题吧

都能正确的进行读ID和擦,应该不是时序问题吧
时钟是将近100M

#define AT91C_SM_NWE_SETUP             (0 << 0)
#define AT91C_SM_NCS_WR_SETUP    (0 << 8)
#define AT91C_SM_NRD_SETUP             (0 << 16)
#define AT91C_SM_NCS_RD_SETUP    (0 << 24)
  
#define AT91C_SM_NWE_PULSE      (3 << 0)
#define AT91C_SM_NCS_WR_PULSE    (4 << 8)
#define AT91C_SM_NRD_PULSE             (3 << 16)
#define AT91C_SM_NCS_RD_PULSE    (4 << 24)
  
#define AT91C_SM_NWE_CYCLE              (5 << 0)
#define AT91C_SM_NRD_CYCLE             (5 << 16)

#define AT91C_SM_TDF             (0 << 16)

使用特权

评论回复
8
hao01222|  楼主 | 2008-7-23 11:52 | 只看该作者

写正确了,擦有出现问题

写确实是时序错误

现在遇到一个问题,我写入数据后对该页所在块进行擦写,确不能擦掉该页的内容,而且再次在该页写也不能实现了

请问是什么问题

使用特权

评论回复
9
lomeisi_99| | 2008-7-23 13:50 | 只看该作者

哈哈

时序哪错了?
不能擦除?不是坏块吧,之前你不是说可以擦吗?

使用特权

评论回复
10
hao01222|  楼主 | 2008-7-24 10:04 | 只看该作者

就是数据写入之后就不能擦了

就是数据写入之后就不能擦了
写入之前是可以擦的
任何一页的数据写入之后,我想擦除整个块,但发送擦除命令后,读出该页还是原来的数据

但是在那些未写入数据的页确可以擦除,不知道这是一个什么缘故。

时序上是
#define AT91C_SM_NWE_PULSE       (3 << 0)
#define AT91C_SM_NCS_WR_PULSE    (4 << 8)
#define AT91C_SM_NRD_PULSE       (3 << 16)
#define AT91C_SM_NCS_RD_PULSE    (4 << 24)
应该改成
#define AT91C_SM_NWE_PULSE       (3 << 0)
#define AT91C_SM_NCS_WR_PULSE    (3 << 8)
#define AT91C_SM_NRD_PULSE       (4 << 16)
#define AT91C_SM_NCS_RD_PULSE    (4 << 24)

使用特权

评论回复
11
hao01222|  楼主 | 2008-7-30 16:32 | 只看该作者

问题已经解决

是我程序里的问题,现已解决,谢谢

使用特权

评论回复
12
lomeisi_99| | 2008-7-31 12:46 | 只看该作者

恭喜

使用特权

评论回复
13
温wenwen| | 2012-8-28 16:31 | 只看该作者
你怎么解决的也说一下啊

使用特权

评论回复
14
yf823547490| | 2014-11-20 11:08 | 只看该作者
O(∩_∩)O~,比较鄙视这种  自己有问题了,伸手问大家意见,
自己解决问题了,甩甩尾巴走人,狗屁经验资料都不留下的人,有时候你的一句两句指点,够别人折腾好几天了。

使用特权

评论回复
15
yf823547490| | 2014-11-20 12:28 | 只看该作者
这个问题也折腾我好几天了,问题描述和LZ基本一致,
我是在Nand上移植FATFS,总是不大成功,各种错误都报了,最后自己从各方面测试nand的驱动函数,
才发现,根源问题是  某些BLOCK擦除不成功,我拿到的K9F1G08中
uint32_t Nand_BlockErase(uint32_t Block)
{
  if (Block >= NAND_BLOCK_NUM)return 0;
  
  nand_cmd(NAND_CMD_ERASE0);
  nand_addr(Block & 0xff);
  nand_addr((Block >> 8) & 0xff);
  nand_cmd(NAND_CMD_ERASE1);       
  nand_waitready();
  
  while (!(nand_readstatus() & (1 << 6)));
  if (nand_readstatus() & 0x01) {
    return 0;
  }  
  return 1
}

使用特权

评论回复
16
yf823547490| | 2014-11-20 12:54 | 只看该作者
注意他传送Block地址的时候,直接低8位,再高8位,
这实际上page号的传送方式,因为K9F1G08包含1024*64=65536个page所以需要 16位的地址数据

再看BLOCK仅仅含有1024个,仅需要11位就够了,那么这11位是怎么传的呢?直接先低八位,再高八位么?
查找数据手册:
The Erase operation is done on a block basis. Block address loading is accomplished in two cycles initiated by an Erase Setup command(60h). Only address A18to A 27(X8) or A17 to A 26(X16) is valid while A12 to A17(X8) or A11to A16(X16) is ignored.

所以说只有A18~A27的数据是有效的,对比
3rd Cycle A12 A13 A14 A15 A16 A17 A18 A19    Row Address
4th Cycle A20 A21 A22 A23 A24 A25 A26 A27    Row Address

所以Block的数据不能像page一样直接先传低8为再高8位,
必须先将BLOCK号向左移动6位,跟数据手册上说的额A18~A27对正,才能传过去。修改代码如下:
uint32_t Nand_BlockErase(uint32_t Block)
{
  if (Block >= NAND_BLOCK_NUM)return 0;
  
        Block=Block<<6;
  nand_cmd(NAND_CMD_ERASE0);
  nand_addr(Block & 0xff);
  nand_addr((Block >> 8) & 0xff);
  nand_cmd(NAND_CMD_ERASE1);       
  nand_waitready();
  
  while (!(nand_readstatus() & (1 << 6)));
  if (nand_readstatus() & 0x01) {
    return 0;
  }  
  return 1;
}

测试后一切OK了, FATFS也能正常跑起来了

使用特权

评论回复
17
yf823547490| | 2014-11-20 12:57 | 只看该作者
最后啰嗦一下,也是希望如果碰到相同问题的人能更轻松地解决。

为什么会出现类似  

写入之前是可以擦的
任何一页的数据写入之后,我想擦除整个块,但发送擦除命令后,读出该页还是原来的数据

但是在那些未写入数据的页确可以擦除,不知道这是一个什么缘故。


这样的问题呢?

使用特权

评论回复
18
yf823547490| | 2014-11-20 13:03 | 只看该作者
分析如下:

如上所述,如果ERACE BLOCK传送的地址是不正确的,那么例如我擦除BLOCK 1000,实际上擦除的是BLock 2;
可能拿到板子的时候,nandflash已经全部擦除过一次,也可能是nand flash出厂就是这样,所有BLOCK 都是oxff,

这样的话就是第一条描述 ,写入前都是可以擦的,因为本来就是0xff,擦出是否成功都是0xff,所以误认为写入前是可以擦除的,实际上没有擦除

因为刚开始是0xff,所以数据是可以写入的,但是写入之后,想要擦除却擦除不掉,读出来的页还是之前写入的数据,这正是因为传送的BLOCK地址错误,导致该BLOCK没有正确擦除啊

未写入数据的页还是0xff,所以还是会被认为是可以擦除

最终现象就是,和LZ描述的一样      一旦写入一次就无法再次擦除和写入

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

17

主题

49

帖子

0

粉丝