本原理:在 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 pillow库安装报错

    报错信息: D:\pythontest\duanxinhongzha>pip3 install pillowCollecting pillow Could not find a version ...

  2. NOIp2018集训test-10-15 (bike day1)

    B 君的第一题 求斐波那契数列模n的循环节. 1.暴力bsgs,毕姥爷好像说循环节最大是6*n还是多少的,反之比较小,直接bsgs这题是可以过的.但是我非常蠢重载运算符的时候把相等返回成了小于,然后根 ...

  3. NX二次开发-UFUN所有对象类型的宏定义

    /**************************************************************************** Copyright (c) 2010 Sie ...

  4. [Nowcoder] 数数字

    题意:...咕咕懒得写了. 思路: 裸的记搜... #include <bits/stdc++.h> using namespace std; #define ll long long m ...

  5. hdu多校第六场1005 (hdu6638) Snowy Smilel 线段树/区间最大和

    题意: 给定一个矩阵,矩阵上有若干点,每个点有正或负的权值,找一个方框框住一些点使得方框中点权值最大. 题解: 离散化横纵坐标,容易将这个问题转化为在矩阵上求最大和子矩阵的问题. 普通的n*n的矩阵的 ...

  6. Spring-Security (学习记录七)--实现FilterInvocationSecurityMetadataSource的类将无法切入声明式事物

    目录 1 查看继承关系 2 说明 3 查看源码: 实现了FilterInvocationSecurityMetadataSource 的类将无法切入声明式事物. 原因: 1 查看继承关系 先查看Fil ...

  7. xml初步,DTD和Schema约束

    XML 可扩展的标记语言(!!!可扩展) 作用 1.存放数据 2.配置文件 语法 文档声明 <?xml version="1.0" encoding="UTF-8& ...

  8. uoj33 【UR #2】树上GCD

    题目 大致是长剖+\(\rm dsu\ on\ tree\)的思想 先做一个转化,改为对于\(i\in[1,n-1]\)求出有多少个\(f(u,v)\)满足\(i|f(u,v)\),这样我们最后再做一 ...

  9. spring在普通类中获取session和request

    在使用spring时,经常需要在普通类中获取session,request等对像.比如一些AOP拦截器类,在有使用struts2时,因为struts2有一个接口使用org.apache.struts2 ...

  10. JS函数 有参数的函数 参数可以多个,根据需要增减参数个数。参数之间用(逗号,)隔开

    有参数的函数 上节中add2()函数不能实现任意指定两数相加.其实,定义函数还可以如下格式: function 函数名(参数1,参数2) { 函数代码 } 注意:参数可以多个,根据需要增减参数个数.参 ...