本文介绍了编写驱动必备基础知识,编写驱动的难点之处。并从按键驱动到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内核完全注释
Linux设备驱动程序
Linux设备驱动开发详解
上面两本是介绍Linux kernel软件驱动框架的
Link and loader
Linux内核源代码情景分析(上册)
相关文章
系列教程
系统编程系列
- 如何实现自己的操作系统
- 手把手教你构建 C 语言编译器
- 如何编写Linux驱动?
- 海思MPP&UNF构架源代码级分析
- 使用 Shell 脚本实现一个简单 Docker
- Github build-your-own-x 系列
百善孝为先,论心不论迹,论迹贫家无孝子;万恶淫为首,论迹不论心,论心世上少完人。
——名言赏析
《唾玉集》
烂柯真诀妙通神,
一局曾经几度春。
自出洞来无敌手,
得饶人处且饶人。