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;}
- Nand Flash 芯片选中
#define NF_nFCE_L() {rNFCONF&=~(1<<11);}
- Nand Flash 芯片不选中
#define NF_nFCE_H() {rNFCONF|=(1<<11);}
- 初始化 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); /* A9A16, (Page Address) */
NF_ADDR((blockPage>>8)&0xff); /* A17A24, (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, 每一个字节存放什么由程序员自己定义, 通常,
* 我们在 Byte0Byte2
存 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); /* A9A16, (Page Address) */
NF_ADDR((blockPage>>8)&0xff); /*
A17A24, (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); /* A9A16, (Page
Address) */ NF_ADDR((blockPage>>8)&0xff); /* A17A24, (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); /* A9A16, (Page Address) */
NF_ADDR((blockPage>>8)&0xff); /* A17A24, (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); /*
A9A16, (Page Address) , 是基于块擦*/ NF_ADDR((blockPage>>8)&0xff); /* A17A24, (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 烧写程序原理及结构的更多相关文章
- Arduino 003 Ubuntu(Linux) 系统下,如何给板子烧写程序
Ubuntu/Linux 系统下,如何给Arduino板子烧写程序 使用的虚拟机软件:VMware 11 我的Ubuntu系统:Ubuntu 14.04.10 TLS Arduino 软件的版本:Ar ...
- NOR Flash擦写和原理分析
NOR Flash擦写和原理分析 1. NOR FLASH 的简单介绍 NOR FLASH 是很常见的一种存储芯片,数据掉电不会丢失.NOR FLASH支持Execute On Chip,即程序可以直 ...
- NOR Flash擦写和原理分析 (一)
1. NOR FLASH 的简单介绍 NOR FLASH 是很常见的一种存储芯片,数据掉电不会丢失.NOR FLASH支持Execute On Chip,即程序可以直接在FLASH片内执行(这意味着存 ...
- 【转】NOR Flash擦写和原理分析
1. NOR FLASH 的简单介绍 NOR FLASH 是很常见的一种存储芯片,数据掉电不会丢失.NOR FLASH支持Execute On Chip,即程序可以直接在FLASH片内执行(这意味着存 ...
- 转载:NOR Flash擦写和原理分析
1. NOR FLASH 的简单介绍 NOR FLASH 是很常见的一种存储芯片,数据掉电不会丢失.NOR FLASH支持Execute On Chip,即程序可以直接在FLASH片内执行(这意味着存 ...
- GD32电压不足时烧写程序导致程序运行异常的解决方法
一直使用的GD32F450前段时间遇到这样一个问题,当使用J-Link供电给板子烧写程序之后,程序运行缓慢,就像运行在FLASH高速部分之外一样,但是如果使用外部供电烧写,就不会出现这个问题,而且一旦 ...
- 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 ...
- Linux下USB烧写uImage kernel
Linux下USB烧写uImage kernel 1.启动开发板,进入u-boot:(如果开发板中没有系统,可以通过用SD卡方式启动开发板进入) U-Boot 2011.06 (Mar 19 ...
- xilinx Vivado的使用详细介绍(2):创建工程、添加文件、综合、实现、管脚约束、产生比特流文件、烧写程序、硬件验证
xilinx Vivado的使用详细介绍(2):创建工程.添加文件.综合.实现.管脚约束.产生比特流文件.烧写程序.硬件验证 Author:zhangxianhe 新建工程 打开Vivado软件,直接 ...
随机推荐
- thinkphp 原生分页
paginate() 是有三个参数: 第一个参数是 $listRows [int],也就是当前的页数 第二个参数是 $simple [boolean], 是否简洁模式或者总记录数 第三个参数是 $co ...
- [JZOJ 5860] 荒诞
思路: 头皮发麻的操作... 理解一下题意会发现:排名为\(i\)的前缀正好是第\(i\)个前缀. 所以问题就变成了求\(1->len\)的平方和,注意取模即可. #include <bi ...
- [luogu 4389] 付公主的背包
题意:求一个较大的多重背包对于每个i的方案数,答案对998244353取模. 思路: 生成函数: 对于一个\(V\) 设: \(f(x) = \sum_{i=0}^{oo} x ^ {V * i} = ...
- 微信-小程序-开发文档-服务端-接口调用凭证:auth.getAccessToken
ylbtech-微信-小程序-开发文档-服务端-接口调用凭证:auth.getAccessToken 1.返回顶部 1. auth.getAccessToken 本接口应在服务器端调用,详细说明参见服 ...
- c++-文件分离
实现文件分离 1.头文件中不要使用using namespace,由于c++编译的特性,由于初学还没深入了解,不做具体编译的解释 2.由于没有了命名空间,所以string定义要写成std::strin ...
- TVS(瞬态抑制二极管)、Schottky(肖特基二极管)、Zener (齐纳二极管,也称稳压二极管)主要特点及区别和使用
1. 简单介绍 TVS TVS(Transient Voltage Suppressor)二极管,又称为瞬态抑制二极管,是普遍使用的一种新型高效电路保护器件,它具有极快的响应时间(亚纳秒级)和相当高的 ...
- sklearn中模型抽取
特征抽取sklearn.feature_extraction 模块提供了从原始数据如文本,图像等众抽取能够被机器学习算法直接处理的特征向量. 1.特征抽取方法之 Loading Features fr ...
- 【POJ】1426 Find The Multiple
题目链接:http://poj.org/problem?id=1426 题意:给定一个正整数n,找一个比n大且能只由01构成的且能够被n整除的数. 题解:这个就是在后面添0和添1小心试探.一定要是添0 ...
- 织梦自增函数[field:global name=autoindex/]常见用法
看来不少朋友需要不了解这个自增函数的用法,在这里我列举一些常见的写法以及作用. [field:global name=autoindex/] !--普通打印递增的数字-- [field:globa ...
- javascript面向对象编程笔记(基本数据类型,数组,循环及条件表达式)
javascript面向对象编程指南 最近在看这本书,以下是我的笔记,仅供参考. 第二章 基本数据类型.数组.循环及条件表达式 2.1 变量 区分大小写 2.3 基本数据类型 数字:包括浮点数与整数 ...