兆易创新 嵌入式开发 一面:RTOS 任务划分、Flash 与固件内存
- 轮次
- 一面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 自我介绍(2 到 3 分钟)。
- 你对嵌入式开发工程师这个岗位怎么理解?
- 简历上部分项目的开发周期看起来比较短,你怎么看待?
- RTOS 多任务项目中任务如何划分?任务优先级的设计思路是什么?
- RTOS 项目里中断的使用原则是什么?哪些逻辑不适合放在中断上下文?
- 平时项目中常用哪些调试手段?逻辑分析仪的采样频率和通道该怎么选?
- printf 调试会踩哪些坑?有没有遇到过加了打印之后 bug 消失的现象,原理是什么?
- RTOS 任务栈溢出会有什么现象?怎么排查栈溢出?
- 讲一个项目里印象最深的 bug,完整说明现象、定位过程和解决方案。
- 你的项目偏向通信类嵌入式,为什么想来兆易创新做嵌入式开发?
- 多层软件架构的项目,分层思路是什么?多实例隔离是什么意思,解决什么问题?
- 高负载并发场景下出现报文分片丢失,可能有哪些原因,怎么排查修复?
- 资源泄露、变量未初始化、返回值遗漏、深浅拷贝这类代码隐患,如何发现和修复?
- C 语言的全局变量和局部变量可以同名吗?会产生什么效果?工程上有什么编码建议?
- 什么是非易失性存储?NOR Flash 和 NAND Flash 的核心差异是什么?
- BSS 段存放什么内容?data 段和 BSS 段有什么区别?
- FTL 闪存转换层主要承担哪些功能?
- 固件开发里静态内存池与 malloc 动态内存如何选型?动态内存有哪些弊端?
- 什么是内存对齐?嵌入式固件开发中内存不对齐会带来什么风险?
- 为什么选择兆易创新?你如何看待国产芯片的嵌入式方向?
《参考解析》
任务划分按「职责 + 周期」切,优先级按「实时性 + 阻塞行为」定。常见切法是把数据采集、业务处理、通信收发、日志上报拆成独立任务,每个任务的周期和阻塞点尽量单一,避免一个任务里既等信号量又做长耗时计算。优先级从高到低一般是:硬实时采集与中断下半部处理 > 通信协议解析与应答 > 业务状态机 > 日志与界面刷新。优先级不是越高越好,实时任务设得过多会让低优先级任务饿死;能用事件驱动(信号量、消息队列、任务通知)唤醒的就不要用轮询延时,否则时基抖动会吃掉实时性。
中断上下文只做「快进快出」的事:置标志位、搬运少量数据到环形缓冲区、清中断标志、唤醒任务。浮点运算、循环延时、阻塞等待、动态内存申请、打印、以及任何可能拿锁的操作都不能放进中断——一旦在里面等待,中断延迟被拉长,高优先级中断被推迟,轻则丢数据重则死机。协议解析、业务判断这类逻辑放到任务里做,中断只负责把数据交接过去。
「加了 printf 之后 bug 消失」是典型的时序被改变:printf 走串口、耗时不确定、还可能带锁,插入之后打乱了原来的执行节奏,把竞争窗口挪开了,于是复现不了。这类现象恰恰说明问题是时序竞争或临界区保护缺失,而不是 printf 修好了它。正确做法是先用逻辑分析仪或引脚打点做非侵入式观测,定位到具体竞争点,再补临界区或调整优先级。真要靠打印,也得用 ringbuffer + 单独任务输出,避免在关键路径上同步等待。
栈溢出的现象与排查:现象通常是随机 HardFault、变量莫名被改、任务跑飞、偶尔死机,且换编译优化等级或加几行代码后现象变化。排查三步:一是打开 RTOS 的栈高水位统计,看每个任务历史最小剩余栈;二是在任务切换钩子里检查栈指针是否越界,或给栈底填魔数(0xDEADBEEF)周期性检查是否被覆盖;三是代码层面把大局部数组、大结构体挪出栈(改静态或堆),递归改迭代。根因多半是「局部大缓冲 + 深调用链 + 中断嵌套」叠加。
NOR 与 NAND 的差异要落在「能不能当内存用」上:NOR 支持字节级随机读,可以 XIP 直接跑代码,擦写慢、容量小、单价高,适合放固件与启动代码;NAND 按页读写、按块擦除,密度高、单位容量便宜,但不能原地改写、有坏块、需要 ECC,必须靠 FTL 做逻辑地址到物理地址的映射、垃圾回收、磨损均衡和坏块管理,eMMC、UFS、SSD 的介质都是 NAND。答这题时把「谁做地址映射」「谁负责坏块」「为什么 NAND 需要 ECC」串起来讲,比背参数有说服力。
BSS 与 data 的区别本质是「要不要占 Flash」:data 段放显式初始化为非 0 的全局和静态变量,初值存在 Flash 里,启动时拷贝到 RAM;BSS 段放未初始化或初始化为 0 的全局和静态变量,不占 Flash 空间,启动时由启动代码统一清零。所以把大数组写成 static uint8_t buf[4096] = {0}; 与不写初值,在镜像大小上没区别,但写成 = {1} 就会实打实占 4KB Flash。
静态内存池 vs malloc:高可靠固件优先静态内存池或固定块分配器,分配时间可确定、不会碎片化、失败可预期;malloc 的分配耗时与堆状态相关,长期运行会碎片化,极端情况下明明总空闲够却分配失败,还可能因为堆和栈相向增长而越界。动态申请如果非用不可,就限定在初始化阶段一次性申请,运行期不再 free。
内存对齐的风险集中在三处:结构体成员按边界补齐会有 padding,跨平台传输结构体时要显式打包并约定字节序;部分处理器(尤其是 ARM 某些配置和外设 DMA)不支持非对齐访问,会触发 UsageFault 或总线错误;DMA 缓冲区的地址与长度往往要求按 cache line 或 4 字节对齐,否则会出现数据错乱或 cache 一致性问题。__attribute__((packed)) 能省空间,但会让成员访问变成非对齐,驱动层慎用。