更新时间:2025 12 14 00:23:57 作者 :庆美网 围观 : 70次
学院:**学院
姓名:
学号:
专业:

摘要:宫崎骏(Miyazaki Hayao,1941年1月5日-),日本知名动画导演、动画师及漫画家, 出生于东京都文京区,1963年进入东映动画公司,1985年与高烟勋共同创立古卜力工作案,其出品的动漫电影以精湛的技术、动人的故事和温暖的风格在世界动漫界独树一帜,能与美国迪士尼、 梦工厂的作品相比肩,受到全世界不分种族、不分国籍、不分文化的各类观众的一致好评。其动国作品大多涉及人类与自然之间的关系、和平主义及女权运动。宫崎骏在日本动画界占有超重里级 的地位,更在全球动画界具有无可替代的地位,迪士尼称他为“动画界的黑泽明,《时代周刊》评价他为全球最具影响力的人物。
下面是我对web简单的一个应用,利用dreamwave工具,和photoshop软件设计了一个具有个人风格的个人网站,首先我先从网站设计的方向和目的、网站设计中涉及的知识点、网站设计的整个流程出发,然后通过自己设计的这个个人网站作品来说明并演示一个完整的网站制作过程。本论文详细的介绍了整个网站设计的全过程。虽然还有一些不足之处,但页面整体比较美观大方,具有线上店铺风格,效果良好。
设计主要包括以下几个版块:
1.人物介绍板块
2.采访视频板块
3.手稿欣赏板块
4.主要作品模块
网站规划思想
宫崎骏(Miyazaki Hayao,1941年1月5日-),日本知名动画导演、动画师及漫画家, 出生于东京都文京区,1963年进入东映动画公司,1985年与高烟勋共同创立古卜力工作案,其出品的动漫电影以精湛的技术、动人的故事和温暖的风格在世界动漫界独树一帜,能与美国迪士尼、 梦工厂的作品相比肩,受到全世界不分种族、不分国籍、不分文化的各类观众的一致好评。其动国作品大多涉及人类与自然之间的关系、和平主义及女权运动。宫崎骏在日本动画界占有超重里级 的地位,更在全球动画界具有无可替代的地位,迪士尼称他为“动画界的黑泽明,《时代周刊》评价他为全球最具影响力的人物。
作为宫崎骏的动画迷,我结合课上所需的HTML网页知识设计一个介绍宫崎骏的网页,包含图文、视频等多种素材可以选择。
网站的目录结构如下:
css ——存放CSS文件
imgs ——存放图片文件
js ——-存放js文件
index.html ———–人物介绍页面
yinyue.html ———–采访视频页面
shougao.html ———手稿欣赏页面
liuyan.html———主要作品页面
综合知识的运用情况
2、使用链接:为方便读者的查阅,在各页面n****栏都设置了页面链接。
3、插入跳转菜单为了使读者能快捷的回到自己感兴趣的页面,于是在各个页面都插入了跳转菜单。
网页中涉及的知识点
1、可视化网站设计制作软件dreamweaver的熟练使用,站点的创建、导入以及管理;
2、主页的创建和设置,模块的保存与应用和子网页的创建、完成;
3、用photoshop软件对图片素材进行必要的处理;
4、网站整体布局和超链接的添加;
遇到的问题及解决办法
难点:
1.body背景图片显示问题
2.页面美观度不够高,Dreamewver CS6软件应用不够熟练,软件中所涉及得制作方法以及工具没有更好的应用。
解决办法:
1.配色原则:避免网页杂、乱,有时候单一色彩不为也是一种独特,用色柔和,减少视觉混乱,对比度强的色彩不能应用于一般网站。
2.字体问题:字体是整个网页最醒目的部分,若字体不协调会给人一种枯燥的感觉,避免用杂色字体,防止浏览者眼花缭乱。
3.制作习惯:制作一个网页首要的是完美的构思,应该先构思好再动手制作,素材搜集完整,根据主题选材,不能脱离主题,确保所用材料与主题相关。
4.完整性:网站的基本格式完整,相关链接,友情链接必不可少,这也增加了网页的方便性
5.合适选取适当尺寸的背景图片非常重要
网页截图
首页(index.html):使用了
HTML5结构标签,对宫崎骏的事迹进行了高度概括。
头部:(一个顶部图片和n****)
中间:
尾部:
2 采访视频:使用video标签嵌入一个本地mp4视频
3手稿欣赏:使用无框线的三行两列的表格对手稿进行布局排列
4主要作品:使用带有框线和背景色的表格对主要作品进行罗列,内部文字居中,超链接加蓝色下划线。
心得与体会:
建立一个网站就像盖一幢大楼一样,它是一个系统工程,有自己特定的工作流程,你只有遵循这个步骤,按部就班地一步步来,才能设计出一个满意的网站。首先,我们要确立网站主题。网站主题就是你建立的网站所要包含的主要内容,一个网站必须要有一个明确的主题。特别是对于像我这样的个人网站,你不可能像综合网站那样做得内容大而全,包罗万象。你没有这个能力,也没这个精力。网站的主题无定则,只要是你感兴趣的,任何内容都可以,但主题要鲜明,在你的主题范围内内容做到大而全、精而深。
然后,我们要找材料。明确了网站的主题以后,你就要围绕主题开始搜集材料了。常言道:“巧妇难为无米之炊”。要想让自己的网站有血有肉,能够吸引住用户,你就要尽量搜集材料,搜集得材料越多,以后制作网站就越容易。材料既可以从图书、报纸、光盘、多媒体上得来,也可以从互联网上搜集,然后把搜集的材料去粗取精,去伪存真,作为自己制作网页的素材。
找到材料后,我们还要规划网站。一个网站设计得成功与否,很大程度上决定于设计者的规划水平,规划网站就像设计师设计大楼一样,图纸设计好了,才能建成一座漂亮的楼房。网站规划包含的内容很多,如网站的结构、栏目的设置、网站的风格、颜色搭配、版面布局、文字图片的运用等,你只有在制作网页之前把这些方面都考虑到了,才能在制作时驾轻就熟,胸有成竹。也只有如此制作出来的网页才能有个性、有特色,具有吸引力。如何规划网站的每一项具体内容,我们在下面会有详细介绍。
做好以上三步之后,我们就要选择合适的制作工具。尽管选择什么样的工具并不会影响你设计网页的好坏,但是一款功能强大、使用简单的软件往往可以起到事半功倍的效果。网页制作涉及的工具比较多,首先就是网页制作工具了,在这里,我们一般都是用有“网络三剑客”之称的Dreamweaver、Fireworks、flash来制作网页,对于图片部分的处理,个人觉得Photoshop比较好用。
最后,我们就需要按照规划一步步地把自己的想法变成现实了,这是一个复杂而细致的过程,一定要按照先大后小、先简单后复杂来进行制作。所谓先大后小,就是说在制作网页时,先把大的结构设计好,然后再逐步完善小的结构设计。所谓先简单后复杂,就是先设计出简单的内容,然后再设计复杂的内容,以便出现问题时好修改。在制作网页时要多灵活运用模板,这样可以大大提高制作效率。网页做好之后,就要发布到Web服务器上,才能够让全世界的朋友观看,还要不断地进行宣传,这样才能让更多的朋友认识它。
以上就是我对于网页制作的一些个人心得,由于本人的技术还不是很成熟,还存在很多的不足(如:背景过于单调和网页布置不合理)。选择学习这门课是很正确的选择,虽然在以后不会再有机会去上了,但我还是会通过各种方式继续页设计和制作的,同时很感谢带我入门的徐兵老师,让我有机会去学习有关网页的知识,谢谢!
1)实验平台:正点原子水星 STM32F4/F7 开发板
2)摘自《STM32F7 开发指南(HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-13912-1-1.html
第四十四章 NAND FLASH 实验
水星 STM32F767 核心板上面,板载了一颗 512MB 的 NAND FLASH 芯片,型号为:
MT29F4G08,我们可以用它来存储数据,相对于 SPI FLASH(W25Q256)和 SD 卡等存储设备,
NAND FLASH 采用 8 位并口访问,具有访问速度快的优势。
本章,我们将使用 STM32F767 来驱动 MT29F4G08,并结合一个简单的坏块管理与磨损均
衡算法,实现对 MT29F4G08 的读写控制。本章分为如下几个部分:
44.1 NAND FLASH 简介
44.2 硬件设计
44.3 软件设计
44.4 下载验证
44.1.1 NAND FLASH 简介
NAND FLASH 的概念是由东芝公司在 1989 年率先提出,它内部采用非线性宏单元模式,
为固态大容量内存的实现提供了廉价有效的解决方案。NAND FLASH 存储器具有容量较大,
改写速度快等优点,适用于大量数据的存储,在业界得到了广泛应用,如:SD 卡、TF 卡、U
盘等,一般都是采用 NAND FLASH 作为存储的。关于 NAND FLASH 的基础知识,请大家自
行百度学习。接下来,我们介绍 NAND FLASH 的一些重要知识。
(1)NAND FLASH 信号线
NAND FLASH 的信号线如表 44.1.1.1 所示:
表 44.1.1.1 NAND FLASH 信号线
因为 NAND FLASH 地址/数据是共用数据线的,所以必须有 CLE/ALE 信号,告诉 NAND
FLASH,发送的数据是命令还是地址。
(2)存储单元
NAND FLASH 存储单元介绍,我们以水星 STM32F767 开发板所使用的 MT29F4G08(x8,
8 位数据)为例进行介绍,MT29F4G08 的存储单元组织结构如图 44.1.1.1 所示:
图 44.1.1.1 MT29F4G08 存储单元组织结构图
由图可知:MT29F4G08 由 2 个 plane 组成,每个 plane 有 2048 个 block,每个 block 由 64
个 page 组成,每个 page 有 2K+64 字节(2112 字节)的存储容量。所以,MT29F4G08 的总容
量为:2*2048*64*(2K+64)= 553648128 字节(512MB)。其中,plane、block、page 等的个数
根据 NAND FLASH 型号的不同,会有所区别,大家注意查看对应 NAND FLASH 芯片的数据
手册。
NAND FLASH 的最小擦除单位是 block,对 MT29F4G08 来说,是(128+4)K 字节,NAND
FLASH 的写操作具有只可以写 0,不能写 1 的特性,所以,在写数据的时候,必须先擦除 block
(擦除后,block 数据全部为 1),才可以写入。
NAND FLASH 的 page 由 2 部分组成:数据存储区(data area)和备用区域(spare area),
对 MT29F4G08 来说,数据存储区大小为 2K 字节,备用区域大小为 64 字节。我们存储的有效
数据,一般都是存储在数据存储区(data area)。备用区域(spare area),一般用来存放 ECC(Error
Checking and Correcting)校验值,在本章中,我们将利用这个区域,来实现 NAND FLASH 坏
块管理和磨损均衡。
NAND FLASH 的地址分为三类:块地址(Block Address)、页地址(Page Address)和列地
址(Column Address)。以 MT29F4G08 为例,这三个地址,通过 5 个周期发送,如表 44.1.1.2
所示:
表 44.1.1.2 MT29F4G08 寻址说明
表中,CA0~CA11 为列地址(Column Address),用于在一个 Page 内部寻址,MT29F4G08
的一个 Page 大小为 2112 字节,需要 12 个地址线寻址;PA0~PA5 为页地址(Page Address),用
于在一个 Block 内部寻址,MT29F4G08 一个 Block 大小为 64 个 Page,需要 6 个地址线寻址;
BA6~BA17 为块地址(Block Address),用于块寻址,MT29F4G08 总共有 4096 个 Block,需要
12 根地址线寻址。
整个寻址过程,分 5 次发送(5 个周期),首先发送列地址,在发送页地址和块地址。这里提醒一下:块地址和页地址,其实是可以写在一起的,由一个参数传递即可,所以表中的 BA
并不是由 BA0 开始的,大家可以理解为这个地址(PA+BA)为整个 NAND FLASH 的 Page 地
址。在完成寻址以后,数据线 I/O0~ I/O7 来传输数据了。
(3)控制命令
NAND FLASH 的驱动需要用到一系列命令,这里我们列出常用的一些命令,给大家做一
个简单介绍,方便大家了解 NAND FLASH 的操作,如表 44.1.1.3 所示:
表 44.1.1.3 NADN FLASH 操作常用命令
表 44.1.1.3 中,我们需要注意两点:1,有的指令一个周期完成传送,有的指令需要分两次
传送(2 个周期);2,指令名称,不同厂家的数据手册里面,标注可能不一样,但是其指令值
(HEX 值)一般都是一样的。
上表中,前四条命令相对比较简单,这里我们主要介绍后面五条指令。
1,READ PAGE
该指令用于读取 NAND 的一个 Page(包括 spare 区数据,但不能跨页读),该指令时序如
图 46.1.1.2 所示:
图 44.1.1.2 READ PAGE 指令时序图
由图可知,READ PAGE 的命令分两次发送,首先发送 00H 命令,然后发送 5 次地址
(Block&Page&Column 地址),指定读取的地址,随后发送 30H 命令,在等待 RDY 后,即可
读取 PAGE 里面的数据。注意:不能跨页读,所以最多一次读取一个 PAGE 的数据(包括 spare
区)。
2,WRITE PAGE
该指令用于写一个Page的数据(包括spare区数据,但不能跨页写),该指令时序如图46.1.1.3
所示:
图 44.1.1.3 READ PAGE 指令时序图
由图可知,WRITE PAGE 的命令分两次发送,首先发送 80H 命令,然后发送 5 次地址
(Block&Page&Column 地址),指定写入的地址,在地址写入完成后,等待 tADL 时间后,开
始发送需要写入的数据,在数据发送完毕后,发送 10H 命令,最后发送 READ STATUS 命令,
查询 NAND FLASH 状态,等待状态为 READY 后,完成一次 PAGE 写入操作。
3,ERASE BLOCK
该指令用于擦除 NAND 的一个 Block(NAND 的最小擦除单位),该指令时序如图 44.1.1.4
所示:
图 44.1.1.4 ERASE BLOCK 指令时序图
由图可知,ERASE BLOCK 的命令分两次发送,首先发送 60H 命令,然后发送 3 次地址
(BLOCK 地址),指定要擦除的 BLOCK 地址,随后发送 D0H 命令,在等待 RDY 成功后,完
成一个 BLOCK 的擦除。
4,READ FOR INTERNAL DATA MOVE
该指令用于在 NAND 内部进行数据移动时(页对页),指定需要读取的 PAGE 地址,如有
必要,可以读取出 PAGE 里面的数据。该指令时序如图 44.1.1.5 所示:
图 44.1.1.5 READ FOR INTERNAL DATA MOVE 指令时序图
由图可知,READ FOR INTERNAL DATA MOVE 的命令分两次发送,首先发送 00H 命令,
然后发送 5 次地址(Block&Page&Column 地址),指定读取的地址,随后发送 35H 命令,在等
待 RDY 后,可以读取对应 PAGE 里面的数据。在内部数据移动过程中,我们仅用该指令指定
需要拷贝的 PAGE 地址(源地址),并不需要读取其数据,所以最后的 Dout 过程,一般都可以
省略。
5,PROGRAM FOR INTERNAL DATA MOVE
该指令用于在 NAND 内部进行数据移动时(页对页),指定需要写入的 PAGE 地址(目标
地址),如有必要,在拷贝过程中,可以写入新的数据,该指令时序如图 46.1.1.6 所示:
图 44.1.1.6 PROGRAM FOR INTERNAL DATA MOVE 指令时序图
如图 44.1.1.6 所示,该指令,首先发送 85H 命令,然后发送 5 次地址(Block&Page&Column
地址),指定写入的页地址(目标地址),源地址则由 READ FOR INTERNAL DATA MOVE 指
令指定。接下来分两种情况:1,要写入新的数据(覆盖源 PAGE 的内容);2,无需写入新的
数据;
对于第 1 种情况,在等待 tWHR(或 tADL)之后,开始写入新的数据,数据在页内的起始
地址,由 C1&C2 指定,写入完成后,发送 10H 命令,开始进行页拷贝,在等待 RDY 后,完成
一次页对页的数据拷贝(带新数据写入)。
对于第 2 种情况,在发送完 5 次地址后,无需发送新数据,直接发送 10H 命令,开始进行
页拷贝,在等待 RDY 后,完成一次页对页的数据拷贝(不带数据写入)。
注意:页对页拷贝,仅支持同一个 plane 里面互相拷贝(源地址和目标地址,必须在同一
个 plane 里面),如果不是同一个 plane 里面的页,则不可以执行页对页拷贝。
NAND FLASH 其他命令的介绍,请大家参考 MT29F4G08 的数据手册。
(4)ECC 校验
ECC,英文全称为:Error checking and Correction,是一种对传输数据的错误检测和修正的
算法。NAND FLASH 存储单元是串行组织的,当读取一个单元的时候,读出放大器所检测到
信号强度会被这种串行存储结构削弱,这就降低了所读信号的准确性,导致读数出错(一般只
有 1 个 bit 出错)。ECC 就可以检测这种错误,并修正错误的数据位,因此,ECC 在 NAND FLASH
驱动里面,被广泛使用。
ECC 有三种常用的算法:汉明码(Hamming Code)、RS 码(Reed Solomon Code)和 BCH 码。
STM32 的 FMC 模块就支持硬件 ECC 计算,使用的就是汉明码,接下来,我们就给大家简单介
绍一下汉明码的编码和使用。
1,汉明码编码
汉明码的编码计算比较简单,通过计算块上数据包得到 2 个 ECC 值(ECCo 和 ECCe)。为
计算 ECC 值,数据包中的比特数据要先进行分割,如 1/2 组、1/4 组、1/8 组等,直到其精度达
到单个比特为止。我们以 8 bit 即 1 字节的数据包为例进行说明,如表 44.1.1.4 所示:
表 44.1.1.4 8bit 数据包校验的数据分割
8 位数据可以按:1/2、1/4 和 1/8 进行分割(1/8 分割时,达到单个比特精度)。简单说一下
上表的看法,以 1/2 分割偶校验为例,1/2 分割时,每 4 个 bit 组成一个新 bit,新的 bit0 等于原
来的 bit0~3,新的 bit1 等于原来的 bit4~7,而我们只要偶数位的数据,也就是新 bit0 的数据,
实际上就是原来的 bit0~3 的数据,这样就获取了 1/2 偶校验的数据。其他分割以此类推。
表 46.1.1.3 中,数据包上方的三行数据经计算后,得到偶校验值(ECCe),数据包下方的
三行数据经计算后,得到奇校验值(ECCo)。1/2 校验值经“异或”操作构成 ECC 校验的最高
有效位,1/4 校验值构成 ECC 校验的次高有效位,最低有效位由具体到比特的校验值填补。ECC
校验值(ECCo 和 ECCe)的计算过程,如图 46.1.1.7 所示:
图 46.1.1.7 计算奇偶 ECC 值
即偶校验值 ECCe 为“101”,奇校验值 ECCo 为“010”。图 1 所示为只有 1 字节数据的数
据包,更大的数据包需要更多的 ECC 值。事实上,每 n bit 的 ECC 数值可满足 2^n bit 数据包的
校验要求。不过,汉明码算法要求一对 ECC 数据(奇+偶),所以总共要求 2n bit 的 ECC 校验
数据来处理 2^n bit 的数据包。
得到 ECC 值后,我们需要将原数据包和 ECC 数值都写入 NAND 里面。当原数据包从 NAND
中读取时,ECC 值将重新计算,如果新计算的 ECC 不同于先前编入 NAND 器件的 ECC,那么
表明数据在读写过程中发生了错误。例如,原始数据 01010001 中有 1 个单一的比特出现错误,
出错后的数据是 01010101。此时,重新计算 ECC 的过程如图 46.1.1.8 所示:
图 46.1.1.8 出错时计算的奇偶 ECC 值
可以看到,此时的 nECCo 和 nECCe 都为 000。此时,我们把所有 4 个 ECC 数值进行按位
“异或”,就可以判断是否出现了 1 个单一比特的错误或者是多比特的错误。如果计算结果为全
“0”,说明数据在读写过程中未发生变化。如果计算的结果为全“1”,表明发生了 1 bit 错误,
其他情况,则说明有至少 2bit 数据出现了错误。不过,汉明码编码算法只能够保证更正单一比
特的错误,如果两个或是更多的比特出错,汉明码就无能为力了(可以检测出错误,但无法修
正)。不过,一般情况 SLC NAND 器件(STM32 仅支持 SLC NAND)出现 2bit 及以上的错误
非常罕见,所以,我们使用的汉明码基本上够用。
对 4 个 ECC 进行异或的计算方法如下:
ECCe^ECCo^nECCe^nECCo=101^010^000^000=111
这样,经过上式计算,4 个 ECC 的“异或”结果为全 1,表示有 1 个 bit 出错了。对于这种
1 bit 错误的情况,出错的地址可通过将原有 ECCo 值和新 ECCo 值(nECCo)进行按位“异或”
来得到,计算方法如下:
ECCo^nECCo=010^000=010
计算结果为 010(2),表明原数据第 2 bit 位出现了问题。然后,对出错后的数据的 bit2 进
行取反(该位与 1“异或”即可),就可以得到正确的数据:01010101^00000100=01010001。
一个 8 位数据,需要 6 位 ECC 码,看起来效率不高,但是随着数据的增多,汉明码编码效
率将会越来越高。比如,我们一般以 512 字节为单位来计算 ECC 值,只需要 24bit 的 ECC 码即
可表示(2^12=4096bit=512 字节,12*2=24bit)。汉明码编码算法的原理,我们就给大家介绍到
这里。
2,STM32 硬件 ECC
STM32 的 FMC 支持 NAND FLASH 硬件 ECC 计算,采用的就是汉明码计算方法。可以实
现 1bit 错误的修正和 2bit 以上错误的检测,支持页大小按 256、512、1024、2048、4096 和 8192字节为单位进行 ECC 计算。
当 FMC 的硬件 ECC 功能开启后,FMC 模块根据用户设置的参数(计算页大小、数据位宽
等)对 NAND FLASH 数据线上传递的(读/写)数据进行 ECC 计算,数据传输结束后,ECC
计算结果自动存放在 FMC_ECCR 寄存器中。不过 STM32 的硬件 ECC 只负责计算 ECC 值,并
不对数据进行修复。错误检测和数据修复,需要用户自己实现。另外,STM32 的硬件 ECC 支
持存储区域 3,其他存储区域不支持!!
STM32 硬件 ECC 计算结果读取过程(以 512 字节页大小为例):
1, 设置 FMC_PCR 的 ECCEN 位为 1,使能 ECC 计算
2, 写入/读取 512 字节数据
3, 等待 FMC_SR 的 FEMPT 位为 1(等待 FIFO 空)
4, 读取 FMC_ECCR,得到 ECC 值
5, 设置 FMC_PCR 的 ECCEN 位为 0,关闭 ECC,以便下一次重新计算
重复以上步骤,就可以在不同时刻进行读/写数据的 ECC 计算。在实际使用的时候,我们
在写入/读取数据时,都要开启 STM32 的硬件 ECC 计算。写入的时候,将 STM32 硬件 ECC 计
算出来的 ECC 值写入 NAND FLASH 数据所存 Page 的 spare 区。在读取数据的时候,STM32
硬件 ECC 会重新计算一个 ECC 值(ecccl),而从 spare 区对应位置,又可以读取之前写入的 ECC

值(eccrd),当这两个 ECC 值不相等的时候,说明读数有问题,需要进行 ECC 校验,ECC 检
查和修正代码如下:
//获取 ECC 的奇数位/偶数位
//oe:0,偶数位
// 1,奇数位
//eccval:输入的 ecc 值
//返回值:计算后的 ecc 值(最多 16 位)
u16 NAND_ECC_Get_OE(u8 oe,u32 eccval)
{
u8 i;
u16 ecctemp=0;
for(i=0;i<24;i++)
{
if((i%2)==oe) if((eccval>>i)&0X01)ecctemp+=1<<(i>>1);
}
return ecctemp;
}
//ECC 校正函数
//eccrd:读取出来,原来保存的 ECC 值
//ecccl:读取数据时,硬件计算的 ECC 只
//返回值:0,错误已修正
// 其他,ECC 错误(有大于 2 个 bit 的错误,无法恢复)
u8 NAND_ECC_Correction(u8* data_buf,u32 eccrd,u32 ecccl)
{
u16 eccrdo,eccrde,eccclo,ecccle;
u16 eccchk=0;
u16 errorpos=0;
u32 bytepos=0;
eccrdo=NAND_ECC_Get_OE(1,eccrd);
//获取 eccrd 的奇数位
eccrde=NAND_ECC_Get_OE(0,eccrd);
//获取 eccrd 的偶数位
eccclo=NAND_ECC_Get_OE(1,ecccl);
//获取 ecccl 的奇数位
ecccle=NAND_ECC_Get_OE(0,ecccl);
//获取 ecccl 的偶数位
eccchk=eccrdo^eccrde^eccclo^ecccle;
if(eccchk==0XFFF)
//全 1,说明只有 1bit ECC 错误
{
errorpos=eccrdo^eccclo;
//计算出错 bit 位置
bytepos=errorpos/8;
//计算字节位置
data_buf[bytepos]^=1<<(errorpos%8); //对出错位进行取反,修正错误
}else return 1;
//不是全 1,说明至少有 2bit ECC 错误,无法修复
return 0;
}
经过以上代码处理,我们就可以利用 STM32 的硬件 ECC,修正 1bit 错误,并报告 2bit 及
以上错误。
44.1.2 FTL 简介
因为 NAND FLASH 在使用过程中可能会产生坏块,且每个 BLOCK 的擦除次数是有限制
的,超过规定次数后,BLOCK 将无法再擦除(即产生坏块),因此,我们需要这样一段程序,
它可以实现:1,坏块管理;2,磨损均衡;从而使应用程序可以很方便的访问 NAND FLASH
(无需关系坏块问题),且最大限度的延长 NAND FLASH 的寿命。
这里给大家介绍 FTL,FTL 是 Flash Translation Layer 的简写,即闪存转换层,它是一个
NAND 闪存芯片与基础文件系统之间的一个转换层,它自带了坏块管理和磨损均衡算法,使得
操作系统和文件系统能够像访问硬盘一样访问 NAND 闪存设备,而无需关心坏块和磨损均衡问
题。
本章,我们将给大家介绍一个比较简单的 FTL 层算法,它可以支持坏块管理和磨损均衡,
提供支持文件系统(如:FATFS)的访问接口,通过这个 FTL,我们可以很容易的实现 NAND
FLASH 的文件系统访问。
要做好 NAND FLASH 的坏块管理,我们有以下几点需要实现:
1, 如何识别坏块,标记坏块;
2, 转换表
3, 保留区
1,如何识别坏块,标记坏块
经过前面的介绍,我知道 NAND 在使用过程中,会产生坏块,而坏块我们是不能再用来存
储数据的,必须对坏块进行识别和标记,并保存这些标记。
NAND FLASH 的坏块识别有几种方式:1,NAND 厂家出厂的时候,会在每个 Block 的第
一个 page 和第二个 page 的 spare 区的第一个字节写入非 0XFF 的值来表示,我们可以通过这个
判断该块是否为坏块;2,通过给每个 Block 写入数值(0XFF/0X00),然后读取出来,判断写
入的数据和读取的数据是否完全一样,来识别坏块;3,通过读取数据时,校验 ECC 错误,来
识别坏块。
NAND FLASH 的坏块标记:坏块标记,我们使用每个 Block 的第一个 page 和第二个 page
(第二个 page 是备份用的)spare 区的第一个字节来标记,当这个字节的值为 0XFF 时,表示该块为好块,当这个字节的值不等于 0XFF 时,表示该块为坏块。以 MT29F4G08 为例,坏块
表示方法,如表 44.1.2.1 所示:
表 44.1.2.1 NAND FLASH 坏块标记说明表
上图中,假设某个 Block 为坏块,那么它的第一个 page 和第二个 page 的 spare 区第一个字
节,就不是 0XFF 了(我们改为 0XAA),以表示其是一个坏块。如果是好块,这两个字节,必
须都是 0XFF,只要任何一个不是 0XFF,则表示该块是一个坏块。
这样,我们只需要判断每个 Block 的第一和第二个 page 的 spare 区的第一个字节,就可以
判断是否为坏块。达到了标记和保存坏块标记的目的。
2,转换表
文件系统访问文件的时候,使用的是逻辑地址,是按顺序编号的,它不考虑坏块情况。而
NAND FLASH 存储地址,我们称为物理地址,是有可能存在坏块的。所以,这两个地址之间,
必须有一个映射表,将逻辑地址转换为物理地址,且不能指向坏块的物理地址,这个映射表我
们称之为逻辑地址-物理地址转换表,简称转换表,如图 44.1.2.1 所示:
图 44.1.2.1 逻辑-物理地址转换表
图 44.1.2.1 表示某个时刻,逻辑地址与物理地址的对应关系。由图可知,逻辑地址(0~n)
到物理地址的映射,映射关系不是一一对应的,而是无序的,这个映射关系是不固定的,随时
可能会变化,逻辑地址到物理地址,通过映射表进行映射,所以映射表也是随时需要更新的。
图中,我们假定 NAND 的第 5 个 Block 是坏块,那么映射表一定不能将这个块地址映射给
逻辑地址,所以,必须对这个块进行坏块标记,不再作为正常块使用,坏块标记请参考前面的介绍。另外,当产生了一个坏块的时候,我们必须从保留区(下文介绍)提取一个未用过的块
(Block),来替代这个坏块,以确保所有逻辑地址,都有正常的物理地址可用。
逻辑地址到物理地址的映射关系,我们采用一个数组来存储,这个数组即映射表(简称:
lut 表),同时,这个映射表必须存储到 NAND FLASH 里面,以便上电后重建。这里,我们也
是利用每个 Block 的第一个 page 的 spare 区来存储映射表,另外,还需要标记这个 Block 是否
被使用了,所以,Block 第一个 page 的 spare 区规划,如表 44.1.2.2 所示:
表 44.1.2.2 每个 Block 第一个 page 的 spare 区前 4 个字节规划表
如表 44.1.2.2 所示,每个 Block 第一个 page 的 spare 区第一个字节用来表示该块是否为坏
块(前面已介绍);第二个字节用来表示该块是否被占用(0XFF,表示未占用;0XCC,表示已
被占用);第三和第四个字节,用来存储该块所映射到的逻辑地址,如果为 0XFFFF,则表示该
块还未被分配逻辑地址,其他值,则表示该块对应的逻辑地址,MT29F4G08 有 4096 个 Block,
所以这两个字节表示的有效逻辑地址范围,就是 0~4095。因此,我们要想判断一个 Block 是否
是一个未被使用的好块,只需读取这个 Block 第一个 page 的 spare 区前四个字节,如果为
0XFFFFFFFF 则说明是一个未被使用的好块。
上电的时候,重建映射表(lut 表)的过程就是读取 NAND FLASH 每个 Block 第一个 page
的 spare 区前 4 个字节,当这个块是好块(第一个字节为 0XFF),且第三和第四字节组成的 u16
类型数据(逻辑地址,记为:LBNnum),小于 NAND FLASH 的总块数,则这个 Block 地址(物
理地址,记为:M)就是映射表里面第 LBNnum 个元素所对应的地址,即:lut[LBNnum]=M。
3,保留区
保留区有两个作用:1,产生坏块的时候,用来替代坏块;2,在复写数据的时候,用来替
代被复写的块,以提高写入速度,并实现磨损均衡处理;
第一个作用,如图 46.1.2.1所示,当产生坏块后(第 5个块),使用一个保留区里面的块(n+2),
来替代这个坏块,从而保证每个逻辑地址,都有对应的物理地址(好块地址)。
第二个作用,当文件系统要往某个已经被写过数据的块里面写入新数据的时候,由于
NAND 的特性,必须是要先擦除,才能写入新数据。一般的方法:先将整个块数据读出来,然
后改写需要写入新数据的部分,然后擦除这个块,然后重新写入这个块,这个过程非常耗时,
且需要很大的内存(MT29F4G08 一个 Block 大小为 128K 字节),所以不太实用。
比较好的办法,是利用 NAND FLASH 的页拷贝功能,它可以将 NAND FLASH 内部某个
Block 的数据,以页为单位,拷贝到另外一个空闲的 Block 里面,而且可以写入新的数据(参
见 46.1.1 节的指令介绍),利用这个功能,我们无需读出整个 Block 的数据,只需要在页拷贝过
程中,在正确的地址写入我们需要写入的新数据即可。这就要求 NAND FLASH 必须有空闲的
块,用作页拷贝的目标地址,保留区里面的块,就可以作为空闲块,给页拷贝使用。而且,为
了保证不频繁擦除一个块(提高寿命),我们在保留区里面应预留足够的空闲块,用来均分擦除
次数,从而实现简单的磨损均衡处理。
这样,FTL 层的坏块管理和磨损均衡原理,就给大家介绍完了。我们根据这个原理,去设
计相应的代码,就可以实现 FTL 层的功能,从而更好的使用 NAND FLASH。
前面提到,我们需要用到 ECC 校验,来确保数据的正确性,一般的软件 ECC 校验都是由
FTL 层实现,我们为了简化代码,并利用 STM32 的硬件 ECC 计算,加快 ECC 计算的速度,我
们在 FTL 层并不做 ECC 计算和校验,而是放到 NAND FLASH 的底层驱动去实现。在 46.1.1
节最后,我们给大家介绍了 ECC 原理和纠错方法,每 512 个字节的数据,会生成 3 个字节的
ECC 值,而这个 ECC 值是必须存储在 NAND FLASH 里面,同样我们将 ECC 值存储在每个 page
的 spare 区,而且,为了方便读写,我们用 4 个字节来存储这 3 个字节的 ECC 值,ECC 存储关
系如表 44.1.2.3 所示:
表 44.1.2.3 每个 page 的 spare 区 ECC 存储关系表
如上表所示,每个 page 的一个数据区有 2048 个字节,而每 512 字节数据生成一个 ECC 值,
用 4 个字节存储,这样,每个 page 需要 16 个字节用于存储 ECC 值。表中的 ECCx1~ECCx4,
(x=0~63),就是存储的 ECC 值,从每个 page 的 spare 区第 16 个字节(0X10)开始存储 ECC
值,总共占用 16 字节,对应关系为:ECCx1→数据区 0~511 字节;ECCx2→数据区 512~1023
字节;ECCx3→数据区 1024~1535 字节;ECCx4→数据区 1536~2047 字节;
在 page 写入数据的时候,我们将 STM32 硬件计算出的 ECC 值写入 spare 区对应的地址,
当读取 page 数据的时候,STM32 硬件 ECC 会计算出一个新的 ECC 值,同时,可以在该 page
的 spare 区读取之前保存的 ECC 值,比较这两个 ECC 值,就可以判断数据是否有误,以及进行
数据修复(1bit)。注意:我们对 ECC 处理是以 512 字节为单位的,如果写入/读取的数据不是
512 的整数倍,则不会进行 ECC 处理。
44.1.3 FMC NAND FLASH 接口简介
在第十八和十九章,我们对 STM32F767 的 FMC 接口进行了简介,并利用 FMC 接口,实
现了对 MCU 屏和 SDRAM 的驱动。本章,我们将介绍如何利用 FMC 接口,驱动 NAND FLASH。
STM32F767 FMC 接口的 NAND FLASH/PC 卡控制器,具有如下特点:
两个 NAND FLASH 存储区域,可独立配置
支持 8 位和 16 位 NAND FLASH
支持 16 位 PC 卡兼容设备
支持硬件 ECC 计算(汉明码)
支持 NAND FLASH 预等待功能
通过 46.1.1 的介绍,我们对 NAND FLASH 已经有了一个比较深入的了解,包括接线、控
制命令和读写流程等,接下来,我们介绍一些配置 FMC NAND FLASH 控制器需要用到的几个
寄存器。
首先,我们介绍 NAND FLASH 的控制寄存器:FMC_PCR,该寄存器各位描述如图 44.1.3.1
所示:
图 44.1.3.1 FMC_PCR 寄存器各位描述
该寄存器只有部分位有效,且都需要进行配置:
PWAITEN:该位用于设置等待特性:0,禁止;1,使能。这里我们设置为 0,禁止使用控
制器自带的等待特性,因为如果使能的话,将导致 RGB 屏抖动(STM32 硬件 bug)。
PBKEN:该位用于使能存储区域:0,禁止;1,使能。我们要正常使用某个存储区域,必
须设置该位为 1,所以,这个位要设置为 1。
PTYP:该位用于设置存储器类型:
0,保留;
1,NAND FLASH。我们用来驱动 NAND FLASH,
所以该位设置为 1。
PWID:这两个位,用于设置数据总线宽度:00,8 位宽度;01,16 位宽度。我们使用的
MT29F4G08 为 8 位宽度,所以这里应该设置为:00。
ECCEN:该位用于使能 STM32 的硬件 ECC 计算逻辑:0,禁止/复位 ECC;1,使能 ECC
计算;每次读写数据前,应该设置该位为 1,在数据读写完毕,读取完 ECC 值之后,设置该位
为 0,复位 ECC,以便下一次 ECC 计算。
TCLR:这四个位用于设置 CLE 到 RE 的延迟:0000~1111,表示 1~16 个 HCLK 周期。对
应 NAND FLASH 数据手册的 tCLR 时间参数,这里设置的 t_clr=(TCLR+SET+2)*THCLK。TCLR
就是本寄存器的设置,SET 对应 MEMSET 的值(我只用到 MEMSET),THCLK 对应 HCLK 的
周期。MT29F4G08 的 tCLR 时间最少为 10ns,以 216M 主频计算,一个 HCLK=4.63ns(下同),
我们设置 TCLR=5,则 t_clr 至少为 6 个 HCLK 即 27.8ns。
TAR:这四个位用于设置 ALE 到 RE 的延迟:0000~1111,表示 1~16 个 HCLK 周期。对应
NAND FLASH 数据手册的 tAR 时间参数,这里设置的 t_ar=(TAR+SET+2)*THCLK。TAR 就是
本寄存器的设置,SET 对应 MEMSET 的值(我只用到 MEMSET),THCLK 对应 HCLK 的周期。
MT29F4G08 的 tAR 时间最少为 10ns,我们设置 TAR=5,则 t_ar 至少为 6 个 HCLK 即 27.8ns。
ECCCPS:这三个位用于设置 ECC 的页大小:000,256 字节;001,512 字节;010,1024
字节;011,2048 字节;100,4096 字节;101,8192 字节。我们需要以 512 字节为单位进行
ECC 计算,所以 ECCCPS 设置为:001 即可。
接下来,我们介绍 NAND FLASH 的空间时序寄存器:FMC_PMEM,该寄存器各位描述如
图 44.1.3.2 所示:
图 44.1.3.2 FMC_PMEM 寄存器各位描述
该寄存器用于控制 NAND FLASH 的访问时序,非常重要。我们先来了解下 NAND FLASH
控制器的通用存储器访问波形,如图 44.1.3.3 所示:
图 44.1.3.3 NAND FLASH 通用存储器访问波形
由图可知,MEMxSET+MEMxHOLD 控制 NWE/NOE 的高电平时间,MEMxWAIT 控制
NWE/NOE 的低电平时间,MEMxHIZ 控制写入时数据线高阻态时间。接下来我们分别介绍这
几个参数:
MEMSETx:这八个位定义使能命令(NWE/NOE)前,地址建立所需要的 HCLK 时钟周期
数,表示 NWE/NOE 的高电平时间,0000 0000~1111 1111 表示 1~256 个 HCLK 周期。MT29F4G08
的 tREH/tWH 最少为 10ns,我们设置 MEMSETx=1,即 2 个 HCLK 周期,约 9.3ns。另外,
MEMHOLDx,也可以用于控制 NWE/NOE 的高电平时间,在连续访问的时候,MEMHOLDx
和 MEMSETx 共同构成 NWE/NOE 的高电平脉宽时间。
MEMWAITx:这八个位用于设置使能命令(NWE/NOE)所需的最小 HCLK 时钟周期数(使
能 NWAIT 将使这个时间延长),实际上就是 NWE/NOE 的低电平时间,0000 0000~1111 1111
表示 1~256 个 HCLK 周期。MT29F4G08 的 tRP/tWP 最少为 10ns,我们设置 MEMWAITx =3,
即 4 个 HCLK 周期,约 18.5ns。这里需要设置时间比较长一点,否则可能访问不正常。
MEMHOLDx:这八个位用于设置禁止使能命令(NWE/NOE)后,保持地址(和写访问数
据)的 HCLK 时钟周期数,也可以用于设置一个读写周期内的 NWE/NOE 高电平时间,0000
0000~1111 1111 表示 0~255 个 HCLK 周期。我们设置 MEMHOLDx=1,表示 1 个 HCLK 周期,
加上前面的 MEMSETx,所以 NEW/NOE 高电平时间为 3 个 HCLK,即 13.9ns 左右。
MEMHIZx:这八个位定义通用存储空间开始执行写访问之后,数据总线保持高阻态所持
续的 HCLK 时钟周期数。该参数仅对写入事务有效,0000~1111 1111 表示 1~256 个 HCLK 周期。
我们设置 MEMHIZx=1,表示 2 个 HCLK 周期,即 9.3ns 左右。
接下来,我们介绍 NAND FLASH 的 ECC 结果寄存器:FMC_ECCR,该寄存器各位描述如
图 46.1.3.4 所示:
图 44.1.3.4 FMC_ ECCR 寄存器各位描述
该寄存器包含由 ECC 计算逻辑计算所得的结果。根据 ECCPS 位(在 FMC_PCRx 寄存器)
的设置,ECCx 的有效位数也有差异,如表 44.1.3.1 所示:
表 44.1.3.1 ECC 结果相关位
我们以 512 字节为页大小(ECCPS=001),所以 ECCx 的低 24 位有效,用于存储计算所得
的 ECC 值。
接下来,我们介绍 NAND FLASH 的状态和中断寄存器:FMC_SR,该寄存器各位描述如
图 46.1.3.5 所示:
图 44.1.3.5 FMC_SR 寄存器各位描述
该寄存器我们只关心第 6 位:FEMPT 位,该位用于表示 FIFO 的状态。当 FEMPT=0 时,
表示 FIFO 非空,表示还有数据在传输;当 FEMPT=1 时,表示 FIFO 为空,表示数据传输完成。
在计算 ECC 的时候,我们必须等待 FEMPT=1,再去读取 ECCR 寄存器的值,确保数据全部传
输完毕。
至此,FMC NAND FLASH 部分的寄存器就介绍完了,关于 FMC NAND FLASH 控制器的
详细介绍,请大家参考《STM32F7 中文参考手册》第 13.6 节。通过以上三个小节的了解,我
们就可以开始编写 NAND FLASH 的驱动代码了。
水星 STM32F767 核心板板载的 MT29F4G08 芯片挂在 FMC NAND FLASH 的控制器上面
(NCE3),其原理图如图 44.1.3.6 所示:

图 44.1.3.6 MT29F4G08 原理图
从原理图可以看出,MT29F4G08 同 STM32F767 的连接关系:
I/O[0:7]接 FMC_D[0:7]
CLE 接 FMC_A16_CLE
ALE 接 FMC_A17_ALE
WE 接 FMC_NWE
RE 接 FMC_NOE
CE 接 FMC_NCE3
R/B 接 FMC_NWAIT
最后,我们来看看实现对 MT29F4G08 的驱动,需要对 FMC 进行哪些配置。这里我们需要
引入 stm32f7xx_II_fmc.c/stm32f7xx_hal_nand.c 源文件以及对应的头文件。具体步骤如下:
1)使能 FMC 时钟,并配置 FMC 相关的 IO 及其时钟使能。
要使用 FMC,当然首先得开启其时钟。然后需要把 FMC_D0~7、FMC_A16_CLE 和
FMC_A17_ALE 等相关 IO 口,全部配置为复用输出,并使能各 IO 组的时钟。使能 FMC 时钟
和 IO 口初始化方法前面多次讲解,这里就不累赘了。
2)初始化 NAND,设置控制参数(设置 FMC_PCR3)和时间参数(设置 FMC_PMEM3)。
该步骤通过设置寄存器 FMC_PCR3(因为使用的是 FMC_NAND_BANK3 所以对应寄存器
FMC_PCR3)来设置 NAND FLASH 的相关控制参数,比如数据宽度、CLR/AR 延迟、ECC 页
大小等,通过设置寄存器 FMC_PMEM3(因为使用的是 FMC_NAND_BANK3,所以对应寄存
器 FMC_PMEM3)来设置 NAND 的相关时间参数,控制 FMC 访问 NAND FLASH 的时序。HAL
库提供了 NAND FLASH 初始化函数 HAL_NAND_Init:
HAL_StatusTypeDef HAL_NAND_Init(NAND_HandleTypeDef *hnand,
FMC_NAND_PCC_TimingTypeDef *ComSpace_Timing,
FMC_NAND_PCC_TimingTypeDef *AttSpace_Timing);
该函数有三个入口参数,第一个入口参数 hnand 用来设置 NAND FLASH 的控制参数,第
二个入口参数 ComSpace_Timing 用来设置 NAND 通用存储器空间时序,第三个入口参数
AttSpace_Timing 用来设置 NAND 特性存储器空间时序。这里我们着重讲解第一个入口参数
hnand 的定义,该参数为 NAND_HandleTypeDef 结构体类型,该结构体定义为:
typedef struct
{
FMC_NAND_TypeDef
*Instance;
FMC_NAND_InitTypeDef Init;
HAL_LockTypeDef
Lock;
__IO HAL_NAND_StateTypeDef State;
NAND_InfoTypeDef Info;
}NAND_HandleTypeDef;
这里我们主要关注成员变量 Init 的含义,该成员变量是 FMC_NAND_InitTypeDef 结构体类
型,该结构体定义为:
typedef struct
{
uint32_t NandBank;
//BANK 编号
uint32_t Waitfeature;
//等待 特性使能/失能
uint32_t MemoryDataWidth; //数据总线宽度:8 位/16 位
uint32_t EccComputation;
//ECC 计算逻辑使能/失能
uint32_t ECCPageSize;
//ECC 页大小:256/512/1024/2048/4096/8192 字节
uint32_t TCLRSetupTime;
//CLE 到 RE 的延迟
uint32_t TARSetupTime;
//ALE 到 RE 的延迟
}FMC_NAND_InitTypeDef;
这些成员变量设置值对应的是 FMC_ PCR 寄存器相应位,这些成员变量的含义我们都已经
注释了,如有不理解的地方请参考前面 FMC_ PCR 寄存器讲解。
对于 FMC 的时序参数,这里我们就不做 过都讲解,请参考前面讲解。
HAL 库同样为 NAND 初始化提供了 MSP 回调函数 HAL_NAND_MspInit:
void HAL_NAND_MspInit(NAND_HandleTypeDef *hnand);
该函数内部一般用来使能时钟,初始化 IO 口。
3)配置 FMC_PCR3 寄存器,使能存储区域 3。
在 FMC 的配置完成后,最后,设置 FMC_PCR3 寄存器的 PBKEN 位(bit2)为 1,使能存
储区域 3。 如果使用 HAL 库,那么在函数 HAL_NAND_Init 的尾部有使能存储区域的操作,
我们就不需要重复进行此步骤。操作方法为:
__FMC_NAND_ENABLE(hnand->Instance, hnand->Init.NandBank);
通过以上几个步骤,我们就完成了 FMC 的配置,可以访问 MT29F4G08 了,最后,因为我
们使用的是 FMC 的 BANK3,所以 MT29F4G08 的访问地址为 0X80000000,而 NAND FLASH
的命令/地址控制由 CLE/ALE 控制,也就是由 FMC_A17_CLE 和 FMC_A16_ALE 控制,因此,
发送命令和地址的语句为:
44.2 硬件设计
本章实验功能简介:开机后,先检测 NAND FLASH 并初始化 FTL,如果初始化成功,则
显示提示信息,然后按下 KEY0 按键,可以通过 FTL 读取扇区 2 的数据;按 KEY1 按键,可以
通过 FTL 写入扇区 2 的数据;按WK_UP 按键,则可以恢复扇区 2 的数据(防止损坏文件系统);
DS0 指示程序运行状态。
本实验用到的硬件资源有:
1) 指示灯 DS0
2) KEY0、KEY1 和 WK_UP 按键
3) 串口
4) LCD 模块
5) MT29F4G08
这些我们都已经介绍过(MT29F4G08 与 STM32F767 的各 IO 对应关系,请参考光盘原理
图),接下来我们开始软件设计。
44.3 软件设计
打开本章实验工程可以看到,我们在 HARDWARE 分组之下添加了 nand.c,ftl.c 以及
nandtester.c 三个源文件,同时包含了对应的头文件。
由于代码量比较多,我们这里就不将所有代码贴出来了,仅挑一些重点的函数,给大家介
绍,详细的代码请大家打开本例程源码查看。
这里我们需要说明一下,由于 ST 官方 HAL 库提供的 NAND 相关驱动函数我们在使用过
程发现了很多兼容性问题,并且没有提供坏块管理操作,使用起来并不是非常方便。所以我们
ALIENTEK 团队重写了一套 NAND 操作函数供大家参考。
在 nand.c 里面,我们只介绍:NAND_Init、HAL_NAND_MspInit、NAND_ReadPage 和
NAND_WritePage 等三四个函数。NAND_Init 函数代码如下:
该函数用于初始化 NAND FLASH,主要是调用函数 HAL_NAND_Init 函数初始化 NAND,
配置相关控制参数和 FMC 时序,另外,该函数会读取 NAND ID,从而判断 NAND FLASH 的
型号,执行不同的参数初始化。nand_dev 是我们在 nand.h 里面定义的一个 NAND 属性结构体,
存储 NAND FLASH 的一些特性参数,方便驱动。
函数 HAL_NAND_MspInit 内容这里我们就不列出来了,该函数是 NAND 的 MSP 初始化回
调函数,用来初始化与 MCU 相关的步骤,包括时钟使能和 IO 初始化。
接下来,我们看 NAND_ReadPage 函数的代码,如下:
该函数用于读取 NAND 里面的数据,通过指定页地址(PageNum)和列地址(ColNum),
就可以读取 NAND FLASH 里面任何地址的数据,不过该函数读数据时不能跨页读,所以一次
最多读取一个 Page 的数据(包括 spare 区数据)。当读取数据长度为 NAND_ECC_SECTOR_SIZE
(512 字节)的整数倍时,将执行 ECC 校验,ECC 校验完全是按照 46.1 节介绍的方法来实现,
当出现 ECC 错误时,调用 NAND_ECC_Correction 函数(46.1.1 节已经介绍)进行 ECC 纠错,
可以实现 1bit 错误纠正,并报告 2bit 及以上的错误。
接下来,我们看 NAND_WritePage 函数的代码,如下:
该函数用于往 NAND 里面写数据,通过指定页地址(PageNum)和列地址(ColNum),就
可以往 NAND FLASH 里面任何地址写数据(包括 spare 区),同样,该函数也不支持跨页写。
当读取数据长度为 NAND_ECC_SECTOR_SIZE(512 字节)的整数倍时,将执行 ECC 校验,
并将 ECC 值写入 spare 区对应的地址,以便读取数据时,进行 ECC 校验。
nand.c 里面的其他代码以及 nand.h 里面的代码,请大家参考本例程源码。接下来,我看 ftl.c
里面的代码,该文件,我们只介绍:FTL_Init、FTL_Format、FTL_CreateLUT、FTL_LBNToPBN、
FTL_WriteSectors 和 FTL_ReadSectors 等七个函数。
首先,FTL_Init 函数代码如下:
该函数用于初始化 FTL,包括:初始化 NAND FLASH、为 lut 表申请内存、创建 lut 表等
操作,如果创建 lut 表失败,则会通过 FTL_Format 函数格式化 NAND FLASH。
FTL_Format 函数代码如下:
该函数用于格式化 NAND FLASH,执行的操作包括:1,检测/搜索整个 NAND 的坏块,
并做标记;2,分割所有好块,93%用作物理地址(并进行逻辑编号),7%用作保留区;3,重
新创建 lut 表。此函数,将我们在 46.1.2 节介绍的 FTL 层坏块管理的几个要点(识别坏块并标
记、生成转换表、生成保留区),都实现了,从而完成对 NAND FLASH 的格式化(不是文件系
统那种格式化,这里的格式化是指针对 FTL 层的初始化设置)。
接下来,我们看 FTL_CreateLUT 函数,该函数代码如下:
该函数用于重建 lut 表,读取保存在每个 Block 第一个 page 的 spare 区的逻辑编号,存储在
nand_dev.lut 表里,并初始化有效块(nand_dev.valid_blocknum)和好块(nand_dev.good_blocknum)
的数量,完成转换表(lut 表)的创建。
接下来,我们看 FTL_LBNToPBN 函数,该函数代码如下:
该函数用于将逻辑块地址改为物理块地址,输入参数:LBNNum,表示逻辑块编号,返回
值表示 LBNNum 对应的物理块地址。有了该函数,就可以很方便的实现逻辑块地址到物理块
地址的映射。
接下来,我们看 FTL_WriteSectors 函数,该函数代码如下:
该函数非常重要,它是 FTL 层对文件系统的接口函数,用于往 NAND FLASH 里面写入数
据,用户调用该函数时,无需关心坏块和磨损均衡问题,完全可以把 NAND FLASH 当成一个
SD 卡来访问。该函数输入参数:SectorNo 用于指定扇区地址,扇区大小由 SectorSize 指定,一
般我们设置 SectorSize=NAND_ECC_SECTOR_SIZE,方便进行 ECC 校验处理。
该函数根据 SectorNo 和 SectorSize,首先计算出逻辑块地址(LBNNo),然后将逻辑块地
址转换为物理块地址(PBNNo),然后再计算出块内的页地址(PhyPageNo)和页内的偏移地址
(PageOffset),然后计算该页内还可以连续写入的扇区数(如果可以连续写,则可以提高速度),
然后判断要写入的区域,数据是否全为 0XFF,如果全是 0XFF,则直接写入,写入完成对该物
理块进行已被使用标记。如果不是全 0XFF,则需要利用 NAND 页拷贝功能,将本页数据拷贝
到另外一个 Block,并写入要写入的数据,这个操作由 FTL_CopyAndWriteToBlock 函数来完成。
最后,我们看 FTL_ReadSectors 函数,该函数代码如下:
该函数也是 FTL 层对文件系统的接口函数,用于读取 NAND FLASH 里面的数据,同样,
用户在调用该函数时,无需关系坏块管理和磨损均衡问题,可以像访问 SD 卡一样,调用该函
数,实现读取 NAND FLASH 的数据。该函数的实现原理,同前面介绍的 FTL_WriteSectors 函
数基本类似,不过该函数对读数时出现的 ECC 错误,进行了处理,对于读取数据时出现 1bit ECC
错误的 Block,进行两次读取(多次确认,以免误操作),如果两次读取都有 1bitECC 错误,那
么该 Block 可能是坏块,当出现此错误后,我们先将该 Block 的数据,拷贝到另外一个 Block
(备份现有数据),然后对该 Block 进行擦除和写 0,然后判断擦除/写 0 是否正常,如果正常,
则说明这个块不是坏块,还可以继续使用。如果不正常,则说明该块确实是一个坏块,必须进
行坏块标记,并重建 lut 表。如果读数时出现 2bit ecc 错误,这个不一定就是出错了,而有可能
是读取还未写入过数据的 Block(未写入过数据,那么 ECC 值,肯定也是未写入过,如果进行
ECC 校验的话,必定出错),导致的 ECC 错误,对于此类错误,我们直接不予处理(忽略)就
可以了。
ftl.c 里面的其他代码以及 ftl.h 里面的代码,这里就不做介绍了,请大家参考本例程源码。
另外,nandtester.c 和 nandtester.h 这两个文件,主要用于 usmart 调试 nand.c 和 ftl.c 里面的相关
函数,这里也不做介绍了,请大家参考本例程源码。
最后,打开 main.c 文件,代码如下:
此部分代码比较简单,我们先初始化相关外设,然后初始化 FTL,在 FTL 初始化成功以后,
先对扇区 2 的数据进行备份,随后进入死循环,检测按键,可以通过 KEY0/KEY1/KEY2 按键
对扇区 2 的数据进行读取、写入和还原操作。同样,DS0 闪烁,用于提示程序正在运行。
最 后 , 我 们 将 NAND_EraseChip 、 NAND_EraseBlock 、 FTL_CreateLUT 、 FTL_Format 、
test_writepage 和 test_readpage 等函数加入 USMART 控制,这样,我们就可以通过串口调
试助手,测试 NAND FLASH 的各种操作了,方便大家测试。软件部分就给大家介绍到这里。
44.4 下载验证
在代码编译成功之后,我们通过下载代码到 ALIENTEK 水星 STM32 开发板上,得到如图
44.4.1 所示界面:
图 44.4.1 程序运行效果图
此时,我们可以按下 KEY0/KEY1/WK_UP 等按键进行对应的测试。我们按 KEY0,可以读
取扇区 2 里面的数据,通过串口调试助手查看,如图 44.4.2 所示:
图 44.4.3 串口观看扇区 2 里面的数据
另外,我们还可以利用 usmart,调用相关函数,执行不同的操作,如图 44.4.4 所示:
图 44.4.4 USMART 调用相关函数
站在推动 Web 发展方面发挥的作用是不可否认的。从克服浏览器视频功能的限制到使用 WebSockets 推送广告(以防止广告拦截广告),您必须不断想出巧妙的方法,才能让自己处于 Web 技术创新的前沿。
最近,我有幸采访了大型站Pornhub的一名Web开发工程师,了解了相关的开发技术,Web API的改进,以及成为一名站开发工程师的感受。
注意:由于站行业竞争激烈,有些问题他们无法回答我,这一点我理解。
站需要显示大量图片内容。在开发过程中,您是否使用了大量图片和视频占位符?开发过程中的内容体验与最终产品之间是否存在很大差距?
事实上,我们在开发这个网站时没有使用任何占位符!归根结底,代码和功能才是最重要的,至于界面,我们现在已经很熟悉了。一开始有点困难,但我们很快就习惯了。
在开发过程中,你们是如何模拟直播视频流和第三方广告脚本的?它们都是重要的资源。
播放器分为两个组件,基础组件实现核心功能,用于触发事件,开发分开进行,集成时需要用到第三方脚本和广告,这样可以尽早发现问题,对于一些特殊情况,我们会配合广告商手动触发一些随机事件。
典型网页至少包含一个视频、一些 GIF 广告、一些实时预览和其他视频的缩略图。如何衡量网页性能?如何最大程度地提高网页性能?
我们使用多种评估系统。
播放器会向我们发送视频播放性能和用户播放状态;
我们使用了第三方RUM系统;
我们使用 WebpageTest,以便能够看到特定时间发生的情况。
我认为播放器是前端最重要和最复杂的功能之一。如何通过在视频前插入广告、标记视频的关键部分、更改播放速度等来保持播放器的性能、功能和稳定性?
我们有一个专门负责播放器开发的团队,他们的首要任务是持续监控播放器的性能。我们使用所有可用的工具:浏览器性能工具、WebpageTest、性能指标等。每次发布之前,我们都会进行一轮严格的 QA,以确保稳定性和质量。
视频团队有多少全职开发人员?有多少前端开发人员?
如果按照整个产品的规模来算,我只能说我们的团队是中等规模。
在您从事站开发期间,您看到前端领域有哪些发展?哪些新的 Web API 对您有很大帮助?
我看到前端技术在很多方面都在进步。
从使用纯CSS到使用LESS和Mixin,再到使用灵活的网格系统和图片标签来适应不同的分辨率和屏幕尺寸;
jQuery、jQueryUI 逐渐淡出了我们的视线,回归到更加面向对象的纯 JavaScript 编程,一些框架在特定场景下也发挥着非常有趣的作用;
我们非常喜欢新的 IntersectionObserver API,它对于加载图像非常高效;
我们还使用画中画 API 让视频浮动在页面上,但我们仍在获取用户对这个想法的反馈。
展望未来,您希望看到哪些 Web API 有所改变、改进或新增?
我们预计这些 API 会发生变化或改进:Beacon、WebRTC、Service Worker 和 Fetch。
Beacon:在iOS上存在一些问题,pageHide事件支持不够好;
Fetch:没有下载进度,也无法拦截请求;
WebRTC:直播的时候,如果分辨率不够高,会受到一些限制;
服务工作线程:对 navigator.serviceWorker.register 的调用不会被服务工作线程的 Fetch 事件处理程序拦截。
过去几年,WebVR 有所改进。现在它有多大用处?站会投入多少精力来支持 VR 内容?Pornhub 的 WebVR 是否涉及触觉?
我们正在研究如何在沉浸式空间中使用 WebXR。作为最大的内容分发平台,我们必须为用户提供以自己的方式体验我们网站上的内容的机会。但我们仍在探索使用这些新媒体时内容和平台应该是什么样子。
我们是支撑VR、计算机视觉、虚拟主播的主要平台,并将继续推动新技术的发展。
每个页面上都有不同类型的媒体和内容,对于桌面或移动设备需要考虑的最重要的事情是什么?
我们主要考虑操作系统和浏览器所施加的功能限制。例如,iOS和Android的访问权限和功能有很大差异。
一些 iOS 设备不允许在全屏模式下使用自定义播放器,并将强制使用原生 QuickTime 播放器。Android 给予我们完全控制权,并且可以在全屏模式下使用我们的播放器。
再比如HLS视频流,IE、Edge对HLS视频流的质量非常挑剔,所以我们需要控制视频的质量,否则播放时会出现断续或者重影的情况。
Pornhub 目前支持的最低浏览器版本是多少?它还支持 IE 吗?
我们长期支持 IE,但最近停止了对 IE 11 之前的版本的支持。此外,我们还停止了对 Flash 播放器的支持。我们现在主要支持 Chrome、Firefox 和 Safari。
你能分享一下 Pornhub 的技术栈吗?从服务器到前端,你使用了哪些库?
基本上,我们使用了这些东西:
Nginx;
PHP;
MySQL的;
Memcached/Redis。
其他技术包括 Varnish、ElasticSearch、NodeJS、Go 语言和 Vertica。
对于前端,我们主要使用纯 JavaScript。我们正在逐步淘汰 jQuery,并开始使用 Vue.js 等框架。
对于外行人来说,站通常充斥着视频缩略图、视频、直播和广告。从开发者的角度来看,站有什么独特之处?
我们努力让每个品牌都具备一定的独特性,拥有不同的内容、界面体验和功能,并且我们使用了许多不同的算法。
当你接受 Pornhub 采访时,你脑子里在想什么?你有没有犹豫过?如果有,你是如何克服这些感觉的?
我并没有觉得有什么不对,毕竟这个挑战对我来说很有吸引力。想到有数百万人会使用我开发的东西,我就兴奋不已。这个想法很快得到了验证,当我开发的功能首次推出时,我非常自豪,并告诉我的朋友去看看!站永远不会消亡,它为我们提供了稳定的工作来源。
开发站可能与开发普通网站不同。当您告诉朋友、家人和熟人您正在开发站时,您会感到羞耻吗?您会犹豫是否要告诉他们?
我对自己开发的东西很自豪,身边的人都知道、喜欢,也成了大家茶余饭后的谈资,很有意思。
您在其他地方开发过其他网站,Pornhub 的工作氛围是否不同?
这里的气氛非常轻松和友好,我认为这与其他地方没有什么不同。
作为前端开发者,你需要和哪些团队紧密合作?你通常使用哪些沟通方式?
我们需要与后端开发人员、QA 和产品经理进行交互。大多数时候我们会去各自的工作站讨论问题,然后使用聊天工具(Microsoft Teams),然后发送电子邮件。
最后,作为一名站的开发者,您还有什么想分享的吗?
我很高兴能参与开发一款拥有如此庞大用户群的产品。我们处于技术发展的前沿,这让一切都变得有趣且富有挑战性。
后记
这次采访很有启发性。我很惊讶他们在开发时不使用图像。Pornhub 处于网络技术的前沿——WebXR、WebRTC 和 Intersection Observer API。我也很高兴看到他们开始逐步淘汰 jQuery,因为当前的网络 API 非常棒。
OK,本文到此结束,希望对大家有所帮助。
最近,阿伦(Aellen)深深地从事高端室内设计,并被定位为“建筑和装饰零售服务提供商”,他正式启动了一项全新的商业计划,该计划在北京酿造了很长时间。通过重塑价
上限锁定指示器用于显示盖锁是否已打开。关闭指示灯的方法非常简单,只需按键盘上的盖子锁定键即可。如果指示灯打开,则意味着大写锁已打开;再次按CAPS锁定键,指示灯
安装失败和WindowsUpdate有关系,按如下操作,即可安装成功:首先保证系统用户是Administrator;如果需要切换用户:同时按【ctral+alt
手机快播怎么看片或者下载视频方法1:关于如何在移动kuaibo上观看电影的问题,打开kuaibo,然后单击左上角的“打开按钮”。中间会有一个搜索框。输入您要观看
光学变焦,是通过光学镜头中镜片移动来放大与缩小所拍景物,光学变焦倍数越大,能拍摄的景物就越远。光学变焦并不会改变图片的分辨率,图片的像素数也保持不变,这就是光学
就决定给老妈挑套物美价廉的键盘,最好一套的自己用的赛睿的五颜六色键盘配大白鼠,等有钱换个大钢鼠其实还有一个雷蛇炼狱磨砂蓝,但感觉已经过了用雷蛇的年纪了其实平时用
用户评论
终于找到flash源代码了!当年想学习做动画可是找不到资源,这个贴实在太棒了!可以分享一下哪些软件能打开这些源文件吗?
有19位网友表示赞同!
我有一个flash动画项目搁置好多年了,现在突然想重新修订!没想到连源代码都找回来了,真是激动!不知道有哪些平台可以用来制作和发布flash动画啊!?
有9位网友表示赞同!
说实话,这些flash源代码有点看不懂。当年学的时候只用了简单插件就搞定了效果,现在看来那些复杂的函数代码都是个谜啊。。。
有20位网友表示赞同!
这flash动画真的很有年代感!感觉这种技术早就过时了,现在的网页怎么都是HTML5动画?
有7位网友表示赞同!
下载了几个flash源代码看了看,真是一点也不像现代的代码風格... 还是HTML5简单吧!
有12位网友表示赞同!
哇!懐かしい!我 dulu pernah belajar flash animation di sekolah, tapi sekarang udah lupa semua! Ini bagus banget buat aku jogjas!
有7位网友表示赞同!
当年学习flash动画可是花了很多时间,现在看看这些源代码竟然这么简洁!不愧是曾经的宠儿啊!
有7位网友表示赞同!
FLASH确实很有历史意义,当年可是我的青春记忆了!不过现在的HTML5真的更方便灵活啊...
有5位网友表示赞同!
想问这flash源代码可以直接在浏览器里运行吗?还是需要安装一些特殊的软件?
有15位网友表示赞同!
这些flash动画源代码真是太珍贵了!希望能找到更多古老的动画资源,重新感受一下当年科技的风采。
有7位网友表示赞同!
"Flash的源代码"这个关键词实在太吸引人了!我也想看看那些曾经流行的动画是怎么制作出来的。
有8位网友表示赞同!
flash动画虽然老旧,但很多经典作品至今都让人印象深刻!现在看这些源代码感觉是打开了一个全新的世界啊!
有8位网友表示赞同!
FLASH 真的是一个时代的结晶啊! 如今HTML5时代了, 可这东西的魅力始终存在。 感谢分享!
有10位网友表示赞同!
这帮人太牛了吧!还能找到这么古老的flash源代码,简直是宝藏!
有5位网友表示赞同!
我当年用Flash做出的动画作品,现在看来真是土气不堪...
有6位网友表示赞同!
FLASH 的时代毕竟已经过去了。现在的HTML5更加灵活实用,更适合现代网页开发。
有6位网友表示赞同!
这个帖子让我感觉回到了学生时代的学习时光,那时候对电脑动画充满了憧憬和热情!
有12位网友表示赞同!
下载了几个flash源代码看了一下,虽然写的有点古老,但逻辑结构还是很好理解的。
有12位网友表示赞同!