面灵AI→

嵌入式大厂面试 100+ 场总结:高频题单与「把一条链路讲到边界」的答法

时间
2026-10
来源
牛客网

《面试题目》

一、C / 内存 / 启动

  1. volatile 能解决什么,不能解决什么?
  2. static / const 在嵌入式里各举一个真实场景。
  3. 指针和数组的本质区别,sizeof 为什么不同?
  4. 结构体内存对齐规则是什么,协议场景有什么坑?
  5. 大小端怎么判断,什么时候必须显式转换?
  6. 栈溢出常见表现有哪些,如何定位?
  7. .text / .data / .bss 各放什么,上电后谁负责初始化?
  8. 链接脚本在 MCU 工程里解决什么问题?

二、中断 / RTOS

  1. 中断上下文和任务上下文有什么区别?
  2. 为什么 ISR 里一般不做耗时操作?
  3. 临界区是什么?关中断、关调度、互斥锁如何选型?
  4. 任务切换的本质是什么?
  5. 什么是优先级反转,常见怎么解决?
  6. 队列、信号量、互斥锁分别适合什么场景?
  7. 哪些 RTOS API 能在中断里调用?调错会怎样?
  8. 任务栈怎么估算,水位怎么看?

三、总线 / DMA / 排障

  1. UART / SPI / I2C 核心区别和选型依据?
  2. I2C 出现 NACK 或总线挂死,你怎么处理?
  3. DMA 相对中断传输的优缺点是什么?
  4. 什么时候必须考虑 Cache 一致性?
  5. CAN 为什么适合车载,终端电阻起什么作用?
  6. 一次「通信偶发失败」,你的标准排查顺序是什么?

四、Bootloader / OTA / 可靠性

  1. MCU 从上电复位到 APP 运行,关键阶段有哪些?
  2. Bootloader 跳转 APP 要注意哪些点?
  3. Flash 分区一般怎么划分?
  4. OTA 过程断电怎么办?
  5. A/B 分区和单分区回滚各解决什么问题?
  6. 看门狗怎么设计才算「健康才喂」?
  7. 参数区掉电保护你怎么做?

五、Linux / 驱动 / 视觉

  1. 用户态和内核态的核心区别是什么?
  2. 字符设备驱动基本框架是什么?
  3. 设备树解决了什么问题,如何对应到 probe?
  4. 中断上半部和下半部如何分工?
  5. 摄像头不出图,你从哪一层开始查?
  6. V4L2 取流链路大致怎么走?

六、项目与综合

  1. 介绍你最有含金量的项目,并说明你个人的职责边界。
  2. 项目里最难的一个 bug,完整讲定位链。
  3. 为什么这里用消息队列而不是全局变量?
  4. 如果系统要保证 10ms 周期任务,你会如何设计和验证?
  5. 如果重新做这个模块,你会改哪三处?

《参考解析》

volatile 的边界。 它告诉编译器「这个对象可能被程序之外改变」,禁止把它缓存到寄存器、禁止删除看似冗余的读写,用于寄存器映射、ISR 与主循环共享的标志、多任务共享的简单变量。它不提供原子性、不保证内存序、不解决竞态——volatile int flag 保护不了一个需要「读-改-写」的计数器,那要用关中断、原子指令或互斥。答到这里再补一个现场:调试时去掉 volatile 后开 -O2 循环卡死,就是编译器把标志读提到循环外了。

ISR 里为什么不能做耗时操作。 中断会打断正常调度,ISR 执行越久,中断延迟越大,同优先级与更低优先级的任务都被推迟,实时性直接崩;同时 ISR 通常不能睡眠、不能拿可能阻塞的互斥锁,容易造成优先级反转或死锁。正确做法是 ISR 只做「清标志、读数据、投递队列/信号量」,协议解析、日志、业务处理放到任务里。反过来还要注意 FromISR 版本 API 与不能在 ISR 里调用的接口。

临界区选型。 关中断适合极短、且必须防住 ISR 的临界区(几个指令周期);关调度(挂起调度器)适合防任务间切换但仍允许中断;互斥锁适合可能较长的临界区、且持锁者会睡眠的场景,但绝不能在 ISR 里用。选择依据是「谁可能并发访问」和「临界区多长」,不是习惯。

优先级反转。 低优先级任务持锁、高优先级任务等锁、中优先级任务抢 CPU,导致高优先级被中优先级拖住。解法是优先级继承(持锁者临时提升到等待者的优先级)或优先级天花板(持锁即升到该锁可能涉及的最高优先级);设计上还要避免长临界区和嵌套锁。经典案例就是火星探路者号的重启故障。

I2C 挂死恢复。 NACK 先分清是地址错、从设备忙还是根本没接;总线挂死(某设备把 SDA 拉低不放)的标准恢复是:把 SCL 当普通 GPIO 手动打 9 个以上时钟,直到 SDA 释放,再发 STOP;仍不释放就复位该外设或整条总线电源。工程上要加超时、重试上限与总线恢复函数,并在驱动层记录错误计数——「偶发失败」的定位往往就靠这些计数。

DMA 与 Cache 一致性。 DMA 绕过 CPU 直接读写内存,若 CPU 侧有 D-Cache,就可能读到 DMA 写入前的旧数据(或 DMA 读到还在 Cache 里没落盘的新数据)。有 Cache 的 SoC 上必须在传输前后做 cache invalidate / clean(或把缓冲放到非缓存区),并按 cache line 对齐、避免同一行里混放 DMA 与非 DMA 数据。MCU 上多数没有 D-Cache,这个问题不出现,但一旦上 Cortex-A 或带 Cache 的 M7,就是必答项。

通信偶发失败的标准排查顺序。 先分层定位:软件层看错误码与超时计数、驱动层看寄存器状态与中断计数、物理层用逻辑分析仪/示波器看波形与时序。然后按「电源与地 → 上拉与终端电阻 → 时钟与速率 → 线序与干扰 → 从设备状态」逐项排除,最后才怀疑协议实现。能否说出「我先看哪个计数、用什么工具、怎么复现」是这道题的分水岭。

Bootloader 跳转 APP。 关中断、确认 APP 分区校验通过、设置主栈指针(MSP)为 APP 向量表的第一个字、把复位向量写入 PC 跳转;跳转前要复位外设(尤其 SysTick、NVIC、DMA),否则中断还挂在 Bootloader 的向量表上;APP 的链接地址与向量表偏移(VTOR)必须和分区一致。做不到这些的典型现象是「跳过去跑飞」或「进不了中断」。

OTA 断电与回滚。 关键是把「升级」做成事务:新固件先完整写入备用分区并做 CRC/签名校验,校验通过才改「启动标志」,Bootloader 启动时按标志选分区;升级中掉电,标志未改就仍从旧分区启动(A/B 的核心价值);单分区方案则要保留可回滚的旧镜像或至少保留 bootloader 与恢复模式。升级失败要能自动回滚并上报,版本号与回滚次数写进持久化区,避免「反复回滚死循环」。

看门狗「健康才喂」。 喂狗必须由「所有关键任务都还活着」这个条件驱动:各任务定期置位自己的标志,看门狗任务检查全部标志后才喂并统一清零;某个任务卡死,标志不来,看门狗复位。只在主循环里无脑喂狗等于没有看门狗。再补一条:复位后要把复位原因记录下来,否则现场永远查不清是谁把它喂挂的。

10ms 周期任务怎么设计与验证。 设计侧:用硬件定时器中断或 RTOS 的周期定时器做时基,任务优先级要高于非实时任务,执行时间必须显著小于周期(留足余量),把耗时操作拆出去或放到低优先级任务,共享数据用无锁队列或短临界区,避免动态内存分配与阻塞调用。验证侧:用示波器/逻辑分析仪打 GPIO 翻转测周期抖动,统计最坏执行时间(WCET)与超时次数,做长时间跑机与压力注入(中断风暴、总线拥塞),并给出「抖动 P99 是多少」这样的数字——「我测过」比「应该没问题」有说服力。

不同公司的侧重。 消费电子(OPPO/vivo/小米)问功耗、稳定性、内存与异常收敛;安防通信(海康/大华/中兴)偏 Linux、进程线程与 IPC、网络与性能排障;强实时/飞控影像(大疆)抠周期、抖动、DMA、队列满与中断预算;工控吃通信可靠性与长时间跑机;车企/Tier1 几乎必问 CAN/CAN FD、诊断、Boot/OTA 回滚与 ECU 复位恢复;摄像头岗会从「模组能不能出图」一路挖到 I2C 初始化、MIPI、DMA、丢帧与花屏。同一道题在不同公司要给的落点不一样。

项目怎么讲才经得起挖。 每个主力项目准备三分钟版与十分钟版,外加「一个最难 bug 的完整定位链」和「一条失败路径(超时、重试、降级、安全态、日志)」。高分口述的结构是:结论一句 → 机制两句 → 我项目里怎么用 → 出问题怎么查 → 边界是什么。相反,只背定义、只能演示 happy path、简历写「负责整体」而细节全是队友做的,是二面最常见的淘汰原因。