刚入行的朋友问我最多的问题就是:MCU 和 Linux 驱动开发到底选哪个?作为一个在芯片公司摸爬滚打多年的驱动工程师,我太理解这种纠结了。网上关于这两个方向的讨论很多,但大多是罗列技术点,很少有人从实际工作内容和职业发展路径的角度去拆解。今天我就结合自己这些年的经历,以及我带过的不少新人的真实情况,聊聊我的看法。
先说结论:这两个方向没有绝对的优劣,只有适不适合你当前的情况,以及你未来想走什么样的路。
很多刚入行的朋友容易被“Linux 比 MCU 高级”这种说法误导。我见过学了几个月 Linux 驱动却连字符设备驱动模型都讲不清楚的人,也见过把一颗 8 位 MCU 玩出花来的老工程师。技术方向的选择,本质上是对你个人兴趣、学习习惯和职业规划的匹配,而不是单纯比哪个技术栈更“高端”。
这篇文章我会从工作内容、技术栈特点、学习曲线、职业发展、薪酬水平等多个维度,把两个方向掰开揉碎了讲清楚。文章不会给你一个绝对的答案,但会给你一套完整的决策框架,让你根据自己的情况做出判断。
一、两个方向的工作日常:到底每天在干什么
1.1 MCU 方向:与硬件打交道最多的人
MCU 开发者的日常工作,可以用“贴近硬件、事无巨细”来形容。你可能在调试一块基于 STM32 的板子,手里拿着示波器、万用表,眼睛盯着逻辑分析仪。你写的代码直接操作寄存器,要精确到每个 bit 的配置。
举个例子,你用 J-Link 给 STM32 下载程序,如果连不上,你要排查是接线问题、供电问题还是芯片本身被锁死了。你用的 CH340 串口模块如果没识别到,你要去设备管理器里看驱动装没装对。这些看似琐碎的事情,其实是 MCU 开发者的日常。即便是一个经验丰富的老手,也经常要面对这些“低级”问题。
MCU 开发的核心在于理解外设的工作原理。你要清楚 USART 的波特率是怎么计算的,要知道 DMA 在什么场景下能替代中断来减轻 CPU 负担,要明白 PWM 的死区时间如何配置才能防止上下桥臂直通。这些知识没有捷径,只能一点点啃芯片参考手册(Reference Manual)和数据手册(Datasheet)。
1.2 Linux 驱动方向:构建“操作系统与硬件”的桥梁
Linux 驱动开发的日常工作,则更像是“戴着镣铐跳舞”。你面对的不再是裸机环境下的绝对控制,而是一个庞大、复杂的操作系统。你写的驱动要符合 Linux 内核的各种框架和规范,比如 platform 总线模型、设备树(Device Tree)、字符设备框架、块设备框架、网络设备框架等。
刚入行时,你可能会花大量时间阅读内核源码,理解struct file_operations这个结构体里每个函数指针的作用,搞明白probe函数是在什么时候被调用的,以及它被调用之前,设备树里需要配置哪些属性。
你的工作场景可能是一台运行着 Ubuntu 的电脑,通过串口或者网络连接到一块 ARM 开发板。你交叉编译一个内核模块,然后用insmod命令加载它,接着用dmesg看打印信息。如果驱动崩溃了,你还得学会用kgdb或者 JTAG 调试器去分析内核的Oops信息。这些工具链和调试手段,就比 MCU 开发里单纯看寄存器复杂得多。
1.3 两者的核心区别:从“管房间”到“管物业公司”
用一个生活化的比喻来总结:MCU 开发就像是你要自己盖一间平房。从地基开始,每一块砖、每一根电线、每一条水管,你都要亲自铺设,你对房子里的所有细节有绝对掌控权。但相应地,房子盖好之后,你想加个暖气片,可能都得重新动土。
Linux 驱动开发则像是在一个大城市里管理一栋写字楼。你不用管大楼的主体结构(内核),但你要负责大楼里电梯(字符设备)、中央空调(平台设备)、网络布线(网络设备)的正常运转。你要严格遵守城市的管理条例(内核 API 和编程规范),不能随意改造大楼的结构。好处是,你想在楼里新增一个功能模块,只要按照标准和规范来做,可以非常灵活,而且可以利用城市现成的水电气网(内核提供的通用框架)来支撑你的功能。
这两种工作模式,决定了你平时接触的人和事完全不同。MCU 工程师经常要和硬件工程师、PCB layout 工程师开会,讨论引脚冲突、电源纹波。而 Linux 驱动工程师除了和硬件工程师打交道,还要花很多时间与负责上层应用的同事沟通,确认用户空间的接口设计是否符合他们的需求。
二、技术栈深度拆解:你将要面对的真正挑战
2.1 MCU 技术栈:寄存器级别的掌控力
选择 MCU 方向,意味着你首先要过“寄存器”这一关。无论是 8051、STM32、还是 GD32、NXP 的 i.MX RT,核心都是看懂芯片手册,正确配置寄存器。
现在很多芯片厂商都推出了图形化配置工具,比如 ST 的 STM32CubeMX。你可以通过图形界面勾选外设,自动生成初始化代码。但实际开发中,问题往往出在图形化工具没有暴露出来的细节上。某一次我调一个基于 STM32F407 的项目,ADC 采样值一直不准,用官方工具配置的定时器触发采样始终不对。后来我直接查阅参考手册,才发现是 ADC 的采样周期在高速时钟下需要额外配置一个分频因子,而 CubeMX 的界面里这个选项藏得很深。
MCU 开发的另一个重点是调试能力。除了常规的断点调试(通过 ST-Link 或 J-Link),你还需要学会一些“土办法”。比如,用 GPIO 翻转来测试代码执行时间,用串口打印关键变量,甚至在某些极端情况下,对着 datasheet 里的时序图,一个 bit 一个 bit 地分析波形。
此外,MCU 开发在今天早已不是简单的“裸机”开发。RTOS(实时操作系统)已经成为中高端 MCU 项目的主流选择。FreeRTOS、RT-Thread、Zephyr 等系统,引入了任务调度、信号量、消息队列等概念。开发者的思维要从“前后台大循环”转变为“多任务并发”。有时还需要处理更底层的芯片 BSP,比如国产的 RT-Thread 就经常用来跑在诸如乐鑫 ESP32、国民技术、华大等芯片上。这就涉及到tc397+eb-tresos这类复杂 MCU 的 MCAL(微控制器抽象层)配置,很多车规级 MCU 开发会用到 EB tresos 工具,这套工具链用起来相当繁琐,光是配置一个 MCU 的时钟树和引脚复用就能让人头皮发麻。
2.2 Linux 技术栈:框架与机制的理解力
Linux 驱动开发对抽象能力的要求明显更高。你不仅要懂硬件(寄存器、中断、DMA),还要深刻理解 Linux 内核的设计哲学。
比如说,你写一个 I2C 设备的驱动,不能像在 MCU 上那样直接操作 I2C 控制器的寄存器来读写。在 Linux 下,你需要注册一个i2c_driver结构体,实现probe、remove、suspend、resume等回调函数。你要和设备树里的compatible属性进行匹配,匹配成功后,内核会调用你的probe函数。在probe函数里,你要通过 Linux 提供的 I2C 子系统 API(如i2c_transfer)来和设备通信,而不是直接访问寄存器。
这背后涉及到很多机制:驱动模型(Driver Model)、设备树(Device Tree)、中断子系统、内核的并发与同步机制(自旋锁、互斥锁、RCU)、内核内存管理(kmalloc、kzalloc、vzalloc)等。
刚开始接触这些概念时,确实会觉得抽象。很多新人的痛苦在于,明明照着网上的教程写了一个简单的字符设备驱动,能够成功insmod,但为什么printk的输出没有马上显示在终端上?这就涉及到内核的 printk 级别控制以及串口控制台(console)的注册时机。在启动早期,串口控制台还没注册,printk的信息只能存放在内核日志缓冲区里。
Linux 驱动的开发环境也比 MCU 更加复杂。你需要熟悉 Linux 常用命令大全,比如lsmod、modprobe、dmesg、insmod、rmmod、lspci、lsusb、i2cdetect等。你需要配置交叉编译环境,设置ARCH和CROSS_COMPILE环境变量。你还需要掌握内核模块的编译方法——Kbuild 系统。
2.3 两者并非割裂:底层思维的共通性
很多新人有一个误区,认为 MCU 和 Linux 驱动是两个完全独立的领域。但以我多年的工作经验看,两者的底层思维是相通的,只是抽象层级不同。
无论是给 MCU 写一个轮询 GPIO 的代码,还是在 Linux 下写一个按键驱动,你都需要准确理解中断的工作机制:触发条件、中断处理函数中的“快速处理、慢速处理”分离原则(在 MCU 里是中断处理函数和主循环配合,在 Linux 里是 top half 和 bottom half)。
再比如,寄存器读写。在 MCU 上是直接操作物理地址,在 Linux 里你需要用ioremap或设备树提供的地址资源配合of_iomap来映射寄存器。理解了ioremap的作用,你就明白为什么它可以让你用虚拟地址访问物理寄存器。
还有 DMA(直接内存访问)机制。MCU 里的 DMA 和 Linux 下的 DMA 子系统虽然 API 不同,但背后的思想一致:为了把 CPU 从繁重的数据搬运工作中解放出来。
这也是为什么我建议很多新人,即使未来决定做 Linux 驱动,起步时先用一块 MCU 把中断、时钟、I2C、SPI 这些基本外设玩熟了,会有极大的帮助。因为 Linux 内核驱动里所有的机制,都可以在 MCU 裸机开发中找到“原型”或“影子”。反之,如果你只懂 MCU 而完全不理解操作系统,在 Linux 开发中很容易陷入“只见树木不见森林”的困境。
三、选型决策:不是“哪个好”而是“哪个适合”
3.1 封装的简单性和内在的复杂性
网上经常有“学 Linux 比学 MCU 难”的说法,这种说法有一定道理,但很容易误导新人。
MCU 开发的“简单”,是建立在芯片厂商已经把外围电路和底层硬件都设计好的基础上的。你拿到一块 STM32 的开发板,接上 ST-Link 和 CH340 串口线,装好 J-Link 或者 ST-Link 驱动,打开 Keil 或者 STM32CubeIDE,点两下鼠标就能点灯。这种快速反馈会让新人很有成就感,但也容易让人产生“嵌入式开发不过如此”的错觉。
然而,MCU 开发一旦深入到具体的项目,复杂的程度会瞬间提升。比如你要做一个电机驱动项目,用 TB6612 模块驱动一个直流电机。看起来很简单,烧录代码,电机转了。但如果你要做一个 FOC(磁场定向控制)的永磁同步电机驱动,你需要理解 Clarke 变换、Park 变换、SVPWM(空间矢量调制)等算法,还要处理电流环、速度环、位置环的 PID 调参。这些算法虽然可以跑在 MCU 上,但门槛并不低。
Linux 开发的“难”,主要难在入门时的认知负担重。你需要理解进程地址空间、内核态和用户态的区别、系统调用流程等。但一旦你跨过了这道坎,很多开发工作是“框架化”的。Linux 内核已经帮你把 80% 的通用逻辑做完,你只需要按照框架填充剩下 20% 的差异化部分。
我用过一个很形象的类比:MCU 开发像做手工艺品,每个细节都靠手工打磨,上限高但下限也低;Linux 驱动开发像搭积木,你需要学会看懂图纸(内核框架),但一旦学会了,搭建速度会非常快。
3.2 从长远职业发展看两个方向
从职业发展上看,两个方向都有光明的未来,但路径确实不同。
MCU 方向的职业发展,通常和“细分行业”深度绑定。比如,做 TWS 耳机、智能手表、BMS 电池管理、电机控制、汽车电子(ECU)的 MCU 工程师,和做小家电、玩具、传感器模组的 MCU 工程师,工作内容虽然有交叉,但行业经验非常重要。一个懂 BMS 的 MCU 工程师,换到电机控制行业,也需要重新学习很多行业知识。但 MCU 工程师的优势在于,你可以成为一个“全栈式”的硬件/嵌入式工程师,对硬件电路、PCB layout、软件算法都有涉猎,这在初创公司和小团队中非常吃香。
Linux 驱动的职业发展,则更偏向“软件化”。你可能从一个字符设备驱动开始,逐步走向平台设备驱动、网络驱动、显示驱动(DRM/KMS 子系统)、音频驱动(ALSA 子系统)等。随着工作年限增长,你会发现 Linux 驱动的知识体系和内核本身一样庞大。你可以选择成为某个子系统的专家,比如 V4L2 框架下的摄像头驱动专家,这在 AIoT(人工智能物联网)、智能视觉、机器人领域非常抢手。相关热搜里提到的“视觉驱动”、“海康相机驱动”,就是典型的 Linux 视频采集驱动方向。
从薪酬角度看,在同一个城市和同级别公司里,资深 Linux 驱动工程师的薪酬天花板通常会略高于 MCU 工程师。因为 Linux 驱动的技术壁垒更深、培养周期更长、行业内的人才供给更稀缺。但这不意味着 MCU 工程师没有高薪,如果你在某一细分行业(如高端汽车电子)做资深专家,收入同样可观。
不过有一点要提醒你:无论选哪个方向,都不建议只停留在应用层或者只懂配置工具。一个只会用 STM32CubeMX 生成代码、调调 API 的 MCU 工程师,和一个只会改设备树、不同驱动框架细节的 Linux 工程师,职业危险度都很高。技术底层逻辑,永远是立身之本。
3.3 怎样判断自己更适合哪个?给自己做个“适配测试”
我不鼓励你直接问别人“哪个好”,因为答案往往是基于对方自己的经历和利益立场的。我建议你做一个简单的自我测试:
你更享受哪一种思维方式?
MCU 开发需要你具备“从零到一”的构建思维,享受直接控制硬件的快感。遇到一个问题,你倾向于从时序图、寄存器配置、信号完整性等方面去分析。喜欢看着示波器上自己调整寄存器后波形变化的感觉。
Linux 驱动开发需要你具备“系统化思维”和“抽象思维”,喜欢理解机制是如何运转的。遇到问题,你倾向于从框架的角度去思考:这个功能应该归属于内核哪个子系统?现有的机制能不能复用?驱动与用户空间的接口如何设计更合理?
你对底层原理的兴趣点在哪里?
你可以试着问自己几个问题:
- 看到一只 LED 灯,你是否会好奇它的限流电阻、压降怎么计算?还是更关心如何通过
write()系统调用,让用户态程序把字符串送给内核态的驱动? - 一个串口没输出,你是先拿万用表量电压检查电平,还是先查是不是终端的 termios 配置把波特率设错了?
- 对于一块陌生的开发板,你是更兴奋于上手操作寄存器点亮它的 LCD 屏,还是更兴奋于去移植一个 U-Boot 和 Linux 内核让它跑起来?
你的耐心和抗压能力如何?
MCU 开发的调试周期通常较短,看到一个问题,往往在几小时到一两天内就能定位。而 Linux 驱动开发,尤其是内核崩溃问题,可能调试一周都是常态,你需要有足够的耐心去反复阅读内核源码、查阅邮件列表。
3.4 参考建议:从 MCU 切入,但不设限
我知道有些新人已经下定决心搞 Linux 驱动,觉得这才是“正道”。我不是要劝退你,而是想给出一条我个人认为风险更低、收益更稳的路径:先选一个便宜好上手的 MCU 板子(STM32、ESP32 都可以)硬啃一周,把中断、定时器、I2C、SPI 这些基础外设跑通,建立对硬件的“手感”。然后再开始接触 Linux 驱动。
为什么这么做?因为 Linux 驱动开发的本质,仍然是“驱动硬件”。如果你连真实的硬件怎么工作都没概念,直接一头扎进内核源码和抽象的设备模型里,很容易出现认知断层。比如,你在 Linux 里写一个 I2C 设备的驱动,你调用i2c_transfer()发送一条消息,底层硬件到底发生了哪些信号变化?如果你没有在 MCU 上直接操作过 I2C 寄存器,没有用逻辑分析仪看过波形,你会很难理解这套抽象背后的真实世界。
当然,如果你已经有一定编程基础,并且对操作系统原理、Linux 命令行、vim 都已经非常熟悉,直接上手 Linux 驱动也不是不行。那时候你的阻力主要来自于对硬件概念的陌生,你可能要补一些数字电路的基础知识。
四、实操路径:如何快速入门与有效避坑
4.1 MCU 方向的入门路线
如果你暂时决定从 MCU 开始,我根据带新人入门的经验,推荐一套学习路径:
第一步:选一块经典板子,别贪多。首选 STM32F103C8T6(蓝丸板)或者 STM32F407 探索板。这两种板子资料丰富、开源项目多,遇到问题很容易搜到解决方案。
第二步:搭建环境。下载并安装 Keil MDK 或 STM32CubeIDE。准备好 ST-Link 或 J-Link 下载器,安装对应驱动。别小看这一步,很多新人就卡在了 J-Link 驱动安装上。记住,驱动装好以后,在设备管理器里看到“J-Link”设备才算成功。
第三步:用 CubeMX 生成一个最基础的程序。配置 GPIO、USART、定时器、ADC。先实现“点灯、按键、串口打印”三板斧。熟悉调试器的使用,包括设置断点、查看寄存器和外设的值。
第四步:深入学习中断和 DMA。这是 MCU 的核心,也是最容易出问题的地方。比如,配置外部中断时,要注意 GPIO 的上升沿、下降沿触发模式,以及中断服务函数上extern "C"的问题(如果你用 C++ 的话)。使用 DMA 时,要注意缓存一致性、传输完成中断标志位的清除顺序。
第五步:引入 RTOS。建议从 FreeRTOS 或者国产的 RT-Thread 开始。尝试用信号量同步两个任务,用消息队列传输数据,用软件定时器做周期任务调度。理解任务栈的大小与优先级分配对实时性的影响。
第六步:实战一个小项目。做一个基于 ESP32+MPU6050 的姿态解算装置,或者做一个用 TB6612 驱动直流电机并实现速度闭环控制的智能小车。项目期遇到调试问题,不要急着找答案,先自己推理、看时序图、量引脚电平。
4.2 Linux 驱动方向的入门路线
如果经过思考,还是觉得 Linux 驱动更有吸引力,这里也有一套相对平滑的路线:
第一步:把 Linux 操作系统基础补牢。你需要熟悉 Linux 系统安装,比如在 VirtualBox 或 VMware 上装一台 Ubuntu。掌握 Linux 常用命令大全:ls、cat、grep、find、ps、kill、top、netstat、ifconfig、ip、mount等。至少要能达到“拿到一个未知系统,能用命令行摸清它的软硬件配置”的程度。
第二步:推荐一边用虚拟机学习,一边用真机实验。不建议完全在虚拟机上学习 Linux 驱动,因为虚拟机的硬件环境是虚拟化的,看不到真实的硬件模型。建议购买一块性能不错的 ARM 开发板,如瑞芯微 RK3568、树莓派 4B、或全志的 V3s/V851s 等。
第三步:从最简单的字符设备驱动开始。写一个只包含open、read、write、release的虚拟字符设备驱动。用insmod和rmmod加载、卸载模块。配合mknod创建设备节点,或者使用udev动态创建设备节点。这时候,你需要理解file_operations、module_init、module_exit等核心要素。
第四步:进入设备树的世界。学会编写设备树文件,添加一个新的 i2c 设备节点或 spi 设备节点。当设备树下有匹配的compatible字符串时,内核会触发对应的probe。这个阶段,你才能算真正走进了 Linux 驱动的大门。
第五步:深入研究中断和并发控制。这可能是 Linux 驱动里最困难、最晦涩的部分。你要理解中断上下文、软中断、tasklet、工作队列。特别是并发问题:如果你在probe函数里注册了中断,中断处理函数里又访问了一个全局变量,同时你在write函数里也修改了它,不加上锁,系统崩溃只是时间问题。使用spinlock还是mutex?这取决于你代码所在的上下文。
第六步:参与一个真实外设驱动项目。比如驱动一个 SPI 接口的 LCD 屏(ili9341)、CSI 接口的摄像头(OV5640)、或者一个标准的 USB 转串口芯片(CH340/CP2102)。实际上,接触这些芯片时,往往还会遇到驱动安装问题。比如在 Linux 下,很多 USB 转串口的驱动其实是内核自带的(cdc_acm、ftdi_sio、ch341),不需要额外安装。但如果你用的是其他厂商的 USB 转 UART 芯片,比如 CP2102,那么你可能需要确认内核配置里是否使能了CONFIG_USB_SERIAL_CP210X。
完成这些步骤后,你应该已经能独立阅读相当一部分内核源码,并能根据自己的需求修改驱动或者开发新的驱动了。
4.3 两个方向都会遇到的“隐性坑”
不论你选哪条路,有些坑是共通的,提前了解可以帮你少走很多弯路。
一是不要只看芯片手册,不看内核源码。这类错误在 MCU 和 Linux 方向都有。比如,在 Linux 下调试 I2C 设备时,如果只查芯片 datasheet 上某个寄存器的地址,却不知道 I2C 子系统还会在主控侧进行 PEC 校验或者重试,你就会疑惑为什么同样读写寄存器,MCU 上没问题,Linux 下却会超时。
二是要重视工具链,不要只盯着代码逻辑。在 MCU 方向,你用错了 J-Link 版本或者下载算法配置错误,会导致没法调试。在 Linux 方向,你交叉编译工具链版本与内核源码不匹配,编出的模块根本加载不进去。这都属于“环境问题”引发的 bug,而且往往比代码逻辑 bug 更折腾人。
三是不要忽视芯片的 Errata(勘误表)。芯片厂商会在勘误表里列出芯片的已知问题。我见过一个工程师调试 MCU 的 SPI,怎么配都不对,折腾了两天,最后才发现是芯片有一个勘误,片选信号在某些情况下会多翻转一次。在 Linux 方向,很多复杂 SoC 也会有官方或社区维护的 Errata 说明,了解这些,可以少做无用功。
四是注意制造工艺与全球芯片供应链的实际情况。现在很多项目都在做国产化替代,比如用国内厂商的 MCU 替代进口型号,或者在 Linux 设备树中适配国产网卡、存储芯片。这时候,技术能力是一方面,与 FAE 的沟通协调能力也非常重要。你不仅要看懂代码,还要能够清楚地向 FAE 描述你遇到的时序问题和寄存器配置问题。
五、真实案例与个人建议
5.1 两个我亲眼见过的成长轨迹
我在现在的公司带过两个新人,他们的成长路径很有代表性,这里分享给你参考。
第一位是做 MCU 方向的新人。他本科是电子信息工程,在学校就比较多地接触了单片机,对 STM32 非常熟。毕业进了我们公司后,开始负责一个 BMS 项目的 MCU 开发。他很擅长解决硬件带来的问题,能靠示波器测量波形定位 PCB 布局导致的信号串扰。几年时间,他已经成长为整个项目组里硬件问题的“定海神针”,工资涨幅也不错。但你会发现,他的知识深度主要集中在那几个特定的电池管理芯片上,如果换一个完全不同的行业,他可能需要一段不短的适应期。
另一位是做 Linux 驱动方向的新人。他本来学的是计算机专业,Linux 命令用得极溜。刚入职时对硬件几乎一窍不通,连 TTL 电平和 RS232 电平的区别都搞不清楚。但他花了一个月,硬是把一块开发板上的所有外设驱动(GPIO、I2C、SPI、UART)都自己写着跑了一遍。后来又啃了《Linux 设备驱动程序》和大量内核源码。现在他已经是我们部门负责复杂传感器驱动的主力,无论是新的触控芯片调试,还是视觉驱动(基于 V4L2 框架的摄像头),他都能快速上手。他的成长路径很陡峭,但过程中也经历过无数次内核崩溃、代码无响应的折磨。
这两个例子说明,技术栈的选择和个人的学习路径、基础有很大关系,没有绝对的好坏。
5.2 关于学习资源的一个具体清单
很多新人会问我要学习资料,我一般不会推荐太多,因为收藏了不看也是白搭。但有几个资料,我觉得是无论如何都要啃一遍的:
- MCU 方向:《STM32 中文参考手册》、《Cortex-M3 权威指南》。前者是 ST 官方的参考手册,后者是讲内核架构的经典。
- Linux 方向:《Linux 设备驱动程序(第三版)》(网上有免费的中文版)、《奔跑吧 Linux 内核》、Linux 内核源码里的
Documentation目录。 - 通用工具:学会用
git看代码,学会用grep和ctags在如山的源码里遨游。在实践中,很多问题不是靠“背”能解决的,而是靠你能够快速定位到相关源码并读懂它。
5.3 给当前还在纠结的人一个落地策略
如果你现在仍旧纠结,我建议你不要在“选哪个”上花太多时间,因为这个问题很难通过“想”想明白。更有效的做法是:给自己定一个两周的计划,直接上手体验。
第一周:买一块 STM32 开发板(成本 50 元以内),实现 UART 打印、外部中断、定时器、I2C 读取一个传感器。记录你的感受:你对寄存器操作反感吗?看到逻辑分析仪上的波形会兴奋吗?
第二周:在电脑上装一台虚拟机 Ubuntu,学习 Linux 常用命令。然后准备一块树莓派或者 ARM 开发板(成本 200-500 元),写一个最简单的字符设备驱动,用dmesg查看输出。记录你的感受:你对内核编译、设备树这些抽象概念感到烦躁,还是很有探索欲?
两周之后,看看你的情绪反应。如果你在 MCU 那边花了一天时间终于靠操作 IO 寄存器点亮了 LED,兴奋得发朋友圈,而 Linux 那边却让你昏昏欲睡,那就选 MCU。反之,如果你对点灯已经麻木,却对printk打印出来的Hello, kernel!津津乐道,那就勇敢地冲 Linux 驱动。
最后别忘了,这两个方向并不是互斥的。一个成熟的嵌入式工程师,往往既懂 MCU 也懂 Linux 驱动。你先选一个作为主攻方向,站稳脚跟后再涉猎另一个,两条腿走路,才能在变化的技术浪潮中走得稳、走得远。
我个人在实际工作中的体会是,驱动开发这个行当,真正值钱的不是你能调用什么 API,而是你对硬件本身的感知力,以及你排查问题的系统性思路。这种能力,不管是在 MCU 寄存器里还是在 Linux 内核源码里,都是相通的。选一个你更有热情的入口,剩下的路,走着走着就宽了。