本文介绍了编写驱动必备基础知识,编写驱动的难点之处。并从按键驱动到Sensor驱动简单介绍示范了驱动编写过程。并给出了驱动学习方法和评价驱动能力的技术指标!
驱动学习
•整个内核70%以上是各种驱动代码
•每一个你日常使用的小功能背后都有复杂的实现!
•Linux 驱动程序设计模式(40%) char,block,net,input,pci,usb,Platform(bus,device,driver),kset,kobject,proc,sysfs,ioctl,mmap,miscdevice, softirq,tasklet,workqueue, console,
•内核相关知识(30%):内核目录结构,内存访问,ipc,锁,内核数据结构,不通内核版本api,热拔插netlink,内核线程,中断处理(注册,共享),设备树,
•硬件相关知识(30%): 总线,协议(I2C,I2S,SPI,USB,PCI,sensor,bt1120,bt656,LCD),各种CPU、传感器(ADC,sensor,temperature etc)工作原理
前置基础知识
模拟电路,数字电路
硬件总线协议,各种RFC文档;
了解硬件电路设计,能看懂电路图。示波器等工具的使用
对C语言了如指掌,各种特殊宏的用法,对内核基本数据结构了解。
熟悉C系统编程,应用层编程
内核软件子系统,各种软件框架
上述知识你都有了一定了解之后,你才能开始尝试去开发驱动了!
学习曲线非常陡峭,必须一次性踏上台阶,否则后续又得重新攀爬。
这么多基础知识要求,基本就限定了只有科班计算机相关专业才能在这一行深入钻研了。
编写驱动困难之处
打怪升级困难。要有硬件项目才能给你升级涨经验!一个公司硬件项目周期极长,可能几年都做不了几个新硬件项目
新手与熟手完成同样任务时间差异极大!强者越强,你有经验,有难度的活都给你,你没经验,练手的机会都不会给你
一切都是以懵懂中开始的。内核代码量太大,没有任何人熟悉所有模块,你不可能都熟悉之后再开始动手修改。内核版本之间接口一直变动,没有稳定的软件方法。接口总线RFC文档太长,一般至少几千页的英文文档,你不可能都看完才开始动手。硬件设计可能有漏洞,不是官方设计出错,而是现实情况是当初设计RFC标准的人就没有考虑到这种异常情况
不同总线接口调试方法和工具差异极大,和医院不同科室使用不同工具差不多,你会不会使用某种工具,可能使你的工作效率差异几十倍
软件开发,你有一台电脑就足够了。硬件驱动开发,必须有对应的硬件开发板,调试工具Jtag,PC端调试工具,示波器,电源等一整套设备才能开始工作
所有书本的知识,都是过时的,落后的。任何一个实际硬件项目,基本都是独一无二的,驱动程序也是独一无二,全世界都没有第二个人做同样的东西!几乎没有任何参考。
网络上面所有相关教程,实际使用一般至少有一半以上是不切和实际的,错误的,没法使用。需要以你的基础知识从头推导,纠正相关部分的错误!
写驱动好比挖隧道
- 不知道隧道下面什么地质情况,什么岩层结构,是否好施工
- 是否有地下水,多大的地下水没法确定
- 是否能完工没法确定
- 完工时间多久没法确定
- 在你完工之前,你不知道还需要多长时间才能完工,是否能完工都不清楚
- 等等
写驱动,就是给你一个垃圾场,要你组装出来一个能走动的钟表!
- 不知道是否缺少零件,你要对整个软硬件构架了如指掌,比硬件更熟悉硬件
- 零件是否损坏,有可能多个零件,这个损坏,哪个没有损坏,你换一个同样的零件,说不定可行,也可能不可行
- 零件是否符合设计规范性能,有可能这个设计错误,根本就是不可能成功的
- 这个零件的说明书和零件是否匹配,给错了没有?外行连给到手的资料判断是否正确资料的能力都没有
- 由于你的上游一开始拿到的也是错误的资料,所以给你的也是错误资料
- 由于商业,保密等各种原因,一开始就给你错误的资料,故意不给你正确资料的情况也有
- 零件是否完好,是否工作正常
- 在你组装好,能走动之前,你不知道能否组装好手表
- 组成的钟表走时快慢是否正常,能够走动起来,说明零件大抵不差了,是驱动开发决定性进展
- 钟表能走动了,后续就是走时准确的调整。性能优化,续航优化,软件框架优化,内存优化,稳定性优化,电磁兼容等等
从一堆垃圾零件,组装出来一个能走的钟表!从上图到下图的过程!
实现出来
组装好,把驱动跑起来是第一步
性能优化
对于访问外设emmc,不同时序参数访问性能差距很大。对跑分影响很大!
续航优化
不用外设时,可以关闭对应外设电源,或者根据负载动态调节
内存优化
内存占用,Zero Copy,指针传递
稳定性优化
稳定性,眼图,高速性能
电磁兼容
电磁兼容测试,各种标准
等等其它方面
驱动开发深入下去,是一座又一座高山需要攀爬,但基本的驱动开发还是不难的。
驱动案例
每一个外设都有复杂的物理,材料,结构,光学,工艺,版本等等各种复杂因素需要研究,考虑。当然不是每个外设都这么复杂,复杂的摄像头子系统涉及的知识技术几年就研究不完!
每一款芯片构架差异都很大,会有不同的内核软件构架,德州仪器TI一份完整的芯片手册就有3000多页,至少看完前四章(几百页英文文档)才能说对芯片有基本了解。
简单的按键
按键硬件设计方法常用的就有3、4种。每种硬件设计,内核就要好几种软件框架可以实现它。
学习驱动可以从它开始。万里长征第一步,后面慢慢学习I2C,SPI, NAND等外设驱动。
摄像头驱动介绍
可以说是整个手机最复杂的外设驱动!研究两年只能说刚入门。
3A算法是核心: AWB 启动白平衡,AE自动曝光,AF自动对焦
理论上就没有完善的解决方案,只有近似解决方案。技术理论发展很快,经常有新技术和方法出来。
感觉这个很复杂?很正常,整套软件系统自己搞定就需要几十人的团队,一般也就是需要修改整套系统种的某一部分。Sensor驱动,ISP tunning等。
下面简单图解ISP驱动相关知识
涉及到Sensor专有知识点有
- 黑电平与线性化
- Green Imbalance
- 坏点消除
- Vignetting 与 Color shading
- SNR 与 Raw Denoise
- Dynamic Range 与 Tone Mapping
- MTF 与 Demosaic
- 色彩空间与色彩重建
- Color Correction Matrix 与 3D LUT
- Gamma与对比度增强
- Sharpening
- Color Space Conversion
- 空域降噪
- 时域降噪
- Color Aberrance Corrention and Depurple
- 闪光灯
- HDR
- Exif 与 DNG
- 图像防抖
- 编解码知识 H264 H265等
Sensor子系统涉及到的知识大概有如上,个人做过的最复杂的子系统就这个了。
会写简单驱动,到会写sensor驱动,到会写ISP系统,中间都隔了几年时间差距。
驱动的技术级别
要做好驱动,要熟悉硬件,总线协议,要会怀疑每一处地方,其它每个人给的信息都可能是错误的,如何定位这个错误就是驱动的工作。成功的路径只有一个,而失败的路径千千万万,驱动的的工作就是找到这条成功的路。
必备:入门水平
必备:入门水平,能在别人指导下完成一些简单驱动开发。在一些深入,系统学习后进入下一阶段。
基本的数电模电基础。
熟悉一些常用开发工具。
熟悉linux 内核基本驱动框架。懂得基本内核原理。
独立实现过char字符设备。
调试过一些常见总线接口设备。比如常见的I2C,SPI设备。
中等水平
中等水平:能够按照指示完成任务,需要大量的时间和大量产品开发慢慢积累经验,完成本阶段进阶。
熟练使用各种开发工具。
对linux驱动绝大部分常用框架都有研究。
能够进行ip core外围器件级别的移植。
熟悉内核锁的使用,了解中断上下文。
能够分析定位解决时序问题。
用gpio模拟实现过I2C,SPI等总线驱动。
对oops定位分析,驱动调试熟悉。
对proc,sys,debugfs熟悉或者做过。
能够在现有驱动基础上修改,阅读datasheet对接新硬件。
在一些行业应用领域能够在fae帮助下完成外围设备驱动。
了解arm硬件构架,懂得基本arm汇编指令。基本c程序优化。
懂得基本pcb升级,打板贴片流程。
能够解决大部分硬件异常问题。
高手进阶
高手进阶:能够独当一面,带领团队。
工具什么的无所谓,有自己一套最高效的配置工具。
能够进行ip core级别的移植。
熟悉并懂得使用各种内核锁,能用内核线程实现一些复杂需求,中断上下文实现都有做过。
对应用层构架各种技术方法也都非常熟悉。
知道单核、多核同构、异构构架的内核、驱动、应用层设计差异及处理方法,优化方法。
熟悉arm构架,arm指令集。懂得怎么根据硬件构架,芯片指令集优化程序。
知道怎么使用汇编,cache优化。知道cache一致性原理及其实现。
深入研究过linux内核实现机制。
熟悉编译,汇编,链接原理。能够定位一些复杂问题,知道怎么通过编译器,链接器实现一些非标准的功能。
独立实现过绝大部分外围驱动。
能够独立从头开始实现一些复杂框架驱动。例如网络设备,视频设备等。
在一些具体应用业务上研究的非常深入,达到行业一流水平。
深入研究过绝大部分总线接口。比如音视频接口,编解码,usb,网络等业务。
画过pcb,或者至少了解pcb设计,绘制,打板过程中的各种问题。
能够熟练协助硬件定位解决各种问题。
超一流高手进阶
超一流高手进阶:技术方面基本没有什么可以难倒你的了。
自己去实现基本的uboot,内核。
能够自己设计实现全新的内核框架。
开始一些具体应用的结构,物理,数学,光学等方面深入研究。
一些问题能否解决,怎么解决,更多的从数学角度分析。
参与主线linux kernel开发。
对hdl,Verilog深入了解,自己设计芯片ip core。
以上都是个人见解,仅供参考!
硬件设计
下面是硬件工程师的能力需要掌握的能力,驱动对这些不一定要精通,但一定要懂!作为驱动工程师要比硬件工程师更懂硬件,才能发现并解决硬件问题
- 基础学科和电路相关学科的理论能力,主要涉及高等数学、复变函数、大学电路、大学物理、模拟电路、数字电路、高速电路设计、信号完整性、电磁仿真、EMS/EMI设计等;
- 器件选型、电路设计能力;PCB设计与绘制,PCB生产工艺与流程,各种硬件设计标准,环保标准,各国的电路、工艺、环保等标准
故障定位、联合调试能力; - 电路板焊接、手工工具使用能力;
- 万用表、示波器、频谱仪、时序分析仪、矢量网络分析仪等仪器仪表的使用能力;
- 常见数字信号的总线和接口的理解和测试能力;
- 文档阅读、撰写能力;
- 新方案和平台的学习能力;
- 代码debug能力;
- 问题描述和沟通能力。
信号完整性
信号完整性是指在电路中从发射端到接收端,信号在传输和处理过程中能够保持其原始质量和数据完整性的能力。当信号受到任何形式的损失或变形时,就会损害其完整性,并导致数据错误、跳闸和其他问题。
为了维持信号完整性,需要考虑主要的因素:
反射:信号反射是由于信号传输线路不匹配、连接器品质差、排布方式不当造成的现象,反射会导致信号幅度降低、延迟和失真。
接入损耗:当信号通过多个组件(例如 PCB迹道、基板穿孔、插头、接口和连接器等)时,信号的路径会产生接触阻抗变化,这种变化会产生不同级别的功率损失。
串扰:由于超近距离物理链接和电场交互作用,两条相邻线路之间会产生频域与时间域上的干扰。
时钟偏移和抖动:由于温度波动、震动、噪声及晶体管本身等影响,时钟频率的稳定性可能会出现相对误差,从而引起抖动或者不同频段的交叉干扰。
非线性效应:过度开启、过度关断和电流饱和等导致非线性的行为会引起因求得对谐波失真、交调失真、截止失真和互交调制等影响。
地面反弹和回归损耗: 相邻板层之间产生了地较差,这样传输线路上天线肯定设计在一端上,然而模式(典型的是 TEM、vs TE/TM)会影响抑制和放射。通过地掩盖和 返工方式优化此项效果。
维持信号完整性的主要方法包括:使用高品质的线路和连接器、选择适当的电缆阻抗匹配、考虑噪声源问题和EMC防护、按要求使用功率地面、使用屏蔽技术、使用合适的静电保护、并使用冗余机制和误码纠正机制等等。
维护信号完整性是现代电子设计中至关重要的一个方面,很多电气、无线、测试和计算机网络领域中需要保证信号完整性。
Linux Performance
Linux observability tools, Linux static performance analysis tools, Linux benchmarking tools, Linux tuning tools, and Linux sar
参考
相关书籍
Linux内核完全注释
Linux设备驱动程序
Linux设备驱动开发详解
上面两本是介绍Linux kernel软件驱动框架的
Link and loader
Linux内核源代码情景分析(上册)
相关文章

系列教程
系统编程系列
- 如何实现自己的操作系统
- 手把手教你构建 C 语言编译器
- 如何编写Linux驱动?
- 海思MPP&UNF构架源代码级分析
- 使用 Shell 脚本实现一个简单 Docker
- Github build-your-own-x 系列
百善孝为先,论心不论迹,论迹贫家无孝子;万恶淫为首,论迹不论心,论心世上少完人。
——名言赏析
《唾玉集》
烂柯真诀妙通神,
一局曾经几度春。
自出洞来无敌手,
得饶人处且饶人。