本原理:在 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. Python 爬虫-抓取小说《盗墓笔记-怒海潜沙》

    最近想看盗墓笔记,看了一下网页代码,竟然不是js防爬虫,那就用简单的代码爬下了一节: """ 爬取盗墓笔记小说-七星鲁王宫 """ from ...

  2. HDU1501-Zipper-字符串的dfs

    Given three strings, you are to determine whether the third string can be formed by combining the ch ...

  3. Lombok 常用注解

    Lombok Lombok 能以简单的注解形式来简化 java 代码,提高开发人员的开发效率.例如开发中经常需要写的 javaBean,都需要花时间去添加相应的 getter/setter,也许还要去 ...

  4. cors是什么?django中怎么解决这个问题?

    跨域资源共享(CORS) 是一种机制. 当一个资源从与该资源本身所在的服务器不同的域.协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求.(CORS是一种可以让你实现跨站点请求并同时阻止恶意 ...

  5. mysql实现访问审计

    mysql的连接首先都是通过init_connect初始化,然后连接到实例. 我们利用这一点,通过在init_connect的时候记录下用户的thread_id,用户名和用户地址实现db的访问审计功能 ...

  6. netty 文件传输

    FileServer package com.zhaowb.netty.ch13_1; import io.netty.bootstrap.ServerBootstrap; import io.net ...

  7. mysql 数据库基本命令

    停止mysql服务:net stop mysql      //管理员方式运行 启动mysql服务:net start mysql 进入数据库:mysql -u root -p 查看数据库:show ...

  8. arm-linux-gcc 的使用

    1. 编译 C 文件,生成 elf 可执行文件 h1.c 源文件 #include <stdio.h> void hellofirst(void) { printf("The f ...

  9. K8S之WebApi部署

    转载声明 本文转自:ASP.NET Core on K8S学习初探(3)部署API到K8S 1.下载镜像 docker pull edisonsaonian/k8s-demo 因为是测试流程,直接把文 ...

  10. c# 使用Expression 生成sql

    使用Expression 生成sql  update语句的时候遇到了个问题 ,Expression<Action<T>>  la   这个委托里面老获取不到 引用类型的值,甚至 ...