总结:软件开发的3个⽅向与嵌⼊式Linux学习路线(驱动⽅向)曾经和同事⼀起吃饭,听他们吐槽程序员压⼒太⼤,我开玩笑说去送外卖会不会更好;但细数了⼀下,还是程序员⾹。
我想,能够选择程序员作为职业⽣涯的开始应该算是⼀种幸运:收⼊还⾏,虽然会顶着项⽬进度的压⼒,但只需要吃学习的苦。
现在软件开发⾮常热门,下⾄各种操作系统、上⾄五花⼋门的框架;让初学者眼花缭乱,很多⼈很迷茫,担⼼学习的某样东西以后很快被新兴事物代替。
我曾听过亚马逊创始⼈Jeff Bezos说过的⼀句话:
⼈们经常问,在接下来的10年⾥,会有什么样的变化。但是我只问,未来的10年,什么是不变的?——Jeff Bezos
我认为,⾏业和⽅向都不是最重要的,按我对《软技能:代码之外的⽣存指南》其中提到的“冲量”的理解,竞争⼒=选择+积累。
程序员的三⼤⽅向
韦东⼭将程序员的⽅向分为3类:专业领域、业务领域、操作系统领域。⽽按我的理解是:专业领域,业务领域,底层领域。
负责底层领域的⼈,主要的⼯作是向其他开发⼈员提供操作底层硬件的接⼝,有时候甚⾄需要搭建业务开发⼈员程序运⾏的系统环境,计算软件运⾏时所需要的最⼩资源;配合硬件⼯程师进⾏联调,从软、硬件2个⾓度排除解决PCBA上存在的问题;有时候还需要参与硬件设计(主要是CPU外围),设计⾏业应⽤的数据链路架构。
从事业务开发的⼈,需要了解⼀些操作系统知识,善⽤各种库进⾏,常常使⽤操作系统的接⼝(系统调⽤)进⾏应⽤层开发。⼀般都需要从⾏业出发、对产品有⼀定的认识,了解⼀些业务需求,搞清楚业务的关系。
所以,当领导的⼈,多是做应⽤的。⼀旦钻⼊了某个⾏业,很难换⾏业。因此,选择⼀个好的⾏业⾮常重要。——韦东⼭
对专业开发的⼈来说,他们常常⾯对的是业务中某⼀个核⼼需求的实现,像科研⼈员⼀样,更多地需要对理论知识有⾜够的积累;⾼数中的很多东西是他们的⽼朋友;编程语⾔只是他们实现⽬标的⼯具。
这3类⼯种直接可以没有明确的界定,只要学习能⼒⾜够强,甚⾄可以相互转换,⽽且这种转换后的变化可能是更加得⼼应⼿的⼯作。
我们来讲讲底层领域吧。
底层领域
底层开发需要在于芯⽚⼚商或者板级开发商的BSP,包括3种:
0、BSP开发
1、裸机开发
2、基于操作系统的驱动开发
BSP开发:我曾经以为底层移植需要从通⽤的BootLoader或者kernel做移植,没成想实际上这⼀块属于板级供应商的⼯作。除⾮是进⼊到这些供应商从事⼯作或者进⾏产品底层的深度定制,否则没啥机会⽤到芯⽚上的编程经验。
实际上,⼤部分的移植⼯作都只是简单的适配。
裸机开发往往是⾯对⼀些对资源要求⽐较苛刻,⽆法运⾏操作系统的场景。例如物联⽹领域,尤其是通过电池供电产品;也有⼀些不需要上系统的原因在于调度和通讯的⽅式⽐较简单,⽤前后台(轮询+中断)系统⾜以解决这些问题。
⽽操作系统开发的开发根据系统的不同⽽不同;嵌⼊式常见的操作系统很多(过时的WinCE就不说了),由简到难的有:uCos、FreeRTOS;VxWorks,RT-Thread,
其中,⽐较成熟⽽被⼈⼴泛认识的有:Linux、FreeRTOS、RT-Thead。
我建议学习的路线,“从裸机到系统”:
0、学习⼀款MCU,例如STM32
1、了解操作系统原理
2、买个资料丰富、有条理⽽且社区友好的开发板,移植并开发有关的系统
3、在2的基础上,研究Linux
当然,不仅如此,经常和硬件⼯程师打交道也是⼀项⼯作内容。
操作系统领域所包含的内容,简单地说,就是制作出⼀台装好系统的专⽤“电脑”,可以分为:
为产品规划硬件:按需求、性能、成本和资源选择主芯⽚,搭配周边外设,交由硬件开发⼈员设计。
给单板适配操作系统、编写驱动以控制外部设备
定制维护、升级等整体量产⽅案
为应⽤开发⼈员搭建开发环境
从系统⾓度解决疑难杂症linux系统vim编辑器
韦东⼭:我在中兴公司上班时,写驱动的时间其实是很少的,⼤部分时间是调试:系统调优,上帮APP⼯程师、下帮硬件⼯程师查问题。我们从⼚家、⽹上得到的源码,很多都是标准的,当然可以直接⽤。但是在你的产品上也许优化⼀下更好。⽐如我们可以把摄像头驱动和DMA驱动揉合起来,让摄像头的数据直接通过DMA发到DSP去。
我们可以在软件和硬件之间起桥梁作⽤,对于实体产品,有可能是软件出问题也可能是硬件出问题,⼀般是底层系统⼯程师⽐较容易出问题。当硬件、软件应⽤出现问题,他们解决不了时,从底层软件⾓度给他们出主意,给他们提供⼯具。再⽐如⽅案选择:芯⽚性能能否达标、可⽤的BSP是否完善等等,这只能由负责整个⽅案的⼈来考虑,他必须懂底层。
在操作系统领域,对知识的要求很多:
外语能⼒:熟读各种芯⽚⼿册(我曾见过⼀种很少见的配置说明,要需要有⼀定的理解能⼒)
硬件能⼒:懂硬件知识才能看懂电路图
系统框架:有编写、移植驱动程序的能⼒,汇编
系统理论:对操作系统本⾝有⼀定的理解,才能解决各类疑难问题
通信协议:从最简单的串⼝到SPI、IIC、CAN上⾄TCP/IP
驱动开发:外设的配置
应⽤开发:C/C++
缺点:它绝对是⼀个⼤坑,没有兴趣、没有毅⼒的⼈慎选:
发育缓慢:⼴⽽杂的知识,要学很久;没有经验的时候,需要从软件开发开始学习
岗位机会少:绝对⽐APP的职位少(数量减少、薪资提⾼)
门槛⾼(当然薪⽔相对就⾼)
优点:
不担⼼⾏业限制:学好后,⾏业通杀,想换⾏就换⾏;想⾃⼰做产品就⾃⼰做产品。
⼯作量稳定:不会被经常变动的需求搞得天天加班。(所以说⽂档先⾏,先规划再开发)
驱动开发,我认为适合于这些⼈:
1、硬件⼯程师:想转软件开发,从底层软件⼊门会⽐较好,硬件经验能够⽤得上;
2、应⽤开发⼈员:想深⼊了解底层的⼈,不会整天被底层卡脖⼦;
3、裸机开发⼈员:⾯对⽇益复杂的资源调度处理开始⼒不从⼼;有资源能够上系统的硬件平台可以搞搞。
4、想拥有整体调试能⼒的⼈:拥有底层能⼒对调试来讲是⼀把利刃;
嵌⼊式软件中⼀定有的部分:
简单的OS:内核、驱动、任务。
⽐较庞⼤的OS:bootloader、内核、驱动、⽂件系统、应⽤程序(任务)。
零基础快速⼊门
假设您是零基础,我们规划了如下⼊门路线图:
前⾯的知识,是后⾯知识的基础,建议按顺序学习。每⼀部分,不⼀定需要学得很深⼊透彻
软件
C语⾔:
基本语法
结构体、指针
复杂宏定义
通⽤:
数据结构+算法
应⽤
PC-Linux(例如Centos、Ubuntu)
Linux常见命令
开发环境配置、搭建
Linux常见编辑器的使⽤(vim,emacs)
硬件
原理图、芯⽚⼿册
各类通讯协议
我们学习硬件知识的⽬的在于能看懂原理图,看懂通信协议,看懂芯⽚⼿册;不求能设计原理图,更不求能设计电路板。对于正统的⽅法,你应该这样学习:
①学习《微机原理》,理解⼀个计算机的组成及各个部件的交互原理。
②学习《数字电路》,理解各种门电路的原理及使⽤,还可以掌握⼀些逻辑运算(与、或等)。
嵌⼊式学习路线
裸机程序
概述:从简单的裸机开发⼊⼿,先掌握硬件操作。对于基于ARM+Linux的裸机学习,这么做可以学得更深,并且更贴合后续的Linux学习。
Linux驱动开发 = Linux驱动程序软件框架 + 通过软件操作硬件
实际上这个部分就是通过软件操作硬件:不需要依赖其他框架,你可以按你⾃⼰的意愿来组织编写代码;你只需要知道如何读写物理地址即可。(必要时,使⽤芯⽚提供的资源对硬件进⾏控制)
⼀切从零编写代码、管理代码,可以让我们学习到更多知识:
实际上这些知识在BootLoader中学习会更有体会
需要了解芯⽚的上电启动过程,知道第1条代码如何运⾏
需要掌握怎么把程序读⼊内存
需要理解内存怎么规划使⽤,⽐如栈在哪,堆在哪
需要理解代码重定位
需要知道中断发⽣后,软硬件怎么保护现场、跳到中断⼊⼝、调⽤中断程序、恢复现场
你会知道:
main函数不是我们编写的第1个函数(链接地址,加载地址的概念等内容)
芯⽚从上电开始,程序是怎么被搬运执⾏的(不同芯⽚加载代码的差异)
函数调⽤过程中,参数是如何传递的(C函数形参列表与汇编寄存器的对应关系)
中断发⽣时,每⼀个寄存器的值都要⼩⼼对待(异常模式)
代码段、数据段、BSS段(程序在内存中的分布情况)
程序的运⾏:上电复位、代码重定位、位置⽆关码、CPU异常/中断
驱动硬件:时钟,内存,中断,GPIO,IIC,SPI,Flash,LCD等(⽚内资源如何使⽤)
学习裸机开发的⽬的有两个:
1、掌握裸机程序的结构,为后续的u-boot作准备
2、练习硬件知识,即:怎么看原理图、芯⽚⼿册,怎么写代码来操作硬件
后⾯的u-boot可以认为是裸机程序的集合,我们在裸机开发中逐个掌握各个部件,再集合起来就可以得到⼀个u-boot了。后续的驱动开发,也涉及硬件操作,你可以在裸机开发中学习硬件知识。
注意:如果你并不关⼼裸机的程序结构,不关⼼bootloader的实现,这部分是可以先略过的。
推荐两本书:杜春蕾的《ARM体系结构与编程》,韦东⼭的《嵌⼊式Linux应⽤开发完全⼿册》。
BootLoader
概述:
如果你是软件⼯程师,⽆论是ARM9、ARM11、A8还是A9,对我们来说是没有差别的。⼀款芯⽚,上⾯有CPU,还有众多的⽚上设备(⽐如UART、USB、LCD控制器)。我们写程序时,并不涉及CPU,只是去操作那些⽚上设备。
所以:差别在于⽚上设备,不在于CPU核;差别在于寄存器操作不⼀样。
因为我们写驱动并不涉及CPU的核⼼,只是操作CPU之外的设备,只是读写这些设备的寄存器。
学习⽬标:
uboot框架、修改uboot命令、uboot启动内核的细节
适配uboot的⽅法(适配相近的硬件板⼦到实际的板⼦上,并做修改)
读写不同的介质下的程序
调通⽹络,能够启动内核
学习⽅法:
①先学习《从零编写bootloader》,这可以从最少的代码理解bootloader的主要功能
②再看书上对u-boot的讲解,并结合《分析u-boot 1.1.6的视频》来理解
③最后,有时间有兴趣的话,看《移植⼀个全新u-boot的视频》,这不是必须的。
学习程度:
理解u-boot的启动过程,特别是u-boot代码重定位:怎么从Flash上把⾃⼰读⼊内存
知道bootloader如何给内核传递参数
知道bootloader是根据“bootcmd”指定的命令启动内核
掌握BootLoader⼀些调试技巧
内核
描述:内核本⾝不是我们学习的重点,但是了解⼀下内核的启动过程,还是很有必要的:⼯作中有可能要修改内核以适配硬件,掌握了启动过程才知道去修改哪些⽂件。
结合代码分析内核启动流程
配置、适配内核
学习程度:
①知道机器ID的作⽤,根据机器ID到单板对应的⽂件
②知道Makefile、Kconfig的作⽤,知道怎么简单地配置内核
③知道怎么修改分区
④作为⼊门:只求理解,不要求能移植
⽂件系统
⽂件系统的学习其实指的是:构建⼀个根⽬录⽂件系统,此后将其制作为镜像;这个镜像的类型是我们平时所说的
概述:
在驱动程序开发阶段,我们喜欢搭建⼀个最⼩根⽂件系统来调试驱动;
在开发应⽤程序时,也需要搭建⽂件系统,把各种库、配置⽂件放进去;
在发布产品时,你还需要修改配置⽂件,使得产品可以⾃动运⾏程序;
甚⾄你想实现插上U盘后⾃动启动某个程序,这也要要修改配置⽂件;
这⼀切,都需要你理解根⽂件系统的构成,理解内核启动后是根据什么配置⽂件来启动哪些应⽤程序。
学习内容:
init进程
构建最⼩根⽂件系统,烧写到单板上
学习程度:
①理解配置⽂件的作⽤
②知道根⽂件系统中lib⾥的⽂件来⾃哪⾥
③可以制作、烧写⽂件系统映象⽂件
驱动
字符驱动设备
描述:
对每⼀个驱动,先了解硬件原理,然后从零写代码,从简单到复杂,逐渐完善它的功能。
以LED、按键驱动为例,练习开发过程中碰到的机制:查询、休眠-唤醒、中断、异步通知、poll、同步、互斥等等。后续更复杂的驱动程序,就是在这些机制的基础上,根据硬件特性设计出精巧的软件框架。
学习内容:
设备框架
应⽤与驱动的关系
查询、中断、休眠唤醒、poll、异步、同步、互斥、阻塞
学习路线:
字符设备驱动程序之概念介绍、编写编译、测试改进、操作LED
字符设备驱动程序之查询⽅式的按键驱动程序
字符设备驱动程序之中断⽅式的按键驱动:Linux异常处理结构、Linux中断处理结构、编写代码、poll机制、异步通知、同步互斥阻塞、定时器防抖动
输⼊⼦系统概念介绍、编写驱动程序
应⽤程序、库、内核、驱动程序的关系
Linux驱动程序的分类和开发步骤
驱动程序的加载和卸载
字符设备驱动程序开发
字符设备驱动程序中重要的数据结构和函数
LED驱动程序源码分析
Linux异常处理体系结构
Linux异常处理体系结构概述
Linux异常处理的层次结构
常见的异常
Linux中断处理体系结构
中断处理体系结构的初始化
⽤户注册中断处理函数的过程
中断的处理过程
卸载中断处理函数
使⽤中断的驱动程序⽰例
按键驱动程序源码分析、测试程序情景分析
学习⽅法:
1、沿着数据流向,从应⽤程序出发,对驱动程序的使⽤进⾏情景分析。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论