本原理:在 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;}

  1. Nand Flash 芯片选中

#define NF_nFCE_L()             {rNFCONF&=~(1<<11);}

  1. Nand Flash 芯片不选中

#define NF_nFCE_H()             {rNFCONF|=(1<<11);}

  1. 初始化 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)

{

} else {

}

NF_nFCE_H(); /* 取消
Nand Flash 选中*/ return 0;

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)

{

}  else  {

}

}

NF_nFCE_H();
/* 取消
Nand Flash 选中*/
NF_MarkBadBlock(block); /* 标记为坏块 */
return 0;

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

}

}

ADS 下 flash 烧写程序原理及结构的更多相关文章

  1. Arduino 003 Ubuntu(Linux) 系统下,如何给板子烧写程序

    Ubuntu/Linux 系统下,如何给Arduino板子烧写程序 使用的虚拟机软件:VMware 11 我的Ubuntu系统:Ubuntu 14.04.10 TLS Arduino 软件的版本:Ar ...

  2. NOR Flash擦写和原理分析

    NOR Flash擦写和原理分析 1. NOR FLASH 的简单介绍 NOR FLASH 是很常见的一种存储芯片,数据掉电不会丢失.NOR FLASH支持Execute On Chip,即程序可以直 ...

  3. NOR Flash擦写和原理分析 (一)

    1. NOR FLASH 的简单介绍 NOR FLASH 是很常见的一种存储芯片,数据掉电不会丢失.NOR FLASH支持Execute On Chip,即程序可以直接在FLASH片内执行(这意味着存 ...

  4. 【转】NOR Flash擦写和原理分析

    1. NOR FLASH 的简单介绍 NOR FLASH 是很常见的一种存储芯片,数据掉电不会丢失.NOR FLASH支持Execute On Chip,即程序可以直接在FLASH片内执行(这意味着存 ...

  5. 转载:NOR Flash擦写和原理分析

    1. NOR FLASH 的简单介绍 NOR FLASH 是很常见的一种存储芯片,数据掉电不会丢失.NOR FLASH支持Execute On Chip,即程序可以直接在FLASH片内执行(这意味着存 ...

  6. GD32电压不足时烧写程序导致程序运行异常的解决方法

    一直使用的GD32F450前段时间遇到这样一个问题,当使用J-Link供电给板子烧写程序之后,程序运行缓慢,就像运行在FLASH高速部分之外一样,但是如果使用外部供电烧写,就不会出现这个问题,而且一旦 ...

  7. STM32用JLINK 烧写程序时出现NO Cortex-m device found in JTAG chain现象和解决方案

    现象 CPU: STM32107VC 用JLINK 烧写程序时出现NO Cortex-m device found in JTAG chain 如图无法查找到硬件就是CPU 提示1:NO Cortex ...

  8. Linux下USB烧写uImage kernel

    Linux下USB烧写uImage kernel   1.启动开发板,进入u-boot:(如果开发板中没有系统,可以通过用SD卡方式启动开发板进入)   U-Boot 2011.06 (Mar 19 ...

  9. xilinx Vivado的使用详细介绍(2):创建工程、添加文件、综合、实现、管脚约束、产生比特流文件、烧写程序、硬件验证

    xilinx Vivado的使用详细介绍(2):创建工程.添加文件.综合.实现.管脚约束.产生比特流文件.烧写程序.硬件验证 Author:zhangxianhe 新建工程 打开Vivado软件,直接 ...

随机推荐

  1. DELPHI 异形窗体

    一定有很多人看到过一些奇形怪状的窗体,例如一些屏幕精灵.其实实现起来非常容易,做到三点就好啦.下面我使用Delphi做了一个VCL控件(TBmpShape),你只需要指定一幅图片就可以将窗体变成你的图 ...

  2. lua之table|模块|包

    一.table table是   Lua的一种数据结构用来帮助我们创建不同的数据类型,如:数字.字典等. Lua table使用关联型数组,你可以用任意类型的值来作数组的索引,但这个值不能是   ni ...

  3. C++学习 | C++ Implement的使用 | 消除 warning C4251 | 精简库接口

      在编写C++动态库的过程中,我们常常会听到某个要求:请隐藏动态库头文件里类接口里的成员变量!或者自己在编写动态库时,突然意识到自己好像让调用者看到的信息太多了,而这些信息根本无需被调用者看到,往往 ...

  4. flutter 修饰盒子

    decoration: BoxDecoration( borderRadius: BorderRadius.circular(), //圆角 gradient: RadialGradient( col ...

  5. iOS开发UIResponder简介API

    #import <Foundation/Foundation.h> #import <UIKit/UIKitDefines.h> #import <UIKit/UIEve ...

  6. shell得到两个文件的差集

    第一种方法: grep: [root@hdp05 src]# grep -vxFf leadering.txt leaderNum.txt [root@hdp05 src]# cat leaderin ...

  7. 20140422 ALT+F8 四个强制类型转换

    一.static_cast, dynamic_cast, const_cast http://www.cnblogs.com/chio/archive/2007/07/18/822389.html h ...

  8. 20130324 LBP CSLBP 全局存储区 局部存储区 char c[]=”hello world”和char *str=”hello world”的区别

    1.LBP and CSLBP 2.再论char c[]=”hello world”和char *str=”hello world”的区别 /**************代码1************ ...

  9. scrapy的使用-scrapy shell

    进入     该目录下执行scrapy shell 文件, 在命令行可执行该文件中链接的xpath语法,和BeautifulSoup语法.

  10. 调用存储过程取到数据通过NPOI存到Excel中

        //调用  public ActionResult GenerateExcel() {             DataTable headerTable = new DataTable(); ...