荣耀嵌入式软件二面 面经

二面和一面相比完全不是一个量级,一面还算是考察基础知识,二面更像是在和你讨论技术方案,每个问题都有大量追问,而且他会故意提出反驳意见看你怎么应对。项目聊了将近四十分钟,他把我项目里的每个技术决策都问了一遍为什么,有几次我答不上来被他直接指出设计上的问题。

1. 讲一下 FreeRTOS 的任务状态机,每种状态之间的转换条件是什么,阻塞状态和挂起状态有什么本质区别?

答:FreeRTOS 的任务有五种状态:运行、就绪、阻塞、挂起、删除。

运行状态是任务正在占用 CPU 执行,单核系统里同一时刻只有一个任务处于运行状态。

就绪状态是任务具备运行条件,等待调度器分配 CPU。所有就绪任务按优先级排在就绪列表里,调度器每次选优先级最高的就绪任务运行。

阻塞状态是任务在等待某个事件发生,比如等待信号量、等待队列有数据、等待延时到期。处于阻塞状态的任务不占用 CPU,调度器不会选它运行。阻塞有超时机制,等待时可以指定最长等待时间,超时后任务自动回到就绪状态。

挂起状态是通过 vTaskSuspend 显式挂起的任务,和阻塞状态的本质区别是:阻塞状态有明确的唤醒条件,事件发生或超时后会自动恢复;挂起状态没有唤醒条件,必须由其他任务或中断调用 vTaskResume 才能恢复,不会自动唤醒。挂起状态通常用于调试或者需要暂停某个任务的场景。

删除状态是任务调用 vTaskDelete 后进入的状态,任务的栈和 TCB 等待空闲任务回收,空闲任务会定期清理已删除任务的资源。

状态转换:就绪→运行是调度器选中;运行→就绪是被高优先级任务抢占或时间片用完;运行→阻塞是等待事件;阻塞→就绪是事件发生或超时;运行/就绪→挂起是被显式挂起;挂起→就绪是被显式恢复。

2. 互斥锁的优先级继承是怎么实现的,有没有它解决不了的场景?

答:优先级继承的实现原理:当高优先级任务尝试获取一个已被低优先级任务持有的互斥锁时,FreeRTOS 会临时把低优先级任务的优先级提升到和高优先级任务一样,让它尽快执行完临界区并释放锁。低优先级任务释放锁之后,优先级恢复到原来的值。这个过程由互斥锁的获取和释放函数内部自动处理,不需要用户干预。

在 FreeRTOS 的实现里,互斥锁的 TCB 里记录了持有者,获取失败时检查持有者的优先级,如果低于当前任务就提升它的优先级,同时把当前任务加入等待列表。释放时恢复持有者的原始优先级,唤醒等待列表里优先级最高的任务。

优先级继承解决不了的场景:

第一是链式优先级反转。任务 A 持有锁1,任务 B 持有锁2 等待锁1,任务 C 等待锁2。优先级继承只能处理直接的持有者,链式场景需要递归地传播优先级提升,FreeRTOS 的实现不支持递归传播,这种场景下优先级反转仍然存在。

第二是多锁场景。一个任务同时持有多个锁,另一个高优先级任务等待其中一个,优先级继承会提升持有者的优先级,但如果持有者还在等待另一个锁,情况会变得复杂,可能出现死锁。

第三是优先级继承本身不能防止死锁,只能缓解优先级反转。如果两个任务互相等待对方持有的锁,优先级继承无法解决,还是会死锁。

3. 你了解 tickless idle 模式吗,它是怎么实现低功耗的,有什么代价?

答:正常情况下 FreeRTOS 的 SysTick 每个 tick 都会产生中断,即使系统里所有任务都在阻塞等待,CPU 也会被 SysTick 定期唤醒,无法进入深度睡眠。

tickless idle 模式的思路是:当所有任务都处于阻塞状态时,调度器计算出最近一个任务会在多久后唤醒,然后关闭 SysTick,让 CPU 进入低功耗睡眠模式,同时用一个低功耗定时器(比如 RTC 或者 LPTIM)在那个时间点唤醒 CPU。CPU 醒来后根据实际睡眠时长补偿系统 tick 计数,然后恢复 SysTick,继续正常调度。

实现上,FreeRTOS 提供了 vPortSuppressTicksAndSleep 这个弱函数接口,用户根据具体芯片实现低功耗进入和退出的逻辑,FreeRTOS 在空闲任务里调用它。

代价有几个方面。首先是实现复杂,需要根据具体芯片配置低功耗定时器,处理各种唤醒源,不同芯片差异很大。其次是 tick 补偿有误差,睡眠期间如果有外部中断提前唤醒,补偿的 tick 数可能不精确,对时间精度要求高的场景需要额外处理。另外进入和退出低功耗模式本身有时间开销,如果任务频繁切换,这个开销可能抵消省电效果,tickless 更适合任务间隔较长的场景。

4. 讲一下 ARM Cortex-M 的异常处理机制,HardFault 发生时 CPU 做了什么,怎么从 HardFault 里获取有用的调试信息?

答:异常处理机制:Cortex-M 有一套固定的异常处理流程。异常发生时,如果当前优先级允许响应,CPU 完成当前指令后进入异常入栈流程,自动把 xPSR、PC、LR、R12、R0-R3 这八个寄存器压入当前使用的栈(MSP 或 PSP,取决于当前模式),然后从向量表取出对应的处理函数地址,跳转执行。异常处理函数返回时,CPU 从栈里弹出这八个寄存器,恢复到被打断的状态继续执行。

HardFault 是一个兜底异常,当其他异常(MemManage、BusFault、UsageFault)没有使能或者在处理过程中又发生了错误,都会升级为 HardFault。常见触发原因有访问非法地址、执行非法指令、除零、未对齐访问(在某些配置下)。

从 HardFault 获取调试信息的方法:

HardFault 发生时,CPU 已经把出错时的寄存器压栈了,关键是找到这个栈帧。在 HardFault_Handler 里,通过读取 LR 寄存器的值判断出错时用的是 MSP 还是 PSP,然后读取对应的栈指针,从栈帧里取出 PC 值,这个 PC 就是出错时正在执行的指令地址。

拿到 PC 之后,在 map 文件里查找这个地址对应的函数和行号,就能定位到出错位置。

另外 SCB 里有几个状态寄存器提供更多信息:CFSR(Configurable Fault Status Register)记录了具体的错误类型,BFAR 记录了导致 BusFault 的访问地址,MMFAR 记录了导致 MemManage fault 的地址。把这些信息打印出来对定位问题很有帮助。

如果有调试器,直接在 HardFault_Handler 里打断点,查看 Call Stack 窗口,IDE 通常能自动解析栈帧显示出错位置。

5. 讲一下 Flash 的写入原理,为什么 Flash 只能写 0 不能写 1,擦除和写入的关系是什么?

答:Flash 的存储单元是浮栅晶体管,浮栅是一个被绝缘层包围的导体,通过控制浮栅上的电

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

嵌入式面试八股文全集 文章被收录于专栏

这是一个全面的嵌入式面试专栏。主要内容将包括:操作系统(进程管理、内存管理、文件系统等)、嵌入式系统(启动流程、驱动开发、中断管理等)、网络通信(TCP/IP协议栈、Socket编程等)、开发工具(交叉编译、调试工具等)以及实际项目经验分享。专栏将采用理论结合实践的方式,每个知识点都会附带相关的面试真题和答案解析。

全部评论
佬请问荣耀社招会有机考吗
点赞 回复 分享
发布于 04-04 17:02 陕西
这个必须付钱看吗,有免费的吗
点赞 回复 分享
发布于 03-29 18:10 陕西

相关推荐

开场: 1、自我介绍研究方向:2、介绍下你的研究方向这块实习:3、实习做了哪些工作4、系统的数据来源5、系统这些数据量大不大,用什么存储的6、慢查询排查优化完整流程讲一下7、这块MySQL的数据量大吗,怎么样的8、Caffeine参数怎么设置的9、Caffeine命中率统计过吗10、如何保证Caffeine命中率11、Redisson分布式锁解决缓存击穿是什么样的场景12、没拿到Redisson分布式锁的线程直接返回吗13、Caffeine + Redis + 数据库的三级缓存会出现缓存击穿吗,怎么解决项目:AI项目14、这是开源的还是你们真实存在的,介绍下15、召回率准确率有测量吗点评16、这个是开源项目吗17、介绍下你做了哪些优化18、滑动窗口限流用的Redis哪个数据结构19、这里面key这些怎么设置的20、滑动窗口和请求数设的多少21、那如果很高并发请求,这块还可行吗,怎么办22、做过压力测试吗23、Redis 是单体的吗还是24、Lua 脚本里redis key怎么构成的八股:25、常见限流算法还知道哪些,讲一下26、Lua脚本能保证原子性吗27、Kafka rebalance场景说一下28、Kafka 分区数与消费者组消费者数这里的关系讲一下29、Kafka 重复消费怎么解决30、Kafka 消费堆积怎么解决31、线程和进程的区别32、InnoDB默认隔离级别是,解决了哪些问题,怎么解决幻读的33、事务四大特性34、Spring 怎么解决Bean对象循环依赖的35、ArrayList是线程安全的吗,List里面有哪些是线程安全的36、ConcurrentHashMap如何保证线程安全的37、final关键字的作用38、synchronized 和 ReentrantLock 区别39、垃圾回收了解吗40、OOM如何排查优化,了解过吗41、实际用过MAT吗42、Redis有哪些数据结构43、Redis底层用了哪些数据结构44、Redis过期删除策略和内存淘汰策略
点赞 评论 收藏
分享
时间线: 4.7投递4.13测评4.16一面4.22二面4.25主页显示挂了面试整体流程就是先提前进入荣耀给你发的邮件的链接,上面有个排队人数,这时候等就可以了。等到你了会给你发会议编号的手机短信,把编号填上去就可以直接见到面试官了。一面,全程拷打项目,八股就问了两三个很简单的:1.自我介绍2.定时任务的数据库表的组成是怎样的?每个表有哪些字段?3.定时项目这里面如果任务在某一环投递失败了怎么办 ?4.你觉得你的项目还有哪些可以提升的地方?(这个问题连问了我三次)5.Java内存结构了解吗?6.redis zset 的底层结构?跳表为什么这么快?查询的过程是怎样的?7.你平时都用哪些ai工具?用的过程有遇到哪些问题?ps:还有一些问题忘记了,主要是面试前有点紧张,忘录音了。但基本上都是在问项目,ai相关的好像一个没问。二面,全程33分钟左右,都是一些开放性的问题:1.在 AI 冲击下,为何仍选择投身软件开发行业?2.你对这个荣耀实习岗位的理解是什么?3.是否有认识的学长在荣耀工作?4.分享一个你引以为傲的经历。这段经历中你认为自己做得好的地方有哪些?5.日常使用哪些 AI 开发工具?6.是否关注 AI 工具的 token 消耗?如何经济地使用?7.你这个项目是独立完成还是团队协作?8.你在其中的角色是什么?9.你在项目中产生的独特价值是什么?10.你对荣耀公司及其岗位有何了解?11.是什么吸引你报名荣耀的岗位?12.使用过哪些具体荣耀产品?13.请简要介绍你的家庭和个人情况。14.目前是否有恋爱关系?15.对未来工作地点有何期望?16.未来更倾向从事哪个领域的软件开发?互联网、金融还是制造业?17.你有什么想了解的问题吗?总结:整体下来一二面的体验还不错,面试官都挺和蔼的,特别是二面的面试官感觉他说的比我还多。虽然最后挂了,但收获也蛮多的,再接再厉吧💪
查看23道真题和解析
点赞 评论 收藏
分享
评论
1
9
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务