嵌入式linux_嵌入式 linux和嵌入式单片机 - CSDN
嵌入式linux 订阅
嵌入式 Linux是嵌入式操作系统的一个新成员,其最大的特点是源代码公开并且遵循GPL协议,近几年来已成为研究热点。目前正在开发的嵌入式系统中,有近50%的项目选择Linux作为嵌入式操作系统。 [1]  嵌入式linux 是将日益流行的Linux操作系统进行裁剪修改,使之能在嵌入式计算机系统上运行的一种操作系统。嵌入式linux既继承了Internet上无限的开放源代码资源,又具有嵌入式操作系统的特性。嵌入式Linux的特点是版权费免费;购买费用媒介成本技术支持全世界的自由软件开发者提供支持网络特性免费,而且性能优异,软件移植容易,代码开放,有许多应用软件支持,应用产品开发周期短,新产品上市迅速,因为有许多公开的代码可以参考和移植,实时性能RT_Linux Hardhat Linux 等嵌入式Linux支持,实时性能稳定性好安全性好。 [2] 展开全文
嵌入式 Linux是嵌入式操作系统的一个新成员,其最大的特点是源代码公开并且遵循GPL协议,近几年来已成为研究热点。目前正在开发的嵌入式系统中,有近50%的项目选择Linux作为嵌入式操作系统。 [1]  嵌入式linux 是将日益流行的Linux操作系统进行裁剪修改,使之能在嵌入式计算机系统上运行的一种操作系统。嵌入式linux既继承了Internet上无限的开放源代码资源,又具有嵌入式操作系统的特性。嵌入式Linux的特点是版权费免费;购买费用媒介成本技术支持全世界的自由软件开发者提供支持网络特性免费,而且性能优异,软件移植容易,代码开放,有许多应用软件支持,应用产品开发周期短,新产品上市迅速,因为有许多公开的代码可以参考和移植,实时性能RT_Linux Hardhat Linux 等嵌入式Linux支持,实时性能稳定性好安全性好。 [2]
信息
广泛应用
移动电话
行业协会
Embedded Linux Consortum
中文名
嵌入式linux
出    现
20世纪60年代晚期
嵌入式linux简介
嵌入式linux 是将日益流行的Linux操作系统进行裁剪修改,使之能在嵌入式计算机系统上运行的一种操作系统。嵌入式linux既继承了Internet上无限的开放源代码资源,又具有嵌入式操作系统的特性。嵌入式Linux的特点是版权费免费;购买费用媒介成本技术支持全世界的自由软件开发者提供支持网络特性免费,而且性能优异,软件移植容易,代码开放,有许多应用软件支持,应用产品开发周期短,新产品上市迅速,因为有许多公开的代码可以参考和移植,实时性能RT_Linux Hardhat Linux 等嵌入式Linux支持,实时性能稳定性好安全性好。 [2]  如果分别让10位工程师给出嵌入式系统的定义,将得到10个不同的答案。一般来说,大部分的嵌入式系统执行特定的任务。我们假定最简单的嵌入式系统包括输入/输出功能,以及一些控制逻辑,该系统基于它的配置执行某些类型的功能。按照这个标准,可以认为一个包含实现控制逻辑74123计数器以及一个状态是一个嵌入式系统。也许可以补充说,该系统必须可通过存储在固件中的软件进行编程。这个新的嵌入式系统定义包括输入/输出(I/O),以及存储在系统固件中的控制逻辑。一个带有鼠标、键盘、网络连接并运行图形用户界面(GUI,graphical user interface)多任务操作系统的桌面计算机显然满足这些要求,但我们能认为它是一个嵌入式系统吗?如果桌面计算机不是一个嵌入式系统,那么手持设备呢?它们有I/O功能,可以运行存储在固件中的控制逻辑。有人说,桌面计算机和手持设备都有通用计算机设备,可以运行软件来执行许多不同的任务,与之不同的是,嵌入式系统(例如,洗碗机控制器或飞行导航系统)主要是为特定任务而设计的。这种特定的功能限定使嵌入式设备有功能上的唯一性。如果是这样,为什么一些嵌入式系统设计成具有附加的功能,如存储在非易失性存储器中的程序,并且具有运行可以完成原始设计范围之外的任务的多任务操作系统的能力呢?在过去,区分嵌入式系统和通用计算机比简单得多。例如,可以很容易地区分出一个基于8051的T1分幅卡嵌入式系统和一台Sun UNIX工作站。从功能方面很难区分一台Sun工作站和一个包含PowerPC以及32MB内存和16MB闪存的机顶盒。这样的机顶盒可以运行带GUI的多任务操作系统,可现场升级,可以同时运行多个程序(如视频控制器、数字录像和Java虚拟机),还可以进行安全的因特网在线交易。很难判断这种机顶盒是否是一个嵌入式系统。显然,硬件性能的提升和价格的下降使通用计算机和嵌入式系统之间的界限变得很模糊,技术的进步使得我们很难定义什么是嵌入式。
收起全文
  • 嵌入式Linux驱动开发

    2019-05-13 10:27:28
    说到Linux驱动,尤其是嵌入式Linux驱动,大家可能会望而却步,因为入门太难!很多书上或课程基本是这样的:一上来给我们展示一大堆高深莫测的代码,感觉是C语言,又感觉不是C语言。说它是C语言,这里能找到一些C的...
  • 嵌入式Linux C编程基础

    2020-07-21 20:12:16
    本课程是全套课程的第0.2.3课(预科第三课程),主题linux系统下C语言开发学习,总共25小时左右的课程。该视频是我在联嵌科技代课期间随堂真实录制,学生均为根本没接触过C语言的应届毕业生(现在全部毕业,从事...
  • 嵌入式Linux开发基础

    2018-10-22 21:38:03
    嵌入式Linux开发环境的构建,Linux命令行的基本使用,VI、GCC、Makefile基本工具的使用,交叉开发环境的使用。 学习条件: 1.C语言编程基础
  • 掌握写汇编代码的能力,可以分析任意裸板包括U-boot、内核里的相关汇编代码; 掌握常用的硬件部件的操作,比如GPIO,UART,I2C,LCD,触摸屏; 深入理解ARM体系统架构,可以写出具备中断功能的裸板程序,对程序...
  • 本文就结合笔者经历写一写个人的嵌入式Linux入门的一些步骤和经验。不当之处,望方家指正。 在正式开始之前,先花一点时间写写笔者学习的经历。我是计算机专业,因此,对于模拟电路、数字电路、操作系统原理、...

    李迟按:

    嵌入式入门文章比比皆是,不同的人有不同的入门方法。本文就结合笔者经历写一写个人的嵌入式Linux入门的一些步骤和经验。不当之处,望方家指正。

    在正式开始之前,先花一点时间写写笔者学习的经历。我是计算机专业,因此,对于模拟电路、数字电路、操作系统原理、数据库原理、编译原理、计算组成原理、计算机体系结构、数据结构等等课程,都是必修课。我虽然都不精通,但起码是学习了。

    我从大二开始就已经接触51和AVR单片机,当时机缘巧合,由同专业的同学——也是我老乡带我开始的。然后开始画板、做板、焊板、写程序这些路子,前后陆续接触大约一两年时间,这些经历对于自学嵌入式Linux打下很好的基础。——事实上,在我开发单片机时,我已经计划好要学嵌入式,而且是偏向软件方向。

    同时我也开始安装Linux,自己捣鼓,包括虚拟机安装、物理机安装。因为考试和困难放弃一段时间,但最后还是继续。

    后来大三买了一块ARM9的开发板,自己捣鼓(不用“研究”,是因为以纯粹的门外汉去进行的)uboot、内核、根文件系统。本着不服输的精神,虽然一度放弃,但还是坚持下去。

    在毕业时慢慢摸到一些门道。但此时技术还不够,代码量还不够,后来工作多年,大量接触各式不同的技术,虽然并没有很深入,但足够养成习惯,——解决问题、研究新技术的方法、习惯。

    综上,我走的路子概括为:单片机-->使用Linux-->嵌入式Linux(u-boot->kernel->rootfs)。软件知识:基础必修课->linux环境编译->Linux驱动。

    从上文可以看到,笔者是作为计算机专业的学生而进入嵌入式Linux领域的。但并不是说一定要在学校学习那些课程才能入门。无论学习什么知识,都是靠自己进行的,但有了过来人指点、带你入门,往往省时省力很多——而这正是本文的目的。

    下面进入正文部分。

    一、系统环境

    1、环境搭建

    开发嵌入式需要大量辅助软件,一般来说,我们是在电脑上开发好程序,然后通过某些方式将程序下载到开发板上运行。按这个顺序列出一些我认为必须的:

    Linux系统:主要作为程序开发的系统,选择多人使用并资源丰富的版本,建议ubuntu或fedora,目前我使用ubuntu。可以使用在虚拟机或物理机上。

    虚拟机:有条件的推荐使用物理机安装,但一般经常使用vmware这类虚拟机软件,通过这个软件安装ubuntu系统,然后设置共享。然后在这个系统上交叉编译。

    共享方式:有的人喜欢用vmware自带共享功能,有的人喜欢用samba共享。个人建议在ubuntu中设置samba共享,这样可以在windows上将ubuntu共享目录映射成为其中一个盘符,这样做,就可以在windows下操作linux系统的目录、文件了,不过前提是需要网络性能良好。另一种常见的共享方式是nfs,多用于主机和开发板之间的文件传输。

    开发IDE:有的人建议在linux系统中用vim或emacs,但作为初学者入门,不要如此,使用vim、emacs学习成本高,而会打击积极性。在samba共享情况下,建议使用Notepad++、source insight进行代码编辑

    交叉编译:交叉编译是嵌入式一个很重要的概念。由于我们编译的程序是在开发板(开发板又称目标板)上运行的,但开发板又没有环境进行编译,所以带出“交叉编译”概念。即在一台linux主机系统上使用交叉编译器对代码进行编译,但编译得到的二进制文件无法在该主机运行,只能在开发板上运行。不同的板子使用的交叉编译器不同。一般使用商家自带的交叉编译器。

    下载手段:根据应用场合,可以用jtag烧录器下载程序(适用如u-boot开发)。可以使用tftp方式下载程序(适用kernel开发)。在开发板系统启动后且网络正常情况下,可以使用tftp下载、nfs拷贝等方式进行调试(适用于应用层程序开发)。

    另外对于USB转串口线、网络这类的东西,就不一一详细说明了。

     

    掌握程度:不同人使用的开发环境不尽相同。原则上只要是自己熟悉的环境就可以了,以提高开发效率为准则。

    推荐软件:vmware、notepad++、source insight、tftpd32(均为windows系统软件)。

    2、系统使用

    工欲善其事,必先利其器。系统环境使用熟悉程度越高,越能提高开发速度。举个例了,曾经遇到过别人在设备上调试应用程序,步骤是:编码、编译、制作软件包、用工具升级软件包到设备上,设备上电看效果。这一系列步骤中,制作包、升级软件包耗时很长,对于调试十分不利。如果使用NFS,时间能省至少三分之二。所以说,环境的熟悉是十分重要和必要的。

    本节主要针对Linux系统,对于入门者而言,Linux系统的使用是一个大坎。但要知道,嵌入式开发是离不开linux系统的,是必须学的。目前网络资料十分广泛,几乎遇到的问题都在找到答案,但质量往往良莠不齐,有些甚至会误导人。因此,建议一边学一边做笔记,把自己的疑问、心得、步骤都记录下来(比如,记录第1小节提到的nfs、samba服务安装的步骤)。

    如果时间允许,最好找书本来学习,边看书边敲命令。因为书籍介绍比较系统,有利于了解全貌,再逐个知识点深入,做到胸有成竹。下面列一下需要学习的知识点。

    1、掌握常用命令。必须要学的命令不多,像查看文件、拷贝文件、创建文件、查找文件、显示日期、查看/修改IP,等等。这些常用命令只要使用次数多了,就能熟练掌握。具体的自行搜索。

    2、掌握软件安装步骤。一般linux系统发行版自带有安装工具,如unbutu,在联网情况下直接输入命令apt-get install tool-name,就能安装了。

    3、编译源码方式安装软件。有些工具提供源码需要自己进行编译(比如要在开发板上运行的程序,则无法通过apt-get来安装,需要交叉编译)。linux编译一般有三个步骤:

    配置:./configure

    编译:make

    安装:make install。

    这个知识点自行百度。

    4、了解linux文件系统、目录结构、设备文件。如根目录名称是“/”,配置文件一般位于/etc目录,运行程序一般位于/bin、/sbin、/usr/bin、/usr/sbin,等等。因为嵌入式涉及到根文件系统概念,因而需要对linux目录结构有了解。如果感兴趣,可以去搜索一下LFS。

    5、学习IO重定向、管道概念,学习并会写简单shell脚本。

    6、学习编辑器vi的简单使用(因为有些情况下只有这个编辑器可用)、编译器gcc用法、Makefile知识、gdb调试。(此项针对开发而言)

    推荐资源:

    笔者的主页和博客有大量linux系统使用、软件编译、Makefile,等等文章,欢迎前来围观。

    学习建议:

    1、看书、网络搜索

    2、学会man命令(这是linux内置的帮助命令,比如要了解cp命令的用法,则输入man cp)

    3、记录笔记

    二、应用层

    1、C/C++语言

    C/C++语言本身与具体平台相关不大,但必须结合具体环境平台才能展现其作用。比如,MFC使用C/C++,QT也使用C/C++,Linux内核中使用C,单片机使用C,等等。环境不同,其侧重点不同。在学校里学习C/C++语法,考完试,却没有结合实际项目编程,就有人纠结学了C/C++不懂能做什么。只有真正在某一领域使用了C语言,它才是一个可以看得见、摸得着的东西,而不再是抽象的。

     

    这里结合Linux系统,列举出一些要掌握、学习的知识点。

    1、linux系统编程基本概念:Makefile、gcc、gdb。

    2、文件IO操作。

    3、进程控制、进程间通信、多线程操作

    4、信号处理

    5、网络编程

    6、串口编程

     

    另外也列举C/C++语言的学习点:

    1、标准库

    输入输出(fprintf、sscanf)、文件操作(fopen、fclose)、字符类操作(isalpha、islower)、字符串操作(strcpy、strcmp、memcpy)、信号处理(signal)、日期时间(mktime、ctime)

    2、C++ STL

    向量vector、队列queue、栈stack、列表list。

    推荐网站:http://www.cplusplus.com/reference/

     

    下面列出一些我认为较好的书籍。每种类型的书籍应用场合不同,按需求学习。——不仅嵌入式Linux领域,其它很多领域同时需要C,因而要提高C技能。

    入门篇:

    《Linux C 编程一站式学习》

    《Linux C从入门到精通》

    《Linux C编程从初学到精通 》

    《Linux C编程实战》

    《嵌入式linux应用开发完全手册》 (该书对嵌入式Linux开发整体都有讲述,一书以看窥全貌,入门适用)

    linux网络编程篇:

    《UNIX网络编程》

    《UNIX环境高级编程》

    C/C++提高篇:

     

    《C陷阱与缺陷》

    《C专家编程》

    《C和指》

    《C++沉思录》

    《C/C++深层探索》

    《Effective C++中文版》

    《提高c++性能的编程技术》

    《0 bug:C/C++商用工程之道》 (这本书网络有一定争论,笔者认为有部分的确有可取之处,请辩证看待)

     

    学习路线:

    环境:安装虚拟机linux,配置好samba,有windows下用notepad++编写代码,然后在命令行使用gcc编译并运行。像ubuntu安装必要开发工具sudo apt-get install build-essential 这类的知识点本文就不涉及了。

    实践:首先了解linux下gcc编译基本概念,然后逐个知识点学习。以上每点均是一个知识块,需要手动写代码。建议在github上建立仓库,形成自己的代码库,方便日后使用。

    2、版本控制

    版本控制可以提高开发效率,目前很多公司使用svn或git进行代码管理,很多开源项目——包括kernel,都使用git来管理。对于不涉密的代码,推荐使用github托管,而不便公开的代码,可以在bitbucket或csdn上托管。养成保存代码的习惯很重要。笔者很多年前没有代码托管意识,一次电脑被偷,导致很多代码消失了,如今想找也想不回来了。

    版本控制学习成本不大,无非创建仓库、提交代码这些过程,结合日常编码练习,慢慢熟悉掌握即可。

     

    笔者录制了一个git教程,欢迎观看:

    http://edu.csdn.net/course/detail/4562

    3、脚本

    Linux系统的脚本语言有很多,使用场合也不同,主要目的是提高开发效率。比如:在shell脚本中完成代码的编译并拷贝到nfs共享目录(或tftp服务目录)。这样只需要执行脚本就完成多项工作,节省很多时间。

    4、界面开发

    界面开发不是笔者强项,就写一写笔者的经历。笔者接触过的界面开发有QT、SDL、MFC。这些都是作为工具而存在的,不是专门研究,都是工作需要时再去学习,边学习边实践。

    比如,做一个视频采集的软件,使用了SDL进行显示。

    比如,为了显示YUV格式的文件,使用MFC编写一个播放器。

    5、其它书籍推荐

    内功修炼篇:

    《程序员的自我修养——链接、装载与库》(偏底层的人建议看看)

    《高效程序员的45个习惯 敏捷开发修炼之道》

    《高质量程序设计指南》(建议看看,工作中编写代码一定要注意编码规范,否则维护难度太大)

    《Linux开发工具箱:项目开发的最有效途径》(对应英文版本《The Linux Programmer's Toolbox》,网络有资源)

    (注:入门级别书籍不建议购买,通过网络资源或去图书馆借书等手段来学习就行了。当然经济条件允许的除外)

    笔者这几年也积累一定的文章,欢迎阅读:http://blog.csdn.net/subfate/article/category/752115

    三、底层

    这里说的底层包括三大方面,这三大方面缺一不可。

    bootloader:作为上电运行的第一个程序,负责最原始的初始化操作,初始化芯片、初始化内存、初始化IO复用,读取内核代码并将控制权移交到内核,从而完成使命。

    kernel:提供基本的运行环境,提供外设操作控制接口。

    rootfs:向用词(应用层)提供基本操作环境,包括命令行、程序库等。

    1、bootloader(启动装载程序)

    嵌入式Linux常见的bootloader是u-boot,而X86领域中一般称为BIOS。u-boot的学习没有捷径,最好是在有ARM开发板情况下进行研究,通过打印信息的方法跟踪其流程。但是,看懂u-boot代码需要电路基本知识、芯片手册知识等等。——这些知识,同样适用于内核驱动的开发。

    首先要建立的是整体概念和认识。建议先把厂商提供的u-boot源码编译通过,并下载到开发板上看到正常结果后,再用串口打印信息搜索代码,以了解u-boot的代码流程。然后再慢慢研究。如果bootloader不是学习重点,在有一定概念前提下就可以跳过到内核驱动层了,不过就笔者经验来看,bootloader和内核关系十分密切且部分代码是相通的。

    一般初始化的代码是汇编代码,对于入门者而言,初学阶段不用追究,等有一定基础后再回头研究也不晚。

    笔者许多年前移植过u-boot,写了几篇文章,版本旧了一些,但对于学习而言还有有好处的:

    http://blog.csdn.net/subfate/article/category/751064

    笔者曾经研究过x86的开源bios,写了几篇文章,大家可以看看。虽然对于u-boot学习帮助不大,但可以了解笔者如何从零开始学习一个未知的知识。地址:http://blog.csdn.net/column/details/15826.html

    2、kernel(内核)

    内核是比较大的一块,涉及内容十分多。作为入门者,与u-boot类似,首先要建立的整体概念。先把厂商提供的内核源码编译通过,并下载到开发板上,串口会打印很多启动信息,这些启动信息能帮助我们学习内核,自己也可以在内核中打印语句,以了解其流程。

    每一个平台芯片不同,外设不同,内核均不同,需要进行移植。所谓的“移植”,就是找到合适的驱动,修改适应到该平台的过程。比如,某平台使用2个LCD屏,一个是3.5寸的,另一个是4.3寸的,这需要对内核进行修改。比如,这个平台使用nand flash是1GB的,另一个平台使用的是512MB的,也需要修改内核。其它如EEPROM、电源芯片、网卡,等等,均如此。

    内核知识点分2部分,一是kernel本身的知识点,如内存管理机制(MMU)、时间管理、同步机制,等等。二是外设驱动,如LED灯、GPIO、按键。

    初学者建议学习:

    1、了解内核编译的过程:配置内核、编译uImage。

    2、了解platform驱动模型(笔者文章有现成的模板,已经应用于很多个平台上)。

    3、了解一般外设驱动模型。建议从简单的LED、GPIO入门。

     

    高阶知识点:

    1、学习各种子系统,如MTD、USB、IIC、SPI、RTC、WDT。

    2、学习内核知识,如延时队列、时间管理,同步机制,等等。

    以下是笔者笔记关于内核专题的目录:

     

    推荐资源:

    《Linux设备驱动程序》第三版

    《Linux设备驱动开发详解》

    笔者开了一个专栏讲内核的,欢迎阅读:http://blog.csdn.net/column/details/15829.htm

     

    3、rootfs(根文件系统)

     

    一般情况下,开发板厂商会提供根文件系统,如果没有,则可以自己编译制作。一般嵌入式Linux使用busybox制作文件系统必要的程序、库、配置文件。因为busybox编译出来的内容体积小,节省空间,所以很多ARM开发板上都是用busybox的。另外还涉及到文件系统格式,像Yaffs2、ramfs、ext4、UBI,等等。所有这些知识点,请自行搜索学习。

    掌握程度:

    1、知道系统启动过程涉及到哪些脚本。知道上电启动时如何添加自己程序启动。

    2、了解各目录功能、存储哪些文件(如改IP在哪个配置文件,动态库在哪些目录)。

    四、其他知识

    1、电路原理图、datasheet

    作为底层开发人员来说,能看懂硬件原理图和datasheet是必要的一项技能。

    看懂硬件原理图,就可以知道这个系统上有什么器件,哪些器件有什么功能,如何连接(使用什么协议),提供什么接口。有了这些认知后,才会对系统有一个全局整体的认识掌握。对于开发人员来说绝对是有利的。

    看懂datasheet,才能知道如何访问器件,如何操作器件,了解其时序。

    另外,对于嵌入式经常接触到的如I2C协议,SPI协议等等的协议也要掌握。

     

    掌握程度:不需要像硬件专业同学那样学习数电、模电课程。但起码掌握上升沿、下降沿的概念,知道高电平、低电平概念,懂得看I2C协议的时序图。懂得如何找到datasheet中关键信息(寄存器说明、时序图)。

    学习路线:碎片时间多的人,建议在遇到不懂知识点时上网搜索学习。有条件的建议借书或买来学习。

     

    2、英文

    作为开发人员,英文是无涯逾越的坎,因为datasheet还有开发手册,几乎都是英文的。英文资料的特点是长句子多,而技术性术语多。初看英文的资料,可能进展很慢,但只要坚持下去,就会发现,英文手册也就那些术语而已。遇到不懂的术语,就记录下来。积累多了,阅读就慢慢顺畅了。除了术语外,语法难度,远低于高考、四级水平。

    值得说的是,国外原版书籍或手册,用词往往通俗易懂,但翻译成中文后,有的术语不对,有的句子顺序不对。这加大了阅读难度,也是造成技术书籍难懂的原因之一。

    个人经历:在某次旅途火车上,用手机看了一遍ONVIF协议手册,多年后再回看,基本已掌握。但目前ONVIF中文资料还是少。看懂英文资料,无疑有很大帮助。

    某次工作遇到网络问题,中文搜索无果,去各大英文论坛看,无意发现pause frame,继而看ieee802.3标准手册找权威说明,最后解决。这里英文资料帮了很大忙。

     

    3、其它

    其实很有许多其它知识,无法一一列举。

    本文提及的众多知识点,但绝不是在炫耀水平——因为那是笔者工作被逼去了解掌握的。但总而言这,在认清自己专注核心技能外,多掌握一些技能,总归有好处的。

    五、入门路线

    这里以偏重嵌入式Linux(ARM)驱动开发为例,给出一条入门的路线。

    1、买一款使用广泛、资料多的ARM开发板。因为使用的人多,你遇到的问题别人可能早就遇到并解决了,这样能省很多时间,并且提高自信心。可以到某宝上看看板子。因为是学习使用,最好便宜又适用的。

    2、使用vmware安装一个ubuntu系统。在vmware软件中设置物理桥接方式上网。在ubuntu设置好samba服务、nfs服务、tftp服务。

    3、首先自己动手亲自编译u-boot、kernel,烧写到板子上(注:有可能rootfs不提供源码,而是提供img镜像文件)。

    4、自己修改kernel,并编译busybox,烧写到板子,在板子挂载NFS,在虚拟机交叉编译一个Helloworld程序,并在板子上运行。

    5、根据兴趣,开始捣鼓:u-boot、kernel、应用层开发、QT开发。

    5、选择自己重点关注方面,继续研究。

    这个路线不一定要严格遵守时间轴。

    六、补充

    以上这些项,因不同人的基础而异。像硬件专业的同学,数电、模电和电路图已经掌握,就要加强C和Linux系统的学习。反之,计算机软件专业的同学,就要去学习硬件知识。等等。

    对于书籍,有的可能一下子无法理解,那是因为功力不到。有的可能觉得没有用处,那是因为还没有涉及此方面。比如,非计算专业的人看《编译原理》,《操作系统原理》,《计算机体系结构》,肯定是看不懂的,而且初学者也不必要看。又比如,嵌入式有的领域使用到H264编码、MPEG编码,802.11、CDMA,如果不是进入有关行业的,也不必学习。另外网上很多人写的嵌入式入门文章提到0.11内核版本、2.4内核版本的书,还有离散数字、算法导论的书,并不是都适用所有人。 所以大家一定要量体裁衣,有多大胃口吃多少饭,有多大头戴多大帽,根据自己已有的知识和所处的阶段进行选择。

    另外要说明的是,很多知识点是密不可分的,且界线是很模糊的。比如应用层和底层。因为有时出现问题,并不知道具体哪里的问题,这就需要站在比较高的层面(系统视野)看问题,才会快速定位并解决问题。建议以某一方面为核心点,另一方面做了解掌握。如果有能力,最好都学。

    本文所列举的项目条款,根据个人实际情况学习。建议逐步学习,各个击破。理论上知识点学得越多,越有利于看问题深度、广度的提高。

    一般情况下,嵌入式Linux没有速成。但可以达到入门速成,根据个人能力,我认为大约半个月~2个月即可,不过入门后就要不断学习和积累了,——这个积累,需要精力、时间的投入。

    在后续的系列文章中,笔者将介绍嵌入式Linux入门的一些方法和步骤,当然,不会详细到每个命令,每个驱动,只是根据笔者经验来描述,因此,更多的是经验的分享。

    PS:

    本文提到的服务设置这类操作,自行搜索了解。

    本文提到硬件、协议这类知识,自行搜索了解。

    文中提到书籍的机构与笔者无利益关系,不构成购买理由,请自行把控。

    李迟 2017.6.1 周四 (在远方顺祝我家大锤节日快乐,礼物上周已经网购回去了)

     

    展开全文
  • 前言嵌入式知识点复习一嵌入式知识点复习二 --体系结构嵌入式知识点复习三 --ARM-LINUX嵌入式开发环境嵌入式知识点复习四 --arm-linux文件编程嵌入式知识点复习五 --arm-linux进程编程嵌入式知识点复习六 --arm-...

    嵌入式知识点复习一

    1、 嵌入式系统的一般组成结构

    在这里插入图片描述

    2、嵌入式硬件系统的结构
    (1)嵌入式处理器+外围硬件
    (2)常见的外围硬件:电源、时钟、内存、I/O、通信、调试;
    3、嵌入式处理器
    (1)ARM、S3C6410、STM32单片机、华为海思、高通骁龙等
    (2)Intel /AMD 都不是嵌入式处理器
    4、嵌入式操作系统
    功能:
    种类:嵌入式linux;WinCE;Vxworks;μC/OS-II;Android;IOS。注意:linux不是嵌入式操作系统;MAC OS WINDOWS XP/7/8/10都不是

    嵌入式知识点复习二 --体系结构

    1、ARM:ADVANCED RISC MACHINES,是一款嵌入式微控制器,也是一家嵌入式处理器设计厂商。设计高性能、低功耗的嵌入式处理器。
    2、ARM微处理器工作状态:两种指令对应两种状态(通常情况)
    (1)Thumb状态、ARM状态;
    (2)32位定长ARM指令,16位定长Thumb指令。
    (3)ARM1176支持ARM指令、Thumb指令、Jazelle指令,故有三种状态:ARM状态、Thumb状态、Jazelle状态。
    3、异常:
    (1)处理器执行某些区别于用户指令的任务,如中断处理、复位、调试等;为了区分用户指令,因此称为异常;
    (2)异常的种类与类型(1176为例):7种,中断(IRQ)、快中断(FIQ)、未定义(Undef)、数据中止(DABT)、预取指中止(PABT)、软中断、复位(reset)
    4、工作模式:根据系统执行正常或异常指令不同,分为8种工作模式:用户模式、系统模式、中断模式、快中断模式、未定义模式、中止模式(对应数据中止异常、预取指中止)、SVC管理模式(软中断、复位)、SM安全监视器模式。
    5、寄存器:
    (1)ARM处理器均为32位寄存器;
    (2)ARM1176寄存器数量:40个
    (3)ARM1176寄存器包括:未分组寄存器、分组寄存器、CPSR、SPSR;
    (4)未分组寄存器(所有模式通用):9个,R0~R7;R15(PC)
    (5)分组寄存器(不同工作模式下专用,不同模式稍有不同):
    ① R8~R14;
    ② 6个不同模式下的SPSR寄存器:SPSR_irq,SPSR_fiq,SPSR_abt,
    SPSR_und,SPSR_svc,SPSR_mon
    (6)可复用寄存器:
    ① SP堆栈指针寄存器-R13,用于保存子程序调用或异常处理的临时数据;
    ② LR连接寄存器-R14,用于保存子程序调用或异常处理时,主程序调用指令/中断跳转指令的下一条指令的入口地址,以便于恢复主程序;
    ③ PC程序计数器-P15,用于保存要执行的指令的地址。
    (7)PSR程序状态寄存器:
    ① 包括CPSR当前程序状态寄存器和SPSR备份的程序状态寄存器;
    ② CPSP用于保存当前模式下处理器模式、状态、中断使能、大小端模式及条件位等信息;
    ③ SPSR用于备份异常发生前的CPSR寄存器的值,以便异常处理结束时能返回用户程序状态。
    6、ARM支持两种中断:IRQ和FIQ
    7、ARM数据存储格式:大端(big endian)和小端(little endian)
    8、采用RISC架构的ARM微处理器一般具有如下特点:
     
    ① 体积小、低功耗、低成本、高性能;
    ② 支持Thumb(16位)/ARM(32位)双指令集,能很好地兼容8位/16位器件;
    ③ 大量使用寄存器,指令执行速度更快;
    ④ 大多数数据操作都在寄存器中完成;
    ⑤ 寻址方式灵活简单,执行效率高;
    ⑥ 指令长度固定;
    ⑦ 指令支持按 条件执行;
    ⑧ 内存访问采用load/store实现。

    嵌入式知识点复习三 --ARM-LINUX嵌入式开发环境

    一、交叉开发模式
    1、组成结构
    (1)宿主机:开发主机,一般由PC、发行版linux系统、开发工具(本地及交叉编译)(代码编辑器Vi,编译器GCC、调试器GDB、工程管理器MAKE、NFS等)组成;
    (2)目标机:嵌入式系统,一般由ARM硬件、BOOTLOADER、内核、根文件系统构成;
    (3)连接工具:串口线、网线、USB线等。
    2、理解编译工具链与交叉编译工具链的异同
    (1)相同点:
    ① 用于支持的语言的编译、链接与调试,编译器用法相同;
    ② 通常都有编译器、链接器、调试器、库及其他二进制工具构成。
    (2)不同点:
    ① 编译工具链一般用于本机编译、本机执行的开发模式;
    ② 交叉编译工具链用于宿主机编译,目标机运行的交叉开发模式;
    ③ 编译器一般Linux发行版都配备,直接调用gcc命令即可;
    ④ 交叉编译器一般需根据宿主机软硬件环境,进行gcc、相关库、工具进行有针对性的定制。
    ⑤ 实验室使用的OK6410开发板定制的编译器为32位的,其交叉编译工具链主要arm-linux-gcc,arm-linux-g++arm-linux-gdb等构成。
    二、开发工具的用法
    1、Vi的工作模式及其切换-掌握使用Vi完成源代码编辑、保存及退出的常见按键操作;
    2、GCC:GNU Compiler Collection,GUN编译器套件,特点:
    ① 支持绝大多数高级语言的编译,既支持传统的C/C++,Fortan,Objective-C ,也支持java,python,go等语言;
    ② 支持汇编语言;
    ③ 支持绝大多数的主流处理器平台;
    ④ 便于构建交叉编译工具链。
    3、gcc/arm-linux-gcc用法:
    ① 基本用法:gcc hello.c;arm-linux-gcc hello.c;输出a.out
    ② 推荐用法:gcc hello.c -o hello/arm-linux-gcc hello.c -o hello ,可以指定输出文件名称;
    ③ 主要的编译参数
    -Wall 打印全部警告信息;
    -O{0-3,s} 支持代码优化,0无优化;
    -g 支持gdb调试;
    -lpthread 支持多线程。

    4、make及Makefile
    (1)make:工程管理器,利用执行Makefile文件实现工程管理(编译、链接、生成工程镜像、安装、清理、卸载等);
    (2)make用法:编写Makefile,在终端下执行make命令即可。
    (3)Makefile文件编写示例:
    一个工程,2个源文件testa.c ,testb.c,一个头文件testb.h,编译器为arm-linux-gcc,生成的可执行文件为test,需支持代码优化、打印警告信息,支持gdb调试等编译选项,其Makefile文件如下:
    SRC=testa.testb b.c testb.h
    EXEC=test
    CC=arm-linux-gcc
    CFLAGS=-Wall -O2 -g
    (EXEC):(EXEC):(SRC)
    $(CC) $(SRC) -o $(EXEC) $(CFLAGS)

    嵌入式知识点复习四 --arm-linux文件编程

    1、linux文件编程概述
    (1)文件描述符:Linux中文件分为4种:普通文件、目录文件、链接文件、设备文件要区分这些文件就要了解“文件描述符”;
    文件描述符是一个非负的整数,他是一个索引值,并指向内核中每个进程打开文件的记录表。当打开一个现存文件或创建一个新文件时,内核就向进程返回一个文件描述符,当需要读/写文件时,也需要把文件描述符作为参数传递给相应的函数。
    (2)基本I/O操作
    Linux的输入/输出(I/O)操作,通常为5个方面:打开,读取,写入,和关闭
    对应的有5个系统调用:
    open,read,write,close,lseek
    所需要的头文件:
    #include <sys/types.h>
    #include <unistd.h>
    1.open函数
    open函数的原型如下:
    int open(const char *pathname, int flags, mode_t mode)
    函数传入参数含义如下:
    pathname:为字符串,表示被打开的文件名称,可以包含路径。
    flags :为一个或多个标志,表示文件的打开方式,常用标志如表所示:
    O_RDONLY 只读方式打开
    O_WRONLY 只写方式打开
    O_RDWR  读/写方式打开
    O_CREAT 如果文件不存在,就创建新的文件
    O_EXCL 如果使用O_CREAT时文件存在,则可返回错误消息
    O_TRUNC  如果文件已存在,且以只读或只写成功打开,则先全部删除文件中原有的数据
    O_APPEND  以添加方式打开文件,在打开文件的同时,文件指针指向文件的末尾、
    注意:在open函数中,flags参数可以用过“|”组合而成,O_RDONLY,O_WRONLY,O_RDWR这三种方式是互斥的,不可同时使用,因此这3个参数只能出现一个。

    mode 被打开文件的存取权限模式,可以使用八进制数来表示新文件的权限,也可以采用<sys/stat.h>中定义的符号常量,当打开已有文件时,将忽略这个参数,函数返回值:成功则返回文件描述符,出错返回-1。

    文件模式符号常量:
    S_IRWXU   00700    所属用户读。写和执行权限
    S_IRUSR   00400   所属用户读权限
    S_IWUSR   00200   所属用户写权限
    S_IXUSR   00100   所属用户执行权限

    S_IRWXG  00070   组用户读,写和执行权限
    S_IRGRP   00040   组用户读权限 
    S_IWGRP   00020  组用户写权限
    S_IXGRP   00010  组用户执行权限

    S_IRWXO  00007  其他用户读,写和执行权限
    S_IROTH  00004  其他用户读权限
    S_IWOTH  00002  其他用户写权限
    S_IXOTH  00001  其他用户执行权限
    2.read和write函数
    函数原型如下:
    ssize_t read(int fd, void *buf,size_t count)
    ssize_t write(int fd,const void *buf, size_t count)
    函数传入参数含义如下:
    fd 文件描述符
    buf 指定存储器独处数据的缓冲区
    count 指定读出或写入的字节数
    3.close函数
    当使用完文件时可以使用close关闭文件,close会让缓冲区中的数据写回磁盘,并释放文件所占的资源,close的原型如下:
    int close(int fd)
    函数传入参数:fd文件描述符
    函数返回值:若文件顺利关闭则返回0,发生错误则返回-1,并置errno,通常文件在关闭时出错是不常见的,但也不是不可能的情况,他别是在关闭通过网络访问的文件时就会出现这种情况。
    4.lseek函数
    主要用于移动文件读写指针,主要用于获取文件大小和拓展文件(先分配空间、然后再填充内容),函数原型如下:
    off_t lseek(int fd, off_t offset, int whence)
    参数 fd:文件描述符。
    offset:偏移量,每一读写操作所需要移动的距离,单位是字节的数量,可正可负(向前移,向后移)
    whence
    (当前位置基点): SEEK_SET:当前位置为文件的开头,新位置为偏移量的大小。
    SEEK_CUR:当前位置为文件指针的位置,新位置为当前位置加上偏移量。
    SEEK_END:当前位置为文件的结尾,新位置为文件的大小加上偏移量的大小。
    返回值 成功:文件的当前位移
    -1:出错

    实例:(1)参考实验2:linux文件编程;
    (2)网盘:/linux编程源代码/IO(readwrite、fcntl)下相关代码

    嵌入式知识点复习五 --arm-linux进程编程

    一、Linux进程编程
    进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是操作系统进行资源分配和调度的基本单位,是操作系统结构的基础。
    1 进程控制
    子进程创建:fork()函数
    在Linux中创建一个新进程的唯一方法是使用fork()函数。fork()函数是Linux中一个非常重要的函数,和以往遇到的函数有一些区别,因为fork()函数看起来执行一次却返回两个值。
    1)fork()函数说明
    fork()函数用于从已存在的进程中创建一个新进程。新进程称为子进程,而原进程称为父进程。
    使用fork()函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间,包括进程的上下文、代码段、进程堆栈、内存信息、打开的文件描述符、符号控制设定、进程优先级、进程组号、当前工作目录、根目录、资源限制和控制终端等,而子进程所独有的只有它的进程号、资源使用和计时器等。
    因为子进程几乎是父进程的完全复制,所以父子两进程会运行同一个程序。这就需要用一种方式来区分它们,并使它们照此运行,否则,这两个进程不可能做不同的事。
    实际上是在父进程中执行fork()函数时,父进程会复制一个子进程,而且父子进程的代码从fork()函数的返回开始分别在两个地址空间中同时运行,从而使两个进程分别获得所属fork()函数的返回值,其中在父进程中的返回值是子进程的进程号,而在子进程中返回0。因此,可以通过返回值来判断该进程的父进程还是子进程。
    2)fork()函数语法
    在这里插入图片描述
    进程等待函数
    1)wait()函数,无条件等待,父进程阻塞直到子进程结束
    在这里插入图片描述
    2)waitpid()函数,指定等待某个子进程结束以及等待的方式(阻塞或非阻塞)
    所需头文件 #include <sys/types.h>
    #include <sys/wait.h>
    函数原型 pid_t waitpid(pid_t pid, int *status, int options)
    函数参数 pid pid>0:只等待进程ID等于pid的子进程,不管已经有其他子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
    pid=-1:等待任何一个子进程退出,此时和wait作用一样。
    pid=0:等待其组ID等于调用进程的组ID的任一子进程。
    pid<-1:等待其组ID等于pid的绝对值的任一子进程。
    status 同wait
    options WNOHANG:若由pid指定的子进程并不立即可用,则waitpid不阻塞,此时返回值为0
    WUNTRACED:若某实现支持作业控制,则由pid指定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态。
    0:同wait,阻塞父进程,等待子进程退出。
    函数返回值 正常:结束的子进程的进程号
    使用选项WNOHANG且没有子进程结束时:0
    调用出错:-1
    所需头文件 #include <sys/types.h>
    #include <sys/wait.h>

    函数原型 pid_t waitpid(pid_t pid, int *status, int options)
    函数参数 pid pid>0:只等待进程ID等于pid的子进程,不管已经有其他子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
    pid=-1:等待任何一个子进程退出,此时和wait作用一样。
    pid=0:等待其组ID等于调用进程的组ID的任一子进程。
    pid<-1:等待其组ID等于pid的绝对值的任一子进程。
    status 同wait
    options WNOHANG:若由pid指定的子进程并不立即可用,则waitpid不阻塞,此时返回值为0
    WUNTRACED:若某实现支持作业控制,则由pid指定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态。
    0:同wait,阻塞父进程,等待子进程退出。
    函数返回值 正常:结束的子进程的进程号
    使用选项WNOHANG且没有子进程结束时:0
    调用出错:-1

    进程结束:exit()和_exit()

    所需头文件 exit:#include <stdlib.h>
    _exit:#include <unistd.h>
    函数原型 exit:void exit(int status);
    _exit:void _exit(int status);
    函数传入值 status是一个整型的参数,可以利用这个参数传递进程结束时的状态。
    通常0表示正常结束;其他的数值表示出现了错误,进程非正常结束。
    在实际编程时,可以用wait系统调用接收子进程的返回值,进行相应的
    处理。

    所需头文件 exit:#include <stdlib.h>
    _exit:#include <unistd.h>
    函数原型 exit:void exit(int status);
    _exit:void _exit(int status);
    函数传入值 status是一个整型的参数,可以利用这个参数传递进程结束时的状态。
    通常0表示正常结束;其他的数值表示出现了错误,进程非正常结束。
    在实际编程时,可以用wait系统调用接收子进程的返回值,进行相应的
    处理。

    两者的区别:
    (1)_exit()函数的作用最为简单:直接使进程终止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;
    (2)exit()函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序。
    (3)exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是"清理I/O缓冲"。
    Linux下的进程间通信
    进程间通信用于实现参数传递及通信功能;Linux支持的常用的进程间通信方法:管道、消息队列、共享内存、信号量、套接口等等。
    实例:(1)实验三:Linux进程编程;
    (2)网盘linux编程源代码目录下fork文件下相关实例(FIFO、msgque、shm)。

    嵌入式知识点复习六 --arm-linux网络编程

    1、程序流程
    (1)网络通信程序架构-客户端/服务器架构
    (2)流程如下图:
    在这里插入图片描述
    TCP通信

    2、函数说明
    socket()
    Sockfd=socket(AF_INET,SOCK_STREAM,0);

    Bind()
    s_add.sin_family=AF_INET;IPV4协议
    s_add.sin_addr.s_addr=inet_addr(“192.168.1.123”);IP地址192.168.1.123
    s_add.sin_port=htons(0x8888);端口号是8888

    if(-1 == bind(Sockfd,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))

    listen()服务器端侦听函数
    listen(Sockfd,5)服务器侦听来自客户端的请求
    accept()服务器端接受客户端连接请求
    nfp = accept(Sockfd, (struct sockaddr *)(&c_add), sizeof(struct sockaddr);

    send()数据发送函数
    send(nfp,“hello,welcome to my server”,32,0)
    recv()数据接收函数
    recv(nfp,buffer,1024,0)
    关闭连接
    Close(nfp)
    关闭服务器
    Close(Sockfd)
    实例:(1)实验四:网络聊天室设计
    (2)网盘/linux编程源代码/socket下相关代码

    嵌入式知识点复习七 --linux字符型设备驱动初步

    一、Linux字符设备驱动初步
    1、Linux设备类型
    (1)字符设备:只能一个字节一个字节的读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后顺序进行。字符设备是面向流的设备,常见的字符设备如鼠标、键盘、串口、控制台、LED等。
    (2)块设备:是指可以从设备的任意位置读取一定长度的数据设备。块设备如硬盘、磁盘、U盘和SD卡等存储设备。
    (3)网络设备:网络设备比较特殊,不在是对文件进行操作,而是由专门的网络接口来实现。应用程序不能直接访问网络设备驱动程序。在/dev目录下也没有文件来表示网络设备。

    2、开发流程

    3、关键函数讲解(以2.6以下版本内核为例)
    (1)驱动模块注册register_chrdev()函数
    原型:register_chrdev(unsigned int major, const char *name,const struct file_operations *fops);
    major:主设备号,该值为 0 时,自动运行分配。而实际值不是 0 ;
    name:设备名称;
    fops:操作函数,实现驱动定义的open、read、write、close等内核函数与应用程序调用的open、read、write、close间的映射;
    返回值:
    major 值为 0 ,正常注册后,返回分配的主设备号。如果分配失败,返回 EBUSY 的负值 ( -EBUSY ) 。major 值若大于 linux/major.h (2.4内核)中声明的最大值 (#define MAX_CHRDEV 255) ,则返回EINVAL 的负值 (-EINVAL) 。指定 major 值后,若有注册的设备,返回 EBUSY 的负值 (-EBUSY)。若正常注册,则返回 0 值
    (2)驱动注销unregister_chrdev()函数
    原型:
    #include <linux.fs.h>
    int unregister_chrdev (unsigned int major, const char *name)
    变量:
    major 主设备号
    name 设备文件
    返回值:
    major 值若大于 linux/major.h (2.4 内核)中声明的最大值 (#define MAX_CHRDEV 255),返回 EINVAL的负值 (-EINVAL)。指定了 major的值后,若将要注销的 major 值并不是注册的设备驱动程序,返回 EINVAL的负值 ( -EINVAL )。正常注销则返回 0值。
    (3)File_operation结构体
    file_operations结构是建立驱动程序和设备编号的连接,内部是一组函数指针,每个打开的文件,也就是file结构,和一组函数关联,这些操作主要用来实现系统调用的
    struct file_operations {
      struct module *owner;//拥有该结构的模块的指针,一般为THIS_MODULES
    loff_t (*llseek) (struct file *, loff_t, int);//用来修改文件当前的读写位置
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);//从设备中同步读取数据
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);//向设备发送数据
    ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一个异步的读取操作
    ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一个异步的写入操作
      int (*readdir) (struct file *, void *, filldir_t);//仅用于读取目录,对于设备文件,该字段为NULL
    unsigned int (*poll) (struct file *, struct poll_table_struct *); //轮询函数,判断目前是否可以进行非阻塞的读写或写入
      int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); //执行设备I/O控制命令
      long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); //不使用BLK文件系统,将使用此种函数指针代替ioctl
      long (*compat_ioctl) (struct file *, unsigned int, unsigned long); //在64位系统上,32位的ioctl调用将使用此函数指针代替
      int (*mmap) (struct file *, struct vm_area_struct *); //用于请求将设备内存映射到进程地址空间
      int (*open) (struct inode *, struct file *); //打开
      int (*flush) (struct file *, fl_owner_t id);
      int (*release) (struct inode *, struct file *); //关闭
      int (*fsync) (struct file *, struct dentry *, int datasync); //刷新待处理的数据
      int (*aio_fsync) (struct kiocb *, int datasync); //异步刷新待处理的数据
      int (*fasync) (int, struct file *, int); //通知设备FASYNC标志发生变化
      int (*lock) (struct file *, int, struct file_lock *);
      ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
      unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
      int (*check_flags)(int);
      int (*flock) (struct file *, int, struct file_lock *);
      ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
      ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
      int (*setlease)(struct file *, long, struct file_lock **);
    };
    实例:见网盘/linux编程源代码/ok6410ledrv

    展开全文
  • 最近在学习系统移植的相关知识,在学习和调试过程中,发现了很多问题,也解决了很多问题,但总是对于我们的开发结果有一种莫名其妙的感觉,纠其原因,主要对于我们的开发环境没有一个深刻的认识,有时候几个简单的...

    最近在学习系统移植的相关知识,在学习和调试过程中,发现了很多问题,也解决了很多问题,但总是对于我们的开发结果有一种莫名其妙的感觉,纠其原因,主要对于我们的开发环境没有一个深刻的认识,有时候几个简单的命令就可以完成非常复杂的功能,可是我们有没有想过,为什么会有这样的效果?如果没有去追问,只是机械地完成,并且看到实验效果,这样做其实并没有真正的掌握系统移植的本质。
    在做每一个步骤的时候,首先问问自己,为什么要这样做,然后再问问自己正在做什么?搞明白这几个问题,我觉得就差不多了,以后不管更换什么平台,什么芯片,什么开发环境,你都不会迷糊,很快就会上手。对于嵌入式的学习方法,我个人方法就是:从宏观上把握(解决为什么的问题),微观上研究(解决正在做什么的问题),下面以自己学习的arm-cortex_a8开发板为目标,介绍下自己的学习方法和经验。
    嵌入式Linux系统移植主要由四大部分组成:
    一、搭建交叉开发环境
    二、bootloader的选择和移植
    三、kernel的配置、编译、和移植
    四、根文件系统的制作

    第一部分:搭建交叉开发环境

    先介绍第一分部的内容:搭建交叉开发环境,首先必须得思考两个问题,什么是交叉环境? 为什么需要搭建交叉环境?

    先回答第一个问题,在嵌入式开发中,交叉开发是很重要的一个概念,开发的第一个环节就是搭建环境,第一步不能完成,后面的步骤从无谈起,这里所说的交叉开发环境主要指的是:在开发主机上(通常是我的pc机)开发出能够在目标机(通常是我们的开发板)上运行的程序。嵌入式比较特殊的是不能在目标机上开发程序(狭义上来说),因为对于一个原始的开发板,在没有任何程序的情况下它根本都跑不起来,为了让它能够跑起来,我们还必须要借助pc机进行烧录程序等相关工作,开发板才能跑起来,这里的pc机就是我们说的开发主机,想想如果没有开发主机,我们的目标机基本上就是无法开发,这也就是电子行业的一句名言:搞电子,说白了,就是玩电脑!
    然后回答第二个问题,为什么需要交叉开发环境?主要原因有以下几点:
    原因1:嵌入式系统的硬件资源有很多限制,比如cpu主频相对较低,内存容量较小等,想想让几百MHZ主频的MCU去编译一个Linux kernel会让我们等的不耐烦,相对来说,pc机的速度更快,硬件资源更加丰富,因此利用pc机进行开发会提高开发效率。
    原因2:嵌入式系统MCU体系结构和指令集不同,因此需要安装交叉编译工具进行编译,这样编译的目标程序才能够在相应的平台上比如:ARM、MIPS、               POWEPC上正常运行。
    交叉开发环境的硬件组成主要由以下几大部分
    1.开发主机
    2.目标机(开发板)
    3.二者的链接介质,常用的主要有3中方式:(1)串口线 (2)USB线 (3)网线
    对应的硬件介质,还必须要有相应的软件“介质”支持:
    1.对于串口,通常用的有串口调试助手,putty工具等,工具很多,功能都差不多,会用一两款就可以;
    2.对于USB线,当然必须要有USB的驱动才可以,一般芯片公司会提供,比如对于三星的芯片,USB下载主要由DNW软件来完成;
    3.对于网线,则必须要有网络协议支持才可以,常用的服务主要两个
    第一:tftp服务:
          
    主要用于实现文件的下载,比如开发调试的过程中,主要用tftp把要测试的bootloader、kernel和文件系统直接下载到内存中运行,而不需要预先烧录到Flash芯片中,一方面,在测试的过程中,往往需要频繁的下载,如果每次把这些要测试的文件都烧录到Flash中然后再运行也可以,但是缺点是:过程比较麻烦,而且Flash的擦写次数是由限的;另外一方面:测试的目的就是把这些目标文件加载到内存中直接运行就可以了,而tftp就刚好能够实现这样的功能,因此,更没有必要把这些文件都烧录到Flash中去
    第二:nfs服务:
          
    主要用于实现网络文件的挂载,实际上是实现网络文件的共享,在开发的过程中,通常在系统移植的最后一步会制作文件系统,那么这是可以把制作好的文件系统放置在我们开发主机PC的相应位置,开发板通过nfs服务进行挂载,从而测试我们制作的文件系统是否正确,在整个过程中并不需要把文件系统烧录到Flash中去,而且挂载是自动进行挂载的,bootload启动后,kernel运行起来后会根据我们设置的启动参数进行自动挂载,因此,对于开发测试来讲,这种方式非常的方便,能够提高开发效率。
          另外,还有一个名字叫samba的服务也比较重要,主要用于文件的共享,这里说的共享和nfs的文件共享不是同一个概念,nfs的共享是实现网络文件的共享,而samba实现的是开发主机上Windows主机和Linux虚拟机之间的文件共享,是一种跨平台的文件共享,方便的实现文件的传输。
    以上这几种开发的工具在嵌入式开发中是必备的工具,对于嵌入式开发的效率提高做出了伟大的贡献,因此,要对这几个工具熟练使用,这样你的开发效率会提高很多。等测试完成以后,就会把相应的目标文件烧录到Flash中去,也就是等发布产品的时候才做的事情,因此对于开发人员来说,所有的工作永远是测试。
          通过前面的工作,我们已经准备好了交叉开发环境的硬件部分和一部分软件,最后还缺少交叉编译器,读者可能会有疑问,为什么要用交叉编译器?前面已经讲过,交叉开发环境必然会用到交叉编译工具,通俗地讲就是在一种平台上编译出能运行在体系结构不同的另一种平台上的程序,开发主机PC平台(X86 CPU)上编译出能运行在以ARM为内核的CPU平台上的程序,编译得到的程序在X86 CPU平台上是不能运行的,必须放到ARM CPU平台上才能运行,虽然两个平台用的都是Linux系统。相对于交叉编译,平常做的编译叫本地编译,也就是在当前平台编译,编译得到的程序也是在本地执行。用来编译这种跨平台程序的编译器就叫交叉编译器,相对来说,用来做本地编译的工具就叫本地编译器。所以要生成在目标机上运行的程序,必须要用交叉编译工具链来完成。
          这里又有一个问题,不就是一个交叉编译工具吗?为什么又叫交叉工具链呢?原因很简单,程序不能光编译一下就可以运行,还得进行汇编和链接等过程,同时还需要进行调试,对于一个很大工程,还需要进行工程管理等等,所以,这里 说的交叉编译工具是一个由编译器、连接器和解释器组成的综合开发环境,交叉编译工具链主要由binutils(主要包括汇编程序as和链接程序ld)、gcc(为GNU系统提供C编译器)和glibc(一些基本的C函数和其他函数的定义) 3个部分组成。有时为了减小libc库的大小,也可以用别的 c 库来代替 glibc,例如 uClibc、dietlibc 和 newlib。
          那么,如何得到一个交叉工具链呢?是从网上下载一个“程序”然后安装就可以使用了吗?回答这个问题之前先思考这样一个问题,我们的交叉工具链顾名思义就是在PC机上编译出能够在我们目标开发平台比如ARM上运行的程序,这里就又有一个问题了,我们的ARM处理器型号非常多,难道有专门针对我们某一款的交叉工具链吗?若果有的话,可以想一想,这么多处理器平台,每个平台专门定制一个交叉工具链放在网络上,然后供大家去下载,想想可能需要找很久才能找到适合你的编译器,显然这种做法不太合理,且浪费资源!因此,要得到一个交叉工具链,就像我们移植一个Linux内核一样,我们只关心我们需要的东西,编译我们需要的东西在我们的平台上运行,不需要的东西我们不选择不编译,所以,交叉工具链的制作方法和系统移植有着很多相似的地方,也就是说,交叉开发工具是一个支持很多平台的工具集的集合(类似于Linux源码),然后我们只需从这些工具集中找出跟我们平台相关的工具就行了,那么如何才能找到跟我们的平台相关的工具,这就是涉及到一个如何制作交叉工具链的问题了。
    通常构建交叉工具链有如下三种方法:
    方法一 :分步编译和安装交叉编译工具链所需要的库和源代码,最终生成交叉编译工具链。该方法相对比较困难,适合想深入学习构建交叉工具链的读者。如果只是想使用交叉工具链,建议使用下列的方法二构建交叉工具链。
    方法二: 通过Crosstool-ng脚本工具来实现一次编译,生成交叉编译工具链,该方法相对于方法一要简单许多,并且出错的机会也非常少,建议大多数情况下使用该方法构建交叉编译工具链。
    方法三 :直接通过网上下载已经制作好的交叉编译工具链。该方法的优点不用多说,当然是简单省事,但与此同时该方法有一定的弊端就是局限性太大,因为毕竟是别人构建好的,也就是固定的,没有灵活性,所以构建所用的库以及编译器的版本也许并不适合你要编译的程序,同时也许会在使用时出现许多莫名其妙的错误,建议读者慎用此方法。
         crosstool-ng是一个脚本工具,可以制作出适合不同平台的交叉编译工具链,在进行制作之前要安装一下软件:
         $ sudo apt-get install  g++  libncurses5-dev  bison  flex  texinfo automake  libtool  patch  gcj  cvs  cvsd  gawk 
         crosstool脚本工具可以在http://ymorin.is-a-geek.org/projects/crosstool下载到本地,然后解压,接下来就是进行安装配置了,这个配置优点类似内核的配置。主要的过程有以下几点:
         1. 设定源码包路径和交叉编译器的安装路径
         2. 

    修改交叉编译器针对的构架

     

    修改交叉编译器针对的构架 
         3. 增加编译时的并行进程数,以增加运行效率,加快编译,因为这个编译会比较慢。
         4. 关闭JAVA编译器 ,减少编译时间
         5. 编译
         6. 添加环境变量
         7. 刷新环境变量。
         8. 测试交叉工具链
         到此,嵌入式Linux系统移植四大部分的第一部分工作全部完成,接下来可以进行后续的开发了。

    第二部分:bootloader的选择和移植
    一、Boot Loader 概念
           就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境,他就是所谓的引导加载程序(Boot Loader)。

    【图1】Flash存储中存放文件的分布图

     二、为什么系统移植之前要先移植BootLoader?
          BootLoader的任务是引导操作系统,所谓引导操作系统,就是启动内核,让内核运行就是把内核加载到内存RAM中去运行,那先问两个问题:第一个问题,是谁把内核搬到内存中去运行?第二个问题:我们说的内存是SDRAM,大家都知道,这种内存和SRAM不同,最大的不同就是SRAM只要系统上电就可以运行,而SDRAM需要软件进行初始化才能运行,那么在把内核搬运到内存运行之前必须要先初始化内存吧,那么内存是由谁来初始化的呢?其实这两件事情都是由bootloader来干的,目的是为内核的运行准备好软硬件环境,没有bootloadr我们的系统当然不能跑起来。

    三、bootloader的分类。
          首先更正一个错误的说法,很多人说bootloader就是U-boot,这种说法是错误的,确切来说是u-boot是bootloader的一种。也就是说bootloader具有很多种类,大概的分类如下图所示:

    【图2】bootloader分类图

          由上图可以看出,不同的bootloader具有不同的使用范围,其中最令人瞩目的就是有一个叫U-Boot的bootloader,是一个通用的引导程序,而且同时支持X86、ARM和PowerPC等多种处理器架构。U-Boot,全称 Universal Boot Loader,是遵循GPL条款的开放源码项目,是由德国DENX小组开发的用于多种嵌入式CPU的bootloader程序,对于Linux的开发,德国的u-boot做出了巨大的贡献,而且是开源的。
          u-boot具有以下特点:

          ① 开放源码;
          ② 支持多种嵌入式操作系统内核,如Linux、NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS;
          ③ 支持多个处理器系列,如PowerPC、ARM、x86、MIPS、XScale;
          ④ 较高的可靠性和稳定性;
          ⑤ 高度灵活的功能设置,适合U-Boot调试、操作系统不同引导要求、产品发布等;
          ⑥ 丰富的设备驱动源码,如串口、以太网、SDRAM、FLASH、LCD、NVRAM、EEPROM、RTC、键盘等;
         ⑦ 较为丰富的开发调试文档与强大的网络技术支持;
          其实,把u-boot可以理解为是一个小型的操作系统。

    四、u-boot的目录结构
          * board 目标板相关文件,主要包含SDRAM、FLASH驱动;
          * common 独立于处理器体系结构的通用代码,如内存大小探测与故障检测;
          * cpu 与处理器相关的文件。如mpc8xx子目录下含串口、网口、LCD驱动及中断初始化等文件;
          * driver 通用设备驱动,如CFI FLASH驱动(目前对INTEL FLASH支持较好)
          * doc U-Boot的说明文档;
          * examples可在U-Boot下运行的示例程序;如hello_world.c,timer.c;
          * include U-Boot头文件;尤其configs子目录下与目标板相关的配置头文件是移植过程中经常要修改的文件;
          * lib_xxx 处理器体系相关的文件,如lib_ppc, lib_arm目录分别包含与PowerPC、ARM体系结构相关的文件;
          * net 与网络功能相关的文件目录,如bootp,nfs,tftp;
          * post 上电自检文件目录。尚有待于进一步完善;
          * rtc RTC驱动程序;
          * tools 用于创建U-Boot S-RECORD和BIN镜像文件的工具;

    五、u-boot的工作模式
          U-Boot的工作模式有启动加载模式和下载模式。启动加载模式是Bootloader的正常工作模式,嵌入式产品发布时,Bootloader必须工作在这种模式下,Bootloader将嵌入式操作系统从FLASH中加载到SDRAM中运行,整个过程是自动的。下载模式就是Bootloader通过某些通信手段将内核映像或根文件系统映像等从PC机中下载到目标板的SDRAM中运行,用户可以利用Bootloader提供的一些令接口来完成自己想要的操作,这种模式主要用于测试和开发。

    六、u-boot的启动过程
          大多数BootLoader都分为stage1和stage2两大部分,U-boot也不例外。依赖于cpu体系结构的代码(如设备初始化代码等)通常都放在stage1且可以用汇编语言来实现,而stage2则通常用C语言来实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。
    1、 stage1(start.s代码结构)
     U-boot的stage1代码通常放在start.s文件中,它用汇编语言写成,其主要代码部分如下:
    (1) 定义入口。由于一个可执行的image必须有一个入口点,并且只能有一个全局入口,通常这个入口放在rom(Flash)的0x0地址,因此,必须通知编译器以使其知道这个入口,该工作可通过修改连接器脚本来完成。
    (2)设置异常向量(exception vector)。
    (3)设置CPU的速度、时钟频率及中断控制寄存器。
    (4)初始化内存控制器 。
    (5)将rom中的程序复制到ram中。
    (6)初始化堆栈 。
    (7)转到ram中执行,该工作可使用指令ldrpc来完成。
    2、 stage2(C语言代码部分)
    lib_arm/board.c中的start armboot是C语言开始的函数,也是整个启动代码中C语言的主函数,同时还是整个u-boot(armboot)的主函数,该函数主要完成如下操作:
    (1)调用一系列的初始化函数。
    (2)初始化flash设备。
    (3)初始化系统内存分配函数。
    (4)如果目标系统拥有nand设备,则初始化nand设备。
    (5)如果目标系统有显示设备,则初始化该类设备。
    (6)初始化相关网络设备,填写ip,c地址等。
    (7)进入命令循环(即整个boot的工作循环),接受用户从串口输入的命令,然后进行相应的工作。

    七、基于cortex-a8的s5pc100bootloader启动过程分析
    s5pc100支持两种启动方式,分别为USB启动方式和NandFlash启动方式:
    1. S5PC100 USB启动过程
    [1] A8 reset, 执行iROM中的程序
    [2] iROM中的程序根据S5PC100的配置管脚(SW1开关4,拨到4对面),判断从哪里启动(USB)
    [3] iROM中的程序会初始化USB,然后等待PC机下载程序
    [4] 利用DNW程序,从PC机下载SDRAM的初始化程序到iRAM中运行,初始化SDRAM
    [5] SDRAM初始化完毕,iROM中的程序继续接管A8, 然后等待PC下载程序(BootLoader)
    [6] PC利用DNW下载BootLoader到SDRAM
    [7] 在SDRAM中运行BootLoader

    2. S5PC100 Nandflash启动过程
    [1] A8 reset, 执行IROM中的程序
    [2] iROM中的程序根据S5PC100的配置管脚(SW1开关4,拨到靠4那边),判断从哪里启动(Nandflash)
    [3] iROM中的程序驱动Nandflash
    [4] iROM中的程序会拷贝Nandflash前16k到iRAM
    [5] 前16k的程序(BootLoader前半部分)初始化SDRAM,然后拷贝完整的BootLoader到SDRAM并运行
    [6] BootLoader拷贝内核到SDRAM,并运行它
    [7] 内核运行起来后,挂载rootfs,并且运行系统初始化脚本

    八、u-boot移植(基于cortex_a8s5pc100为例)
    1.建立自己的平台
    (1).下载源码包2010.03版本,比较稳定
    (2).解压后添加我们自己的平台信息,以smdkc100为参考版,移植自己s5pc100的开发板
    (3).修改相应目录的文件名,和相应目录的Makefile,指定交叉工具链。
    (4).编译
    (5).针对我们的平台进行相应的移植,主要包括修改SDRAM的运行地址,从0x20000000
    (6).“开关”相应的宏定义
    (7).添加Nand和网卡的驱动代码
    (8).优化go命令
    (9).重新编译 make distclean(彻底删除中间文件和配置文件) make s5pc100_config(配置我们的开发板)   make(编译出我们的u-boot.bin镜像文件)
    (10).设置环境变量,即启动参数,把编译好的u-boot下载到内存中运行,过程如下:
    1. 配置开发板网络
           ip地址配置:
           $setenv ipaddr 192.168.0.6               配置ip地址到内存的环境变量
           $saveenv                                 保存环境变量的值到nandflash的参数区

           网络测试:
           在开发开发板上ping虚拟机:
           $ ping 192.168.0.157(虚拟机的ip地址)
     
           如果网络测试失败,从下面几个方面检查网络:
           1. 网线连接好
           2. 开发板和虚拟机的ip地址是否配置在同一个网段
           3. 虚拟机网络一定要采用桥接(VM--Setting-->option)
           4. 连接开发板时,虚拟机需要设置成静态ip地址

        2. 在开发板上,配置tftp服务器(虚拟机)的ip地址
           $setenv serverip 192.168.0.157(虚拟机的ip地址)
           $saveenv
        3. 拷贝u-boot.bin到/tftpboot(虚拟机上的目录)
        4. 通过tftp下载u-boot.bin到开发板内存
           $ tftp 20008000(内存地址即可) u-boot.bin(要下载的文件名)

           如果上面的命令无法正常下载:
           1. serverip配置是否正确
           2. tftp服务启动失败,重启tftp服务
              #sudo service tftpd-hpa restart

        5. 烧写u-boot.bin到nandflash的0地址
           $nand erase 0(起始地址)  40000(大小)                    擦出nandflash 0 - 256k的区域
           $nand write 20008000((缓存u-boot.bin的内存地址) 0(nandflash上u-boot的位置) 40000(烧写大小)
        
        6. 切换开发板的启动方式到nandflash
           1. 关闭开发板
           2. 把SW1的开关4拨到4的那边
           3. 启动开发板,它就从nandflash启动

    第三部分:kernel的配置、编译、和移植

    一、将下载好的linux-2.6.35.tar.bz2拷贝到主目录下解压

    二、修改顶层目录下的Makefile,主要修改平台的体系架构和交叉编译器,代码如下:
          ARCH    ?= $(SUBARCH)
          CROSS_COMPILE  ?=
          CROSS_COMPILE  ?= $(CONFIG_CROSS_COMPILE:"%"=%)
          修改以上代码为:
          ARCH    ?= arm                                                       ---->体系架构是arm架构
         CROSS_COMPILE  ?= arm-cortex_a8-linux-gnueabi-    ---->交叉编译器是arm-cortex_a8平台的
          注意:这两个变量值会直接影响顶层Makefile的编译行为,即选择编译哪些代码,用什么编译器进行编译。

    三、拷贝标准版配置文件,目的是得到跟我们开发板相关的配置信息。

    $ cp arch/arm/configs/s5pc100_defconfig    .config
          这里拷贝arch/arm/configs/s5pc100_defconfig到  .config文件是选取跟我们开发板相关的代码。因为Linux支持的平台非常非常多,不仅仅是ARM处理器,当然我们编译的时候只需要编译跟我们平台相关的代码就可以了,平台相关的不需要编译,那么就有个问题,Linux系统中的源代码文件有一万多以个,面对这么庞大的文件数量,我们如何去选择呢?
           其实,我们担心的问题也是写操作系统的那哥们早就担心过的问题了,只不过人家已经把这个问题帮我们解决了,我们只需进行很简单的操作,就可以选择出我们要编译的代码,具体的方法就是把相应平台的_deconfig直接拷贝到顶层目录的.config文件中,这样.config文件中就记录了我们要移植平台的平台信息,因为在配置内核时,系统会把所有的配置信息都保存在顶层目录的.config文件中。注意在第一次,进行make menuconfig时,系统会根据我们选取的平台信息自动选取相关的代码和模块,因此我们只需要进入然后再退出,选择保存配置信息就行了,系统会把这些跟我们移植平台相关的所有配置信息全部保存在顶层目录的.config文件中。

    四、配置内核
          $make menuconfig
         注意:第一次进去,不做任何操作,直接推出,在推出时提示是否保存配置信息,一定要保存配置信息,点击“YES”。这样我们的.config中就已经保存了我们开发平台的信息。
           在这个环节,我们需要关心一个问题,make menuconfig时,系统到低都做了哪些事情?为什么会出现图形化的界面?图形化的界面中的相关内容是从哪里来的?
            图形化的界面当然是由一个特殊的图形库来实现的,还记得第一次make menuconfig时,系统并没有出现图形化的界面,而是报错了,并且提示我们缺少 ncurses-devel ,此时只需要按照要求安装一个libncurses5-dev就行了,sudo apt-get install libncurses5-dev,有了这个图形化库的支持,我们才能够正常显示图形化界面。
           好了,图形化界面的问题解决了,那还有另外一个问题就是图形化界面里面的内容是从哪里来的?要回答这个问题,我们就要提一下Linux内核的设计思想了,Linux 内核是以模块的方式来组织这个操作系统的,那么,为什么要用模块的方式来组织呢?模块的概念又是什么呢?在此来一一回答这个问题。
          Linux2.6内核的源码树目录下一般都会有两个文件:Kconfig和Makefile。分布在各目录下的Kconfig构成了一个分布式的内核配置数据库,每个Kconfig分别描述了所属目录源文件相关的内核配置菜单。每个目录都会存放功能相对独立的信息,在每个目录中会存放各个不同的模块信息,比如在/dev/char/目录下就存放了所有字符设备的驱动程序,而这些程序代码在内核中是以模块的形式存在的,也就是说当系统需要这个驱动的时候,会把这个驱动以模块的方式编译到系统的内核中,编译分为静态编译和动态编译,静态编译内核体积比动态编译的体积要大,前面已经说了每个目录下面都会有一个Kconfig的文件,我们还会问,这个文件中都存放了什么信息?前面说了,每个目录的Kconfig文件描述了所属目录源文件相关的内核配置菜单,有其特殊的语法格式,图形化界面的文字正是从这个文件中读取出来的,如果把这个文件中的相应目录文件的信息全部删除,那么在图形化界面中将看不到该模块的信息,因此也不能进行模块的配置。
           在内核配置make menuconfig(或xconfig等)时,系统会自动从Kconfig中读出配置菜单,用户配置完后保存到.config(在顶层目录下生成)中。在内核编译时,主Makefile调用这个.config,(.config的重要性就体现在,它保存了我们的所有的配置信息,是我们选取源代码并且进行编译源代码的最终依据!!!)就知道了用户对内核的配置情况。上面的内容说明:Kconfig就是对应着内核的配置菜单。假如要想添加新的驱动到内核的源码中,可以通过修改Kconfig来增加对我们驱动的配置菜单,这样就有途径选择我们的驱动,假如想使这个驱动被编译,还要修改该驱动所在目录下的Makefile。因此,一般添加新的驱动时需要修改的文件有两种,即:Kconfig 和相应目录的Makefile(注意不只是两个),系统移植的重要内容就是给内核添加和删除相应的模块,因此主要修改的内核文件就是Kconfig 和相应目录的Makefile这两个文件。

    五、编译内核
          $make zImage
           通过上述操作我们能够在 arch/arm/boot 目录下生成一个 zImage 文件,这就是经过压缩的内核镜像。
           内核的编译过程是非常复杂的,注意这里的编译是静态编译,此时会执行顶层目录下的Makefile中的zImage命令,在执行的过程中,会根据当前目录的.config文件去选择编译源代码。编译内核的具体步骤比较复杂,有时间会另写文章详细描述。

    六、通过tftp网络服务下载测试内核
           setenv bootcmd tftp 20008000(内存地址) zImage\;go 20008000
           setenv bootargs nfs nfsroot=192.168.1.199(虚拟机的ip):/source/rootfs ip=192.168.1.200(开发板的ip)  init=/linuxrc(第一个要启动的用户进程) ttySAC0,115200(设置中断为串口1,波特率为:115200)     
           保存环境变量,复位开发板,测试是否能够正常启动(注意:在此之前应设置好需要nfs挂载的文件系统,最后才能看到效果).内核测试和启动过程也是比较复杂的,在后续的文章中会详细介绍。

    第四部分:根文件系统的介绍
        由本文的第一张图:Flash存储中存放文件的分布图可知,文件系统的制作和移植是系统移植的最后一道工序了,在这里首先要提几个问题:
        1.什么是文件系统?
        2.如何实现文件系统?
        3.常用的文件系统有哪些?为什么需要这些文件系统?
        下面来一一回答这些问题:

    文件系统我们在日常生活中则很少听说,但是它确实存在,只是名字不叫文件系统罢了,一般叫资料库。资料库里面的文件众多,我们如何快速准确的找到我们要的那份文件呢?资料库采用了分类索引的方法来实现快速查找。类似于我们学校图书馆的管理方式,一楼可能是哲学类,二楼是社科类的,三楼是电子类的,四楼是计算机类的…………等等,我们把这种进行了分类索引的资料库叫文件系统。
        对于计算机而言,文件其实就是资料数据,只能存储在物理介质上面,比如:硬盘,但是我们人不可能自己读取物理介质上的文件,或者自己把文件写入物理介质,物理介质上文件的读写只能采用程序来完成,为了方便实现,程序又被分成了物理介质驱动程序、内容存储程序和文件内容存储程序。物理介质驱动程序专门用于从物理介质上存取数据;内容存储程序用于把文件内容和文件属性信息打包;文件内容存储程序用于把用户输入形成文件内容,或者取得文件内容显示出来。

    我们可以把一个文件系统(倒树)分解成多个文件系统(倒树)分别存放到存储介质上,比如:一个存储到光盘里,一个存储到硬盘中,在使用时,我们把光盘里的文件系统的根目录挂到硬盘文件系统的一个目录下面,这样访问这个目录就相当于是访问光盘的根目录了,找到了根目录,我们也就可以访问整个光盘上的文件系统了。

    “在Linux系统中一切皆是文件”这句话是我们学习Linux系统的时候常常听到的一句话。虽然有些夸张,但是它揭示了文件系统对于Linux系统的重要性;实际上文件系统对于所有的操作系统都很重要,因为它们把大部分的硬件设备和软件数据以文件的形式进行管理。Linux系统对设备和数据的管理框架图如下:

    【图3】文件系统实现

    [说明]

    A. VFS(virtual file system)是虚拟文件系统,它管理特殊文件(虚拟文件)、磁盘文件和设备文件

    B. fs_operations结构是由一系列文件操作接口函数组成,由文件系统层来完成,为VFS提供文件操作;

    C. 在文件系统层,磁盘文件要实现各种文件系统(如:ext2),设备文件要实现各种抽象的设备驱动

    D. 在设备驱动层,磁盘驱动要实现各种磁盘的驱动程序,其他设备驱动要实现具体的设备驱动

    E. 物理层就是设备自身

     

     


       为什么会有不同的文件类型?

    由于存储介质有很多种,所以没有办法用一种统一的格式存放文件系统到各种不同的存储介质上,而是需要多种不同的存储格式来适应各种存储介质的特性,以求达到存取效率和空间利用率的最优化,这样就需要对每种存储格式制定一个规范,这写规范就叫文件系统类型。常见的文件系统类型有:
    1.Dos
      FAT16
    2.windows
      FAT16、FAT32、NTFS
    3.Linux
      Minix、ext、ext2 、ext3 、ISO9660 、jffs2, yaffs, yaffs2、cramfs, romfs, ramdisk, rootfs、proc、sysfs、usbfs、devpts、 tmpfs & ramfs、 NFS

     

        由此可见,Linux支持的文件系统最多。以不同的介质来分类,如下所示:
    ?  磁盘
        FAT16、 FAT16、FAT32、NTFS、ext、ext2 、ext3、Minix
    ?  光盘
        ISO9660、
    ?  Flash
        jffs2, yaffs, yaffs2、cramfs, romfs
    ?  内存
        Ramdisk、tmpfs & ramfs
    ?  虚拟
        rootfs、proc、sysfs、usbfs、devpts、NFS
        

    常用的存储介质理论上都可以用于存储Linux支持的文件系统;因为我们这里只研究嵌入式系统,而嵌入式系统由于体积和移动特性的限制,不能采用磁盘和光盘,所以只能采用flash类的存储设备、内存和虚拟存储设备作为文件系统的存储介质; 

    flash芯片的驱动程序是由系统来提供,所以它的存取特点完全是flash自身的特点,这时最好有更加适合flash的文件系统——Jffs、Yaffs、Cramfs和Romfs。这些文件系统都是嵌入式Linux系统中常用的文件系统,可以根据特点来选择使用它们,特点如下:
    共同点
    基于MTD驱动
    Jffs
      A.针对NOR Flash的实现
      B.基于哈希表的日志型文件系统
      C.采取损耗平衡技术,每次写入时都会尽量使写入的位置均匀分布
      D.可读写,支持数据压缩
      E.崩溃/掉电安全保护
      F.当文件系统已满或接近满时,因为垃圾收集的关系,运行速度大大放慢
    Yaffs
      A.针对Nand Flash的实现
      B.日志型文件系统
      C.采取损耗平衡技术,每次写入时都会尽量使写入的位置均匀分布
      D.可读写,不支持数据压缩
      E.挂载时间短,占用内存小
      F.自带Nandflash驱动,可以不使用VFS和MTD
    Cramfs
      A.单页压缩,支持随机访问,压缩比高达2:1
      B.速度快,效率高
      C.只读,有利于保护文件系统免受破坏,提高了系统的可靠性,但是无法对其内容进行扩充
    Romfs
      A.简单的、紧凑的、只读的文件系统 
      B.顺序存放数据,因而支持应用程序以XIP(execute In Place,片内运行)方式运行,在系统运行时,节省RAM空间 

        特有的文件系统类型:Ramdisk文件系统
        在Linux系统中,内存经常用于存储文件系统,这种叫做Ramdisk,Ramdisk有两种,一种是完全把内存看成物理存储介质,利用内存模拟磁盘,运用磁盘的文件系统类型;另一种只是在内存中存储了文件系统逻辑结构,运用tmpfs & ramfs文件系统类型:
        tmpfs & ramfs
        1. 概述
        用物理内存模拟磁盘分区,挂载这种分区后,就可以跟读写磁盘文件一样读写这里面的文件,但是操作速度要比磁盘文件快得多;所以一般应用在下面几个方面:
        1)读写速度要求快的文件应该放在这种文件系统中
        2)磁盘分区为flash的情况下,把需要经常读写的文件放在这种文件系统中,然后定期写回flash
        3)系统中的临时文件,如/tmp、/var目录下的文件应该放在这种文件系统中
        4)/dev设备文件(因为设备文件随驱动和设备的加载和卸载而变化),应该放在这种文件系统中
        2. 特点 
        1)由于数据都存放在物理内存中,所以系统重启后,这个文件系统中的数据会全部丢失
        2)ramfs在没有指定最大的大小值情况下,会自动增长,直到用掉系统中所有的物理内存为止,这时会导致系统的崩溃,建议挂载时最好限定其最大的大小值
        3)tmpfs如果指定了大小值,自动增长至大小值后,系统会限定它的大小;这个文件系统占用的物理内存页可以背置换到swap分区,但是ramfs不行

     

     

        不同的文件系统具有不同的制作方法,有的比较复杂,有的比较简单,在此由于篇幅限制,先不做介绍,在后续的文章中会单独介绍文件系统的制作。
        写了一天,终于写完了,总结了一下最近学的系统移植方面的知识,不是很详细,只是从宏观上去把握和理解系统移植的过程,在此做一个记录,以备后忘。

    展开全文
  •  ---循序渐进学习嵌入式开发技术最近经常有用人单位给 我打来电话,问我这有没有嵌入式Linux方面的开发人员,他们说他们单位急需要懂得在嵌入式linux环境下的软件开发人员,我回答说,现在每年毕业的 大学生那么多...

    嵌入式时代已经来临,你还在等什么?

     ---循序渐进学习嵌入式开发技术
    最近经常有用人单位给 我打来电话,问我这有没有嵌入式Linux方面的开发人员,他们说他们单位急需要懂得在嵌入式linux环境下的软件开发人员,我回答说,现在每年毕业的 大学生那么多,还招不到合适的软件开发人员吗?他跟我说,毕业大学生虽然多,但大部分都能力不够,不能达到他们的工作的要求。该公司HR的一句话说出来我 们现在的大学教学和大学生就业的现状:一方面每年那么多大学生毕业找不到合适的工作,另一方面很多用人单位和企业又找不到合适的人才。造成这种现象最基本 的原因是学校教育和社会需求的严重脱节。其他的专业和行业我不清楚,但是对于嵌入式专业和嵌入式软件行业来说,通过与多所高校的老师和在校高年级本科生, 研究生交流,我还是有所了解的,高校的嵌入式专业的教学现状我在前一篇文章里仔细分析过,造成很多嵌入式专业的学生在毕业后,还是很难达到用人单位的要求 最主要的原因在于高校在嵌入式教学方面重理论和轻实践,很多嵌入式专业的老师也没有实际的工作经验,这样培养出的学生可能让他讲起来头头是道,但是让他去 真正编写,调试一个应用程序就傻眼了,不知道从何下手,因为他们在学校的学习可能从来就没有老师带着他们实际调试过嵌入式程序,也没有机会让你去调试嵌入 式应用程序,那些看起来非常不错的嵌入式实验箱大部分时间都躺在实验室睡大觉,只有在上实验课的时候搬出来让大家看2眼,摸2下,还没有弄明白怎么回事, 又要收到实验室睡大觉去了。这样的教学模式,如何能培养出一名合格的嵌入式工程师呢?出现企业找不到合适的人,大学毕业生找不到合适的工作也就不奇怪了。
    嵌入式专业是一门实践性非常强的学科,只有多动手,多实践,多编程,多调试,多看书,多思考才能真正掌握好嵌入式开发技术。
    现 在很多同学也意识到了学校培养模式和社会需求脱节问题,有一部分同学也先行行动起来,开始注重培养自己的实际动手能力,培养自己实际分析问题,解决问题的 问题,培养自己在嵌入式专业实际编程,和调试程序的能力。但是嵌入式专业不同于其他学科,嵌入式专业是一门综合性非常强,涉及知识面非常广的学科,对于初 学者来说,面对那么多教程,课本,那么多知识点,往往不知道从何处下手,不知道哪些是重点,哪些不是重点,这些知识点之间有什么关联,一脸的茫然,然后东 一榔头,西一棒子,折腾了几个月甚至大半年后,还是找不着学习嵌入式的方向,还徘徊在嵌入式开发的大门之外。
    那么,如何从零开始学习嵌入式开发技术, 进入嵌入式开发大门呢,笔者根据自己的嵌入式学习经历和多年的嵌入式linux教学经验,谈谈自己对嵌入式学习的一些想法和意见,希望对大家有所帮助。

    一、练好基本功
    嵌入式系统专业是综合了计算机硬件技术,计算机软件技术以及电子电路技术的一门综合学科,所涉及的内涵和知识非常广泛,包括:数字电路,模拟电路,计算机组成原理,单片机基础,C语言基础,操作系统,数据结构,编译原理,计算机控制,计算机网络等知识。
    在真正学习嵌入式开发之前,u。对于C语言,至少能单独编写调试一个3 ~ 500行的程序,能够了解C语言的基本语法规则,基本语句的使用,理解指针概念并能灵活使用各种指针。
    计算机组成原理要能理解组成一个计算机系统的几大部件,计算机系统的结构,理解系统总线,理解处理器和计算机外部设备的关系,处理器和计算机外设是如何协调工作完成某一项功能的,计算机软件和硬件是如何分工协作完成某一项任务的,理解软件是通过寄存器来控制硬件的。
    数字电路,模拟电路要了解其基本原理个概念,能看懂简单模拟、数字电路原理图。理解数字电路中的寄存器,时序的概念,能看懂芯片手册和时序图。对于其他基础课程,重点要理解其中的一些基本概念,如何使用等等。
    对 于电子,自动化,通信,计算机类专业的学生,在大二、大三开设的专业基础或专业课程中基本包含了以上的大部分课程。因为缺乏实践,可能学得不是很深入,但 是一些基本的概念和基本知识应该还是有所了解,针对一些薄弱环节,自己稍微加强学习一下,基本上已经具备了学习嵌入式开发的基础。在嵌入式基本功学习阶 段,最重要的是C语言和单片机基础,最好是能用C语言开发一个小的单片机程序,例如用C语言实现单片机和PC的串口通信,用C语言控制LED等显示,用C 语言控制数码管显示等小程序。在这个期间需要的学习工具就是单片机51学习开发板。推荐飞凌的OK-51学习开发板。详情参考:

    二、嵌入式Linux应用开发
    嵌 入式开发基础知识学习完后,这时候你已经有了一定的嵌入式开发基础了,可以进行基于单片机的嵌入式系统设计了。单片机编程本身也是属于嵌入式编程,但是在 这里我们只是把单片机开发当作嵌入式系统开发的基础,不把单片机开发作为真正的嵌入式系统开发,在这里我们的嵌入式系统开发是指在带有操作系统的嵌入式平 台上的应用和驱动开发,特别指在嵌入式linux平台上的开发。
    单片机开发在很早以前是非常热门的,现在在一些比较简单的系统上单片机也用的非常 广泛,随着硬件的成本不断降低,在一些比较复杂的嵌入式设备一般都采用嵌入式linux操作系统,在嵌入式linux平台上进行开发,这样可以极大的提高 嵌入式开发效率,提高系统的稳定性和可靠性,降低开发成本。由于linux是一个开源的操作系统,你可以通过阅读linux内核来理解内核的实现机制,如 果有需要,你甚至可以通过修改内核源码来提高系统的性能;同时,全球参与linux开发的队伍非常庞大,网上有大量的嵌入式linux开发资料和源代码, 很多你需要实现的功能在网上基本都能找到相关源码,参考一下别人写的源码,这样可以极大的提高自己的工作效率和技术能力,近几年,随着参与linux开发 的人越来越多,linux系统的稳定性、实时性有了很大的提高,linux系统无论在服务器上还是嵌入式设备平台上都应用越来越广泛,现在包括华为、中 兴、朗讯的各大通信巨头都开始把自己设备的底层平台从vxworks操作系统迁移到linux系统,可以说嵌入式linux是嵌入式技术发展一个方向,是 嵌入式技术的一面旗帜。基于以上原因,我的建议是学嵌入式开发,就学嵌入式linux开发,相对于wince等其他的嵌入式平台,你可以真正学到更多的东 西,学到嵌入式技术的精髓,同时他又符合嵌入式产业发展的方向,不容易被日新月异的技术发展所淘汰。
    有了嵌入式开发的基础,又知道了我们为什么要学习嵌入式linux开发,那我们就要开始动手开始学习了,那如何开始学习嵌入式linux开发,从哪里开始着手呢?
    很 多同学这时候就开始买linux书籍,从图书馆借了一大堆关于linux的书:什么《linux使用基础教程》、《linux源码深度分析》、 《linux情景分析等》、 《linux高级使用指南》等等。结果抱着这些图书看了10天半个月还是不知所云,当初学习的激情慢慢就消退了,最后不了了之,终究没有进入嵌入式开发大 门。究其原因,是因为没有找到合适学习嵌入式开发的方法,做任何事情都有方法可循,找对了学习方法往往就能事半功倍;否则就可能是事倍功半,甚至劳而无 功。接下来我先分析一下同学们的几种常见的嵌入式linux学习误区,然后提出一种比较合适的嵌入式linux学习方法。



    误区一、全身投入学习桌面或服务器版本linux系统
    很 多想学嵌入式linux 的同学经常问我,我不会linux系统,怎么学习嵌入式linux开发,于是他们就花费了大量的精力和时间去研究学习桌面版本linux系统的使用,什么 redhat 、federo,、ubuntu等等都用过,如何配置linux,linux的各种使用命令都背的滚瓜烂熟,linux各种服务器的配置,还原备份各种操 作非常熟悉,以为这样就学会了嵌入式linux开发。其实这是一个学习嵌入式Linux开发的误区。
    Linux桌面环境只是嵌入式linux的一 个开发工具,开发环境而已。我们的目标不是学习linux服务器的配置和使用,linux服务器的高级配置和使用那是另外一个领域,不属于嵌入式 linux讨论的范畴。我们进行嵌入式linux开发,只是把linux桌面环境当作一个工具,在linux桌面环境下运行嵌入式linux开发工具,例 如gcc 编译器,make工具来开发我们的嵌入式linux应用程序而已,对于嵌入式开发工程师来说,没有必要花费那么多的精力和时间去研究linux桌面版和服 务器的应用,只要能了解最基本的操作即可。现在的桌面linux系统的图形化界面做的也相当好,跟window具有相同的易用性能,例如ubuntu很多 操作都可以在图形界面下完成,就没有必要去记每个linux命令了。熟悉linux桌面系统的使用和基本操作命令,安排1~2天时间学习基本就可以掌握 了。

    误区二、直接阅读linux内核源代码
     很多想学linux,在连linux是什么东西,一点都还不会使用的情况下去就阅读linux内核源代码,花了大量时间去阅读《linux源码深度分 析》、《linux情景分析等》等书。这样的结果很可能就是看的头昏眼花,不知所云,最后只能放弃了。这也是同学们学习嵌入式linux的一个误区,在有 一定嵌入式linux开发基础后,带着一定的目的去阅读linux源代码,这样可以极大的提高你的技术能力,但是你在没有任何基础,对linux一点都不 了解的情况下就去阅读linux内核源代码,无异于以卵击石,最后只能是撞个头破血流。

    以上分析了同学们学习嵌入式linux 开发的2个误区,那么如何正确的嵌入式linux开发呢?

    u,学习嵌入式linux也一样。在u, 学习嵌入式linux开发比较适合的切入点是从嵌入式linux应用程序开发开始,即暂时先不去关心嵌入式硬件平台,不去关心linux的底层驱动,先把 精力集中在现有的嵌入式linux平台上进行嵌入式linux应用程序设计开发。学习嵌入式linux开发绝不是看看书就可以学好的,需要多实践,编程调 试;因为嵌入式开发不同于普通的基于PC机或服务器的应用程序开发,嵌入式开发的应用程序是要烧写到嵌入式板卡或开发板上运行的,所以首先你要给自己购买 一块开发板,现在普遍流行的嵌入式开发板都是基于u星的ARM9 CPU S3C2440,性价比极高,在这里我推荐使用飞凌公司FL-2440 高性价比ARM9学习开发板,开发板资源丰富,稳定,同时配有大量的实验源码,视频教程和实验指导书。
     有了开发板后 先后开始学习嵌入式linux开发环境搭建、嵌入式linux开发模型、linux内核移植和文件系统、嵌入式linux应用程序移植、嵌入式linux 多进程,多线程应用程序设计、嵌入式linux网络编程,如果对嵌入式数据库或图形软件开发有兴趣的,可以进一步学习嵌入式linux数据库开发或基于 QT的嵌入式linux图形应用软件设计。每学一章节都要通过相关实验来来验证你从书上学到的东西,同时提高自己编写代码,调试程序的能力。这个过程根据 不同学员的基础不同,大概要花上1 ~ 2个月时间。学完这些课程后,你就有了在现有的嵌入式linux平台上进行应用程序设计开发的能力,到一些嵌入式软件公司去,能够胜任在现有的嵌入式 linux平台上进行上层的应用程序开发工作。但是目前你还不能进行嵌入式linux系统和驱动的开发,也就是说,你现在只能在一个已经构建好的嵌入式 linux平台上进行应用程序开发,而自己还没有能力根据实际需要去重新构建一个嵌入式linux平台。要让自己有能力根据实际需要重新构建一个嵌入式 linux软硬件平台,这时候就需要进行下一阶段的学习了,即嵌入式linux系统和驱动开发。

    三、嵌入式Linux系统和驱动开发


    有 了嵌入式linux平台上开发应用程序的基础,你已经对linux的功能、linux对应用程序提供的接口和系统调用有了一定的了解,知道如何利用 linux提供的功能来进行应用程序开发,知道如何来使用设备驱动来进行应用程序设计,有了这些知识后,你就可以更深入的去学习Linux系统原理和基于 Linux驱动的开发,Linux内核的裁剪,文件系统构,bootloader等等底层的知识了。
    想要更深入学习嵌入式Linux系统和驱动开发,要学的内容非常多包括计算机软件、硬件、操作系统知识。这时候你可以参照以下的学习思路,u包括:ARM体系架构、S3C2440微处理器接口设计、时钟系统、LCD屏接口、存储控制器及系统的存储空间分配、NAND FLASH接口和NOR FLASH接口等。u。 学完这些知识点并通过相关实验验证后,嵌入式Linux系统和驱动的开发就算掌握了差不多了,能够胜任绝大部分基于linux平台的驱动开发工作了。学完 这些知识点,根据学员的不同情况,一般需要花三个月到半年时间。通过这一阶段的学习,你在嵌入式Linux开发领域已经算是有了一定的功底,已经不再被人 称为菜鸟了,已经进入嵌入式linux开发高手行列了。

    四、更上一层楼
     深入理解了嵌入式内核和驱动开发,这时候写个什么驱动对你已经没有什么问题了,开发过程中一些基本问题都难不倒你了。这是你可能想优化一下系统的性能,比 如实时性,提高系统的启动速度,或者优化系统的内存管理机制,要达到修改内核核心机制的境界,你就需要去深入去研读linux内核源码了,参考 《linux源码深度分析》、《linux情景分析等》等linux源码分析的书籍,深入理解linux各部分的实现机制和原理,以及可能存在的问题。你 只有在深入理解现有代码和实现机制的基础上,才能提出更好的改进方案。如果你能达到这个境界,那你已经是高手中的高手,可以笑傲群雄了。

    以 上是笔者结合自己的嵌入式学习经历和嵌入式培训经验总结的一些嵌入式学习方法和步骤,这只是笔者对嵌入式学习的一些看法,希望对那些有兴趣学习嵌入式 linux又不知道从哪开始学的同学们有所帮助。当然,每个人,每个同学的基础,各方面的情况都不一样,每个人都有自己适合的学习方式,本文章总结的一些 学习方法和思路仅供参考,希望大家能找到适合自己的学习嵌入式开发的方式,早日进入嵌入式开发大门。
    万丈高楼平地起,心动不如行动,有志从事嵌入式开发的同学不要再犹豫了,赶紧拿出实际行动,好好学习,为实现自己的伟大梦想而努力奋斗吧
    展开全文
  • 可能是年前跳槽的比较多,遇到不少同学咨询到嵌入式行业发展和职业规划的问题,这里总结一下嵌入式行业的机遇和选择,希望对读者们有所帮助。 我们暂且宏观上把程序员分为3类:业务类,专业类,系统类。 业务类 ...
  •  本文主要介绍我学习嵌入式的经历。并结合自身的经验希望可以对大家有所帮助。 视频及教材:  郭天祥相关视频及教材,天狼星相关视频及教材,野火迷你相关视频及教材以及韦东山100ask官网所介绍的视频及教材 ...
  • 嵌入式Linux系统

    2019-07-15 13:40:03
    思想:先整体后局部 Pc与开发板连接方式 1、UART异步串行通信接口(串口) 2、USB串行通信接口 3、TCP/IP网络通信接口 4、Debug Jtag调试接口 PC:CentOS 7 Demoboard:Friendly arm nano pi neo4 ...
  • 一直都有人问我要书单,在网上搜索大半天,没找到合适的,他们写的太不负责了,遂决定... 本书单内容涉及:linux入门,c语言,数据结构,裸机,Linux应用,Linux驱动,Shell和 Makefile。 本人见识有限,本书单可...
  • 很好的嵌入式linux视频教程 (进程通讯) (编程基础) (文件编程) (进程通讯) (多线程) (网络编程) 进程控制) 进程管理) 高级字符设备驱动) 字符设备驱动) 内存管理子系统) 内核开发基础...
  • 嵌入式Linux C语言应用程序设计,本文档主要介绍了嵌入式Linux下C语言应用程序设计的基础知识,包括:嵌入式Linux系统开发环境构建、Linux C基础知识、ARM Linux进程线程管理、Linux设备驱动开发等内容 此外,C陷阱...
  • 嵌入式Linux应用开发完全手册》全面介绍了嵌入式Linux系统开发过程中,从底层系统支持到上层GUI应用的方方面面,内容涵盖Linux操作系统的安装及相关工具的使用、配置,嵌入式编程所需要的基础知识(交叉编译工具的...
  • 嵌入式LINUX基础教程中文第2版 高清带书签 本书是嵌入式Linux领域的名著。全面深入而又简明地阐述了构建嵌入式Linux系统的精髓。书中不仅剖析了嵌入式Linux系统,而且讲述了处理器、内核、引导加载程序、设备驱动...
  • 嵌入式Linux开发前,你可能需要知道这些基本概念 作者之前编写了一系列嵌入式Linux的开发文档: 关注公众号【微联智控】,并回复【嵌入式Linux资料】,可获取以上pdf文档​的下载链接。 当编写到一定程度...
  • 本书具有由浅入深、通俗易懂和注重实践等特点,适合于没有或者缺乏嵌入式Linux程序设计经验的初学者作为嵌入式Linux C语言开发的自学教材,同时也适合于已掌握C语言基础编程技术,需要提高嵌入式C语言编程实践能力,...
  • 我以前在教嵌入式Linux时,学生常问,”李老师,学习嵌入式Linux有什么好的推荐书啊?“但我知道其实很多同学此前是学过Linux的。他们总觉得嵌入式Linux和基于PC的Linux有很大的区别。诚然,嵌入式Linux的环境和基于...
  • 以Linux操作系统为开发平台,将隐藏在系统开发背后的关于C语言、计算机组成原理、计算机操作系统等方面的机制和知识娓娓道来,不仅能让读者知其然,更要让读者知其所以然,揭开嵌入式Linux C系统开发背后鲜为人知的...
1 2 3 4 5 ... 20
收藏数 154,804
精华内容 61,921
关键字:

嵌入式linux