本原理:在 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. js 彻底理解回调函数

    一.前奏 在谈回调函数之前,先看下下面两段代码: 不妨猜测一下代码的结果. function say (value) { alert(value); } alert(say); alert(say(' ...

  2. Spring-Security (学习记录三)--读取数据库中的用户和角色

    目录 1.先将hibernate的环境整合进来 2.创建一个数据库security,执行security.sql 3.修改spring-security.xml,采用数据库的方式读取用户跟角色 4.u ...

  3. 转-vector与list的区别

    转自:C++ vector和list的区别 数据结构的区别 vector vector与数组类似,拥有一段连续的内存空间,并且起始地址不变.便于随机访问,时间复杂度为O(1),但因为内存空间是连续的, ...

  4. 在jsp页面直接读取mysql数据库显示数据

    闲来无事,学学java,虽说编程语言相通,但是接触一门新知识还是有些疑惑,边学边记录,方便以后温故. 直接给出代码: <%@page import="java.sql.ResultSe ...

  5. Redhat 7.0 安装桌面环境

    1.安装桌面环境组件 #yum groupinstall "Server with GUI" 2.切换到图形界面 #startx 3.设置启动模式为图形界面 #rm /etc/sy ...

  6. postgresql+java数据类型对照

    网上搜了很多都不理想,这里总结的一部分是官网的文档,一部分是网上的,大体没问题 PostgreSQL™                 Java SE 8 date            LocalD ...

  7. C++类成员变量多用指针不用对象

    如A类的成员变量含有B类的对象,那么每个A类对象产生或拷贝都要产生一次B类对象的构造或者拷贝,对象占的空间比较大,对象拷贝比较消耗内存. 如果换成B类的指针,A类对象拷贝,也只会产生4个字节或者8个字 ...

  8. Mysql优化-索引

    1. 索引的本质 MySQL官方对索引的定义为:索引是帮助MySQL高效获取数据的数据结构. 数据库查询是数据库的最主要功能之一.我们都希望查询数据的速度尽可能的快,因此 数据库系统的设计者会从查询算 ...

  9. Linux queue.h之TAILQ队列分析

    转自 这两天想看看memcached的实现,所以先学习了libevent,使用起来还是比较简单的,其实是对select/poll/kqueue等的封装,学习libevent过程中又遇到了linux下队 ...

  10. 【学术篇】SDOI2008 仪仗队

    Part1:传送门&吐槽 水题... 然而由于线筛里面的\(j\)打成了\(i\)然后就不能1A了OvO Part2:题目分析 这个正方形是对称的... 而且很显然对角线上只有一个点会被看到. ...