深度探索嵌入式操作系统:从零开始设计、架构和开发(txt+pdf+epub+mobi电子书下载)

作者:彭东

出版社:机械工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

深度探索嵌入式操作系统:从零开始设计、架构和开发

深度探索嵌入式操作系统:从零开始设计、架构和开发试读:

前言

为什么写这本书

随着移动互联网技术的成熟,物联网也开始崭露头角,由此产生了各种小型、低功耗的智能硬件,这些智能硬件被嵌入到移动电话、手表、冰箱、空调、电视机、洗衣机等常用电子产品中,使这些常用电子产品功能更加强大、更加智能,而且它们可以连接到网络,便于用户远程操控,从而大大改善了人们的生活。

因此,嵌入式行业才变得如此火热,那些被嵌入到电子产品中的智能硬件,也需要一些小巧、特殊的操作系统软件才能正常工作,这类小巧、特殊的操作系统软件,称为嵌入式系统。2013年下半年,我开始学习嵌入式系统,并编写了一个嵌入式操作系统——LMOSEM。在互联网上也认识了不少研究嵌入式的朋友,在他们的要求和规劝下,我终于有勇气把我研究出来的东西归纳、整理成册,也算是我学习的笔记,于是就有了这本书。虽然有很多的顾虑,怕贻笑方家、怕误导同道……但是我的每行代码、每个点子,都在实机上测试过并证明了其正确性,所以也就心下一片坦然了。如果这本书能够被后来者借鉴一二,或者解决他们的一些疑惑,我自然欣慰万分。

关于LMOSEM

关于LMOSEM,这得从LMOS开始说起。2010年下半年,我开始准备要写个操作系统内核,没有其他目的,只是出于学习,出于兴趣。由于是自己独立从零开始设计、编写的,我觉得自己这种行为有点疯狂,索性用LMOS(liberty madness operating system)命名了我的操作系统。LMOS经过这几年的独立开发,现在已经发布了6个测试版本。先后从32位单CPU架构发展到64位多CPU架构,现在的LMOS已经是多进程、多线程、多CPU、支持虚拟内存的x86-64体系下的操作系统内核。LMOS的这些特性,非常适合通用计算机领域,如PC、工作站、小型服务器。这些特性导致LMOS代码量庞大,一些组件不够小巧,削剪起来非常复杂,很难保证削剪后的组件是否健壮,因此LMOS不适合于嵌入式领域,所以笔者才重新开发了LMOSEM——适合嵌入式领域的操作系统。

LMOSEM依然删除了很多代码,因为写书要做到简单,便于理解。即便如此,LMOSEM依然包含了现代操作系统的大部分重要组件,如内存管理、进程管理、驱动模型、文件系统等。这些组件的实现过程在本书中都会有详细的介绍。LMOSEM不支持实时性功能,嵌入式操作系统也不一定要是实时性的操作系统,何况我们是出于学习的目的。为了代码的清晰、简单,我们暂不考虑安全性和性能方面的问题。等到明白了操作系统原理,我们再去不断修正、优化,使之功能变得更多,性能变得更强。笔者开发的LMOSEM操作系统项目,是在Linux操作系统下开发的,用到了Linux操作系统的很多工具。笔者不会和读者讨论为什么不用常用的Windows系统,也不会说谁好、谁不好。如果读者非常喜欢Windows系统,那么也可以尝试着把这个项目迁移到Windows系统下。但是笔者书中演示的环境还是Linux系统。关于如何搭建开发环境,本书后面的章节有详细的介绍。在那里读者会发现用Linux系统开发LMOSEM内核有很多方便之处,如会用到的MAKE、GCC、LD等,这些工具在Linux系统下都很容易得到,在Windows系统下虽然也能做到,但相对麻烦一点。何况今天的Linux系统已经很好用了。

读者对象

·如果读者是一位纯粹的操作系统爱好者,对其有着浓厚的兴趣,那么本书将非常适合。

·如果读者是嵌入式领域的从业者或者学生,也可以从本书中获得很多帮助。

·如果读者是一位普通的应用软件开发者,业余时间也可以翻翻此书,书中的一些设计方法和编程手段,或许可以借鉴一二。

·如果你只是想了解一些计算机硬件系统和软件系统的常识,那么本书同样会让你获益。

如何阅读本书

为了能更轻松地阅读这本书,笔者建议先了解C语言这门编程语言,对数据结构有所了解就更好了。除这些外,笔者假定读者没有其他任何技能。除了需要的上述技能,读者还需要对操作系统有强大的兴趣和求知欲,要有坚强的意志、永远不放弃的精神。开发操作系统内核本身就不是件容易的事,必然会有很多问题在等着我们,但是遇到问题不要害怕,静下心从容面对,只要我们不放弃,问题最终会解决。

本书很简单,没有拐弯抹角,没有反复修饰,但是必要的细节从不漏掉。宁可在细节上啰嗦一点,也不在不相关的地方多写一句。

本书的最终目的是构建一个用于学习的嵌入式操作系统内核,并工作在真正的物理机上。为了达到这一目的,本书大体上分为三部分:综述、硬件部分和软件部分。

综述部分(第1章)。

第1章,先说明操作系统的概念、功能和演进历史,最后得出现代操作系统的模型,使我们可以了解操作系统的轮廓。

硬件部分(第2~3章)。

第2章,从选择硬件平台开始,首先概述硬件平台的整体情况,接着了解编写操作系统内核必需的一些平台上的组件,如实时时钟、定时器、串口、中断控制器、内存芯片、Flash芯片、CPU、MMU等。让读者有初步的印象,在写代码用到某个组件时再详述其内部编程细节。

第3章,详细介绍处理器,重点介绍处理器的结构和特性、处理器的地址空间、处理器的状态和工作模式、处理器的寄存器和指令集。最后介绍处理器中的MMU和Cache,对于MMU,主要介绍MMU的作用和它对操作系统内核开发的影响、如何对MMU编程、MMU的几种地址映射方式。而对于Cache,重点介绍Cache的作用、Cache的类型、Cache的使用。

软件部分(第4~12章)。

第4章,介绍操作系统内核设计、操作系统内核的开发环境、开发操作系统内核的工具:GCC、LD、MAKE,以及它们的使用方法,最后介绍硬件平台的安装与测试。

第5章,首先介绍C语言使用寄存器的约定,以及它是如何处理参数、返回值的。接着介绍C语言基本数据类型的位宽及占用内存的大小,并用它们构建后面将要用到的一些基本的数据结构,如list_h_t、spinlock_t、kwlst_t、sem_t。然后介绍C语言的数据结构在内存中存在的形式、对齐方式。最后介绍GCC独有的嵌入汇编代码的方式。

第6章,开始介绍LMOSEM的初始化,从第一行汇编代码开始、初始化MMU和中断向量、初始化串口设备、初始化内存管理数据结构和中断相应的数据结构,最后对一些数据结构进行测试。

第7章,开始介绍LMOSEM的内存管理组件。LMOSEM的内存管理组件分为三层:块级内存管理、页级内存管理、字级内存管理,这三个层分别应对不同的内存分配请求。本章将结合实际代码介绍如何一步步实现这三大内存管理层。

第8章,介绍LMOSEM的中断管理组件,内容包括中断控制器的细节、中断管理组件的结构、如何处理中断、安装中断处理的回调函数等。

第9章,介绍LMOSEM的设备驱动模型,其中介绍LMOSEM如何管理众多的硬件设备、LMOSEM支持的设备类型、驱动模型的数据结构和基础性代码,最后用两个驱动程序实例介绍如何在LMOSEM的驱动模型下编写规范的设备驱动程序。

第10章,介绍LMOSEM的进程管理组件,包括进程的由来、进程相关的数据结构、系统空转进程的建立与运行、进程调度、新建进程、进程的睡眠与唤醒、进程测试等相关内容。

第11章,介绍LMOSEM的文件系统组件,包括文件系统的设计、文件系统的建立、文件系统的基础操作、文件本身的操作,如文件的打开、新建、读写、删除等。最后对文件系统组件进行严格的测试。

第12章,介绍LMOSEM的接口,包括许多LMOSEM的API和库函数的实现细节,主要包括时间、进程、内存、文件与设备、标准输入/输出等方面的API和库函数。

勘误和支持

由于笔者水平有限,加之编写时间仓促,书中难免会出现一些不准确的地方,恳请读者批评指正,在技术之路上共勉。我的CU博客地址是:http://blog.chinaunix.net/uid/28032128.html。本书源代码已制作成光盘镜像文件,并上传到华章网站(www.hzbook.com),需要的读者可自行下载。

致谢

我,自幼患病,读书不多,计算机成了唯一的兴趣爱好,没有父母的长期支持,连生活都尚且不能自理,更别说完成此书了,他们对我的帮助和关爱,纵使千万言语也难表一二。由于经常在物理机上测试内核,要拆装一些设备和器件,这多亏了我的小弟,因为他一有时间就帮我做这部分工作。当然还有帮助过我的朋友,有一些是身边的,有些是网络中的。对父母、所有的亲人、朋友,我也只有常怀感恩之心,说声谢谢,谢谢他们一直的支持、帮助,谢谢他们一直对我那满满的关爱!

让笔者和你一起带着未知,带着好奇,带着兴奋,踏上操作系统的旅程吧!

第1章 操作系统的功能及为什么需要它

你或许已经卷起了衣袖,或许在摩拳擦掌准备大干一场,打一场硬仗。年轻人嘛,行事总是风风火火的。但不是笔者扫你的兴,泼你冷水,在我们写代码之前还有很长一段路要走,要静下心来。如果写操作系统是一次旅行,那么千万不要错过沿途的风景……

1.1 从hello world开始

操作系统也是软件,也是由一大堆程序组成的,所以不要觉得它多么神秘。既然是程序,我们就要知道它是干什么的以及为什么需要,笔者想用大多数人写的第一个程序——“hello,world!!”来描述这个原因。当然这个程序是用C语言写的。大致过程如图1-1所示。

这个程序正常运行后,会在屏幕上输出hello,world!!这个字符串。显然这个程序中最重要的是printf函数,然而我们并没有实现它。如果你能发现这一点,并迫切地想知道它究竟在背后干了些什么,那说明你和笔者一样有着对问题追根溯源的性格。这个也是我们研究问题本相的原动力。图1-1 hello,world!!程序的生成过程

那么printf在哪儿呢?都干了些什么呢?

它就在应用程序库中,代码虽然没有实现它,但库中实现了,程序链接器最终把它和代码链接装配在一起,这样程序也就能正确工作了,如图1-2所示。图1-2 hello,world!!程序的链接过程

实际中可能有差异,可能printf不是在单独的库中,也可能不只是链接这一个库就行了。但是道理都一样。

printf函数把程序传给它的“hello,world!!”字符串数据复制到一个内存缓冲区中,然后调用操作系统提供的API(应用程序编程接口)函数。可能不同的实现之间有差异,但是大致动作如图1-3所示。图1-3 printf函数的逻辑工作机理

一旦调用操作系统API,代码的控制权就交给了操作系统,执行的也是操作系统的代码。至于实现这一机制的进程,后面的章节会详细讨论。操作系统会根据不同的API函数以及应用程序传递进来的参数完成不同的动作和功能。比如,程序中的printf、调用的API和传递的参数,是要告诉操作系统把它缓冲区中的数据写入标准输出设备上。于是我们在屏幕上就看到了hello,world!!,然后程序就逐层返回到main函数,最后main函数退出,这个小程序也就结束了。下面用图1-4来描述这一过程。

由图1-4可知,真正操控计算机硬件完成显示hello,world!!的是操作系统这个软件。是它在背后默默地工作着。当然它的功能并不只是操控计算机硬件,我们后面会慢慢讨论。

现在来看看没有操作系统能完成这个hello,world!!的程序吗?有!只是我们要做的工作多了很多,我们得亲自实现printf函数、完成控制计算机硬件的程序,并且还要求计算机内部这时只运行这一个应用程序,因为有些硬件同一时间只能被一个程序使用,如图1-5所示。

写上面这样的程序可能对程序员的要求有点高,因为必须要知道计算机硬件的每个细节,否则程序不会出现正常的结果。好吧,我们还是应该承认这个世界存在这种编程高手。

关于hello,world!!这个程序,我们就说到这里。如果没有操作系统,无论开发程序还是运行程序,难度都会很高。

现在去看看先辈是如何一步一步创造出操作系统的。图1-4 hello,world!!程序调用操作系统API的过程图1-5 裸机hello,world!!程序

1.2 操作系统功能演进

在很久以前确实存在上述这种模式的程序,并且每次计算机中只存在一道这样的程序,运行完一道,手工装入第二道……你会发现这太慢了,也太麻烦了,对昂贵的计算机硬件的利用率也太低了,因为这样的程序是不可能让计算机内部所有的设备都工作起来的。

然而首先知道这个问题的不是我们,先辈早已看到这类问题,他们想了个方法,在计算机的内部放入一道监控程序,然后把要执行的所有程序放在一个固定的介质上,每次那个监控程序选择一道要运行的程序装入计算机内部去执行,这道程序执行完了,再装入下一道程序……直到运行完所有的程序。如图1-6所示。从全局看效率高了不少,但是从局部来看,它仍然没有让计算机的所有设备都工作起来。同时也还是没有降低程序员的难度,因为还是要操控程序要用到的硬件。

我们马上会想到,能不能把那个所谓的监控程序稍稍改进和扩展一下,把那些操作各种硬件的代码和实现重要功能的代码,放进监控程序里。然后我们对这些功能进行编号,比如,1号功能是操作键盘的、2号功能是打开硬盘上的文件……最后应用程序要完成什么功能,只要call××号功能,计算机的控制权就会交给监控程序,当监控程序中的代码完成这个功能号对应的服务时就返回到应用程序中。图1-7展示了这一过程。图1-6 古老的监控程序及其执行过程图1-7 进一步扩展的监控程序

这样给应用程序开发人员带来的不只是一点点方便,对他们而言,完全是种解脱。方便是方便了不少,但这还是只运行了一个应用程序,你或许想到了DOS操作系统。是的,DOS就是这样的操作系统。

我们继续思考一种情景:你正在用QQ软件和你的朋友聊天,QQ软件等待你输入消息,然后把这个消息通过网络发送给你的朋友。QQ软件等待你的输入,这个时间可能是几秒钟,甚至更久。这几秒钟对如此之快的计算机来说,无疑是巨大的浪费。如果这时内存中存在着另一个软件,这个几秒钟是否可以拿来运行另一个软件呢?那当然是可以的。比如,我们让这几秒钟切换到KuGou软件上,等到用户输入消息时,再换回来,于是我们就可以一边聊天,一边听音乐了,如图1-8所示。当然这是其中一种比较常见的情景,还有等待网卡上的网络数据包、等待磁盘上的数据、等待声卡缓冲区空闲、等待打印机打印完文档、等待扫描仪的输入等之所以会有以上这些“等待”,是因为计算机内部各种设备的速度不相同,如键盘的输入速度赶不上CPU的速度、磁盘的数据传输速度比不上CPU的数据处理速度……

还是上面的情景,我们继续进一步思考一些问题。QQ和KuGou同时存在于内存中,那么就要占据不同的物理内存空间。作为操作系统当然就要知道哪些内存是空闲的,哪些内存是已经占用的,当然如果QQ程序退出了操作系统就要标识QQ占用的内存已经空闲了,从而可以被用于其他用途。QQ和KuGou是两个不同的程序,操作系统要知道它们的存在,包括它们的一些信息,例如,它们各自占用多大内存、在内存中的什么地址,它们各自执行到哪里了,以及当前CPU上执行的是哪个程序。QQ要记录你的聊天数据,KuGou要读取MP3音乐数据,操作系统就要组织这些数据的存放、读取,以及控制这些数据的访问权限。最后QQ要发送消息,KuGou要播放音乐,这最终都要用到计算机内部具体的硬件设备,QQ要用到网卡和磁盘、KuGou要用到磁盘和声卡,操作系统当然要知道计算机内部有多少设备,每个设备的状态、类型及访问操作方式,以便代替应用程序访问控制设备。图1-8 多道程序的设想

上述情景中,我们思考的问题,当然也是操作系统重点要解决的问题,也可以说是操作系统要完成的功能。先辈还对其进行规划并定义了如下专业的术语。

内存管理:最简单的原因是要在内存中放入不止一道程序。

进程管理:既然内存中有多道程序,首先要知道它们的存在、状态及与这道程序相关的重要信息。

文件系统:用户有那么多的数据,如音乐、电影、文档、其他数据,如何组织它们,以何种形式查找访问它们,如何才能把它们安全地保存在计算机中。

设备管理:由上可知,操作系统必须要知道计算机内部有多少个设备、设备各自是什么类型,设备当前能否被访问,最重要的任务是对应用程序屏蔽设备细节,代替应用软件访问控制设备。

如果站在全局较高的角度看,就是这样的:把计算机内部的设备和设备中的数据统称为“资源”,操作系统即是众多资源的管理者。应用程序无非就是通过操作系统这层软件获取资源、使用资源、释放资源。而操作系统则一边维护众多资源的状态,一边通过众多资源状态,如该资源当前能否使用,或者该资源是共享访问的资源还是互斥访问的资源,从而调度安排众多应用程序有序、高效地运行。最后达到高效使用计算机的目的。

上面所有这些描述或许看上去很陌生,先不要急,我们后面慢慢地一步一步介绍。我们根据上述所有的描述,用一张图来大致表示现代整个计算机系统的结构,如图1-9所示。图1-9 现代操作系统模型

从图1-9不难看出,如此复杂的计算机,有如此多的功能,时刻影响并改变着人们的生活。然而它也是一层一层地建立起来的。或许我们还有很多疑问:如何实现设备管理、进程又是什么、如何实现系统调用……这正是我们后面要解决的问题,现在我们只要明白计算机中有一层叫操作系统的软件,它在背后默默地干了些十分重要的事情,如果没有它事情会变得很糟糕。

1.3 小结

这一章就要结束了,现在我们来回想一下:

1)我们从hello,world!!开始,发现完成输出功能的是一个叫操作系统的软件;

2)后来我们想不用操作系统,也能完成这个小程序,只是困难了很多,重要的是计算机的利用率很低;

3)然后我们做了一个监控程序,让它负责运行这种类型的程序,并对它进行改进,降低了编程者的编程难度,计算机的利用率依然很低;

4)再然后我们在内存中同时放入多个程序,让一个程序因为一些原因不能继续向下运行时,就切换到别的程序,让其开始运行;

5)最后,我们基于第4点的想法,不断地改进和扩展,终于建造出现代操作系统的模型(见图1-9)。

现在休息一下,进行下一步探索,相信会更精彩。

第2章 硬件平台

这可能有点天马行空了。第1章粗略地介绍了操作系统的功能以及为什么需要它,接着就讲到了硬件平台。或许你还在想操作系统的第一行代码是什么、该从哪儿开始呢?不要急,现在所做的一切,都是为了最终的目标而努力着。做任何事情必然都有个过程,不能一蹴而就,心态平静很重要。本章将首先介绍为什么要选择mini2440这个硬件平台,最后介绍我们必须要关注的这个硬件平台上的一些组件。

开始吧!

2.1 选择平台

读者可能没有听说过mini2440,它是一种ARM开发板,这里先搞清楚如何选择一款硬件平台,为什么要选择mini2440,然后介绍mini2440的相关信息。

2.1.1 mini2440

现代计算机系统大都可以从逻辑上分为三大层:硬件层、系统软件层、应用软件层,当然还可以继续细分,如图2-1所示。每层都隐藏自己相关的实现细节,向上层提供相关接口,根据情况决定是否需要调用下层提供的接口。就像第1章分析的printf函数一样,你不必思考它是怎么实现的,只要调用它就行了,具体怎么做是它的事。这就是为什么写一个应用程序,首先要去了解各种应用程序库和这个应用程序运行所在的操作系统平台的API。因为我们要知道这个系统平台提供给应用程序的编程接口。

没有硬件的软件是空中楼阁,没有软件的硬件是一堆废物品,二者缺一不可。就像人一样,不仅要有强健的身躯,还要有智慧的大脑。

我们的目的是写操作系统内核。那么好了,由图2-1可知,首先应该了解某一具体硬件平台提供给我们的“接口”。

现在市面上的计算机平台种类繁多,有各种型号的超级计算机、服务器、PC、嵌入式开发板,当然你可能不会选择超级计算机和服务器来开发操作系统内核,我们要从中选择一个适合我们的。

既然这样,就要选择一个简单、常用、便宜的计算平台作为开发平台。而满足前三个条件的就是mini2440开发板。嵌入式开发板,比通常用的PC简单、便宜,而大多数嵌入式开发者或者学习嵌入式的同学都是从mini2440开发板开始的。下面就开始仔细研究这个开发板。图2-1 现代计算机系统的逻辑分层

2.1.2 mini2440平台的信息

mini2440开发板,是友善之臂公司基于三星公司的S3C2440A芯片,并结合了一系列的外围组件开发出来的一款嵌入式开发板。组件非常丰富,性能不错,也很常用,非常适合嵌入式系统的入门学习。

下面来看看mini2440开发板都有些什么,各自都有什么作用,即用来干什么的,mini2440开发板的概况如图2-2所示。

哇,这看上去各种硬件接口、芯片……真不少。归纳如下。

1)Samsung S3C2440A CPU处理器,主频400MHz,最高533MHz。图2-2 mini2440物理视图(源自友善之臂公司)

2)由2片32MB的SDRAM芯片组成的64MB内存,32位的内存数据总线,SDRAM时钟频率高达100MHz。

3)Flash存储,板载,256MB/1GB Nand Flash,掉电非易失(用户可定制64MB/128MB/256MB/512MB/1GB)。

4)2MB Nor Flash,掉电非易失,已经安装superVIVI引导程序,相当于PC上的BIOS。

5)LCD显示接口,板上集成4线电阻式触摸屏接口,可以直接连接四线电阻触摸屏,支持黑白、4级灰度、16级灰度、256色、4096色的STN液晶屏,尺寸从3.5寸~12.1寸,屏幕分辨率可以达到1024×768像素。标准配置为3.5真彩LCD,分别率240×320,带触摸屏。

6)1个100M以太网RJ-45接口(采用DM9000网络芯片)。

7)3个串行口。

8)1个USB Host。

9)1个USB Slave B型接口。

10)1个SD卡存储接口。

11)1路立体声音频输出接口,一路麦克风接口。

12)1个2.0mm间距10针JTAG接口。

13)4个USERLED灯。

14)6个USER按键(带引出座)。

15)1个PWM控制蜂鸣器。

16)1个可调电阻,用于AD模数转换测试。

17)1个I2C总线AT24C08芯片,用于I2C总线测试。

18)1个2.0mm间距,20pin摄像头接口。

19)1个板载实时时钟电池。

20)电源接口(5V),带电源开关和指示灯。

21)系统时钟源,12MHz无源晶振。

22)内部实时时钟(带后备锂电池)。

23)1个34pin,2.0mm,GPIO接口。

24)1个40pin,2.0mm,系统总线接口。

24条,可真不少啊,还好我们开发操作系统内核时,并不需要关心这个开发板上全部的硬件资源。

现在把那些硬件提供的插口、小灯、按键、电池等都扔了,搅在一起可能看不清楚。看图2-3或许会清楚许多,心情也会愉悦不少。图2-3 mini2440逻辑视图

根据图2-3可以把它们分为这几类:

1)处理器,这是用来执行程序的。

2)存储器,两个不同类型的Flash,当然它们也是存储器,2片32MB SDRAM的内存。

3)关于开发板电源的,不必过多关注。

4)网络,就是网卡。

5)音频。

6)串口,注意图2-3上的串口不是用于处理串口发送、控制等逻辑的串口芯片。

7)I2C总线,这个暂时不必关注。

上面这7种类型的部件,除第1类处理器外,其他部件功能和用途都相对单一,如Flash和SDRAM都是用于存储数据的、音频芯片就是用来处理声音的,它们不做其他的事。但是S3C2440A处理器就不同了,别看它只有指头大小,完成的功能却不容小觑,下面来掀开它神秘的面纱。

S3C2440A是三星公司生产的微处理器,这可不是通常我们认为的微处理器。S3C2440A基于ARM920T核心,ARM920T核心才是我们通常说的CPU、处理器,它支持16/32位精简指令集。它还实现了内存管理单元MMU。S3C2440A还提供了丰富的内部设备,为了组织和连接这些内部设备,它内部采用了先进的微控制总线构架AMBA。为了提高程序的执行速度,S3C2440A还采用了哈佛架构(高速缓冲体系结构),这一结构具有独立的16KB指令,高速缓存和16KB数据高速缓存,每个都是由具有8字长的行(line)组成的。

看了一大堆介绍,可能人都晕了,有时又不能不介绍。下面把S3C2440A内部的构件列举如下。

1)ARM920T CPU,即通常执行程序的CPU。

2)内存控制器,包括SDRAM控制和地址空间的片选逻辑。但本身不包含SDRAM存储芯片,只是用于控制SDRAM存储芯片的。

3)LCD控制器,最大支持4K色STN和256K色TFT,提供1通道DMA供LCD专用。

4)4通道DMA并有外部请求引脚。

5)3通道UART,支持64B发送FIFO和64B接收FIFO。

6)2通道SPI。

7)1通道IIC总线接口,支持多主机。

8)1通道IIS总线音频编码器接口。

9)AC97编解码器接口。

10)支持SD主接口协议1.0版和MMC卡协议2.11的兼容版。

11)2通道USB接口,1个主机通道,1个USB设备通道。

12)4通道PWM定时器和1通道内部定时器、看门狗定时器。

13)8通道10位ADC和触摸屏接口。

14)实时时钟RTC。

15)摄像头接口,最大支持4096×4096像素输入。

16)130个通用I/O口和24通道外部中断源。

17)电源管理,具有普通、慢速、空闲和掉电模式。

18)时钟,具有PLL片上时钟发生器。

19)中断控制器。

你一定在感叹人类的制造工艺,一定在努力地思考人类是怎么把这么多东西集成在一个指头大小的芯片内的,甚至还集成了总线,可以想象那得多复杂。的确,计算机系统是人类发展史上人类自己做过的最复杂的东西之一。

上面的文字也许不够形象,那么用一幅图来打开我们面前这个黑盒子——S3C2440A,如图2-4所示。图2-4 S3C2440A逻辑结构视图

可以看到S3C2440A这个黑盒子里,还有很多黑盒子,我们不继续打开它们了,等到后面用到它们时,再一一打开。最后这个S3C2440A芯片提供了一大堆引脚,这些引脚各有各的功能,它们有的是输入信号的,有的是输出信号的。这个芯片就是这样和开发板上外围部件进行交互的,如从SDRAM内存芯片中读取程序指令执行、向Flash存储芯片中存入数据,控制音频芯片发出声音,用网卡访问网络等。

或许你还沉浸在漫无边际的思考中,在思考这么多设备和芯片都有些什么功能、又是怎么工作的、如何编程控制它们等,下面继续。

2.2 必须要关注的硬件

本节将先了解为什么操作系统内核必须要关注或者操作硬件平台中的一些设备,然后分别介绍必须要关注和操作的一些设备的简要信息。

2.2.1 原因

如果现在,在只有5行代码的程序中有一个错误,我们很快就能找到并解决它。如果100行代码的程序中有一个错误,我们也能容易地找到它。如果10000行代码中有一个错误,找到它就有点难度了。如果1000万行代码中有一个错误,要找到它可真不是件容易的事。而且可能在100行代码中有2个错误,1000行代码中有8个错误,甚至更多。还有可能在修复1个错误时产生了新的错误,等等,面对几千万行代码的操作系统,可能会让你疯掉的。

降低代码行数是个好主意,可是用5行代码去写个功能完善的操作系统是不可能的。于是人们把操作系统分为很多层,每个层又分为多个模块,这样每个分层里的每个模块的代码规模就小了很多。人们还把最重要的功能和一些机制放在一个独立的模块中,这个模块就是操作系统内核。有些功能模块在需要的时候才去装载,这样一个小而精致的内核最后配合那些独立的功能模块就能实现一个功能相当完善的操作系统。

既然操作系统内核是运行在这个硬件平台上的第一层软件,那么它是肯定要或多或少地了解一些这个平台上的硬件的。它究竟要知道多少,与它设计的规模有关,上面说了那么多就是为了证明一点:小而精致的内核更加稳定可靠。除非有必要,我们应该尽可能减少内核的功能,而把那些功能以独立模块的形式存在。

我们用的是mini2440这个平台。那么内核要关注这个平台的哪些硬件呢,后面再介绍内核的设计,先在此想象性地归纳一下:

1)CPU。内核也是程序要CPU去运行的,当然要知道它的细节,我们平台的CPU在S3C2440A那个黑盒子里叫ARM920T。

2)MMU。内核是放在内存中的,CPU要访问内存首先得经过MMU内存管理单元,我们平台的MMU在S3C2440A那个黑盒子里的一个叫CP15的黑盒子里。

3)内存。内核本身和其他程序都是放在内存里面的,我们平台的内存是用两片32MBSDRAM芯片并接在一起做成的64MB的内存。

4)RTC。实时时间,内核当然要知道现在是什么时间了。

5)定时器。内核中有很多功能的实现都依赖于定时器,如进程调度器的实现。

6)UART,串口。在调试内核时能够输出一些信息,表示内核是否工作正常。

7)中断控制器。设备有时要通知CPU,或者表示它的任务已经完成,而平台中那么多设备,这就必须要有专门的控制逻辑来控制它们,这就是中断控制器。内核要管理这些设备硬件,当然要知道它们什么时候需要CPU的关注,什么时候已经完成它们的任务。

对于一个小而精致的内核来说,知道这么多硬件已经够了。你可能会说,我们都还没设计内核呢,这只是想象中的。是的,万一后面不行了,再加入一些不就行了吗,没必要一步到位。

对上面这些硬件的介绍,除了CPU和MMU外,其他的都会在本章中以小节的形式先概述它们功能和用途,先让大家有个印象,做个铺垫。等到后面写操作系统内核真正用到它们时,再详细讨论。CPU和MMU,这两个有点复杂,完成的功能很多,而且在开始之前又必须认真地了解它们。所以后面用专用的章节详细讨论。

2.2.2 RTC

RTC是实时时钟,表示的是我们通常用的时间。比如,人们常说现在什么时间了,就是说的这个RTC时间。

说到自然时间,听到最多的可能就是“现在几点啦”。就再也没有往下思考,可以假想一下,物理世界没有了时间,是不是很有趣、也很可怕,可能世间万物会止步不前,可能我们的青春可以永驻。

在mini2440开发板上,只有一颗RTC备用电池,而完成RTC功能的部件在S3C2440A黑盒子里面。既然是自然界的时间,那么即使在开发板断电后也不能停止运行,这就是它要有备用电池的原因。

RTC可以通过8位BCD数据和CPU通信。这些数据包括年、月、日、星期、时、分和秒的时间信息。RTC单元工作在外部,32.768kHz晶振,并且可以执行闹钟功能。

我们来看看S3C2440A里的RTC单元支持哪些功能,归纳如下:

1)时间:年、月、日、星期、时、分和秒,支持CPU以BCD数据的方式读写。

2)闰年发生器:支持实现和识别哪年是闰年。

3)闹钟功能:能产生闹钟定时中断或者从省电模式下唤醒开发板。

4)已经解决2000年是闰年的问题。

5)支持独立电源引脚也就是用备用电池供电的功能。

6)支持时钟节拍中断,如一秒钟内产生固定次数的中断。

S3C2440A的RTC单元的闰年发生器能够基于天、月和年的BCD数据,从28、29、30或31中决定哪个是每月的最后日。此模块决定最后日时会考虑闰年因素。8位计数器只能够表示为2个BCD数字,因此其不能判决“00”年的问题,即最后两位数为0的年份是否为闰年。例如,不能判别1900年和2000年。请注意1900年不是闰年,而2000年是闰年。因此,S3C2440A中00的两位数是表示2000年,而不是表示1900年。

RTC还能在开发板省电模式中或正常工作模式中在指定的时间上产生一个闹钟信号。在正常工作模式中,只激活闹钟中断信号。在开发板省电模式中,除了激活闹钟中断信号,还激活电源管理唤醒信号。

RTC时间节拍中断可以用于操作系统内核的时间节拍,也可用于内核时间的同步更新等。

虽然RTC单元是操作系统内核必须要关注的硬件之一,但并不在此详细介绍,只是先让大家有个印象,它就是处理自然时间的,还有闹钟等功能。等到写操作系统用到它时再详细地讨论。

2.2.3 定时器

前面说的RTC表示的是自然时间,就是我们常说的:“现在什么时间了”,而这次说的定时器是什么呢,它表示的是从现在开始到将来某一个时刻之间的时间,比如,从下午3点到下午4点之间过去了多少时间。

定时器单元也没有在mini2440开发板上,而是在S3C2440A这个黑盒子里。

S3C2440A内部有5个16位定时器。其中定时器0、1、2、3具有脉宽调制功能。定时器4是一个无输出引脚的内部定时器。定时器0还包含用于大电流驱动的死区发生器。

定时器0和1共用一个8位预分频器,定时器2、3、4共用一个另外的8位预分频器。每个定时器都有一个可以生成5种不同分频信号的时钟分频器。每个定时器模块从相应8位预分频器得到时钟,然后再通过时钟分频器分频后得到其自己的时钟信号。8位预分频器是可编程的。

每个定时器的计数缓冲寄存器中,包含了一个当使能了定时器时被加载到递减计数器中的初始值。定时比较缓冲寄存器中,包含了一个被加载到比较寄存器中与递减计数器相比较的初始值。这种双缓冲特征保证了改变频率时定时器产生稳定的输出。

每个定时器有它自己的由定时器时钟驱动的16位递减计数器。当递减计数器到达零时,产生定时器中断请求,通知CPU定时器操作已经完成。当定时器计数器到达零时,相应的计数值将自动被加载到递减计数器以继续下一次操作。

这5个定时器所有的特性如下:

1)5个16位定时器。

2)2个8位预分频器和两个4位分频器。

3)可编程输出波形的占空比控制。

4)自动重载模式或单稳态脉冲模式。

5)死区发生。

定时器内部工作是靠时钟信号驱动的,事实上不只是定时器,CPU也是,几乎计算平台所有的部件的运行都与时钟信号有关。比如,我们这里的定时器,来一个时钟信号就对自己内部计数器的值减1,减到0时就发出中断通知CPU。分频器就是对时钟频率进行处理,得到一个比当前更低或者更高的频率,当然定时器的分频器是得到更低的时钟频率,同时配合定时器中的计数值,达到精准的定时功能。定时器输入的时钟频率计算公式如下:定时器输入时钟频率=PCLK/{预分频值+1}/{分频值}{预分频值}=0~255{分频值}=2,4,8,16

PCLK是S3C2440A内部APB总线的时钟频率。

这些定时器还可以自动重复定时或者一次性定时,自动重复定时是:比如,开始设定定时器每隔2s产生一次中断,中断产生后它会继续计时到下一个2s钟又产生中断,如此反复。一次性定时是指,时间到达产生中断后就不继续定时了,直到下一次设定。

来看看定时器最常用的一个情景:我们让定时器每隔1ms产生一次中断,然后在中断处理程序中检查一个进程已经运行了多长时间,分配给这个进程的时间它是否已经用完,如果已经用完,就调度其他进程运行。如果没有定时器,我们在应用软件中写入一个死循环代码,操作系统立马就会被这个应用软件锁死,因为系统已经没有任何手段从这个应用程序手里夺回CPU的使用权了。想想吧,这有多可怕!

同样的,操作系统内核,也必须了解这个平台上的定时器,不然就会出现上述情况。但是也不会在这里详述其细节,依然等到用到它时再了解它的编程细节。

2.2.4 串口

一个计算平台有许多输入输出设备:键盘、屏幕、音频、串口甚至网络。当然各种计算平台可能不同,比如mini2440开发板就没有像PC那样的键盘。

我们选择一个最简单且开发板上又有的设备——串口来介绍。

mini2440开发板上只有三个用于连接串口线的接口。真正串口功能单元在S3C2440A芯片内部,有三个功能相同的串口功能单元。

S3C2440A中每个串口单元都是可以基于中断或基于DMA模式操作的。换句话说,串口可以通过产生中断或DMA请求来进行CPU和串口之间的数据传输。串口使用系统时钟可以支持最高115.2Kbit/s的比特率。如果是外部器件提供的外部时钟,则串口可以工作在更高的速度上。

S3C2440A的串口包括了可编程波特率,红外发送/接收,插入1个或2个停止位,5位、6位、7位或8位的数据宽度以及奇偶校验。

每个串口包含一个波特率发生器、发送器、接收器和一个控制单元。波特率发生器可以由总线时钟或外部输入时钟驱动。发送器和接收器包含了64B先进先出缓冲区和数据移位器。将数据写入先进先出缓冲区中接着在发送前复制到发送移位器中。随后将在发送数据引脚移出数据。与此同时从接收数据引脚移入收到的数据,接着从移位器复制到先进先出缓冲区中。

每个串口发送数据是可编程的。由1个起始位、5~8个数据位、1个可选奇偶校验位以及1~2个停止位组成的帧,是由行控制寄存器指定的。发送器也可以产生单帧发送期间强制串行输出为逻辑0状态的断点状态。

与发送类似,接收数据帧也是可编程的。由1个起始位、5~8个数据位、1个可选奇偶校验位以及1~2个停止位组成,也是由行控制寄存器指定的。接收器能够检测出溢出错误、奇偶校验错误、帧错误和断点状态。

这些由1个起始位、5~8个数据位、1个可选奇偶校验位以及1~2个停止位组成的帧。在串口单元中,是逐位在串口线上发送的,发送的速度与串口单元的时钟速度有关,时钟速度越快,发送数据的速度越快,如图2-5所示。图2-5 串口设备通信过程

这些数据可能是其他数据,也可能是字符串的ASCII码。通常情况下我们发送的就是字符串,这样我们的开发板上的串口线连接上PC,在PC上就能看到开发板输出的信息了。

到时我们的操作系统内核就用S3C2440A中的第一个串口作为默认的输出端口。这样就能看到操作系统内核输出的信息了,如系统是否运行正常等,在此先初步认识一下,到我们写代码时再来看看怎么使用它。

2.2.5 中断控制器

先不说中断的概念,现在只要知道中断是各种设备通知CPU的一种方式。由于计算平台上不止一个设备,所以需要一个专门的功能单元来管理这些通知信号(即中断)。让它来决定各设备中断信号的先后次序,以及是否允许各设备的中断信号到达CPU,还有识别是哪个设备的中断信号。这个功能单元就是中断控制器,如图2-6所示。图2-6 设备与中控制器、CPU的连接逻辑视图

mini2440开发板上没有这个功能单元,它存在于S3C2440A这个芯片内部。

S3C2440A中的中断控制器接收来自60个中断源的请求。提供这些中断源的是内部外设或者外部设备,如DMA控制器、串口、IIC、GPIO等。外部设备就是通过GPIO与S3C2440A内部连接起来的。GPIO是什么,怎么连接,我们不在此处介绍,那也不是必须要关心的。

当从内部外设和外部中断请求引脚收到多个中断请求时,中断控制器在仲裁先后次序后才发送请求到ARM920T内核的FIQ或IRQ引脚,ARM920T内核就是图2-6中的CPU。这个后面会介绍。仲裁步骤由硬件优先级逻辑决定,并且将结果写入中断挂起寄存器中,从而通告用户是中断源中的哪一个发生了中断。

中断优先级仲裁,就是当两个不同的设备同时产生中断时,而CPU一次只能响应一个中断请求,中断控制器要在两个或者多个中断信号中选择一个,然后把那个中断请求发送给CPU。和自然世界中一样,事情有轻重缓急,当然中断控制器最好选择一个要求CPU尽可能快地处理其中断请求的设备。

S3C2440A中的中断控制器只能连接32根中断信号线,那么它是怎么支持60个中断源的呢?它采用了二级中断源,就是在一级中断的几根中断信号线上连接几个设备的中断信号线。所以当中断发生时,我们就不能单纯地认为是一个设备发生了中断,而是要进一步根据次级中断的相关信息确定是哪个设备发生了中断,如图2-7所示。图2-7 S3C2440A的中断控制器与设备的连接

操作系统内核的重要功能就是要代替应用软件操控设备,然而设备与CPU的通信大多数是由中断信号来驱动的。中断控制器就是它们之间的必经之路。所以操作系统内核必须要了解并控制中断控制器。在此有个初步印象即可,后面介绍操作系统内核的中断管理时,会详细介绍。

2.2.6 SDRAM

SDRAM是同步动态随机存储器,同步是指它工作需要同步时钟,内部命令的发送与数据的传输都是以这个时钟为基准的。动态是指它内部的存储阵列需要不断地刷新来保证数据不丢失。它是可以随机访问的,就是说可以自由地在指定的地址上进行数据读写。当然也不是绝对自由的,这个访问地址是由存储控制器和总线决定的。我们通常说的内存就是用这种芯片和技术实现的。

mini2440开发板有64MB的SDRAM,它是用两片32MB的SDRAM芯片组成的,这两片32MB的SDRAM芯片存在于开发板上,而它的存储控制功能单元则存在于S3C2440A芯片内部。通过S3C2440A芯片的引脚和外部的SDRAM芯片通信的。

我们先介绍S3C2440A芯片内部的存储控制功能单元,再来介绍mini2440开发板上的两片SDRAM芯片。

S3C2440A芯片内的存储器控制器为访问外部存储器提供了存储器控制的信号。

S3C2440A芯片内的存储器控制器包含以下特性:

1)可通过软件选择大端、小端。

2)总共8个存储器Bank,每个Bank有128MB,总共1GB地址空间。

3)除了Bank0(16/32位),其他全部Bank都可编程访问宽度(8/16/32位)。

4)6个存储器Bank为ROM、SRAM等。其余2个存储器Bank为ROM、SRAM、SDRAM等。

5)7个固定的存储器Bank起始地址,1个可变的存储器Bank起始地址,并且Bank大小可编程。

6)所有存储器Bank的访问周期可编程。

7)支持外部等待扩展总线周期。

8)支持SDRAM自刷新和掉电模式。

S3C2440A的存储地址空间如图2-8所示。

图2-8中的SROM表示的是这个Bank只能连接SRAM或者ROM类型的芯片。Bank6和Bank7上所连接的芯片大小必须相等。比如,Bank6上连接是32MB的SDRAM,那么如果Bank7上要连接存储芯片,也必须是32MB的SDRAM。图2-8也是mini2440开发板上的实际情况。除Norflash和两片32MB的SDRAM芯片外,其余的都在S3C2440A芯片内部,Norflash和两片32MB的SDRAM芯片是在开发板上的。

上面简单说明了S3C2440A的存储控制器和存储系统的物理地址空间,接下来看看SDRAM芯片。数据和程序都是放在它里面运行的,当然操作系统内核也毫不例外,也是放在它里面的。

mini2440开发板使用了两片外接的32MB的SDRAM芯片,型号为HY57V561620或者MT48LC16M16A2,它们并接在一起形成32位的总线数据宽度,这样可以增加访问的速度,并且它们的物理起始地址为0x30000000。可能不同时期出厂的开发板用SDRAM芯片型号不一样,但是功能是一样的。

SDRAM内部是一个存储阵列。可以把它想象成一个表格。和表格的检索原理一样,先指定行,再指定列,就可以准确找到所需要的存储单元。这个表格称为逻辑Bank。目前的SDRAM基本都是4个Bank。寻址的流程就是先指定Bank地址,再指定行地址,最后指定列地址。这就是SDRAM的寻址原理。笔者的开发板是用的SDRAM芯片是32M的HY57V561620,这是一个4Banks×4MB×16bit的SDRAM,也就是由4个逻辑块(即Logical Bank,简称L_Bank)组成的,每个L_Bank有4MB存储单元。2片总共空间为64MB,连接到S3C2440A的Bank6上,所以访问的物理地址空间为0x30000000~0x33FFFFFF。SDRAM芯片结构如图2-9所示。图有点专业,暂时看不懂也没什么问题,有个印象即可。图2-8 S3C2440A的存储地址空间图2-9 SDRAM芯片结构

对于程序员来说,只要认为它就是内存并且是这样的:由8个可以存储1位二进制数据的空间组成的小格子,每个小格子有个地址,通过这个地址可以向小格子里读写8位二进制的数据,2个小格子就可以存放16位二进制数据、4个小格子就可以存放32位二进制数据。最后许多这样的小格子组成一个很大的存储空间,如图2-10所示。

注意,内存芯片(即SDRAM)并不决定内存的物理地址从哪里开始,它只是一个存放数据的空间,如果32MB大小的内存,每个字节一个地址,那么它就有32M个地址编码。内存开始的物理地址是存储控制器和内存芯片地址信号线决定的,比如,存储控制器地址译码信号是从0x30000000地址开始的,那么这个内存可以访问的有效地址空间就是从0x30000000开始到0x31FFFFFF结束。

我们了解了S3C2440A芯片的地址空间,又粗略地看了SDRAM芯片的内部结构,最后只要知道mini2440开发板上有两片32MB的SDRAM芯片,并且它们并接到S3C2440A芯片的Bank6上。因此地址空间是0x30000000~0x33FFFFFF。操作系统内核、应用软件、数据,都是放在这个里面的,CPU就能通过内存地址运行其中的程序和操作其中的数据。后面章节中还有更多关于内存的内容,到时会详细介绍的。图2-10 内存逻辑视图

2.2.7 Norflash

Flash存储器称为闪存,它结合了ROM和RAM的特点,不仅具备电子可擦除、可编程的特点,还可以快速读写数据,而且数据不会因为断电而丢失。这种特性使它可以用于U盘、MP3、智能手机等众多移动智能设备上。

目前Flash闪存芯片主要有两种:Norflash和Nandflash。下面介绍Norflash。

mini2440开发板上有一片2MB大小的Norflash芯片,它连接在S3C2440A的Bank0上,并且可以通过跳线控制。

mini2440开发板上的Norflash芯片特性如下:

1)有22根地址信号线和16根数据信号线。

2)掉电不会丢失数据。

3)支持“片上运行”。

由于它有22根地址信号线和16根数据信号线,所以它能索引Norflash芯片上每个存储字,一次可以传输16位数据,刚好是一个字。这就像SDRAM芯片一样,可以被CPU直接读写。掉电也不会丢失数据。这样写入其中的代码和数据就可以长久地保存。如果它里面包含可执行代码,那么就可以在不需要SDRAM芯片的情况下执行程序。什么情况下需要这样的存储芯片呢?例如,PC上的BIOS系统,CPU运行的第一个程序就是BIOS程序,那个时候连内存都还没初始化呢。再就是mini2440嵌入式开发板的上引导程序,也可以说是BIOS,它也完成了BIOS绝大部分工作,只是叫法不同而已。mini2440开发板在上电时,S3C2440芯片时钟和SDRAM芯片控制器都还没有初始化呢。所以要借助Norflash存储技术。

利用JTAG技术,向Norflash芯片中烧入引导程序,这个引导程序负责初始化开发板上的各种设备,如时钟、SDRAM、串口等。初始化完设备之后,就装载操作系统内核。mini2440开发板上Norflash芯片中烧写的是superVIVI引导程序。这个引导程序功能非常多,我们要用到的是从PC上下载的操作系统内核到mini2440开发板上的SDRAM芯片中,这非常方便。

Norflash芯片内部的实现细节我们不需要知道,我们只要知道mini2440开发板上有2MB的Norflash芯片,它就相当于掉电不丢失数据的内存,当然它的速度赶不上内存,它里面存放的是一个引导程序。我们还可以通过拨动mini2440开发板上一个开关从Norflash芯片开始启动,并且将它连接在S3C2440A的Bank0上,开始的物理地址是0,S3C2440A中的ARM920TCPU,一上电就是从地址0开始执行第1条指令,这样刚好就运行了Norflash芯片中的引导程序。

2.2.8 Nandflash

Nandflash也是Flash闪存的一种,其内部采用非线性单元设计模式,为固态大容量闪存的实现提供了廉价有效的解决方案。Nandflash存储器具有容量较大、改写速度快等优点,适用于大量数据的存储,广泛应用于嵌入式产品中。

由于内部结构相对简单,Nandflash芯片使用复杂的I/O口来串行地存取数据,各个产品或厂商的方法可能各不相同。8个引脚用来传送控制、地址和数据信息。所以不能像Norflash、SDRAM等芯片,可以直接和CPU等设备相连并且寻址到每个存储字节。因此Nandflash芯片需要为它设计专门的控制器才能和其他设备进行通信。

mini2440开发板上有两种Flash闪存,一种是前面说过的Norflash闪存,大小为2MB;另一种是Nandflash,型号为K9F1G08,大小为128MB,旧版本为K9F1208,大小为64MB。Norflash和Nandflash闪存的芯片都存在于mini2440开发板上,前面说过Norflash有足够的地址引脚和数据引脚,因此它可以直接提供类似SRAM接口和CPU相连、通信。而Nandflash闪存则不行,它需要专门的Nandflash控制器,这个Nandflash控制器就存在于S3C2440A这个芯片中。S3C2440A支持这两种Flash启动系统,通过拨动跳线开关,可以选择从Norflash还是从Nandflash启动系统。实际的产品中使用一片Nandflash就够了,因为mini2440开发板是为了方便用户开发学习,所以还保留了Norflash。

要操作Nandflash芯片,从中读取和写入数据。那么就要Nandflash控制器进行操作,对它进行编程,通过Nandflash控制器操作Nandflash芯片。对S3C2440A芯片上的Nandflash控制器的编程步骤如下:

写命令寄存器,向Nandflash控制器写入相关命令,对应于Nandflash芯片的命令周期。

写地址寄存器,向Nandflash控制器写入相关地址,比如上面输入的读写命令是需要读写地址的,对应于Nandflash芯片的地址周期。

读/写数据寄存器,读/写入数据到Nandflash存储器,根据上面相应的命令做相应的动作,可能是读也可能是写数据,对应于Nandflash芯片的读/写周期。

读Nandflash控制器的主ECC寄存器和备份ECC寄存器。对数据进行校验。

等用到Nandflash控制器时,再详细研究其细节。下面介绍Nandflash芯片的结构。

Nandflash芯片的数据是以位的方式保存在存储单元中的,一般来说,一个存储单元中只能存储一个位。这些存储单元以8个或者16个为单位,连接成位行,这些位行会再组成页,这些页面会再组成块。Nandflash芯片有多种结构,笔者使用的Nandflash芯片是K9F1208,它是这样的:每页528B,其中512B用于存放数据,还有16B存放这个页面的数据的校验信息,每32个页面形成一个块,块大小为32×528B。具体一片Flash上有多少个块是根据需要决定的。K9F1208的Nandflash芯片具有4096个块,故总容量为4096×(32×528B)一共是66MB,但是其中的2MB是用来保存ECC校验码等额外数据的,故实际中可使用的空间为64MB,如图2-11所示。

试读结束[说明:试读内容隐藏了图片]

下载完整电子书

若在网站上没有找合适的书籍,可联系网站客服获取,各类电子版图书资料皆有。

客服微信:xzh432

登入/注册
卧槽~你还有脸回来
没有账号? 忘记密码?