新闻  |   论坛  |   博客  |   在线研讨会
ADS的对nand的裸板的驱动部分 ---转载
hong60104 | 2011-09-29 14:38:50    阅读:1341   发布文章


**********************************************************************************
ADS的对nand的裸板的驱动部分
说实话,写的不错,但是就是是针对s3c2410的,特别是在产生ECC校验码的部分体现很明显
**********************************************************************************
2 在 ADS 下 flash 烧写程序
2.1 ADS 下 flash 烧写程序原理及结构
     基本原理:在 windows 环境下借助 ADS 仿真器将在 SDRAM 中的一段存储区域中的数据写到 Nand flash 存
储空间中。烧写程序在纵向上分三层完成:
     第一层: 主烧写函数(完成将在 SDRAM 中的一段存储区域中的数据写到 Nand flash 存储空间中);
     第二层: 为第一层主烧写函数提供支持的对 Nand flash 进行操作的页读、写,块擦除等函数;
     第三层:为第二层提供具体 Nand flash 控制器中对特殊功能寄存器进行操作的核心函数,该层也是真正的
将数据能够在 SDRAM 和 Nand flash 之间实现传送的函数。
     下面对其三层进行分述:
2.2 第三层实现说明
2.1.1 特殊功能寄存器定义
#define rNFCONF      (*(volatile unsigned int *)0x4e000000)
#define rNFCMD       (*(volatile unsigned char *)0x4e000004)           
#define rNFADDR     (*(volatile unsigned char *)0x4e000008)           
#define rNFDATA     (*(volatile unsigned char *)0x4e00000c)          
#define rNFSTAT      (*(volatile unsigned int *)0x4e000010)     
#define rNFECC        (*(volatile unsigned int *)0x4e000014)    
#define rNFECC0     (*(volatile unsigned char  *)0x4e000014)
#define rNFECC1     (*(volatile unsigned char *)0x4e000015)
#define rNFECC2     (*(volatile unsigned char *)0x4e000016)
2.1.2 操作的函数实现
1. 发送命令
#define NF_CMD(cmd)       {rNFCMD=cmd;}
2. 写入地址
#define NF_ADDR(addr)       {rNFADDR=addr;}
3. Nand Flash 芯片选中
#define NF_nFCE_L()       {rNFCONF&=~(1<<11);}
4. Nand Flash 芯片不选中
#define NF_nFCE_H()       {rNFCONF|=(1<<11);}
5. 初始化 ECC
#define NF_RSTECC()       {rNFCONF|=(1<<12);}
6. 读数据
#define NF_RDDATA()        (rNFDATA)
7. 写数据
#define NF_WRDATA(data) {rNFDATA=data;}
8. 获取 Nand Flash 芯片状态
#define NF_WAITRB()         {while(!(rNFSTAT&(1<<0)));}
0/假: 表示 Nand Flash 芯片忙状态
1/真:表示 Nand Flash 已经准备好
2.3 第二层实现说明
2.3.1 Nand Flash 初始化
void NF_Init(void)
{
      /* 设置 Nand Flash 配置寄存器, 每一位的取值见 1.3 节 */
      rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
      /* 复位外部 Nand Flash 芯片 */                 
      NF_Reset();
}
2.3.2 Nand flash 复位
static void NF_Reset(void)
{
      int i;
      NF_nFCE_L();          /* 片选 Nand Flash 芯片*/
      NF_CMD(0xFF);           /* 复位命令                */
      for(i=0;i<10;i++);     /* 等待 tWB = 100ns.     */
      NF_WAITRB();       /* wait 200~500us;          */
      NF_nFCE_H();         /* 取消 Nand Flash 选中*/
}
2.3.3 获取 Nand flash ID
返回值为 Nand flash 芯片的 ID 号
unsigned short  NF_CheckId(void)
{
      int i;
      unsigned short id;
      NF_nFCE_L();                /* 片选 Nand Flash 芯片*/
      NF_CMD(0x90);             /* 发送读 ID 命令到 Nand Flash 芯片 */
      NF_ADDR(0x0);             /* 指定地址 0x0,芯片手册要求                     */
      for(i=0;i<10;i++);             /* 等待 tWB = 100ns.             */
      id=NF_RDDATA()<<8;  /* 厂商 ID(K9S1208V:0xec)   */
      id|=NF_RDDATA();        /* 设备 ID(K9S1208V:0x76)  */
      NF_nFCE_H();                 /* 取消 Nand Flash 选中*/
      return id;
}
2.3.4 Nand flash 写入
以页为单位写入.
参数说明:block  块号
              page   页号
              buffer  指向内存中待写入 Nand flash 中的数据起始位置
返回值:     0:写错误
             1:写成功
static int NF_WritePage(unsigned int block, unsigned int page, unsigned char *buffer)
{
      int i;
      unsigned int blockPage = (block<<5)+page;
      unsigned char *bufPt = buffer;
      NF_RSTECC();    /* 初始化 ECC              */
      NF_nFCE_L();     /* 片选 Nand Flash 芯片*/
      NF_CMD(0x0);    /* 从 A 区开始写               */
      NF_CMD(0x80);  /* 写第一条命令                 */
      NF_ADDR(0);     /*  A0~A7 位(Column Address)   */
      NF_ADDR(blockPage&0xff);   /* A9­A16, (Page Address) */
      NF_ADDR((blockPage>>8)&0xff);   /* A17­A24, (Page Address) */
      NF_ADDR((blockPage>>16)&0xff);  /* A25,  (Page Address) */
      for(i=0;i<512;i++)
      {
           NF_WRDATA(*bufPt++);            /* 写一个页 512 字节到 Nand Flash 芯片 */
      } 
      /*
      * OOB 一共 16 Bytes, 每一个字节存放什么由程序员自己定义, 通常,
      * 我们在 Byte0­Byte2 存 ECC 检验码. Byte6 存放坏块标志.
      */
      seBuf[0]=rNFECC0;  /* 读取 ECC 检验码 0 */
      seBuf[1]=rNFECC1;  /* 读取 ECC 检验码 1 */
      seBuf[2]=rNFECC2;  /* 读取 ECC 检验码 2 */
      seBuf[5]=0xff;         /* 非坏块标志              */
      for(i=0;i<16;i++)
      {
           NF_WRDATA(seBuf[i]); /* 写该页的 OOB 数据块 */
      } 
      NF_CMD(0x10);   /* 结束写命令 */
      /* 等待 Nand Flash 处于准备状态 */  
      for(i=0;i<10;i++);  
      NF_WAITRB();   
      /* 发送读状态命令给 Nand Flash  */
      NF_CMD(0x70);
      for(i=0;i<3;i++);
      if (NF_RDDATA()&0x1)
      {    /*如果写有错, 则标示为坏块                 */
           NF_nFCE_H();  /* 取消 Nand Flash 选中*/
           NF_MarkBadBlock(block);
           return 0;
      } else { /* 正常退出 */
           NF_nFCE_H(); /* 取消 Nand Flash 选中*/
           return 1;
      }
}
2.3.5 Nand flash 读取
参数说明:block:块号
               page:页号
               buffer:指向将要读取到内存中的起始位置
返回值:1:读成功
             0:读失败
static int NF_ReadPage(unsigned int block, unsigned int page, unsigned char *buffer)
{
      int i;
      unsigned int blockPage;
      unsigned char ecc0, ecc1, ecc2;
      unsigned char *bufPt=buffer;
      unsigned char se[16];  
      page=page&0x1f;
      blockPage=(block<<5)+page;
      NF_RSTECC();    /* 初始化 ECC              */   
      NF_nFCE_L();      /* 片选 Nand Flash 芯片*/
      NF_CMD(0x00);   /* 从 A 区开始读               */
      NF_ADDR(0);      /*  A0~A7 位(Column Address)   */
      NF_ADDR(blockPage&0xff);    /* A9­A16, (Page Address) */
      NF_ADDR((blockPage>>8)&0xff);    /* A17­A24, (Page Address) */
      NF_ADDR((blockPage>>16)&0xff);  /* A25,  (Page Address) */
      /* 等待 Nand Flash 处于再准备状态 */ 
      for(i=0;i<10;i++);
      NF_WAITRB();    /*等待 tR(max 12us) */
      /* 读整个页, 512 字节                      */
      for(i=0;i<512;i++)
      {
           *bufPt++=NF_RDDATA();
      }
      /* 读取 ECC 码 */
      ecc0=rNFECC0;
      ecc1=rNFECC1;
      ecc2=rNFECC2;
      /* 读取该页的 OOB 块 */
      for(i=0;i<16;i++)
      {
           se[i]=NF_RDDATA();
      }
      NF_nFCE_H();    /* 取消 Nand Flash 选中*/
      /* 校验 ECC 码, 并返回 */
      if(ecc0==se[0] && ecc1==se[1] && ecc2==se[2])
             return 1;
      else
            return 0; 
}
2.3.6 Nand flash 标记坏块
如果是坏块, 通过写 OOB 块的 Byte6 把该块标记为坏块。
参数说明:block 块号
返回值:1:ok,成功完成标记。
             0:表示写 OOB 块正确.
static int NF_MarkBadBlock(unsigned int block)
{
      int i;
      unsigned int blockPage=(block<<5);
      seBuf[0]=0xff;
      seBuf[1]=0xff;   
      seBuf[2]=0xff;   
      seBuf[5]=0x44;   /* 设置坏块标记 */
      NF_nFCE_L();   /* 片选 Nand Flash 芯片*/
      NF_CMD(0x50);   /* 从 C 区开始写             */
      NF_CMD(0x80);   /* 发送编程命令, 让 Nand Flash 处理写状态 */
      NF_ADDR(0x0);  /*  A0~A7 位(Column Address)   */
      NF_ADDR(blockPage&0xff);   /* A9­A16, (Page Address) */
      NF_ADDR((blockPage>>8)&0xff);   /* A17­A24, (Page Address) */
      NF_ADDR((blockPage>>16)&0xff);  /* A25,  (Page Address) */
      /* 写 OOB 数据块 */
      for(i=0;i<16;i++)
      {
           NF_WRDATA(seBuf[i]);
      }
      NF_CMD(0x10);    /* 结束写命令 */
      /* 等待 NandFlash 准备好 */
      for(i=0;i<10;i++);  /* tWB = 100ns.  */
      NF_WAITRB();
      /*读 NandFlash 的写状态 */ 
      NF_CMD(0x70);   
      for(i=0;i<3;i++);  /* twhr=60ns  */
      if (NF_RDDATA()&0x1)
      {
                     NF_nFCE_H(); /* 取消 Nand Flash 选中*/
                     return 0;
        } else {
                     NF_nFCE_H(); /* 取消 Nand Flash 选中*/
      }
      return 1;
}
2.3.7 Nand Flash 检查坏块
检查指定块是否是坏块.
参数说明:block:块号
返回值:1:指定块是坏块
             0:指定块不是坏块。
static int NF_IsBadBlock(U32 block)
{
      int i;
      unsigned int blockPage;
      U8 data;
      blockPage=(block<<5);
      NF_nFCE_L();         /* 片选 Nand Flash 芯片*/
      NF_CMD(0x50);      /* Read OOB 数据块 */
      NF_ADDR(517&0xf);  /* A0~A7 位(Column Address)   */
      NF_ADDR(blockPage&0xff); /* A9­A16, (Page Address) */
      NF_ADDR((blockPage>>8)&0xff);    /* A17­A24, (Page Address) */
      NF_ADDR((blockPage>>16)&0xff);  /* A25,  (Page Address) */
      /* 等待 NandFlash 准备好 */
      for(i=0;i<10;i++); /* wait tWB(100ns)  */
      NF_WAITRB();
      /* 读取读出值 */
      data=NF_RDDATA();
      NF_nFCE_H();   /* 取消 Nand Flash 选中*/
      /* 如果 data 不为 0xff 时, 表示该块是坏块 */
      if(data != 0xff)
           return 1;
      else
           return 0;   
}
2.3.8 擦除指定块中数据
参数说明:block 块号
返回值:0:擦除错误。(若是坏块直接返回 0;若擦除出现错误则标记为坏块然后返回 0)
             1:成功擦除。
static int NF_EraseBlock(unsigned int block)
{
      unsigned int blockPage=(block<<5);
      int i;
      /* 如果该块是坏块, 则返回 */
      if(NF_IsBadBlock(block))
             return 0;
      NF_nFCE_L();      /* 片选 Nand Flash 芯片*/
      NF_CMD(0x60);   /* 设置擦写模式                  */
      NF_ADDR(blockPage&0xff);   /* A9­A16, (Page Address) , 是基于块擦*/
      NF_ADDR((blockPage>>8)&0xff);    /* A17­A24, (Page Address) */
      NF_ADDR((blockPage>>16)&0xff);  /* A25, (Page Address) */
      NF_CMD(0xd0);   /* 发送擦写命令, 开始擦写 */
      /* 等待 NandFlash 准备好 */
      for(i=0;i<10;i++); /* tWB(100ns) */
      NF_WAITRB();
      /* 读取操作状态                   */
      NF_CMD(0x70);
      if (NF_RDDATA()&0x1)
      {
                      NF_nFCE_H(); /* 取消 Nand Flash 选中*/
                      NF_MarkBadBlock(block); /* 标记为坏块 */
                      return 0;
      }  else  {
                      NF_nFCE_H(); /* 取消 Nand Flash 选中*/
                      return 1;
      }
}
2.4 第一层的实现
2.4.1 NandFlash 烧写主函数说明
参数说明: block 块号
                 srcAddress SDRAM 中数据起始地址
                 fileSize 要烧写的数据长度
返回值: 无
void K9S1208_Program(unsigned int block, unsigned int srcAddress, unsigned int fileSize)
{
         int  i;
         int  programError=0;
         U32  blockIndex;
         U8  *srcPt,  *saveSrcPt;
         srcPt=(U8 *)srcAddress; /* 文件起始地址 */
         blockIndex = block; /* 块号 */
     while(1)
     {
                 saveSrcPt=srcPt;
                /* 如果当前块是坏块,  跳过当前块 */
                 if(NF_IsBadBlock(blockIndex))
                 {
                          blockIndex++;   /* 到下一个块 */
                          continue;
                }
                /* 在写之前, 必须先擦除, 如果擦除不成功, 跳过当前块 */
                if(!NF_EraseBlock(blockIndex))
                {
                            blockIndex++;  /* 到下一个块 */
                            continue;
                }
     
                /* 写一个块, 一块有 32 页 */
                for(i=0;i<32;i++)
                {
                          /* 写入一个页, 如果出错, 停止写当前块 */
                          if(!NF_WritePage(blockIndex,i,srcPt))
                          {
                                 programError=1;
                                 break;
                          }
                          /* 如果操作正常, 文件的写位置加上 1 页偏移,到下一页的起始位置 */
                          srcPt+=512;
                          /* 如果写地址没有超过文件长度, 继续; 超出则终止写 */
                           if((U32)srcPt>=(srcAddress+fileSize))
                                   break;
               }
                /* 如果写一个块时, 其中某一页写失败, 则把写地址恢复写该块之前, 并跳过当前块 */
                 if(programError==1)
                 {
                           blockIndex++;
                           srcPt=saveSrcPt;
                           programError=0;
                           continue;
                 }
                 /* 如果写地址没有超过文件长度, 继续; 超出则终止写 */
                 if((U32)srcPt >= (srcAddress+fileSize))
                           break;
                 /* 如果正常写成功, 继续写下一个块 */
                 blockIndex++;
     }
}

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
当你觉得为时已晚的时候,恰恰是最早的时候!
推荐文章
最近访客