百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

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

cac55 2025-02-20 14:35 9 浏览 0 评论

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

}

}


相关推荐

QQ表情大图(QQ表情大图怎么发)

爷青回 | QQ经典老头像(爷青回这个梗出自哪里)

点个关注不迷路记得点击上方关注我呦点击表情包长按可保存至手机表情包素材来源于网络,仅供分享哦拿完图记得吱一声点击下方分享、在看让更多人看到...

史上最全QQ官方经典头像全面翻新,不光高清还会动

每当看到上面这些头像,总能想起那些年的"轻舞飞扬","缘分天空","追风少年",这些已经模糊的头像给我们留下了太深的印象。这次为了纪念QQ20周年,腾讯官方整合了早期的105个经典头像,进行了全面翻...

QQ最全表情含义图解意思(qq表情含义图解最新 新版 文字)

QQ都不陌生吧!对QQ的表情符号含义你了解多少呢?在本文中最全图解233个表情所表达的含义,供有需人享用。用过QQ的人都晓得它的创始人是马化腾。QQ于1999年2月10日正式推出。QQ是腾讯公司开发的...

海联真人版QQ经典表情(海联真人版qq经典表情在哪)

海联版傲娇的说声“耶”狂拽炫酷就是我淑女应该轻言细语萌萌哒的娇羞哎哟喂小丫头片子机智如我吓死宝宝了欧巴卡几嘛~今天天气好晴朗怎么样?是不是很有趣呢拿起手机给自己拍几张萌萌哒的美照吧...

QQ音乐·音乐灵感独家对话金曲奖「最佳单曲制作人奖」得主JADE

JADE-AllRightJADE-差-点JADE-Goodbye,GoodbyeJADE-IAmLovefeat.乔瑟夫Chillseph下面请听本期灵感电台节目:本期博客...

亿万富豪爱泼斯坦狱中“自杀”,他背后的神秘女人出现在洛杉矶快餐店

爱泼斯坦在狱中离奇“自杀”,但他身负同谋指控的前女友、英国社交名媛希莱恩·麦克斯维尔(GhislaineMaxwell),却意外地出现在了洛杉矶街头平民快餐店,边啃着汉堡,咽着薯条,嘬着奶昔,边埋头...

扛起星战大旗的你们 觉得星战女需要换一身衣裳吗?

马上进入2016年,除了各种总结盘点以外,2016年的新看点也是需要科普一下了。目前最令人期待的应该就是《星球大战》回归了!《StarWars:原力觉醒》1月10日上映,博主不是电影评论员,所以不会...

和人对话的时候,我,最怕的就是,看到了自己内心的惶恐和脆弱

IWannaBeYourSlave(LiveFromGlobalCitizenLive2021),Maneskin很多时候,哪怕最甘于寂寞的人,也需要和人发生关联,需要和这个世界沟...

2024年度串烧完整版(搞笑失败尴尬丢人版)来了

一首APT的时间带你回顾你的2024年年度歌单。·1.《免我蹉跎苦》黄龄。·2.《红昭愿》音阙诗听。·3.《苹果香》狼戈。·4.《免我蹉跎苦》黄龄。·5.《红昭愿》音阙诗听。·6.《苹果香》狼戈。·7...

一课译词:打工人(打工人的翻译)

下午好,各位打工人!近日,“打工人”爆红网络,受到各行各业年轻人的追捧,但这词到底说的是个啥?“打工人”是那些依靠体力或技术的劳动者的统称。除了赚钱这个最大的目标,别的啥也不想;他们意志坚定,也不会迟...

初级词汇题(一)柏拉图指出不是每个孩子都适合上学,你赞成吗?

初级词汇题(一)柏拉图在《理想国》中指出不是每个孩子都适合上学,你赞成吗?今天分享的题目是我基于英文原著改编的初级词汇题A开头的第81道题。背景知识拓展:什么是nativist(先天论者)?什么是哲学...

治愈系英文:每个说不想恋爱的人,心里都装着一个无法拥有的人

Therearesomanypeopleouttherewhowilltellyouthatyoucan't.Whatyou'vegottodoisturna...

首首经典!意大利流行乐队Maneskin作品I WANNA BE YOUR SLAVE

手机点击试听(上边)Maneskin是一支来自罗马的意大利流行摇滚乐队,由主唱DamianoDavid、贝斯手VictoriaDeAngelis、吉他手ThomasRaggi和鼓手...

国家电网新一代电子商务平台投标文件双层PDF制作最全教程

投标知识在招投标过程中,我们经常碰见有些文件要求制成双层PDF格式,那么双层PDF是什么呢?怎么制作呢?今天就给大家普及下。定义双层PDF双层PDF格式文件是一种具有多层结构的PDF格式文件,是PD...

取消回复欢迎 发表评论: