﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-梦想嵌入--动力火锅-文章分类-ARM</title><link>http://www.cnitblog.com/lijiehua/category/2811.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 05 Oct 2011 02:12:59 GMT</lastBuildDate><pubDate>Wed, 05 Oct 2011 02:12:59 GMT</pubDate><ttl>60</ttl><item><title>嵌入式Linux系统及其应用前景 </title><link>http://www.cnitblog.com/lijiehua/articles/10864.html</link><dc:creator>内嵌</dc:creator><author>内嵌</author><pubDate>Sat, 20 May 2006 15:48:00 GMT</pubDate><guid>http://www.cnitblog.com/lijiehua/articles/10864.html</guid><wfw:comment>http://www.cnitblog.com/lijiehua/comments/10864.html</wfw:comment><comments>http://www.cnitblog.com/lijiehua/articles/10864.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/lijiehua/comments/commentRss/10864.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/lijiehua/services/trackbacks/10864.html</trackback:ping><description><![CDATA[
		<font size="2">嵌入式Linux系统及其应用前景 <br /><br />作者：王 卓 包 杰    文章来源：单片机及嵌入式系统应用    点击数：1803    更新时间：2004-9-4 <br />引 言<br /><br />近年来，随着计算技术、通信技术的飞速发展，特别是互联网的迅速普及和3C（计算机、通信、消费电子）合一的加速，微型化和专业化成为发展的新趋势，嵌入式产品成为信息产业的主流。Linux从1991年问世到现在，短短的十几年时间已经发展成为功能强大、设计完善的操作系统之一；可运行在X86、Alpha、Sparc、MIPS、PPC、Motorola、NEC、ARM等多种硬件平台，而且开放源代码，可以定制；可与各种传统的商业操作系统分庭抗争。越来越多的企业和研发机构都转向嵌入式Linux的开发和研究上，在新兴的嵌入式操作系统领域内也获得了飞速发展。<br /><br />1 嵌入式Linux的特点<br /><br />　　嵌入式系统是以应用为中心，以计算机为基础，软硬件可裁剪，适用于系统对功能、可靠性、成本、功耗严格要求的专用计算机系统，系统结构见图1。实时性是嵌入式系统的基本要求，其次，还要求代码小，速度快，可靠性高。嵌入式Linux（Embedded Linux）是指对Linux经过裁剪小型化后，可固化在存储器或单片机中，应用于特定嵌入式场合的专用Linux操作系统。嵌入式Linux的开发和研究已经成为目前操作系统领域的一个热点。与其它嵌入式操作系统相比（详见表1），Linux的特点如下。<br /><br />表1 专用嵌入式实时操作系统与嵌入式Linux的比较<br /><br />　 专用嵌入式实时操作系统 嵌入式Linux操作系统 <br />版权费 每生产一件产品需交纳一份版权费 免费 <br />购买费用 数十万元（RMB） 免费 <br />技术支持 由开发商独家提供有限的技术支持 全世界的自由软件开发者提供支持 <br />网络特性 另加数十万元（RMB）购买 免费且性能优异 <br />软件移值 难（因为是封闭系统） 易，代码开放（有许多应用软件支持） <br />应用产品开发周期 长，因为可参考的代码有限 短，新产品上市迅速，因为有许多公开的代码可以参考和移植 <br />实时性能 好 须改进，可用PT_Linux等模块弥补 <br />稳定性 较好 较好，但在高性能系统中须改进 <br /><br />　　第一，Linux系统是层次结构且内核完全开放。Linux是由很多体积小且性能高的微内核系统组成。在内核代码完全开放的前提下，不同领域和不同层次的用户可以根据自己的应用需要方便地对内核进行改造，低成本地设计和开发出满足自己需要的嵌入式系统。<br /><br />　　第二，强大的网络支持功能。Linux诞生于因特网时代并具有Unix的特性，保证了它支持所有标准因特网协议，并且可以利用Linux的网络协议栈将其开发成为嵌入式的TCP/IP网络协议栈。 此外，Linux还支持ext2、fat16、fat32、romfs等文件系统，为开发嵌入式系统应用打下了很好的基础。<br /><br />　　第三，Linux具备一整套工具链，容易自行建立嵌入式系统的开发环境和交叉运行环境，可以跨越嵌入式系统开发中仿真工具的障碍。Linux也符合IEEE POSIX.1标准，使应用程序具有较好的可移植性。<br /><br />　　传统的嵌入式开发的程序调试和调试工具是用在线仿真器（ICE）实现的。它通过取代目标板的微处理器，给目标程序提供一个完整的仿真环境，完成监视和调试程序；但一般价格比较昂贵，只适合做非常底层的调试。使用嵌入式Linux，一旦软硬件能够支持正常的串口功能，即使不用仿真器，也可以很好地进行开发和调试工作，从而节省一笔不小的开发费用。嵌入式Linux为开发者提供了一套完整的工具链（tool chain）。它利用GNU的gcc做编译器，用gdb、kgdb、xgdb做调试工具，能够很方便地实现从操作系统到应用软件各个级别的调试。<br /><br />　　第四，Linux具有广泛的硬件支持特性。无论是RISC还是CISC、32位还是64位等各种处理器，Linux都能运行。Linux通常使用的微处理器是Intel X86芯片家族，但它同样能运行于Motorola公司的68K系列CPU和IBM、Apple、Motorola公司的PowerPC CPU以及Intel公司的StrongARM CPU等处理器。Linux支持各种主流硬件设备和最新硬件技术，甚至可以在没有存储管理单元（MMU）的处理器上运行。这意味着嵌入式Linux将具有更广泛的应用前景。<br /><br />2 Linux嵌入式系统开发平台<br /><br />    2.1 系统软件操作平台<br /><br />　　操作系统是一种在计算机上运行的软件。它的主要任务是管理计算机上的系统资源，为用户提供使用计算机及其外部设备的接口。它存在的目的是为了管理所有硬件资源，并且提供应用软件一个合适的操作环境。嵌入式系统由于硬件的限制，通常只具有极稀少的硬件资源，如主频较低的CPU、较小的内存、小容量的固态电子盘芯片DoC（Disk on Chip）或DoM（Disk on Module）替代磁盘等。在使用电池的系统中，它还要实现低功耗，延长电池使用时间的功能。<br /><br />　　Linux作为嵌入式操作系统是完全可行的。因为Linux提供了完成嵌入功能的基本内核和所需要的所有用户界面，能处理嵌入式任务和用户界面。将Linux看作是连续的统一体，从一个具有内存管理、任务切换和时间服务及其它分拆的微内核到完整的服务器，支持所有的文件系统和网络服务。Linux作为嵌入式系统，是一个带有很多优势的新成员。它对许多CPU和硬件平台都是易移植、稳定、功能强大、易于开发的。<br /><br />　　嵌入式Linux系统需要下面三个基本元素：系统引导工具（用于机器加电后的系统定位引导）、Linux微内核（内存管理、 程序管理）、初始化进程。但如果要它成为完整的操作系统并且继续保持小型化，还必须加上硬件驱动程序、硬件接口程序和应用程序组。<br /><br />　　Linux是基于GNU的C编译器，作为GNU工具链的一部分，与gdb源调试器一起工作的。它提供了开发嵌入式Linux系统的所有软件工具。<br /><br />    2.2 系统硬件平台<br /><br />　　在选择硬件时，常由于缺乏完整或精确的信息而使硬件选择成为复杂且困难的工作。硬件开发成本常是我们很关心的。当考虑硬件成本时，须要考虑产品的整个成本而不仅是CPU的成本。因为合适的CPU，一旦加上总线逻辑和延时电路使之与外设一起工作，硬件系统就可能变得非常昂贵。如果要寻找嵌入式软件系统，那么，应首先确定硬件平台，即确定微处理器CPU的型号。<br /><br />　　现在比较流行的硬件平台有Intel公司的StrongARM 系列，Motorola公司的DragonBall系列，NEC公司的VR系列，Hitachi公司的SH3、SH4系列等等。选定硬件平台前，首先要确定系统的应用功能和所需要的速度，并制定好外接设备和接口标准。这样才能准确地定位所需要的硬件方案，得到性价比最高的系统。<br /><br />3 嵌入式Linux系统开发模式<br /><br />　　嵌入式系统通常为一个资源受限的系统。直接在嵌入式系统的硬件平台上编写软件比较困难，有时甚至是不可能的。一般流程见图2。目前，一般采用的办法是，先在通用计算机上编写程序，然后，通过交叉编译，生成目标平台上可运行的二进制代码格式，最后下载到目标平台上的特定位置上运行，具体步骤如下。　　　　　　　　　　　<br /><br />　　第一步，建立嵌入式Linux交叉开发环境。目前，常用的交叉开发环境主要有开放和商业两种类型。开放的交叉开发环境的典型代表是GNU工具链，目前已经能够支持x86、ARM、MIPS、PowerPC等多种处理器。商业的交叉开发环境主要有Metrowerks CodeWarrior、ARM Software Development Toolkit、SDS Cross compiler、WindRiver Tornado、Microsoft Embedded Visual C++等。交叉开发环境是指编译、链接和调试嵌入式应用软件的环境。它与运行嵌入式应用软件的环境有所不同，通常采用宿主机/目标机模式，见图3。<br /><br />　　第二步，交叉编译和链接。在完成嵌入式软件的编码之后，就是进行编译和链接，以生成可执行代码。由于开发过程大多是在Intel公司x86系列CPU的通用计算机上进行的，而目标环境的处理器芯片却大多为ARM、MIPS、PowerPC、DragonBall等系列的微处理器，这就要求在建立好的交叉开发环境中进行交叉编译和链接。<br /><br />　　例如，在基于ARM体系结构的gcc交叉开发环境中，arm-linux-gcc是交叉编译器，arm-linux-ld是交叉链接器。通常情况下，并不是每一种体系结构的嵌入式微处理器都只对应于一种交叉编译器和交叉链接器。如对于M68K体系结构的gcc交叉开发环境而言，就对应于多种不同的编译器和链接器。如果使用的是COFF格式的可执行文件，那么在编译Linux内核时，需要使用m68k-coff-gcc和m68k-coff-ld，而在编译应用程序时则需要使用m68k-coff-pic-gcc和m68k-coff-pic-ld。编写好的嵌入式软件经过交叉编译和交叉链接后，通常会生成两种类型的可执行文件：用于调试的可执行文件和用于固化的可执行文件。<br /><br />　　第三步，交叉调试。<br /><br />　　① 硬件调试。如果不采用在线仿真器，可以让CPU直接在其内部实现调试功能，并通过在开发板上引出的调试端口，发送调试命令和接收调试信息，完成调试过程。目前，Motorola公司提供的开发板上使用的是DBM调试端口，而ARM公司提供的开发板上使用的则是JTAG调试端口。使用合适的软件工具与这些调试端口进行连接，可以获得与ICE类似的调试效果。<br /><br />　　② 软件调试。在嵌入式Linux系统中，Linux系统内核调试，可以先在Linux内核中设置一个调试桩（debug stub），用作调试过程中和宿主机之间的通信服务器。然后，可以在宿主机中通过调试器的串口与调试桩进行通信，并通过调试器控制目标机上Linux内核的运行。<br /><br />　　嵌入式上层应用软件的调试可以使用本地调试和远程调试两种方法。如果采用的是本地调试，首先要将所需的调试器移植到目标系统中，然后就可以直接在目标机上运行调试器来调试应用程序了；如果采用的是远程调试，则需要移植一个调试服务器到目标系统中，并通过它与宿主机上的调试器共同完成应用程序的调试。在嵌入式Linux系统的开发中，远程调试时目标机上使用的调试服务器通常是gdbserver，而宿主机上使用的调试器则是gdb。两者相互配合共同完成调试过程。<br /><br />　　第四步，系统测试。整个软件系统编译过程，嵌入式系统的硬件一般采用专门的测试仪器进行测试，而软件则需要有相关的测试技术和测试工具的支持，并要采用特定的测试策略。测试技术指的是软件测试的专门途径，以及能够更加有效地运用这些途径的特定方法。在嵌入式软件测试中，常常要在基于目标机的测试和基于宿主机的测试之间做出折衷。基于目标机的测试需要消耗较多的时间和经费，而基于宿主机的测试虽然代价较小，但毕竟是在仿真环境中进行的，因此难以完全反映软件运行时的实际情况。这两种环境下的测试可以发现不同的软件缺陷，关键是要对目标机环境和宿主机环境下的测试内容进行合理取舍。嵌入式软件测试中经常用到的测试工具主要有：内存分析工具、性能分析工具、覆盖分析工具、缺陷跟踪工具等，在这里不加详述。嵌入式Linux系统的典型构成见图4。<br /><br />以下即为一个典型开发工具的使用流程：<br /><br />① 写入或植入引导码；<br /><br />② 向串口打印字符串的编码；<br /><br />③ 将gdb目标码移植工作串口，可与另一台运行gdb程序的Linux主机系统对话；<br /><br />④ 利用gdb让硬件和软件初始化码在Linux内核启动时工作；<br /><br />⑤ Linux内核启动，串口成为Linux控制口并可用于后续开发；<br /><br />⑥ 如果在目标硬件上已运行了完整的Linux内核，即可调试用户的应用进程。<br /><br />4 嵌入式Linux面临的挑战<br /><br />　　目前，对嵌入式Linux系统的开发正在蓬勃兴起，并已形成了很大的市场。除了一些传统的Linux公司，像RedHat、VA Linux等，正在从事嵌入式Linux的研究之外，一批新公司（如Lineo、TimeSys等）和一些传统的大公司（如IBM、SGI、Motorola、Intel等）以及一些开发专用嵌入式操作系统的公司（如Lynx）也都在进行嵌入式Linux的研究和开发。但就目前的技术而言，嵌入式Linux的研究成果与市场的真正需求还有一些距离，因此，嵌入式Linux走向成熟还需要在以下几个方面有所发展。<br /><br />    (1)Linux的实时性扩充<br /><br />　　实时性是嵌入式操作系统的基本要求。由于Linux还不是一个真正的实时操作系统，内核不支持事件优先级和抢占实时特性，所以在开发嵌入式Linux的过程中，首要问题是扩展Linux的实时性能。对Linux实时性的扩展可以从两方面进行：向外扩展和向上扩展。向外扩展即从范围上扩展，让实时系统支持的范围更广，支持的设备更多。目前的开发所面向的设备仅限于较简单的有实时要求的串/并口数据采集、浮点数据计算等，而像实时网络这样实时系统的高级应用还需进一步发展。向上扩展是扩充Linux内核，从功能上扩充Linux的实时处理和控制系统。如嵌入式系统RT-Linux，它的基本原理是将Linux本身的任务以及Linux内核本身作为一个优先级最低的任务，而实时任务作为优先级最高的任务，即在实时任务存在的情况下运行实时任务，否则就运行Linux本身的任务。实时任务不同于Linux普通进程。它是以Linux的可装载的内核模块(Loadable Kernel Module，LKM)的形式存在的，需要运行实时任务的时候，将这个实时任务的内核模块插入到内核中去，实时任务和Linux一般进程之间的通信通过共享内存或者FIFO通道来实现。<br /><br />    (2)改变Linux内核的体系结构<br /><br />　　Linux的内核体系采用的是Monolithic。在这种体系结构中，内核的所有部分都集中在一起，而且所有的部件在一起编译连接。这样虽然能使系统的各部分直接沟通，有效地缩短任务之间的切换时间，提高系统的响应速度和CPU的利用率，且实时性好；但在系统比较大时体积也比较大，与嵌入式系统容量小、资源有限的特点不符。而另外一种内核体系结构MicroKernel， 在内核中只包括了一些基本的内核功能，如创建和删除任务、任务调度、内存管理和中断处理等部分，而文件系统、网络协议栈等部分都是在用户内存空间运行。这种结构虽然执行效率不如Monolithic内核，但大大减小了内核的体积，同时也方便了整个系统的升级、维护和移植，更能满足嵌入式系统的特点需要。为此，要使嵌入式Linux的应用更加广泛，若将Linux目前的Monolithic内核结构中的部分结构改造成MicroKernel体系结构，可使得到的Linux既具有很好的实时性，又能满足嵌入式系统体积小的要求。<br /><br />　　另外，Linux是一个需要占用存储器的操作系统。虽然这可以通过减少一些不必要的功能来弥补，但可能会浪费很多时间，而且容易带来很大的麻烦。许多Linux的应用程序都要用到虚拟内存，这在许多嵌入式系统中是没有价值的。所以，并不是一个没有磁盘的Linux嵌入式系统就可以运行任何Linux应用程序。<br /><br />    (3)完善Linux的集成开发环境<br /><br />　　提供完整的集成开发环境是每一个嵌入式系统开发人员所期待的。一个完整的嵌入式系统的集成开发环境一般需要提供的工具是：编译/连接器、内核调试/跟踪器和集成图形界面开发平台。其中的集成图形界面开发平台包括编辑器、调试器、软件仿真器和监视器等。在Linux系统中，具有功能强大的gcc编译器工具链，使用了基于GNU的调试器gdb的远程调试功能，一般由一台客户机运行调试程序调试宿主机运行的操作系统内核; 在使用远程开发时还可以使用交叉平台的方式，如在Windows平台下的调试跟踪器对Linux的宿主系统做调试。但是，Linux在基于图形界面的特定系统定制平台的研究上，与Windows操作系统相比还存在差距。因此，要使嵌入式Linux在嵌入式操作系统领域中的优势更加明显，整体集成开发环境还有待提高和完善。<br /><br />5 嵌入式Linux的发展及应用前景<br /><br />　　综上，由于Linux具有对各种设备的广泛支持性，因此，能方便地应用于机顶盒、IA设备、PDA、掌上电脑、WAP手机、寻呼机、车载盒以及工业控制等智能信息产品中。与PC相比，手持设备、IA设备以及信息家电的市场容量要高得多，而Linux嵌入式系统的强大的生命力和利用价值，使越来越多的企业和高校表现出对它极大的研发热情。蓝点软件公司、博利思公司、共创软件联盟、中科红旗等公司都已将嵌入式系统的开发作为自己的主要发展方向之一。<br /><br />　　在嵌入式系统的应用中，Linux嵌入式操作系统所具有的技术优势和独特的开发模式给业界以新异。有理由相信，它能成为Internet时代嵌入式操作系统中的最强音。<br /></font>
<img src ="http://www.cnitblog.com/lijiehua/aggbug/10864.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/lijiehua/" target="_blank">内嵌</a> 2006-05-20 23:48 <a href="http://www.cnitblog.com/lijiehua/articles/10864.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>嵌入式因特网技术的兴起与前景</title><link>http://www.cnitblog.com/lijiehua/articles/10861.html</link><dc:creator>内嵌</dc:creator><author>内嵌</author><pubDate>Sat, 20 May 2006 15:41:00 GMT</pubDate><guid>http://www.cnitblog.com/lijiehua/articles/10861.html</guid><wfw:comment>http://www.cnitblog.com/lijiehua/comments/10861.html</wfw:comment><comments>http://www.cnitblog.com/lijiehua/articles/10861.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/lijiehua/comments/commentRss/10861.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/lijiehua/services/trackbacks/10861.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">Internet带来了一个新时代。 <br /><br />回顾Internet的发展和应用历史，预测Internet的明天对IT企业的战略设计的意义重大。 <br /><br />第一阶段：1980年—1990年Internet发展的萌芽阶段。解决异种计算机的联网和信息交换，采用TCP/IP协议交换文件和信息，主要解决<br />专业领域如银行、军用系统采用不同操作系统的大、中、小型计算机的联网问题，这时并不称之为Internet，TCP/IP网络仅是少数计算机专家的概念，这是Internet发展的萌芽阶段。 <br /><br />第二阶段：1990年—2000年，PC作为客户机，Internet席卷全球。在TCP/IP协议网络之上发明的email和www普遍应用，Internet国际<br />互联网被大众接受，这时一个重要的条件是PC普及的非常广泛，即形成了Client/ Server体系结构（客户机/服务器），进而发展为Browser/Server结构（浏览器/服务器），这时的客户机是已广泛普及的PC，而服务器是相对复杂的，价格昂贵的超级计算机，即我们所谓的“胖服务器”。Internet的发展使IT界的老牌公司也没有料想到会产生路由器的巨大需求，Cisco的成功在于此。另一方面，www的应用又造就了一大批以yahoo为代表的.Com公司，以及电子商务公司，这时候所有的人不得不承认Internet象一场革命改变了世界。 <br /><br />第三阶段：2000年—2010年嵌入式Internet时代。将给地球披上“电子皮肤”，嵌入式片上系统成为瘦服务器。预测未来Internet将向何处去，这是全世界科学家关心的问题，包括美国贝尔实验室总裁Arun Netravali的一批科学家对此做出了预测：在这阶段“将会产生比PC时代 多成百上千倍的瘦服务器和超级嵌入式瘦服务器，这些瘦服务器将与我们这个世界你能想到的各种物理信息、生物信息相联接，通过Internet网自动的、实时的、方便的、简单的，提供给需要这些信息的对象”。 由此可见，如何设计和制造嵌入式瘦服务器、嵌入式网关和嵌入式因特网路由器已成为嵌入式Internet时代的关键和核心技术，北京英 贝多公司历经多年的努力，已经具备和掌握了嵌入式Internet核心技术，并在中国单片机公共实验室的支持下，研发出了具有自主知识产权的基于芯片的超微型Internet网关和瘦服务器，为迎接Internet向嵌入式领域发展的第三阶段作好基础性准备，嵌入式Internet广泛应用将 使我们这个世界变得更加自动化、智能化和人性化。 <br /><br />Internet的伟大之处就在于可以无限地膨胀。《数字化生存》的作者尼古拉·庞帝来中国讲演时，曾预言未来PC的市场份额将减少，可能会出现许多非常便宜的因特网接入设备，他建议的价格只有1美元<br /><br />单片机或微控制器(MCU)，通称嵌入式系统，已经在家庭和工业的各个领域得到了应用。目前大多数嵌入式系统还处于单独应用的阶段，以MCU为核心，与一些监测、伺服、指示设备配合实现一定的功能。Internet 现已成为社会重要的基础信息设施之一, 是信息流通的重要渠道，如果嵌入式系统能够连接到 Internet上面，则可以方便、低廉地将信息传送到几乎世界上的任何一个地方。 将嵌入式系统与Internet结合起来的想法其实很早以前就有了，主要的困难在于，Internet上面的各种通信协议对于计算机存储器、运算速度等的要求比较高，而嵌入式系统中除部分32位处理器以外，大量存在的是8位和16位MCU，支持TCP/IP 等 Internet协议将占用大量系统资源，或根本不可能。而北京英贝多公司以嵌入式微型因特网互连技术为基础的解决方案，把这种假设变成现实，实现嵌入式设备的Internet网络化。又进而独立研发出了有自主知识产权的iSOC（因特网片上系统）芯片，实现了高可靠低成本的嵌入式因特网接入网关和服务器于一体的emISP-soc产品和技术方案。 emISP-soc能够实现基于Internet的远程数据采集、远程控制、自动报警、上传/下载数据文件、自动发送e-mail等功能, 为IST (Internet Sensor Technology网络传感器技术)、HVAC〈家庭环境自动控制)、局部环境自动监测、智能小区管理、网络自动抄表、高速公路 出入口管理等技术的应用与发展提供了技术保证。 中国计算机学会(China Computer Federation) 于 1999年6月举行了“嵌入式系统及产业化在中国的发展前景”研讨会，专家们探讨了嵌入式系统在当今计算机工业中的地位及其网络化问题，认为下一代网络设备中嵌入式设备将大大增加，70％是嵌入式设备。嵌入式系统工业是专用计算机工业，其目的就是要把一切变得更简单、更方便、更普遍、更适用；通用计算机的发展变为功能电脑，普遍进入社会，嵌入式 计算机发展的目标是专用电脑，实现“普遍化计算”，因此可以称嵌入式智能芯片是构成未来世界的“数字基因”。沈绪榜院士预言，“未来十年将会产生针头大小、具有超过1亿次运算能力的嵌入式智能芯片”，这将为我们提供无限的创造空间。 随着市场对超微型嵌入式应用技术的不断增长，以及半导体技术和系统设计方法的进步，在一个硅片上实现一个(过去以为）复杂的系统的时代已经来临，这种芯片称之为“片上系统”（System On a Chip），简称为SOC。SOC的出现将改变并深刻地影响传统的集成电路产业的现状，使设计和功能定义以及决策者远见变得更为重要，这一点也证实了“在后工业时代的经济中，发明创造的价值超过批量生产，所有 的垂直的东西突然变成水平”的经济学现象。 <br /><br />嵌入式Internet时代将为中国的集成电路设计产业提供良机。</font>
		</p>
<img src ="http://www.cnitblog.com/lijiehua/aggbug/10861.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/lijiehua/" target="_blank">内嵌</a> 2006-05-20 23:41 <a href="http://www.cnitblog.com/lijiehua/articles/10861.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ARM7TDMI-S在嵌入式系统中的Bootloader代码设计</title><link>http://www.cnitblog.com/lijiehua/articles/10857.html</link><dc:creator>内嵌</dc:creator><author>内嵌</author><pubDate>Sat, 20 May 2006 15:28:00 GMT</pubDate><guid>http://www.cnitblog.com/lijiehua/articles/10857.html</guid><wfw:comment>http://www.cnitblog.com/lijiehua/comments/10857.html</wfw:comment><comments>http://www.cnitblog.com/lijiehua/articles/10857.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/lijiehua/comments/commentRss/10857.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/lijiehua/services/trackbacks/10857.html</trackback:ping><description><![CDATA[
		<font size="2">ARM7TDMI-S在嵌入式系统中的Bootloader代码设计  <br />文章作者：周永宏 王成飞 何志敏<br />文章类型：设计应用 文章加入时间：2004年12月20日2:47 <br />文章出处：单片机及嵌入式系统应用  <br /><br />--------------------------------------------------------------------------------<br /><br /><br /><br /><br />    摘要：ARM7TDMI-S是ARM公司设计的一款32位精简指令集处理器内核，LPC210x系列是飞利浦半导体公司生产的基于ARM7TDMI-S内核的芯片。在嵌入式系统设计中，针对嵌入式处理器和操作系统的Bootloader代码的设计是一个难点。本文根据用LPC2106进行嵌入式系统设计的实际经验，总结出基于ARM7TDMI-S内核的嵌入式处理器芯片的Bootloader代码设计的一般流程；给出LPC2106芯片在基于μC/OS-II操作系统的嵌入式应用中，BootLoader程序的详细设计流程及其中的一些关键技术和代码。<br /><br />    关键词：ARM7TDMI-S嵌入式系统 BootLoader代码 LPC2106 μC/OS-II<br /><br />引言<br /><br />芯片的Bootloader代码（即启动代码）就是芯片复位后进入操作系统之前执行的一段代码，主要是为运行操作系统提供基本的运行环境，如初始化CPU堆栈、初始化存储器系统等。Bootloader代码与CPU芯片的内核结构、具体芯片和使用的操作系统等因素有关。其功能有点类似于PC机的BIOS（Basic Input/Output System,基本输入输出系统）程序，但是由于嵌入式系统的软硬件都要比PC机的简单，所以它的Bootloader代码要比BIOS程序简单得多。<br /><br />嵌入式系统被定义为：以应用中为心，以计算机技术为基础，软件硬件可裁剪，适用于系统对功能、可靠性、成本、何种、功耗有严格要求的专用计算机系统。嵌入式系统的核心部件是嵌入式处理器。随着嵌入式系统在人们日常生活中的广泛运用，嵌入式处理器得到前所未有的飞速发展。基于ARM核的嵌入式处理器芯片种类繁多。由于ARM公司只设计内核的不生产具体的芯片，即便是基于同一种内核，不同厂家生产的芯片差别很大，因此不易编写出统一的Bootloader代码。ARM公司针对这一问题而采取的策略是，不提供完事的Bootloader代码（ARM公司的开发工具ADS提供了一些功能代码），Bootloader代码不足的部分由芯片厂商提供或者由用户自己编写。飞利浦公司没有提供LPC210x系列的Bootloader代码，所以用户只能自己编写Bootloader代码。<br /><br />1 ARM7TDMI-S和LPC210x<br /><br />ARM7TDMI-S是目前比较低端的ARM核—ARM核不是芯片，它与其它部件如RAM、ROM、片内外设组合在一起才构成实际的芯片。ARM7是用于对成本和功耗都非常敏感的消费应用的低价位、低功耗的32位核。其主要特点如下：冯.诺依曼结构、3段流水线、0.9MIPS/MHz；非常低的功耗；嵌入式ICE-RT（In Circuit Emulation-Real Time，实时在线仿真）逻辑。<br /><br />LPC2104/2105/2106基于一个支持实时仿真和跟踪的ARM7TDMI-S内核，并带有128KB的高速Flash存储器，128位宽度的存储器接口和独特的加速结构，使32位代码能够在最大时钟速率下运行。由于LPC2104/2105/2106具有非常小的尺寸和极低的功耗，它们非常适合于那些将小型化作为主要要求的应用，例如存储取控制和POS机。带有宽范围的串行通信接口、片内多达64KB的SRAM，由于具有大的缓冲区和强大的处理器能力，它们非常适合于通信网关和协议转换器、软件调制解调器、声音识别以及低端的图像处理。而多个32位定时器、PWM输出和32个GPIO，使它们特别适用于工业控制和医疗系统。LPC2106是LPC210x系列的一种，其它两种为LPC2104/2105。它们都基于ARM7TDMI-S内核。三种芯片唯一的区别就是SRAM的容量大小：LPC2106是64KB，而LPC2104是16KB，LPC2105是32KB。<br /><br />2 Bootloader代码<br /><br />2.1 Bootloader代码的作用<br /><br />嵌入式系统的资源有限，应用程序通常都是固化在ROM中运行。ROM中的程序执行前，需要对系统硬件和软件运行环境进行初始化。这些工作是用汇编语言和C语言编写的Bootloader代码完成的。在ARM处理器的嵌入式系统中，Bootloader代码的作用主要有以下几点：<br /><br />*初始化CPU各种模式的堆栈和寄存器；<br /><br />*初始化系统中要使用的各种片内外设；<br /><br />*初始化目标板；<br /><br />*引导操作系统。<br /><br />2.2 Bootlader代码设计的一般流程<br /><br />Bootloader代码是嵌入式系统中应用程序的开头部分，它与应用程序一起固化在ROM中，并首先在系统上运行。设计好Bootloader代码是设计嵌入式程序的关键，也是系统能够正常工作的前提。Bootloader代码所执行的操作主要信赖于CPU内核的类型，以及正在开发的嵌入式系统软件中需要使用CPU芯片上的哪些资源。Bootloader代码的一般流程（即Bootloader代码应该进行的操作）如图1所示。<br /><br />2.3 基于LPC2104和μC/OS-II是多任务的实时操作系统。针对该款芯片和多任务实时操作系统的Bootloader程序的流程如图2所示。<br /><br />2．3．2 关键代码分析<br /><br />；中断向量表，给出了CPU芯片出现异常时应该转去执行的程序地址<br /><br />Vectors<br /><br />LDR PC,ResetAddr<br /><br />LDR PC,UndefinedAddr<br /><br />LDR PC,SWI_Addr<br /><br />LDR PC,SWI_Addr<br /><br />LDR PC,PrefetchAddr<br /><br />LDR PC,DataAbortAddr<br /><br />DCD 0xb9205f80<br /><br />LDR PC,[PC,#-0xff0]<br /><br />LDR PC,FIQ_Addr<br /><br />ResetAddr DCD Reset<br /><br />UndefinedAddr DCD Undefined<br /><br />SWI_Addr DCD SoftwareInterrupt<br /><br />PrefetchAddr DCD PrefetchAbort<br /><br />DataAbortAddr DCD DataAbort<br /><br />Nouse DCD 0<br /><br />IRQ_Addr DCD 0<br /><br />FIQ_Addr DCD FIQ_Handler<br /><br />;InitStack函数，其功能是初始化CPU各种模式的堆栈<br /><br />InitSatck<br /><br />MOV R0,LR ；因芯片模式切换，故将程序返回地址保存至R0，同时在初始化堆栈完成后使用R0返回<br /><br />MSR CPSR_c,#0xd3 ;设置管理模式堆栈<br /><br />LDR SP，StackSvc<br /><br />MSR CPSR_c,#0xd2 ;设置中断模式堆栈<br /><br />LDR SP，StackIrq<br /><br />MSR CPSR_c,#0xd1 ;设置快速中断模式堆栈<br /><br />LDR SP，StackFiq<br /><br />MSR PSR_c,#0xd7 ;设置中止模式堆栈<br /><br />LDR SP，StackAbt<br /><br />MSR CPSR_c,#0xdb ;设置未定义模式堆栈<br /><br />LDR SP，StackUnd<br /><br />MSR CPSR_c,#0xdf ;设置系统模式堆栈<br /><br />LDR SP，StackUsr<br /><br />MOV PC,R0<br /><br />StackUsr DCD UsrStackSpace+(USR_STACK_LEGTH-1)*4<br /><br />StackRvc DCD SvcStackSpace+(SVC_STACK_LEGTH-1)*4<br /><br />StackIrq DCD IrqStackSpace+(IRQ_STACK_LEGTH-1)*4<br /><br />StackFiq DCD FiqStackSpace+(FIQ_STACK_LEGTH-1)*4<br /><br />StackAbt DCD AbtStackSpace+(ABT_STACK_LEGTH-1)*4<br /><br />StackUnd DCD UndtStackSpace+(UND_STACK_LEGTH-1)*4<br /><br />;系统初始化代码<br /><br />Reset<br /><br />BL InitStack ;调用InitStack函数初始化芯片各种模式的堆栈<br /><br />BL TargetResetInit ；调用TargetResetInit函数对系统进行基本初始化<br /><br />B _main ；跳转到ADS提供的启动代码_main函数处，它初始化函数库并最终引导CPU进入操作系统的main()函数<br /><br />    上面的程序代码只包含了流程图中的几个主机步骤。这些步骤都是必不可少的，其余的步骤都在TargetResetInit函数中加以实现。本例中的TargerReset Init函数如下：<br /><br />void TargetResetInit(void)<br /><br />{/*设置系统各部分时钟*/<br /><br />PLLCON=1；<br /><br />#if((Fcclk /4)/Fpclk==1<br /><br />VPBDIV=0;<br /><br />#endif<br /><br />#if((Fcclk/4)/Fpclk==2<br /><br />VPBDIV=2;<br /><br />#endif<br /><br />#if((Fcclk/4)/Fpclk==4<br /><br />VPBDIV=1;<br /><br />#endif<br /><br />#if(Fcco/Fcclk)==1<br /><br />PLLCFG=((Fcclk/Fosc)-1)|(1&lt;&lt;5);<br /><br />#endif<br /><br />#if(Fcco/Fcclk)==2<br /><br />PLLCFG=((Fcclk/Fosc)-1|(2&lt;&lt;5);<br /><br />#endif<br /><br />#if(Fcco/Fcclk)==4<br /><br />PLLCFG=((Fcclk/Fosc)-1|(3&lt;&lt;5);<br /><br />#endif<br /><br />#if(Fcco/Fcclk)==8<br /><br />PLLCFG=((Fcclk/Fosc)-1)|(4&lt;&lt;5);<br /><br />#endif<br /><br />PLLFEED=0xaa;<br /><br />PLLFEED=0x55;<br /><br />while(PLLSTAT &amp;(1&lt;&lt;10)==0)<br /><br />PLLCON=3;<br /><br />PLLFEED=0xaa;<br /><br />PLLFEED=0x55;<br /><br />/*设置存储器加速模块*/<br /><br />MAMCR=2；<br /><br />#if Fcclk&lt;20000000<br /><br />MAMTIM=1;<br /><br />#else<br /><br />#if Fcclk&lt;40000000<br /><br />MAMTIM=2;<br /><br />#else<br /><br />MAMTM=3;<br /><br />#endif<br /><br />#endif<br /><br />/*初始化VIC，使芯片在进入μC/OS-II多任务环境前关中断*/<br /><br />VICIntEnClr=0xffffffff;<br /><br />VICVectAddr=0;<br /><br />VICIntSelect=0;<br /><br />/*其它步骤的代码与实际的软件功能相关，不具有代表性，故在此不列出*/<br /><br />}<br /><br />3 结论<br /><br />本文介绍的Bootloader代码已经在基于Philips公司的LPC2106芯片开发的系统上运行并测试通过。针对不同的CPU芯片编写Bootloader代码，首先要了解该CPU的内核结构、指令系统，其次是具体芯片的结构和各种片上资源，以及所采用的操作系统。以上所列的设计流程不是一成不变的，在具体应用中要权衡取舍。 <br /></font>
<img src ="http://www.cnitblog.com/lijiehua/aggbug/10857.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/lijiehua/" target="_blank">内嵌</a> 2006-05-20 23:28 <a href="http://www.cnitblog.com/lijiehua/articles/10857.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ARM Bootloader 的实现-------C 和ASM 混合编程</title><link>http://www.cnitblog.com/lijiehua/articles/10856.html</link><dc:creator>内嵌</dc:creator><author>内嵌</author><pubDate>Sat, 20 May 2006 15:27:00 GMT</pubDate><guid>http://www.cnitblog.com/lijiehua/articles/10856.html</guid><wfw:comment>http://www.cnitblog.com/lijiehua/comments/10856.html</wfw:comment><comments>http://www.cnitblog.com/lijiehua/articles/10856.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/lijiehua/comments/commentRss/10856.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/lijiehua/services/trackbacks/10856.html</trackback:ping><description><![CDATA[
		<font size="2">http://embedded.homeunix.org<br />1<br />ARM Bootloader 的实现现-------C 和ASM 混合编程<br />Gavin Li ver 0.1 Tuesday, June 03, 2003<br />Cirrus Logic的clps7111~Ep9312 系列ARM core的CPU内置128 字节的boot 程<br />序。这个boot程序为把操作系统下载到裸机提供了极大的方便。这样再焊接电路<br />板之前不用把操作系统预先写入Flash，而且日后升级操作系统也非常方便。<br />这个boot程序的功能是：<br />1. 设置串行口的参数为：9600， 8N1，No FlowControl。<br />2. 然后送出一个&lt; 字符<br />3. 开始接收2K 字节程序（Bootloader）<br />4. 送出一个&gt; 字符<br />5. 跳转去执行这2K 的程序。<br />烧写操作系统的过程是:<br />1. 连接ARM target的产性口和PC的串行口<br />ARM PC<br />RX ------------------- TX<br />TX ------------------- RX<br />GND ---------------- GND<br />2. 从BOOT程序引导ARM target<br />3. 在Windows NT4.0 的console中, 设置串行口的参数9600 8N1<br />C:&gt;mode COM2: baud=9600 data=8 parity=n stop=1<br />4. 在console中把bootloader送到串行口。/b表示以二进制方式<br />C:&gt;copy /b bootldr.bin COM1:<br />5. 在console中, 根据bootloader的设置来调整串行口的参数115200 8N1<br />C:&gt;mode COM2: baud=115200 data=8 parity=n stop=1<br />6. 在console中把vxworks image送到串行口。/b表示以二进制方式<br />C:&gt;copy /b vxworks COM1:<br />7. Power off ARM target，设置其从Flash启动。<br />8. reboot，进入VxWorks<br />这2K字节的程序就是我们说的ARM Bootloader，它的任务一般是：<br />1. 必要的硬件初始化<br />2. 从串行口接收VxWorks的二进制文件，并写入Flash<br />3. 在这过程中，显示一些提示信息。<br />像Bootloader 这样底层的程序一般认为是要用纯汇编来写的。但是用汇编写的程序<br />可读性肯定没有用C写的程序好。汇编程序不宜维护，没办法向其它类型的CPU<br />去移植。这些方面C的程序是没有问题的！&#x1;<br />http://embedded.homeunix.org<br />2<br />那么Bootloader能否用纯C语言去写呢？不可能。因为有些操作特殊寄存器的指<br />令也是特殊指令，用C是实现不了的。有些功能用C也是不能实现的。用C不能<br />作的有：<br />1. 操作CP15寄存器的指令<br />2. 中断使能<br />3. 堆栈地址的设定<br />所以，只要知道这几条汇编指令可以了，不必学习所有的汇编指令。是不是上手很<br />快呀。下面来看看我们在Bootloader中所用到的汇编部分：<br />asm ("_my_start:<br />mov r14, #0x70<br />mcr p15, 0, r14, c1, c0, 0 /* MMU disabled, 32 Bit mode, Little endian */<br />mrs r14, cpsr<br />bic r14, r14, #0x1f /* Mask */<br />orr r14, r14, #0xc0 + 0x13 /* Diasble IRQ and FIQ, SVC32 Mode */<br />msr cpsr, r14<br />ldr r13, =0xc0020000 /* Setup Stack */<br />");<br />简单吧，比看几十K的汇编程序感觉好得多吧。<br />也许你会问：硬件的初始化怎么办？那是要操作寄存器的。<br />我说：看看这段C的代码：<br />*((DWORD*)(dwHardwareBase + HW1_SYSCON1)) = SYSCON1_VALUE;<br />明白了吧，ARM中把寄存器映射在内存中了，就跟读写内存没有区别。<br />现在编写程序的问题已经全部解决了，但是否就没有问题了呢？不是。你的程序应<br />该写成什么样呢？怎么编译生成二进制文件呢？<br />让我们先写一个程序试一下吧：<br />#define DWORD unsigned int<br />int main(void)<br />{<br />register DWORD dwHardwareBase;<br />asm ("_my_start:<br />mov r14, #0x70<br />mcr p15, 0, r14, c1, c0, 0 /* MMU disabled, 32 Bit mode, Little endian */<br />mrs r14, cpsr<br />bic r14, r14, #0x1f /* Mask */<br />orr r14, r14, #0xc0 + 0x13 /* Diasble IRQ and FIQ, SVC32 Mode */<br />msr cpsr, r14<br />ldr r13, =0xc0020000 /* Setup Stack */<br />");<br />dwHardwareBase = (DWORD)0x80000000;<br />return 0;<br />}<br />http://embedded.homeunix.org<br />3<br />编译一下：<br />C:&gt;ccarm -c -O2 -mcpu=arm710 -mlittle-endian -nostdlib -fvolatile -nostdinc –static<br />sam1.c<br />C:&gt;ldarm -o sam1.out -Ttext 10000000 sam1.o<br />ldarm: warning: cannot find entry symbol _start; defaulting to 10000000<br />sam1.o(.text+0xc):fake: undefined reference to `__gccmain'<br />sam1.o(.text+0xc):fake: relocation truncated to fit: ARM_26 __gccmain<br />我们发现应该把main定义成_start<br />#define DWORD unsigned int<br />void start(void) //gcc需要把它定义成_start，vxworks的egcs要把它定义成start。<br />{<br />register DWORD dwHardwareBase;<br />asm ("_my_start:<br />mov r14, #0x70<br />mcr p15, 0, r14, c1, c0, 0 /* MMU disabled, 32 Bit mode, Little endian */<br />mrs r14, cpsr<br />bic r14, r14, #0x1f /* Mask */<br />orr r14, r14, #0xc0 + 0x13 /* Diasble IRQ and FIQ, SVC32 Mode */<br />msr cpsr, r14<br />ldr r13, =0xc0020000 /* Setup Stack */<br />");<br />dwHardwareBase = (DWORD)0x80000000;<br />}<br />编译一下：<br />C:&gt;ccarm -c -O2 -mcpu=arm710 -mlittle-endian -nostdlib -fvolatile -nostdinc –static<br />sam1.c<br />C:&gt;ldarm -o sam1.out -Ttext 10000000 sam1.o<br />C:&gt;objdumparm -d sam1.out &gt; sam1.asm<br />现在来看看汇编的源代码：<br />sam1.out: file format coff-arm-little<br />Disassembly of section .text:<br />10000000 &lt;_start&gt;:<br />10000000: e1a0c00d mov ip, sp<br />10000004: e92dd800 stmdb sp!, {fp, ip, lr, pc}<br />10000008: e24cb004 sub fp, ip, #4<br />1000000c &lt;_my_start&gt;:<br />1000000c: e3a0e070 mov lr, #70<br />10000010: ee01ef10 mcr 15, 0, lr, cr1, cr0, {0}<br />10000014: e10fe000 mrs lr, cpsr<br />10000018: e3cee01f bic lr, lr, #1f<br />1000001c: e38ee0d3 orr lr, lr, #d3<br />http://embedded.homeunix.org<br />4<br />10000020: e129f00e msr cpsr, lr<br />10000024: e59fd000 ldr sp, 1000002c &lt;$$lit_&#x1F;1&gt;<br />10000028: e91ba800 ldmdb fp, {fp, sp, pc}<br />1000002c &lt;$$lit_&#x1F;1&gt;:<br />1000002c: c0020000 andgt r0, r2, r0<br />10000030 &lt;__CTOR_LIST__&gt;:<br />10000030: ffffffff swinv 0x00ffffff<br />10000034: 00000000 andeq r0, r0, r0<br />10000038 &lt;__DTOR_LIST__&gt;:<br />10000038: ffffffff swinv 0x00ffffff<br />1000003c: 00000000 andeq r0, r0, r0<br />哈哈！在&lt;_start&gt;和&lt;_my_start&gt;之间的代码在干什么？是在保存现场吧，还用到了<br />堆栈。而这时堆栈还没初始化，向堆栈里写东西那不乱套了！应该屏蔽这段代码。<br />那就在&lt;_start&gt;之前放一个跳转指令跳到&lt;_my_start&gt;吧。<br />#define DWORD unsigned int<br />asm ("<br />.text<br />.global _start<br />_start:<br />bl _my_start /* Omit the entry code for function c_start() */<br />");<br />void c_start(void)<br />{<br />register DWORD dwHardwareBase;<br />asm ("_my_start:<br />mov r14, #0x70<br />mcr p15, 0, r14, c1, c0, 0 /* MMU disabled, 32 Bit mode, Little endian */<br />mrs r14, cpsr<br />bic r14, r14, #0x1f /* Mask */<br />orr r14, r14, #0xc0 + 0x13 /* Diasble IRQ and FIQ, SVC32 Mode */<br />msr cpsr, r14<br />ldr r13, =0xc0020000 /* Setup Stack */<br />");<br />dwHardwareBase = (DWORD)0x80000000;<br />}<br />再编译看看汇编代码：<br />sam1.out: file format coff-arm-little<br />Disassembly of section .text:<br />10000000 &lt;_start&gt;:<br />http://embedded.homeunix.org<br />5<br />10000000: eb000002 bl 10000010 &lt;_my_start&gt;<br />10000004 &lt;_c_start&gt;:<br />10000004: e1a0c00d mov ip, sp<br />10000008: e92dd800 stmdb sp!, {fp, ip, lr, pc}<br />1000000c: e24cb004 sub fp, ip, #4<br />10000010 &lt;_my_start&gt;:<br />10000010: e3a0e070 mov lr, #70<br />10000014: ee01ef10 mcr 15, 0, lr, cr1, cr0, {0}<br />10000018: e10fe000 mrs lr, cpsr<br />1000001c: e3cee01f bic lr, lr, #1f<br />10000020: e38ee0d3 orr lr, lr, #d3<br />10000024: e129f00e msr cpsr, lr<br />10000028: e59fd000 ldr sp, 10000030 &lt;$$lit_&#x1F;1&gt;<br />1000002c: e91ba800 ldmdb fp, {fp, sp, pc}<br />10000030 &lt;$$lit_&#x1F;1&gt;:<br />10000030: c0020000 andgt r0, r2, r0<br />10000034 &lt;__CTOR_LIST__&gt;:<br />10000034: ffffffff swinv 0x00ffffff<br />10000038: 00000000 andeq r0, r0, r0<br />1000003c &lt;__DTOR_LIST__&gt;:<br />1000003c: ffffffff swinv 0x00ffffff<br />10000040: 00000000 andeq r0, r0, r0<br />成功了！！！！<br />剩下的就是写Flash的程序，我就不多写了，这里给出源代码。需要说明的是：<br />下面的这段指令是生成2K的二进制文件<br />debug bootldr.bin<br />rcx<br />800<br />w<br />q<br />所有的全局变量都定义成const，因为在linux 中用gcc，ld，objcopy 处理过程序后<br />如果不是定义的是const，生成的二进制文件很大，不知道为什么。谁知道原因请<br />来信告知。(gavinux@yahoo.com)<br />在汇编代码的尾部有：&lt;__CTOR_LIST__&gt; 和&lt;__DTOR_LIST__&gt;，象是C++的构<br />造函数和析构函数的列表，不只是否？我现在还不知道什么编译连接的选项能把它<br />去掉。&#x2;<br />http://embedded.homeunix.org<br />6<br />最后问大家一个问题：向bootloader这样对文件大小很敏感的程序（2K size）我们<br />都能够用以上的方法实现，那么是不是VxWorks BSP里的所有程序都能用这个办<br />法实现呢?<br />/***********************************************************************<br />; bootloader for Cirrus Logic clps7111 ARM processor<br />; Author : Gavin Li<br />; web: http://embedded.homeunix.org<br />; rev 0<br />;<br />; INTEL Flash F160C3, F320C3<br />; -- For downloading vxWorks images.<br />; -- The size of the .bin file has to be limited to 2K and this program<br />; is to be downloaded by the on-chip boot program first.<br />; -- Runs in the on-chip 2K SRAM<br />; -- Works together with FTS (on the PC side)<br />; -- F160C3 has 2 M memory with 8 segments and F320C3 has 8 M memory with<br />; 2 segments. F320C3's memory space covers F160C3 and vxWork's image is<br />; normally smaller than 1M, therefor this program works for both 320<br />; and 160 though it is originally for 160.<br />; -- Erase 0.5M or 1M flash according to the image size<br />;<br />; This program is free software; you can redistribute it and/or modify<br />; it under the terms of the GNU General Public License as published by<br />; the Free Software Foundation; either version 2 of the License, or<br />; (at your option) any later version.<br />;<br />; This program is distributed in the hope that it will be useful,<br />; but WITHOUT ANY WARRANTY; without even the implied warranty of<br />; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br />; GNU General Public License for more details.<br />;<br />;**********************************************************************/<br />/* For VxWorks<br />rem asarm -EL -o start.o start.s<br />ccarm -c -O2 -mcpu=arm710 -mlittle-endian -nostdlib -fvolatile -nostdinc -static<br />bootldr.c<br />ldarm -o bootldr.out -Ttext 10000000 bootldr.o<br />objdumparm -d bootldr.out &gt; bootldr.asm<br />coffarmtobin &lt; bootldr.out &gt; bootldr.bin<br />debug bootldr.bin<br />rcx<br />800<br />w<br />q<br />http://embedded.homeunix.org<br />7<br />*/<br />/* For GNU gcc<br />PATH=/home/gavin/armtools/bin:$PATH<br />arm-linux-gcc -O2 -mcpu=arm710 -mlittle-endian -nostdlib -fvolatile -nostdinc -static<br />-e _start -Ttext 10000000 -o bootldr.out bootldr.c<br />arm-linux-objcopy -O binary -S bootldr.out bootldr.bin<br />arm-linux-objdump -d bootldr.out bootldr.asm<br />remeber to make bootldr.bin to 2K size for clps7111/clps7211 system board<br />You will get these warnings, Those are correct, just forget them. :-)<br />bootldr.c: In function `RecvData':<br />bootldr.c:252: warning: assignment of read-only variable `g_dwSaveAddr'<br />bootldr.c:253: warning: assignment of read-only variable `g_dwSaveCount'<br />bootldr.c:268: warning: assignment of read-only variable `g_dwCheckSum'<br />*/<br />/* -B/home/gavin/armtools */<br />#include "clps7111.h"<br />/* flash command defines */<br />#define FLASH_COMMAND_READ_ID 0x90<br />#define FLASH_COMMAND_READ 0xFF<br />#define FLASH_COMMAND_ERASE 0x20<br />#define FLASH_COMMAND_CONFIRM 0xD0<br />#define FLASH_COMMAND_CLEAR 0x50<br />#define FLASH_COMMAND_WRITE 0x40<br />#define FLASH_COMMAND_STATUS 0x70<br />#define FLASH_COMMAND_SUSPEND 0xB0<br />#define FLASH_COMMAND_RESUME 0xD0<br />#define FLASH_COMMAND_CONFIG_SETUP 0x60<br />#define FLASH_COMMAND_LOCK_BLOCK 0x01<br />#define FLASH_COMMAND_UNLOCK_BLOCK 0xD0<br />#define FLASH_STATUS_READY 0x80<br />#define FLASH_STATUS_ERASE_SUSPENDED 0x40<br />#define FLASH_STATUS_WRITE_SUSPENDED 0x04<br />#define FLASH_STATUS_ERROR 0x3E<br />#define FLASH_STATUS_ERASE_ERROR 0x3A<br />#define FLASH_STATUS_PROGRAMING_ERROR 0x1A<br />#define FLASH_START_ADDRESS 0x70000000<br />#define FLASH_CHECK_EMPTY_END_ADDRESS 0x70100000<br />#define FLASH_ERASE_8K_BLOCKS 8<br />#define FLASH_ERASE_64K_BLOCKS 31<br />#define DRAM_BLOCK_SIZE 0x40000 /* 256KB */<br />http://embedded.homeunix.org<br />8<br />#define SYSCON1_VALUE 0x00840100 /* EXCKEN, BZMOD=TOG,<br />UART1EN */<br />#define SYSCON2_VALUE 0x00000006 /* 16bit DRAM, KBD6 */<br />#define MEMCFIG1_VALUE 0x03010100 /* CS3: 8bitC, CS2,1: 32bit, CS0:<br />16bit */<br />#define DRAM_FRESH_RATE 0x83<br />/*#define UART1_CONFIG 0x74005 */ /* 38400 8N1 Enable FIFO */<br />/*#define UART1_CONFIG 0x60003 */ /* 57600 8N1 Enable FIFO */<br />#define UART1_CONFIG 0x74001 /* 115200 8N1 Enable FIFO */<br />#define SYSCON2_VALUE_BEEP_ON 0x00004006 /* BuzzerFreq, 16bit DRAM,<br />KBD6 */<br />#define SYSCON2_VALUE_BEEP_OFF 0x00000006 /* 16bit DRAM, KBD6 */<br />#define HbDdrAData 0x00 /* all inputs */<br />#define HbDdrBData 0x14 /* bit 2,4 output */<br />#define HbDdrDData 0x00 /* all output (direction def reversed) */<br />#define HbDdrEData 0x0F /* all output */<br />#define HbDrBData 0x00 /* HbDrBData &amp; HbDrDData disable printer heating<br />*/<br />#define HbDrDData 0x00<br />#define HbDrEData 0x02 /* UCHARge battery, disable step motor */<br />#define UART1_TX_FIFO_FULL (1&lt;&lt;23)<br />#define UART1_TX_BUSY (1&lt;&lt;11)<br />#define UART1_RX_FIFO_EMPTY (1&lt;&lt;22)<br />#define BUZZER_TOGGLE (1&lt;&lt;9)<br />#define UCHAR unsigned char<br />#define DWORD unsigned int<br />/* Function prototypes */<br />/*<br />void SetCp15(DWORD dwCp15Val);<br />DWORD ReadCp15();<br />*/<br />void PrintMsg(UCHAR * pszMsg);<br />void RecvData(void);<br />DWORD RecvDword(void);<br />void SendChar(register UCHAR ch);<br />UCHAR ReceiveChar(void);<br />void PrintDword(DWORD dwValue);<br />void ToAscii(UCHAR ch, UCHAR * pcAscii);<br />void Beep(void);<br />UCHAR* FlashBlockErase(UCHAR * pucBlockAddr, DWORD dwBlocks, DWORD<br />dwBlockSize);<br />http://embedded.homeunix.org<br />9<br />void FlashChipErase(void);<br />void FlashCheckEmpty(void);<br />void FlashWrite(void);<br />void FlashChipUnlock(void);<br />void FlashErrorHandler(UCHAR * pszMsg, UCHAR * pcAddr2Dump);<br />/* Globle Variable */<br />const DWORD g_dwDramBase[] = {0xc0080000, 0xc0200000, 0xc0280000,<br />0xc0800000, 0xc0880000, 0xc0a00000, 0xc0a80000}; /*DRAM_BLOCK_SIZE each*/<br />const DWORD g_dwSaveAddr; /* Will changed by RecvData() */<br />const DWORD g_dwSaveCount; /* Will changed by RecvData() */<br />const DWORD g_dwCheckSum;<br />const UCHAR g_AsciiTable[] = "0123456789abcdef";<br />const UCHAR g_szByteMsg[] = "0xXX ";<br />const UCHAR g_szWordMsg[] = "0xXXXXYYYY\n";<br />const UCHAR g_szBootLdrStart[] = "+++START LOADER\r\n";<br />const UCHAR g_szReceiving[] = "Receiving data ...\r\n";<br />const UCHAR g_szReceived[] = "Receiving finished!\n";<br />const UCHAR g_szIds[] = "Device code/Manufacturer code: ";<br />const UCHAR g_szUnlockingFlash[] = "Unlocking Flash ...\n";<br />const UCHAR g_szErasingFlash[] = "Erasing flash ...\n";<br />const UCHAR g_szProgrammingFlash[] = "Programming Flash ...\n";<br />const UCHAR g_szDone[] = "Data has been programmed into flash\n";<br />const UCHAR g_szBootLdrEnd[] = "+++BOOTLOADER END\n";<br />const UCHAR g_szEraseFlashError[] = "Error erasing flash\n";<br />const UCHAR g_szFlashNotEmpty[] = "Error flash not empty\n";<br />const UCHAR g_szProgramFlashError[] = "Error programming flash\n";<br />const UCHAR g_szDramError[] = "DRAM Error!\n";<br />/* Implementation */<br />asm ("<br />.text<br />.global _start<br />_start:<br />bl _my_start /* Omit the entry code for function c_start() */<br />");<br />void c_start(void)<br />{<br />register DWORD* pdwFlashStartAddr;<br />register DWORD* pdwFlashEndAddr;<br />register DWORD* pdwDramStartAddr;<br />register DWORD dwHardwareBase;<br />asm ("_my_start:<br />mov r14, #0x70<br />mcr p15, 0, r14, c1, c0, 0 /* MMU disabled, 32 Bit mode, Little endian */<br />mrs r14, cpsr<br />http://embedded.homeunix.org<br />10<br />bic r14, r14, #0x1f /* Mask */<br />orr r14, r14, #0xc0 + 0x13 /* Diasble IRQ and FIQ, SVC32 Mode */<br />msr cpsr, r14<br />ldr r13, =0xc0020000 /* Setup Stack */<br />");<br />dwHardwareBase = (DWORD)HW1base;<br />*((DWORD*)(dwHardwareBase + HW1_INTMR1)) = 0; /* disable Interrupt */<br />*((DWORD*)(dwHardwareBase + (0x1000+HW2_INTMR2))) = 0; /* disable<br />Interrupt */<br />*((DWORD*)(dwHardwareBase + HW1_SYSCON1)) = SYSCON1_VALUE;<br />*((DWORD*)(dwHardwareBase + (0x1000+HW2_SYSCON2))) =<br />SYSCON2_VALUE;<br />*((DWORD*)(dwHardwareBase + HW1_MEMCFG1)) = MEMCFIG1_VALUE;<br />*((DWORD*)(dwHardwareBase + HW1_DRFPR)) = DRAM_FRESH_RATE;<br />/* **** We can call functions from here! **** */<br />PrintMsg((UCHAR*)&amp;g_szReceiving);<br />PrintMsg((UCHAR*)&amp;g_szBootLdrStart);<br />Beep();<br />*((DWORD*)(dwHardwareBase + HW1_UBRLCR1)) = UART1_CONFIG; /*<br />115200 8n1 */<br />/*<br />make sure that before reinitializing UART there is enough<br />time to send out last message<br />So far Beep gives enough time<br />*/<br />pdwFlashStartAddr = (DWORD *)FLASH_START_ADDRESS;<br />RecvData(); /* receive data */<br />PrintMsg((UCHAR*)&amp;g_szReceived);<br />PrintMsg((UCHAR*)&amp;g_szIds); /* display Flash Id message */<br />*((UCHAR *)pdwFlashStartAddr) = FLASH_COMMAND_READ_ID; /* read ID */<br />PrintDword(*pdwFlashStartAddr);<br />PrintMsg((UCHAR*)&amp;g_szUnlockingFlash);<br />FlashChipUnlock();<br />PrintMsg((UCHAR*)&amp;g_szErasingFlash);<br />FlashChipErase();<br />FlashCheckEmpty();<br />PrintMsg((UCHAR*)&amp;g_szProgrammingFlash);<br />FlashWrite();<br />PrintMsg((UCHAR*)&amp;g_szDone);<br />PrintMsg((UCHAR*)&amp;g_szBootLdrEnd);<br />Beep();<br />while(1);<br />http://embedded.homeunix.org<br />11<br />}<br />void PrintMsg(UCHAR * pszMsg)<br />{<br />UCHAR ch;<br />for (;;)<br />{<br />ch = *pszMsg++;<br />if (ch) SendChar(ch);<br />else break;<br />}<br />}<br />void PrintDword(DWORD dwValue)<br />{<br />register DWORD dw;<br />for ( dw = 0; dw &lt; 4; dw++)<br />{<br />ToAscii((dwValue&gt;&gt;(dw*8)), (UCHAR*)&amp;g_szWordMsg + 8 - 2*dw);<br />}<br />PrintMsg((UCHAR*)&amp;g_szWordMsg);<br />}<br />void ToAscii(UCHAR ch, UCHAR * pcAscii)<br />{<br />pcAscii[0] = g_AsciiTable[(ch&gt;&gt;4) &amp; 0x0F];<br />pcAscii[1] = g_AsciiTable[ch &amp; 0x0F];<br />}<br />/**************************************************************/<br />void RecvData()<br />{<br />register DWORD dwBlockCounter, dwInBlockCounter;<br />register DWORD dwCharCounter;<br />register UCHAR * pucBuf;<br />register DWORD dwCheckSum;<br />register UCHAR uc;<br />g_dwSaveAddr = RecvDword(); /* buffer address */<br />g_dwSaveCount = dwCharCounter = RecvDword(); /* count */<br />dwCheckSum = dwBlockCounter = 0;<br />while (1)<br />{<br />pucBuf = (UCHAR*)(g_dwDramBase[dwBlockCounter++]);<br />for (dwInBlockCounter=0;<br />dwInBlockCounter&lt;(DWORD)DRAM_BLOCK_SIZE; dwInBlockCounter++)<br />{<br />uc = ReceiveChar();<br />*pucBuf = uc;<br />if (uc != *pucBuf) {PrintMsg((UCHAR*)g_szDramError); while(1);}<br />http://embedded.homeunix.org<br />12<br />pucBuf++;<br />dwCheckSum += uc;<br />--dwCharCounter;<br />if ((dwCharCounter == 0) || (dwCharCounter &amp; 0x80000000)) /*<br />(int)dwCharCounter &lt;= 0 */<br />{<br />g_dwCheckSum = dwCheckSum;<br />return;<br />}<br />}<br />}<br />}<br />DWORD RecvDword(void)<br />{<br />register DWORD i;<br />register DWORD dw;<br />for (i=dw=0; i&lt;4; i++)<br />{<br />dw |= ReceiveChar()&lt;&lt;(8*i);<br />}<br />return dw;<br />}<br />/***********************************************************************<br />***<br />;<br />; UART driver<br />;<br />;***********************************************************************<br />***/<br />void SendChar(register UCHAR ch)<br />{<br />register DWORD dwReg;<br />dwReg = HW1base;<br />while (*((DWORD*)(dwReg+HW1_SYSFLG1)) &amp; (UART1_TX_FIFO_FULL));<br />while (*((DWORD*)(dwReg+HW1_SYSFLG1)) &amp; (UART1_TX_BUSY));<br />*((UCHAR*)(dwReg + HW1_UARTDR1)) = ch;<br />}<br />UCHAR ReceiveChar(void)<br />{<br />register DWORD dwReg;<br />dwReg = HW1base;<br />while (*((DWORD*)(dwReg + HW1_SYSFLG1)) &amp; (UART1_RX_FIFO_EMPTY));<br />return *((UCHAR*)(dwReg + HW1_UARTDR1));<br />}<br />void Beep(void)<br />{<br />http://embedded.homeunix.org<br />13<br />register DWORD i;<br />register DWORD dwReg;<br />dwReg = (DWORD)(HW1base + 0x1000 + HW2_SYSCON2);<br />*((DWORD*)dwReg) = SYSCON2_VALUE_BEEP_ON;<br />for (i=0; i&lt;0x30000; i++);<br />*((DWORD*)dwReg) = SYSCON2_VALUE_BEEP_OFF;<br />/*<br />dwReg = (DWORD)(HW1base + HW1_SYSCON1);<br />for (j=0x600; j!=0; j--)<br />{<br />*pdwReg |= BUZZER_TOGGLE;<br />for (i=0x100; i!=0; i--);<br />*pdwReg &amp;= ~BUZZER_TOGGLE;<br />for (i=0x100; i!=0; i--);<br />}<br />*/<br />}<br />/*--------------------------------------------------------------------------*/<br />void FlashChipUnlock(void)<br />{<br />register DWORD dw;<br />register UCHAR* pucFlashAddr;<br />register UCHAR ucCmdSetup = FLASH_COMMAND_CONFIG_SETUP ;<br />register UCHAR ucCmdUnlock = FLASH_COMMAND_UNLOCK_BLOCK;<br />pucFlashAddr = (UCHAR*)FLASH_START_ADDRESS;<br />for (dw=0; dw&lt;FLASH_ERASE_8K_BLOCKS; dw++)<br />{<br />*pucFlashAddr = ucCmdSetup;<br />*pucFlashAddr = ucCmdUnlock;<br />pucFlashAddr += 0x2000;<br />}<br />for (dw=0; dw&lt;FLASH_ERASE_64K_BLOCKS; dw++)<br />{<br />*pucFlashAddr = ucCmdSetup;<br />*pucFlashAddr = ucCmdUnlock;<br />pucFlashAddr += 0x10000;<br />}<br />*((UCHAR*)FLASH_START_ADDRESS) =<br />(UCHAR)FLASH_COMMAND_READ;<br />}<br />UCHAR* FlashBlockErase(UCHAR * pucBlockAddr, DWORD dwBlocks, DWORD<br />dwBlockSize)<br />{<br />register UCHAR ucStatus;<br />register DWORD dw;<br />for (dw=0; dw&lt;dwBlocks; dw++)<br />http://embedded.homeunix.org<br />14<br />{<br />*((DWORD*)pucBlockAddr) = (FLASH_COMMAND_CONFIRM&lt;&lt;16) |<br />FLASH_COMMAND_ERASE;<br />*pucBlockAddr = FLASH_COMMAND_STATUS;<br />do {<br />ucStatus = *pucBlockAddr;<br />} while (!(ucStatus &amp; FLASH_STATUS_READY));<br />if (ucStatus &amp; FLASH_STATUS_ERROR)<br />FlashErrorHandler((UCHAR*)&amp;g_szEraseFlashError, pucBlockAddr);<br />pucBlockAddr += dwBlockSize;<br />}<br />return pucBlockAddr;<br />}<br />void FlashChipErase(void)<br />{<br />FlashBlockErase(FlashBlockErase((UCHAR*)FLASH_START_ADDRESS,<br />FLASH_ERASE_8K_BLOCKS, 0x2000),<br />FLASH_ERASE_64K_BLOCKS,<br />0x10000);<br />*((UCHAR*)FLASH_START_ADDRESS) =<br />(UCHAR)FLASH_COMMAND_READ;<br />}<br />void FlashCheckEmpty()<br />{<br />register DWORD dwStartAddr;<br />dwStartAddr = (DWORD)FLASH_START_ADDRESS;<br />do<br />{<br />if (*((DWORD*)dwStartAddr) != (DWORD)(0xFFFFFFFF))<br />FlashErrorHandler((UCHAR*)&amp;g_szFlashNotEmpty, (UCHAR<br />*)dwStartAddr);<br />dwStartAddr += 4;<br />}<br />while (dwStartAddr &lt; (DWORD)FLASH_CHECK_EMPTY_END_ADDRESS);<br />}<br />void FlashWrite()<br />{<br />register DWORD dwValue;<br />register DWORD dwBlockCounter, dwInBlockCounter;<br />register DWORD dwCheckSum;<br />DWORD * pdwFlashAddr;<br />DWORD * pdwBufAddr;<br />int iLength;<br />pdwFlashAddr = (DWORD*)FLASH_START_ADDRESS;<br />iLength = g_dwSaveCount;<br />dwBlockCounter = 0;<br />http://embedded.homeunix.org<br />15<br />while (1)<br />{<br />pdwBufAddr = (DWORD*)(g_dwDramBase[dwBlockCounter++]);<br />for (dwInBlockCounter=0;<br />dwInBlockCounter&lt;((DWORD)DRAM_BLOCK_SIZE/4); dwInBlockCounter++)<br />{<br />dwValue = *pdwBufAddr++;<br />*((UCHAR*)pdwFlashAddr) = FLASH_COMMAND_WRITE;<br />*pdwFlashAddr = ((FLASH_COMMAND_STATUS&lt;&lt;16) |<br />(dwValue&amp;0x0000FFFF));<br />while (!(*pdwFlashAddr &amp; FLASH_STATUS_READY));<br />*pdwFlashAddr = (dwValue&amp;0xFFFF0000) | FLASH_COMMAND_WRITE;<br />*((UCHAR*)pdwFlashAddr) = FLASH_COMMAND_STATUS;<br />while (!(*pdwFlashAddr &amp; FLASH_STATUS_READY));<br />pdwFlashAddr++;<br />if ((iLength-=4) &lt;= 0)<br />{<br />*((UCHAR*)FLASH_START_ADDRESS) =<br />(UCHAR)FLASH_COMMAND_READ;<br />/*<br />dwCheckSum = 0;<br />pdwFlashAddr = (DWORD*)FLASH_START_ADDRESS;<br />for (iLength=(int)g_dwSaveCount; iLength!=0; iLength--)<br />{<br />dwCheckSum += *((UCHAR*)pdwFlashAddr);<br />(UCHAR*)pdwFlashAddr++;<br />}<br />if (dwCheckSum != g_dwCheckSum)<br />PrintMsg((UCHAR*)g_szProgramFlashError);<br />*/<br />return;<br />}<br />}<br />}<br />}<br />void FlashErrorHandler(UCHAR * pszMsg, UCHAR * pcAddr2Dump)<br />{<br />register DWORD dw, dw1;<br />*((UCHAR*)FLASH_START_ADDRESS) =<br />(UCHAR)FLASH_COMMAND_READ;<br />PrintMsg(pszMsg);<br />PrintDword((DWORD)pcAddr2Dump);<br />for (dw=0; dw&lt;16; dw++)<br />{<br />for (dw1=0; dw1&lt;16; dw1++)<br />http://embedded.homeunix.org<br />16<br />{<br />ToAscii(*pcAddr2Dump++, (UCHAR*)&amp;g_szByteMsg + 2);<br />PrintMsg((UCHAR*)&amp;g_szByteMsg);<br />}<br />PrintMsg("\r\n");<br />}<br />Beep();<br />PrintMsg((UCHAR*)&amp;g_szBootLdrEnd);<br />while(1);<br />}<br />/**** end ****/<br />/*************************************************************<br />void SetCp15(DWORD uCp15Val)<br />{<br />asm ("mcr p15, 0, %0, c1, c0, 0;" : : "r"(uCp15Val) );<br />}<br />DWORD ReadCp15()<br />{<br />register DWORD x;<br />asm ("mrc p15, 0, %0, c1, c0, 0;" : "=r"(x) : );<br />return x;<br />}<br />**************************************************************/<br />/* *************************************************************<br />clps7111.h<br />Cirrus CLPS7111 (ARM710A core) CPU registers defination<br />**************************************************************/<br />#ifndef __CLPS7111_H__<br />#define __CLPS7111_H__<br />#define HW1base 0x80000000<br />//ports A-D all 8 bits wide<br />#define HW1_PADR 0x00 // Port A data register<br />#define HW1_PBDR 0x01 // Port B data register<br />#define HW1_PDDR 0x03 // Port D data register<br />#define HW1_PADDR 0x40 // Port A data direction register<br />#define HW1_PBDDR 0x41 // Port B data direction register<br />#define HW1_PDDDR 0x43 // Port D data direction register<br />//port E 3 bits wide<br />#define HW1_PEDR 0x80 // Port E data register<br />#define HW1_PEDDR 0xc0 // Port E data direction register<br />http://embedded.homeunix.org<br />17<br />#define HW1_SYSCON1 0x100 // System control register [32]<br />#define HW1_SYSFLG1 0x140 // System status flags [RO,32]<br />#define HW1_MEMCFG1 0x180 // Exp/ROM mem cfg register 1 [32]<br />#define HW1_MEMCFG2 0x1c0 // Exp/ROM mem cfg register 2 [32]<br />#define HW1_DRFPR 0x200 // DRAM refresh period reg. [8]<br />#define HW1_INTSR1 0x240 // Interrupt status register [RO,16]<br />#define HW1_INTMR1 0x280 // Interrupt mask register [16]<br />#define HW1_LCDCON 0x2c0 // LCD control register [32]<br />#define HW1_TC1D 0x300 // data to/from TC1 [16]<br />#define HW1_TC2D 0x340 // data to/from TC2 [16]<br />#define HW1_RTCDR 0x380 // real time clock data reg. [32]<br />#define HW1_RTCMR 0x3c0 // real time clock match reg. [32]<br />#define HW1_PMPCON 0x400 // DC to DC pump control reg. [12]<br />#define HW1_CODR 0x440 // CODEC data I/O reg. [8]<br />#define HW1_UARTDR1 0x480 // UART1 FIFO data register [8]<br />#define HW1_UBRLCR1 0x4c0 // UART1 bit rate and line ctrl reg. [32]<br />#define HW1_SYNCIO 0x500 // SSI data reg. for master only [16]<br />#define HW1_PALLSW 0x540 // LSW of LCD palette register [32]<br />#define HW1_PALMSW 0x580 // MSW of LCD palette register [32]<br />#define HW1_STFCLR 0x5c0 // clear startup reason flags [WO,-]<br />#define HW1_BLEOI 0x600 // clear batt. low interrupt [WO,-]<br />#define HW1_MCEOI 0x640 // clear media change interrupt [WO,-]<br />#define HW1_TEOI 0x680 // clear tick/watchdog interrupt [WO, -]<br />#define HW1_TC1EOI 0x6c0 // clear TC1 interrupt [WO,-]<br />#define HW1_TC2EOI 0x700 // clear TC2 interrupt [WO,-]<br />#define HW1_RTCEOI 0x740 // clear RTC match interrupt [WO,-]<br />#define HW1_UMSEOI 0x780 // clear UART modem stat changed [WO,-]<br />#define HW1_COEOI 0x7c0 // clear CODEC sound interrupt [WO,-]<br />#define HW1_HALT 0x800 // enter idle state [WO,-]<br />#define HW1_STDBY 0x840 // enter standby state [WO,-]<br />#define HW2base (HW1base|0x1000)<br />#define HW2_FRBADDR 0x000 // LCD frame buffer start address [24]<br />#define HW2_SYSCON2 0x100 // System control register 2<br />#define HW2_SYSFLG2 0x140 // System status register 2<br />#define HW2_INTSR2 0x240 // Interrupt status register [RO]<br />#define HW2_INTMR2 0x280 // Interrupt mask register<br />#define HW2_UARTDR2 0x480 // UART2 data register [8/11]<br />#define HW2_UBRLCR2 0x4c0 // UART2 control register [32]<br />#define HW2_SRXEOF 0x600 // Write to clear Rx FIFO overflow flag<br />#define HW2_KBDEOI 0x700 // Write to clear keyboard interrupt [WO,-]<br />//these registers have the same offset in each bank and share some bitfields<br />//it's useful to give them a generic name.<br />#define HW_SYSCON HW1_SYSCON1<br />#define HW_SYSFLG HW1_SYSFLG1<br />http://embedded.homeunix.org<br />18<br />#define HW_UBRLCR HW1_UBRLCR1<br />#define HW_UARTDR HW1_UARTDR1<br />//SYSCON1/SYSCON2 bitfield<br />//bits 0-3: keyboard scan<br />#define SYSCON1_KBS_MASK 15<br />#define SYSCON1_KBS_ALLHIGH 0<br />#define SYSCON1_KBS_ALLLOW 1<br />#define SYSCON1_KBS_ALLHIZ 2<br />#define SYSCON1_KBS_COL0 8<br />#define SYSCON1_KBS_COL1 9<br />#define SYSCON1_KBS_COL2 10<br />#define SYSCON1_KBS_COL3 11<br />#define SYSCON1_KBS_COL4 12<br />#define SYSCON1_KBS_COL5 13<br />#define SYSCON1_KBS_COL6 14<br />#define SYSCON1_KBS_COL7 15<br />#define SYSCON1_TC1M (1&lt;&lt;4) // TC1 mode (set=prescale)<br />#define SYSCON1_TC1S (1&lt;&lt;5) // TC1 source (set=512KHz)<br />#define SYSCON1_TC2M (1&lt;&lt;6) // TC2 mode<br />#define SYSCON1_TC2S (1&lt;&lt;7) // TC2 source<br />#define SYSCON1_UART1EN (1&lt;&lt;8) // enable UART1<br />#define SYSCON1_BZTOG (1&lt;&lt;9) // drive buzzer directly<br />#define SYSCON1_BZMOD (1&lt;&lt;10) // 0: buzzer uses BZTOG<br />#define SYSCON1_DBGEN (1&lt;&lt;11) // debug mode<br />#define SYSCON1_LCDEN (1&lt;&lt;12) // enable LCD controller<br />#define SYSCON1_CDENTX (1&lt;&lt;13) // CODEC i/f enable Tx<br />#define SYSCON1_CDENRX (1&lt;&lt;14) // CODEC i/f enable Rx<br />#define SYSCON1_SIREN (1&lt;&lt;15) // HP SIR encoding enable<br />#define SYSCON1_ADCKSEL_MASK (3&lt;&lt;16) // ADC clock select<br />#define SYSCON1_ADCKSEL_SHIFT 16<br />#define SYSCON1_EXCKEN (1&lt;&lt;18) // external expansion clock enable<br />#define SYSCON1_WAKEDIS (1&lt;&lt;19) // disable wakeup switchon<br />#define SYSCON1_IRTXM (1&lt;&lt;20) // IrDA Tx mode strategy<br />//SYSCON2<br />//bit 0: serial interface select<br />#define SYSCON2_SERSEL 1<br />#define SYSCON2_CODEC 1 // CODEC Enable<br />#define SYSCON2_KBD6 (1&lt;&lt;1) // if high only pins 0 to 5 of pA are kbd<br />#define SYSCON2_DRAMWID (1&lt;&lt;2) // 1=16-bit DRAM, 0-32-bit DRAM<br />#define SYSCON2_KBWDIS (1&lt;&lt;3) // enforce IRQ mask register for<br />wakeup<br />#define SYSCON2_PCMCIA1 (1&lt;&lt;5) // enable PCMCIA interface 1 (cs4)<br />#define SYSCON2_PCMCIA2 (1&lt;&lt;6) // enable PCMCIA interface 2 (cs5)<br />http://embedded.homeunix.org<br />19<br />#define SYSCON2_UART2EN (1&lt;&lt;8) // enable UART2<br />#define SYSCON2_OSTB (1&lt;&lt;12) // twiddle clocks somehow<br />#define SYSCON2_CLKENSL (1&lt;&lt;13) // high/low: output run/clken on<br />run/clken pin<br />//SYSFLG/SYSFLG2 bitfield<br />#define SYSFLG1_MCDR (1&lt;&lt;0) // media changed direct read<br />#define SYSFLG1_DCDET (1&lt;&lt;1) // 1: mains power<br />#define SYSFLG1_WUDR (1&lt;&lt;2) // wakeup direct read<br />#define SYSFLG1_WUON (1&lt;&lt;3) // started by wakeup<br />//bits 4-7: display ID nibble<br />#define SYSFLG1_DID_mask (15&lt;&lt;4)<br />#define SYSFLG1_CTS (1&lt;&lt;8) // UART1 CTS<br />#define SYSFLG1_DSR (1&lt;&lt;9) // UART1 DSR<br />#define SYSFLG1_DCD (1&lt;&lt;10) // UART1 DCD<br />#define SYSFLG1_UBUSY1 (1&lt;&lt;11) // UART1 busy<br />#define SYSFLG1_NBFLG (1&lt;&lt;12) // new battery (clear w/ STFCLR)<br />#define SYSFLG1_RSTFLG (1&lt;&lt;13) // reset pressed (clear w/ STFCLR)<br />#define SYSFLG1_PFFLG (1&lt;&lt;14) // power fail (clear w/ STFCLR)<br />#define SYSFLG1_CLDFLG (1&lt;&lt;15) // power on reset (clear w/ STFCLR)<br />//bits 16-21: number of 64Hz ticks since last RTC increment<br />#define SYSFLG1_RTCDIV_mask (63&lt;&lt;16)<br />#define SYSFLG1_URXFE1 (1&lt;&lt;22) // UART rx FIFO empty<br />#define SYSFLG1_UTXFF1 (1&lt;&lt;23) // UART tx FIFO full<br />#define SYSFLG1_CRXFE (1&lt;&lt;24) // CODEC rx FIFO empty<br />#define SYSFLG1_CTXFF (1&lt;&lt;25) // CODEC tx FIFO full<br />#define SYSFLG1_SSIBUSY (1&lt;&lt;26) // 1: SSI is shifting data<br />//0: data clear to read<br />#define SYSFLG1_BOOTBIT0 (1&lt;&lt;27)<br />#define SYSFLG1_BOOTBIT1 (1&lt;&lt;28)<br />// bootbit0 bootbit1 boot option<br />// 0 0 32-bit<br />// 0 1 8-bit<br />// 1 0 16-bit<br />// 1 1 reserved<br />#define SYSFLG1_RESERVED (1&lt;&lt;29)<br />http://embedded.homeunix.org<br />20<br />//bits 30-31: version ID<br />#define SYSFLG1_VERID_mask (3&lt;&lt;30)<br />#define SYSFLG2_CHKMODE (1&lt;&lt;6) // 18/13 mode flag<br />#define SYSFLG2_UBUSY2 (1&lt;&lt;11) // UART2 busy<br />#define SYSFLG2_URXFE2 (1&lt;&lt;22) // UART2 rx FIFO empty<br />#define SYSFLG2_UTXFF2 (1&lt;&lt;23) // UART2 tx FIFO full<br />// ;; MEMCFG1<br />// ;; Expansion and ROM selects<br />// ;; byte0 : Ncs0<br />// ;; byte1 : Ncs1<br />// ;; byte2 : Ncs2<br />// ;; byte3 : Ncs3<br />// ;; MEMCFG2<br />// ;; Expansion and ROM selects<br />// ;; byte0 : cs4<br />// ;; byte1 : cs5<br />// ;; byte2 : RESERVED (local SRAM)<br />// ;; byte3 : Boot ROM (cs7)<br />// ;; chip select bytes (cs7, cs4-5 in non-PCMCIA mode, Ncs0-3)<br />// ;; b0-1: bus width<br />// ;; maps onto expansion transfer mode according to value here<br />// ;; and BOOTBIT{0,1} (=BOOTWID[1:0])<br />// ;; b2-3: random access wait state<br />// ;; value #states (nS) speed<br />// ;; 0 4 250<br />// ;; 1 3 200<br />// ;; 2 2 150<br />// ;; 3 1 100<br />// ;; b4-5: sequential access wait state<br />// ;; value #states (nS) speed<br />// ;; 0 3 150<br />// ;; 1 2 120<br />// ;; 2 1 80<br />// ;; 3 0 40<br />// ;; b6: SQAEN<br />// ;; b7: CLKENB<br />#define MEMCFG_WIDTH32 (0&lt;&lt;0)<br />#define MEMCFG_WIDTH16 (1&lt;&lt;0)<br />#define MEMCFG_WIDTH8 (2&lt;&lt;0)<br />#define MEMCFG_WIDTHRESERVED (3&lt;&lt;0)<br />#define MEMCFG_RA_1WAIT (3&lt;&lt;2)<br />#define MEMCFG_RA_2WAITS (2&lt;&lt;2)<br />http://embedded.homeunix.org<br />21<br />#define MEMCFG_RA_3WAITS (1&lt;&lt;2)<br />#define MEMCFG_RA_4WAITS (0&lt;&lt;2)<br />#define MEMCFG_SA_0WAITS (3&lt;&lt;4)<br />#define MEMCFG_SA_1WAIT (2&lt;&lt;4)<br />#define MEMCFG_SA_2WAITS (1&lt;&lt;4)<br />#define MEMCFG_SA_3WAITS (0&lt;&lt;4)<br />#define MEMCFG_SQAEN (1&lt;&lt;6)<br />#define MEMCFG_CLKENB (1&lt;&lt;7)<br />//DRAM refresh period register<br />#define DRFPR_RFSHEN (1&lt;&lt;7)<br />#define DRFPR_RFDIV_MASK 127<br />//interrupt bits for INTSR[12] and INTMR[12]<br />#define INT1_EXTFIQ (1&lt;&lt;0) // external FIQ<br />#define INT1_BLINT (1&lt;&lt;1) // battery low FIQ<br />#define INT1_WEINT (1&lt;&lt;2) // watchdog expired FIQ<br />#define INT1_MCINT (1&lt;&lt;3) // media changed FIQ<br />#define INT1_CSINT (1&lt;&lt;4) // CODEC sound<br />#define INT1_EINT1 (1&lt;&lt;5) // external IRQ 1<br />#define INT1_EINT2 (1&lt;&lt;6) // external IRQ 2<br />#define INT1_EINT3 (1&lt;&lt;7) // external IRQ 3<br />#define INT1_TC1OI (1&lt;&lt;8) // TC1 underflow<br />#define INT1_TC2OI (1&lt;&lt;9) // TC2 underflow<br />#define INT1_RTCMI (1&lt;&lt;10) // RTC compare match<br />#define INT1_TINT (1&lt;&lt;11) // 64Hz tick<br />#define INT1_UTXINT1 (1&lt;&lt;12) // UART1 tx FIFO half empty<br />// or no data in Tx hold. reg.<br />#define INT1_URXINT1 (1&lt;&lt;13) // UART1 rx FIFO half full<br />// or valid data in Rx hold. reg.<br />#define INT1_UMSINT (1&lt;&lt;14) // UART1 modem status changed<br />#define INT1_SSEOTI (1&lt;&lt;15) // SSI end of transfer<br />#define INT2_KBDINT (1&lt;&lt;0) // keyboard interrupt<br />#define INT2_UTXINT2 (1&lt;&lt;12) // UART2 tx FIFO half empty<br />#define INT2_URXINT2 (1&lt;&lt;13) // UART2 rx FIFO half full<br />//PSR bits<br />#define PSR_I (1&lt;&lt;7) // IRQ disable bit<br />#define PSR_F (1&lt;&lt;6) // IRQ disable bit<br />#define PSR_LOCK (PSR_I+PSR_F)<br />#define PSR_MODEMASK 0x1f // Mode mask<br />http://embedded.homeunix.org<br />22<br />#define PSR_MODEUSER 0x10<br />#define PSR_MODEFIQ 0x11<br />#define PSR_MODEIRQ 0x12<br />#define PSR_MODESVC 0x13<br />#define PSR_MODEABORT 0x17<br />#define PSR_MODEUNDEF 0x1b<br />#endif /*#ifndef __CLPS7111_H__*/<br /></font>
<img src ="http://www.cnitblog.com/lijiehua/aggbug/10856.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/lijiehua/" target="_blank">内嵌</a> 2006-05-20 23:27 <a href="http://www.cnitblog.com/lijiehua/articles/10856.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ARM7开发资料</title><link>http://www.cnitblog.com/lijiehua/articles/10855.html</link><dc:creator>内嵌</dc:creator><author>内嵌</author><pubDate>Sat, 20 May 2006 15:24:00 GMT</pubDate><guid>http://www.cnitblog.com/lijiehua/articles/10855.html</guid><wfw:comment>http://www.cnitblog.com/lijiehua/comments/10855.html</wfw:comment><comments>http://www.cnitblog.com/lijiehua/articles/10855.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/lijiehua/comments/commentRss/10855.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/lijiehua/services/trackbacks/10855.html</trackback:ping><description><![CDATA[
		<font size="2">引用<a class="" title="" href="http://www.vckbase.com/" target="">www.vckbase.com</a><br /><br />一、系统概述<br />    ARM DVK-S3C44B0X（S3C3410）（以下简称DVK）开发板是一款以S3C44B0X为核心的ARM系统开发平台。利用该平台上您可以智能手持设备、PDA、工控系统等领域迅速地开发出功能强大，价格低廉，十分具有竞争力的产品，为您赢得市场。<br />    S3C44B0X（以下简称MCU）是韩国Samsung公司开发的一颗功能强大的ARM7系列处理器，其内部组成如下（图1为MCU的内部模块示意图）：<br />（1）    16位/32位 RISC（ARM7TDMI）CPU核<br />（2）    8KB指令/数据Cache，或可选的内部高速SRAM<br />（3）    LCD控制器（可达256色DSTN）<br />（4）    2通道UART（内置16Byte FIFO ，并兼容IrDA1.0）<br />（5）    4通道DMA<br />（6）    8Bank外部存储器接口。每个Bank有独立的片选口，寻址能力高达32MB/Bank×8Bank=256MB，同时Bank6&amp;7还可外接各种FP/EDO/SDRAM<br />（7）    6通道多功能定时器/PWM发生器<br />（8）    71条通用输入/输出口<br />（9）    实时时钟（RTC）<br />（10）    8通道10bit ADC（采样速率可到500KSPS）<br />（11）    1通道IIC总线（可工作于多主模式）<br />（12）    1通道IIS音频数据接口（可工作于主/从模式）<br />（13）    1通道多功能同步串行口（可工作于SPI/SCI模式）<br />（14）    多种省电工作模式<br />（15）    JTAG调试口<br />而DVK在分析了MCU的特性，并结合了便携式/小型嵌入式系统的设计需要，进行了扩展和合理化的系统设计。其特点有：<br />（1）    128K*8bit BOOT-ROM（SST29EE010 FLASH），并可扩展到512KB。<br />（2）    IDE/ATA接口。可用来扩展IDE/ATA硬盘和流行的CF闪存卡<br />（3）    8M*16bit SDRAM<br />（4）    16M*8bit Nand-Flash（KM29U128T）。可扩展为KM29U256T（与前者Pin-Pin兼容）来获得32MB的容量。<br />（5）    USB接口（USBN9603）。<br />（6）    IIS音频DAC（CS4340）<br />（7）    耳机功放（NJM2168）<br />（8）    IIC EEPROM（24LC16）<br />（9）    RTC备用Li电池<br />（10）    4*3小键盘矩阵<br /><br /><br /><br /><br /><br /><br />图1：S3C44B0X内部模块示意图<br /><br />二、硬件部分<br />    DVK的系统框图已经在上小节中大致列出，为了能使您了解地更清楚，下面将按各个功能模块逐一说明。<br />（1）    电源。<br />DVK使用5V~6V/850mA的外部稳压电源（注意极性为内正外负，如下图）进行供电。外部电源经过LM317稳压，并产生供给整个系统的3.3V（VDD）电源，同时3.3V电源经过1个二极管降压得到CPU的核心工作电压为2.5V（CPUVDD）。<br />                                               <br />（2）    复位电路。<br />DVK的上电复位采用阻容充电，后由74HC14整形的方式（此外还有1个手动复位键）。如您对系统的复位要求较高，建议您采用专用的uP电路。<br />（3）    起动ROM（BootROM）。<br />DVK在出货时使用的是SST29EE010/W29EE011，在具体应用中您可以将它替换为SST29EE040以获得更大的代码空间（后面还会提到如何使用16Mbyte的Nand-Flash存放代码）。在BootROM中存放有系统的初始化代码，DVK的产品序列号，简单的Debug工具和系统各个功能模块的测试程序。它在系统中占用了Bank0号存储空间。<br />（4）    系统扩展口。<br />DVK可通过8bit的扩展口进行额外扩展，例如LCD，以太网卡。当您要在该口扩展多个设备时，请务必增加译码电路，以免设备冲突。它在系统中占用了Bank1号存储空间。<br />（5）    Nand-FLASH。<br />DVK中的Nand-Flash型号为：KM29U128T（16Mbyte），它与32Mbyte的KM29U256T的引脚完全兼容。因此您若需要更大的存储空间，扩展起来将是十分方便的。由于Nand-Flash具有很好的非挥发特性，价格相对线性Flash低很多，因此通常被用来存储大量的数据和代码（由于Nand-Flash为Page寻址，当您需要运行其中的代码是，需要先将该代码调入SDRAM/SRAM中运行。这样的运行机制可使您实现在线FirmWare升级）。Nand-Falsh在系统中占用了Bank2号存储空间。<br />（6）    USB。<br />DVK中使用USBN9603进行扩展了一个USB接口，并在系统中占用Bank3号存储空间。<br />（7）    IDE/ATA接口。<br />DVK还提供了1个IDE/ATA接口以满足用户对海量数据进行存储的需要。该接口工作在PIO模式，最大数据传输率最高可至1MB/s。同时用户也可利用该接口扩展CF卡（工作于True-IDE模式）。IDE/ATA接口在系统中占用Bank4号存储空间<br />（8）    SDRAM。<br />DVK所配备的SDRAM具有8MB容量，足以满足目前嵌入式系统对RAM的需求。SDRAM占用Bank6号存储空间。<br />（9）    实时时钟（RTC）。<br />DVK中配有锂电池座，为RTC提供备用电池。<br />（10）    杂项。<br />其余部分（例如IIC、IIS、ADC、SPI/SCI、UART等）均为MCU自身所具有的功能，详细情况您可参考MCU器件手册的相关章节。<br /><br />三、软件/工具部分<br />    DVK在销售时会以附送示范程序和非常有用的调试工具，以便您使用，同时您还可以把这些程序作为模板进行修改从而生成自己的代码。<br />这些程序主要有（源代码形式）：<br />（1）    系统初始化代码<br />（2）    常用函数库（含CPU各功能模块测试程序）<br />（3）    UART下载调试程序<br />（4）    USB协议栈<br />（5）    IDE/ATA接口驱动程序<br />（6）    FAT32文件系统<br />（7）    键盘扫描程序<br />（8）    Nand-Flash驱动程序<br />（9）    128*64 LCD驱动<br />工具主要有（仅提供EXE文件）：<br />（1）    UART下载程序（dnload.exe）<br />    上图为dnload.exe运行时的画面。其命令行格式如下：dnload xxx.bin /y /d:z。xxx.bin为要下传的文件；y为使用的串行口号；z为波特率（115200的z分之一）。<br />（2）    USB PC机端程序<br />我们并没有为DVK特地开发一套USB驱动程序，而是借用了市场上正在销售的一款MP3播放器的上位机程序。<br />    初次在DVK上使能了USB后与PC机相连，PC会提示安装新硬件。在找到hymp3.sys驱动程序后，在设备管理器中会出现Hymp3 2000字样，这说明DVK的驱动程序已经安装完毕。<br /><br /><br /><br />     在安装完驱动程序后，您需再次安装管理软件。安装并运行它后，您会看到上图。（若右边的列表框为灰色，请您按一下Devices按钮进行刷新）。<br />    若您需要下载MP3文件到DVK上，可在左边的列表框中选择文件，然后按Copy To Portable即可。若为其它类型文件，可选择菜单中的Download。<br /></font>
<img src ="http://www.cnitblog.com/lijiehua/aggbug/10855.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/lijiehua/" target="_blank">内嵌</a> 2006-05-20 23:24 <a href="http://www.cnitblog.com/lijiehua/articles/10855.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用GNU工具开发基于ARM的嵌入式系统</title><link>http://www.cnitblog.com/lijiehua/articles/10854.html</link><dc:creator>内嵌</dc:creator><author>内嵌</author><pubDate>Sat, 20 May 2006 15:22:00 GMT</pubDate><guid>http://www.cnitblog.com/lijiehua/articles/10854.html</guid><wfw:comment>http://www.cnitblog.com/lijiehua/comments/10854.html</wfw:comment><comments>http://www.cnitblog.com/lijiehua/articles/10854.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/lijiehua/comments/commentRss/10854.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/lijiehua/services/trackbacks/10854.html</trackback:ping><description><![CDATA[
		<font style="BACKGROUND-COLOR: #ffffff" size="2">当前，ARM公司的32位RISC处理器，以其内核耗电少、成本低、功能强、特有16/32位双指令集，已成为移动通信、手持计算、多媒体数字消费等嵌入式解决方案的RISC标准，市场占有率超过了75 %。多家公司都推出了自己的基于ARM内核的处理器产品，越来越多的开发人员开始了针对ARM平台的开发。通常开发人员需要购买芯片厂商或第三方提供的开发板，还需要购买开发软件，如C编译器或者集成了实时操作系统的开发环境。开发板的价格从数百到上千美元，而编译器、实时操作系统价格更是动辄数千到数万美元。这样，在开发初期，软硬件上的投资就需要上万美元，对于国内大多数开发人员来说，无疑是太贵了。<br /><br />　　庆幸的是，GNU所倡导的自由软件给开发者带来了福音。1984 年，旨在开发一个类似 Unix 的，并且是完全免费的完整操作系统和配套工具：GNU 系统（发音为"guh-NEW"）。GNU的操作系统和开发工具都是免费的，遵循GNU 通用公共许可证 (GPL)协议，任何人都可以从网上获取全部的源代码。关于GNU和公共许可证协议的详细资料，读者可参看GNU网站的中文介绍：http://www.gnu.org/home.cn.html。<br /><br />　　除了大家熟知的Linux操作系统外，GNU的软件还包括编译器（gcc，g++）、二进制转换工具（objdump，objcopy）、调试工具（gdb，gdbserver，kgdb）和基于不同硬件平台的开发库。GNU开发工具的主要缺点是采用命令行方式，用户掌握和使用比较困难，不如基于Windows系统的开发工具好用。但是，GNU工具的复杂性是由于它更贴近编译器和操作系统的底层，并提供了更大的灵活性。一旦学习和掌握了相关工具，也就了解了系统设计的基础知识，为今后的开发工作打下基础。GNU的开发工具都是免费的，遵循GPL协议，任何人都可以从网上获取。笔者参与了一个基于ARM平台的嵌入式Linux系统开发，采用的是摩托罗拉龙珠系列的MC928MX1。从测试代码、引导程序、嵌入式Linux移植、应用程序、图形界面都可以用GNU工具进行开发，不需要在开发工具上做额外的投入。本文所介绍的开发方法同样适用于其它公司的基于ARM的产品。<br /><br />1 硬件平台<br /><br />　　MC928MX1（以下简称MX1）是摩托罗拉公司基于ARM核心的第一款MCU，主要面向高端嵌入式应用。内部采用ARM920T内核，并集成了SDRAM/Flash、LCD、USB、蓝牙（bluetooth）、多媒体闪存卡（MMC）、CMOS摄像头等控制器。关于MX1的详细资料，感兴趣的读者可以参考http://www.motorola.com.cn/semiconductors/。作为应用开发的最小系统必须包括RAM（程序运行空间）、Flash（存放目标代码）和串行接口（用于调试和下载程序）。MX1提供了6个片选端（CS0~CS5），内置了SDRAM控制器，数据宽度32位。在笔者的系统中采用了2片8M×16位的SDRAM和2片4M×16位的同步Flash存储器，分别接入数据线的低16位和高16位，如图1所示。<br /><br />　　图1中SDRAM接片选端CS2，Flash接片选端CS3，其余为SDRAM/Flash的控制信号。最小系统还包括至少1个串行接口，可以采用MX1内置的UART控制器，图略。<br /><br />2 自举模式<br /><br />　　目前，许多嵌入式处理器都提供了自举模式（Bootstrap），供用户写入引导代码。自举模式利用了固化在芯片内部的一段引导程序，当处理器复位时，如果在特定引脚上加信号，则处理器将在复位后执行固化ROM中的程序。例如，MX1提供了4条复位引脚，复位时引脚不同的电平组合可以从不同的片选端启动系统。自举ROM中的程序完成串口的初始化，然后等待用户从串口写入用户代码。自举模式所能接受的是一种专门格式的文本文件，包括数据和要写入/读出的地址。关于自举模式的代码格式，可参考相关芯片的手册。在摩托罗拉的网站还提供了许多小工具，帮助开发者将其它格式的文件转换成为自举模式格式。通过自举模式下载的通常是一段和上位机软件（如超级终端）通信的程序，完成接收数据并写入Flash的操作。写入的数据可以是用户自己的应用程序、数据或者操作系统的内核。通过自举模式下载的引导程序同样可以用GNU工具开发。<br /><br />3 GNU的编译器和开发工具<br /><br />　　GNU提供的编译工具包括汇编器as、C编译器gcc、C++编译器g++、连接器ld和二进制转换工具objcopy。基于ARM平台的工具分别为arm-linux-as、arm-linux-gcc、arm-linux-g++、arm -linux-ld 和arm-linux-objcopy。GNU的所有开发工具都可以从www.gnu.org上下载，基于ARM的工具可以从www.uclinux.org获得。GNU的编译器功能非常强大，共有上百个操作选项，这也是这类工具让初学者头痛的原因。不过，实际开发中只需要用到有限的几个，大部分可以采用缺省选项。GNU工具的开发流程如下：编写C、C++语言或汇编源程序，用gcc或g++生成目标文件，编写连接脚本文件，用连接器生成最终目标文件（elf格式），用二进制转换工具生成可下载的二进制代码。GNU工具都运行在Linux下，开发者需要1台运行Linux的PC作为上位机。由于篇幅所限，不能完整地介绍整个嵌入式操作系统的开发过程，将以第二节中提到的通过自举模式下载的引导程序为例，说明开发的过程。对于像Linux这样的大系统，基本的开发流程是一样的。<br /><br />　　引导程序将通过自举模式下载到MX1的片内RAM，从地址0x00300000开始并执行。完成串口和SDRAM的初始化后，引导程序将等待接收应用程序或操作系统内核，将接收到的数据放在SDRAM中。数据接收完毕后，引导程序将SDRAM中的数据写入Flash，下一次就可以从Flash中直接引导系统了。由于操作系统的内核比较大，如Linux有1 MB以上，下载过程必须考虑纠错。因此，接收部分采用Xmode协议，可以用Windows下超级终端的Xmode发送方式发送文件。<br /><br />    （1）编写C、C++语言或汇编源程序<br /><br />　　通常汇编源程序用于系统最基本的初始化，如初始化堆栈指针、设置页表、操作ARM的协处理器等。初始化完成后就可以跳转到C代码执行。需要注意的是，GNU的汇编器遵循AT&amp;T的汇编语法，读者可以从GNU的站点（www.gnu.org）上下载有关规范。汇编程序的缺省入口是start标号，用户也可以在连接脚本文件中用ENTRY标志指明其它入口点（见下文关于连接脚本的说明）。<br /><br />    （2）用gcc或g++生成目标文件<br /><br />　　如果应用程序包括多个文件，就需要进行分别编译，最后用连接器连接起来。如笔者的引导程序包括3个文件：init.s（汇编代码、初始化硬件） xmrecever.c（通信模块，采用Xmode协议）和flash.c（Flash擦写模块）。<br /><br />分别用如下命令生成目标文件：<br /><br />arm-linux-gcc-c-O2-o init.o init.s<br /><br />arm-linux-gcc-c-O2-o xmrecever.o xmrecever.c<br /><br />arm-linux-gcc-c-O2-o flash.o flash.c<br /><br />其中-c命令表示只生成目标代码，不进行连接；-o 命令指明目标文件的名称；-O2表示采用二级优化，采用优化后可使生成的代码更短，运行速度更快。如果项目包含很多文件，则需要编写makefile文件。关于makefile的内容，请感兴趣的读者参考相关资料。<br /><br />（3）编写连接脚本文件<br /><br />　　gcc等编译器内置有缺省的连接脚本。如果采用缺省脚本，则生成的目标代码需要操作系统才能加载运行。为了能在嵌入式系统上直接运行，需要编写自己的连接脚本文件。编写连接脚本，首先要对目标文件的格式有一定了解。GNU编译器生成的目标文件缺省为elf格式。elf文件由若干段（section）组成，如不特殊指明，由C源程序生成的目标代码中包含如下段：.text（正文段）包含程序的指令代码；.data(数据段)包含固定的数据，如常量、字符串；.bss（未初始化数据段）包含未初始化的变量、数组等。C++源程序生成的目标代码中还包括.fini（析构函数代码）和.init（构造函数代码）等。有关elf文件格式，读者可自行参考相关资料。连接器的任务就是将多个目标文件的.text、.data和.bss等段连接在一起，而连接脚本文件是告诉连接器从什么地址开始放置这些段。例如笔者的引导程序连接文件link.lds为：<br /><br />ENTRY(begin)<br /><br />SECTION<br /><br />{ .=0x00300000;<br /><br />.text : { *(.text) }<br /><br />.data: { *(.data) }<br /><br />.bss: { *(.bss) }<br /><br />}<br /><br />　　其中，ENTRY(begin)指明程序的入口点为begin标号；.=0x00300000指明目标代码的起始地址为0x00300000，这一段地址为MX1的片内RAM；.text : { *(.text) }表示从0x00300000开始放置所有目标文件的代码段，随后的.data: { *(.data) }表示数据段从代码段的末尾开始，再后是.bss段。<br /><br />（4）用连接器生成最终目标文件<br /><br />　　有了连接脚本文件，如下命令可生成最终的目标文件：<br /><br />arm-linux-ld-nostadlib-o bootstrap.elf-T link.lds init.o xmrecever.o flash.o<br /><br />其中，ostadlib表示不连接系统的运行库，而是直接从begin入口；-o指明目标文件的名称；-T指明采用的连接脚本文件；最后是需要连接的目标文件列表。<br /><br />（5）生成二进制代码<br /><br />　　连接生成的elf文件还不能直接下载执行，通过objcopy工具可生成最终的二进制文件：<br /><br />arm-linux-objcopy-O binary bootstrap.elf bootstrap.bin<br /><br />其中-Obinary指定生成为二进制格式文件。Objcopy还可以生成S格式的文件，只需将参数换成-O srec。如果想将生成的目标代码反汇编，还可以用objdump工具：<br /><br />arm-linux-objdump-D bootstrap.elf<br /><br />　　至此，所生成的目标文件就可以直接写入Flash中运行了。如果要通过自举模式下载，还需要转换为自举模式的文件格式，相关转换工具可以在摩托罗拉的网站上找到。<br /><br />　　掌握了GNU工具后，开发者就可以开发或移植C或C++代码的程序。用户可以不需要操作系统，直接开发简单应用程序。但对于更复杂的应用来说，操作系统必不可少。目前流行的源代码公开的操作系统如Linux、μC/OS都可以用GNU工具编译。ARM的Linux已有很多成熟的版本，可以支持ARM720、ARM920、ARM1020等多种处理器，读者可从www.uclinux.org或www.armdevzone.com上获取最新信息。Linux移植过程中和处理器相关的代码都放在arch/arm目录下。对于内核，用户需要做的是设定自己系统的内存映像，RAM起始地址，I/O地址空间和虚拟I/O地址空间，参看arch/arm/mach-integrator/arch.c文件。除了内核外，用户还需要为自己的系统编制各种各样的驱动程序。<br /><br />4 调试工具<br /><br />　　Linux下的GNU调试工具主要是gdb、gdbserver和kgdb。其中gdb和gdbserver可完成对目标板上Linux下应用程序的远程调试。gdbserver是一个很小的应用程序，运行于目标板上，可监控被调试进程的运行，并通过串口与上位机上的gdb通信。开发者可以通过上位机的gdb输入命令，控制目标板上进程的运行，查看内存和寄存器的内容。gdb5.1.1以后的版本加入了对ARM处理器的支持，在初始化时加入－target==arm参数可直接生成基于ARM平台的gdbserver。gdb工具可以从ftp://ftp.gnu.org/pub/gnu/gdb/上下载。<br /><br />　　对于Linux内核的调试，可以采用kgdb工具，同样需要通过串口与上位机上的gdb通信，对目标板的Linux内核进行调试。由于篇幅所限，感兴趣的读者可以从http://oss.sgi.com/projects/kgdb/上了解具体的使用方法。<br /><br />结束语<br /><br />　　本文以一个具体的实例为例，对GNU工具中的常用功能作了介绍。其实GNU工具的功能还远不止这些，更进一步的操作有：针对不同处理器，不同算法的软件优化、高效的内嵌汇编、大型项目管理功能等。相信GNU能成为越来越多开发人员的选择。<br /></font>
<img src ="http://www.cnitblog.com/lijiehua/aggbug/10854.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/lijiehua/" target="_blank">内嵌</a> 2006-05-20 23:22 <a href="http://www.cnitblog.com/lijiehua/articles/10854.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>