龙空技术网

Linux系统移植之—Nand flash驱动编写与移植,学Linux的先收藏

IT百科大学堂 863

前言:

目前我们对“pythonlinuxarm”大体比较重视,各位老铁们都需要学习一些“pythonlinuxarm”的相关内容。那么小编同时在网上汇集了一些关于“pythonlinuxarm””的相关资讯,希望姐妹们能喜欢,朋友们快快来了解一下吧!

Linux系统要跑起来,除了上几章节讲到的uboot、kernel、文件系统的移植,还有一个不可缺少的——Nand flash驱动的移植,搞linux的或者android底层驱动的先收藏,以后工作中会遇到的。

说明:本人近期会陆续上传IT编程相关的资料和视频教程,可以关注一下互相交流:C C++ Java python linux ARM 嵌入式 物联网等。想学编程的朋友进入主页即可看到相关教程和资料。

Nand flash的工作原理

1.1 Nand flash 芯片工作原理

1.1.1 芯片内部存储布局及存储操作特点

1.1.2 重要芯片引脚功能

1.1.3 寻址方式

1.1.4 Nand flash 主要内设命令详细介绍

1.2 Nand Flash 控制器工作原理

1.2.1 Nand Flash 控制器特性

1.2.2 Nand Flash 控制器工作原理

1.3 Nand flash 控制器中特殊功能寄存器详细介绍

1.4 Nand Flash 控制器中的硬件 ECC 介绍

1.4.1 ECC 产生方法

1.4.2 ECC 生成器工作过程

1.4.3 ECC 的运用

2 在 ADS 下 flash 烧写程序

2.1 ADS 下 flash 烧写程序原理及结构

2.2 第三层实现说明

2.1.1 特殊功能寄存器定义

2.1.2 操作的函数实现

2.3 第二层实现说明

2.3.1 Nand Flash 初始化

2.3.3 获取 Nand flash ID

2.3.4 Nand flash 写入

2.3.5 Nand flash 读取

2.3.6 Nand flash 标记坏块

2.3.7 Nand Flash 检查坏块

2.3.8 擦除指定块中数据

2.4 第一层的实现

1 Nand flash 工作原理

S3C2410 板的 Nand Flash 支持由两部分组成:Nand Flash 控制器(集成在 S3C2410 CPU)和 Nand Flash 存储

芯片(K9F1208U0B)两大部分组成。当要访问 Nand Flash 中的数据时,必须通过 Nand Flash 控制器发送命

令才能完成。所以, Nand Flash 相当于 S3C2410 的一个外设,而不位于它的内存地址区.

1.1 Nand flash 芯片工作原理

Nand flash 芯片型号为 Samsung K9F1208U0B,数据存储容量为 64MB,采用块页式存储管理。8 个 I/O

引脚充当数据、地址、命令的复用端口。

1.1.1 芯片内部存储布局及存储操作特点

一片 Nand flash 为一个设备(device), 其数据存储分层为:

1 设备(Device) = 4096 块(Blocks)

1 块(Block) = 32 页/行(Pages/rows) ;页与行是相同的意思,叫法不一样

1 块(Page) = 528 字节(Bytes) = 数据块大小(512Bytes) + OOB 块大小(16Bytes)

在每一页中,最后 16 个字节(又称 OOB)用于 Nand Flash 命令执行完后设置状态用,剩余 512 个字节又

分为前半部分和后半部分。可以通过 Nand Flash 命令 00h/01h/50h 分别对前半部、后半部、OOB 进行定位通过

Nand Flash 内置的指针指向各自的首地址。

存储操作特点:

1. 擦除操作的最小单位是块。

2. Nand Flash 芯片每一位(bit)只能从 1 变为 0,而不能从 0 变为 1,所以在对其进行写入操作之前要一定将相应

块擦除(擦除即是将相应块得位全部变为 1).

3. OOB 部分的第六字节(即 517 字节)标志是否是坏块,如果不是坏块该值为 FF,否则为坏块。

4. 除 OOB 第六字节外,通常至少把 OOB 的前 3 个字节存放 Nand Flash 硬件 ECC 码(关于硬件 ECC 码请参看

Nandflash 控制器一节).

1.1.2 重要芯片引脚功能

I/O0­I/O7:复用引脚。可以通过它向 nand flash 芯片输入数据、地址、nand flash 命令以及输出数据和操作

状态信息。

CLE(Command Latch Enable): 命令锁存允许

ALE(Address Lactch Enable): 地址锁存允许

­CE: 芯片选择

­RE: 读允许

­WE: 写允许

­WP: 在写或擦除期间,提供写保护

R/­B: 读/忙输出

1.1.3 寻址方式

Samsung K9F1208U0B Nand Flash 片内寻址采用 26 位地址形式。从第 0 位开始分四次通过 I/O0-I/O7 进行

传送,并进行片内寻址。具体含义如下:

0-7 位:字节在上半部、下半部及 OOB 内的偏移地址

8 位:值为 0 代表对一页内前 256 个字节进行寻址

值为 1 代表对一页内后 256 个字节进行寻址

9-13 位:对页进行寻址 14-25 位:对块进行寻址

当传送地址时,从位 0 开始

1.1.4 Nand flash 主要内设命令详细介绍

Nand Flash 命令执行是通过将命令字送到 Nand Flash 控制器的命令寄存器来执行。

Nand Flash 的命令是分周期执行的,每条命令都有一个或多个执行周期,每个执行周期都有相映代码表示该周

期将要执行的动作。

主要命令有:Read 1、Read 2、Read ID、Reset、Page Program、Block Erase、Read Status。

详细介绍如下:

1. Read 1:

功能:表示将要读取 Nand flash 存储空间中一个页的前半部分,并且将内置指针定位到前半部分的第一个字节。

命令代码:00h

2. Read 2:

功能:表示将要读取 Nand flash 存储空间中一个页的后半部分,并且将内置指针定位到后半部分的第一个字节。

命令代码:01h

3. Read ID:

功能:读取 Nand flash 芯片的 ID 号

命令代码:90h

4. Reset:

功能:重启芯片。

命令代码:FFh

5. Page Program:

功能:对页进行编程命令, 用于写操作。

命令代码:首先写入 00h(A 区)/01h(B 区)/05h(C 区), 表示写入那个区; 再写入 80h 开始编程模式(写入模式),接

下来写入地址和数据; 最后写入 10h 表示编程结束.

6. Block Erase

功能:块擦除命令。

命令代码:首先写入 60h 进入擦写模式,然后输入块地址; 接下来写入 D0h, 表示擦写结束.

7. Read Status

功能:读取内部状态寄存器值命令。

命令代码:70h

1.2 Nand Flash 控制器工作原理

对 Nand Flash 存储芯片进行操作, 必须通过 Nand Flash 控制器的专用寄存器才能完成。所以,不能对 Nand

Flash 进行总线操作。而 Nand Flash 的写操作也必须块方式进行。对 Nand Flash 的读操作可以按字节读取。

1.2.1 Nand Flash 控制器特性

1. 支持对 Nand Flash 芯片的读、检验、编程控制

2. 如果支持从 Nand Flash 启动, 在每次重启后自动将前 Nand Flash 的前 4KB 数据搬运到 ARM 的内部 RAM 中

3. 支持 ECC 校验

1.2.2 Nand Flash 控制器工作原理

Nand Flash 控制器在其专用寄存器区(SFR)地址空间中映射有属于自己的特殊功能寄存器,就是通过将 Nand

Flash 芯片的内设命令写到其特殊功能寄存器中,从而实现对 Nand flash 芯片读、检验和编程控制的。特殊功能

寄存器有:NFCONF、NFCMD、NFADDR、NFDATA、NFSTAT、NFECC。寄存详细说明见下一节。

1.3 Nand flash 控制器中特殊功能寄存器详细介绍

1. 配置寄存器(NFCONF)功能:用于对 Nand Flash 控制器的配置状态进行控制。

在地址空间中地址:0x4E000000,其中:

Bit15:Nand Flash 控制器使能位,置 0 代表禁止 Nand Flash 控制器,置 1 代表激活 Nand Flash 控制器;

要想访问 Nand Flash 芯片上存储空间,必须激活 Nand Flash 控制器。在复位后该位自动置 0,因此在初始化时

必须将该位置为 1。

Bit12:初始化 ECC 位,置 1 为初始化 ECC;置 0 为不初始化 ECC。

Bit11:Nand Flash 芯片存储空间使能位,置 0 代表可以对存储空间进行操作;置 1 代表禁止对存储空

间进行操作。在复位后,该位自动为 1。

Bit10-8:TACLS 位。根据此设定 CLE&ALE 的周期。TACLS 的值范围在 0-7 之间。

Bit6-4、2-0 分别为:TWRPH0、TWRPH1 位。设定写操作的访问周期。其值在 0-7 之间。

2. 命令寄存器(NFCMD)

功能:用于存放 Nand flash 芯片内设的操作命令。

在地址空间中地址:0x4E000004,其中:

Bit0-7:存放具体 Nand flash 芯片内设的命令值。其余位保留以后用。

3. 地址寄存器(NFADDR)

功能:用于存放用于对 Nand flash 芯片存储单元寻址的地址值。

在地址空间中地址:0x4E000008,其中:

Bit0-7:用于存放地址值。因为本款 Nand flash 芯片只有 I/O0-7 的地址/数据复用引脚且地址是四周

期每次 8 位送入的,所以这里只用到 8 位。其余位保留待用。

4. 数据寄存器(NFDATA)

功能:Nand flash 芯片所有内设命令执行后都会将其值放到该寄存器中。同时,读出、写入 Nand flash

存储空间的值也是放到该寄存器。

在地址空间中地址:0x4E00000C,其中:

Bit0-7:用于存放需要读出和写入的数据。其余位保留代用。

5. 状态寄存器(NFSTAT)

功能:用于检测 Nand flash 芯片上次对其存储空间的操作是否完成。

在地址空间中地址:0x4E000010,其中:

Bit0:置 0 表示 Nand flash 芯片正忙于上次对存储空间的操作;置 1 表示 Nand flash 芯片准备好接收新

的对存储空间操作的请求。

6. ECC 校验寄存器(NFECC)

功能:ECC 校验寄存器

在地址空间中地址:0x4E000014,其中:

Bit0­Bit7: ECC0

Bit8­Bit15: ECC1

Bit16­Bit23: ECC2

1.4 Nand Flash 控制器中的硬件 ECC 介绍

1.4.1 ECC 产生方法

ECC 是用于对存储器之间传送数据正确进行校验的一种算法,分硬件 ECC 和软件 ECC 算法两种,在

S3C2410 的 Nand Flash 控制器中实现了由硬件电路(ECC 生成器)实现的硬件 ECC。1.4.2 ECC 生成器工作过程

当写入数据到 Nand flash 存储空间时, ECC 生成器会在写入数据完毕后自动生成 ECC 码,将其放入到

ECC0-ECC2。当读出数据时 Nand Flash 同样会在读数据完毕后,自动生成 ECC 码将其放到 ECC0-ECC2 当

中。

1.4.3 ECC 的运用

当写入数据时,可以在每页写完数据后将产生的 ECC 码放入到 OOB 指定的位置(Byte 6)去,这样就完成了

ECC 码的存储。这样当读出该页数据时,将所需数据以及整个 OOB 读出,然后将指定位置的 ECC 码与读出数

据后在 ECC0-ECC1 的实际产生的 ECC 码进行对比,如果相等则读出正确,若不相等则读取错误需要进行重

读。

2 在 ADS 下 flash 烧写程序

2.1 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;}

3. Nand Flash 芯片选中

#define NF_nFCE_L()

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

4. Nand Flash 芯片不选中

#define NF_nFCE_H()

{rNFCONF|=(1<<11);}

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

{

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

return 0;

} else {

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)

{

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

NF_MarkBadBlock(block); /* 标记为坏块 */

return 0;

} else {

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

}

}

标签: #pythonlinuxarm