嵌入式大厂面经汇总:从上百场面试看筛选主线与高频题
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
面试官从简历直接追问
- 项目里用了 FreeRTOS,互斥量和二值信号量怎么选?
- 你写过驱动,probe 失败你先看什么?
- 中断上半部为什么要短?为什么有些工作要放到线程化中断?
- DMA 开了 D-Cache 之后,数据为什么偶发错?
C / 内存 / 并发
- volatile 解决什么问题?解决不了什么问题?
- 内存屏障在嵌入式里常见使用场景是什么?
- 栈、堆、.bss、.data、只读段分别放什么?越界会怎样表现?
- 结构体内存对齐如何影响协议解析?
- 中断和主循环同时访问共享变量,最小正确做法是什么?
- 为什么「关中断」不能当成万能临界区方案?
- DMA 传输时 D-Cache 开启,如何保证一致性?
- 野指针、悬空指针、内存泄漏在嵌入式里分别怎么暴露?
RTOS / MCU
- 抢占式调度和时间片轮转如何配合?
- Cortex-M 上 SysTick 和 PendSV 在任务切换里各自做什么?
- 任务栈大小如何估算?栈溢出如何检测?
- 互斥量、二值信号量、计数信号量、队列分别适合什么?
- 优先级反转如何形成?优先级继承如何缓解?
- ISR 里哪些操作不该做?如何把工作推迟到任务?
- 任务「卡住」时,如何区分死锁、优先级反转、栈溢出、中断丢失?
- FreeRTOS 常见堆实现(heap_1~heap_5)选型依据是什么?
- MCU 复位到 main 之前发生了什么?向量表如何组织?
- HardFault 现场如何抓?如何从 LR/CFSR/栈帧反推原因?
- 看门狗该怎么喂?哪些场景必须独立喂狗策略?
- 低功耗休眠与外设时钟门控,唤醒后要恢复哪些状态?
通信 / 驱动 / 外设
- UART 丢字节常见原因有哪些?如何系统性排查?
- SPI 模式(CPOL/CPHA)配错时,现象通常是什么?
- I2C 出现 NACK、总线挂死,驱动层你会怎么处理?
- CAN 仲裁失败和错误帧风暴,软件侧能做什么?
- 中断驱动和 DMA 驱动如何选型?各自坑点是什么?
- 环形缓冲区在生产者-消费者模型里如何做无锁或少锁?
- 粘包、半包、重传、超时在应用层协议里怎么设计?
《参考解析》
大厂嵌入式面在筛什么。 把上百场技术面交叉看下来,题库看起来很散,筛选标准却高度一致:能不能解释真实 bug 而不只是说「指针要注意」;中断、并发、RTOS 的边界说不说得清;启动、链接、设备树、驱动模型、用户态交互有没有整体图;协议与外设问的是异常、容错、吞吐与实时性的取舍,而不是画时序图;项目能不能扛住十五分钟追问。反过来,只会调库、拿 CubeMX 生成的 demo 当项目、八股能背但一问「为什么这样设计、出问题怎么查」就空的人,基本过不了二面强度的追问。不同公司侧重不同(偏协议落地、偏 RTOS 底层、偏 Linux 驱动 BSP、偏系统软件与 C++),但主线不会变:公司决定侧重点,主线决定能不能过。
volatile、Cache 与 DMA 一致性这条线最容易翻车。 volatile 保证的是「每次访问都真的去内存」,它既不保证原子性,也不提供内存屏障,更不解决多核或 DMA 的 Cache 一致性。所以「我加了 volatile 还是偶现错」是标准追问:DMA 写入的内存如果落在 D-Cache 里,CPU 读到的可能是旧副本——正确做法是发送前 clean、接收后 invalidate,或者把 DMA 缓冲区放到 non-cacheable 区域,并在传输完成中断里按屏障顺序再读。内存屏障常见于自旋锁实现、环形缓冲区读写指针的发布、以及中断与主循环之间的「先写数据后置标志」。结构体对齐导致的协议解析错误同样高频:结构体默认按最大成员对齐并插入填充,直接 memcpy 到结构体上按字节解析字段必然错位,正确做法是按字节流逐字段解析或用 __packed 并显式处理端序。
RTOS 考的不是会建任务,而是知道边界。 抢占式调度保证高优先级任务就绪即切换,同优先级之间才用时间片轮转;Cortex-M 上 SysTick 只负责产生节拍与到期检查,真正的上下文切换由 PendSV 在最低优先级执行,保证切换不会打断正在处理的异常。优先级反转的形成是三任务模型:低优先级持锁、高优先级等锁、中优先级把低优先级挤开,高优先级被中优先级「间接阻塞」——解决办法是优先级继承(持锁者临时提到等待者里最高优先级)或优先级天花板,FreeRTOS 的互斥量默认带继承,二值信号量不带。互斥量有所有权(谁能给、支持继承、不能在 ISR 里给),二值信号量没有所有权(适合 ISR 到任务的同步),计数信号量管资源计数,队列管数据传递。任务卡住的四类原因要能靠证据区分:看栈高水位和 vTaskList 判断栈溢出、看是否所有任务都阻塞判断死锁、看中断计数是否还在涨判断中断丢失、看持锁任务的优先级是否被抬升判断反转。ISR 里原则是「只做最短的确定性动作」:不能阻塞、不能拿互斥量、不能做浮点与动态内存,把重活通过队列或任务通知推迟到任务里。
通信协议的分水岭在异常设计。 UART 丢字节按层排查:波特率误差与时钟源、中断优先级与关中断时长、DMA 与 IDLE 标志清除顺序、接收缓冲区溢出,一层层用计数器和示波器定位。SPI 的 CPOL/CPHA 配错表现为整体移位或全 0/全 FF。I2C 遇到 NACK 要区分「地址无应答」和「数据无应答」,总线挂死要能硬件复位或发时钟脉冲解救,并做重试与降级。CAN 的仲裁失败是设计内行为,错误帧风暴则要看错误计数与节点收发器,软件侧能做的是限速、隔离故障节点、必要时总线关闭后按策略恢复。中断驱动与 DMA 驱动的选型看数据量与实时性:高频小包用中断,长块传输用 DMA,代价是 DMA 的长度对齐、Cache 一致性与完成通知都要自己管。环形缓冲区在小数据量、单生产者单消费者场景下用「原子写指针 + 屏障」就能做到少锁;生产者多或数据大,老老实实加锁更稳。
Linux 驱动这条线的答法是「缩小范围」,不是背 API。 问到 probe 失败先看什么,正确顺序是:启动 log 里驱动有没有匹配上(compatible 与设备树是否一致)、时钟、regulator、复位、pinmux 有没有拿到、-EPROBE_DEFER 是否因为依赖设备还没就绪、最后才是硬件与器件地址。中断上半部要短是因为它运行时本级中断被屏蔽、不能睡眠;把可睡眠或耗时的工作放到线程化中断或 workqueue,才能拿锁、能被调度、不拉高系统延迟。面试官真正想确认的是你有没有一条从现象回到原因的排查路径。
项目深挖是最稳定的分水岭。 通过率高的人手里通常有一个能讲十五分钟的项目,结构是:背景与指标(延迟、带宽、功耗、稳定性和误码率)、你的职责边界、关键设计与取舍、至少一个完整故障闭环(现象 → 假设 → 证据 → 修复 → 回归)、结果可验证(日志、波形、压测与长稳数据)。面经里反复出现的血泪点几乎都是项目被问穿:DMA 说不清 Cache、驱动说不清 probe、RTOS 说不清优先级、稳定性说不清偶现死机定位。时间有限时的准备顺序建议是:先修一条主线(MCU/RTOS 或 Linux/驱动二选一做深,另一条保持能对话),再打穿 C 基础与调试并准备三类排障故事,然后只深挖一个能扛追问的项目,最后按目标公司补侧重点。先背三百道题、项目还是糊的,是绝大多数人的做法,也是最容易在二面被逆转的做法。