地平线 嵌入式软件开发 二面 面经

最近把地平线 嵌入式软件开发二面的题目总结下了,大家可以参考参考,难度还是有的。

1. 请详细介绍你做过的一个嵌入式项目,从架构设计角度说明整体分层,以及你负责的核心模块。

2. Linux 内核启动流程是怎样的?从 BootLoader 到用户态程序运行,中间经历了哪些关键阶段?

3. 讲一下你对 Linux 内存管理机制的理解:虚拟内存、页表机制、缺页中断是如何工作的?

4. 在多核嵌入式系统中,Cache 一致性问题是如何产生的?硬件与软件层面分别如何解决?

5. 详细讲一下中断机制:从硬件触发到驱动处理的完整流程。上半部和下半部为什么要分离?

6. 如果一个驱动出现偶发性崩溃或内核 panic,你会如何排查?给出完整思路。

7. 解释 spinlock、mutex、semaphore 的底层差异,以及它们在中断上下文中的使用限制。

8. 讲一下 DMA 的完整工作流程,包括缓存一致性处理、内存对齐要求以及常见问题。

9. 设备树在 Linux 驱动中的作用是什么?驱动是如何通过 compatible 字段完成匹配的?

10. 如果一个嵌入式系统出现偶发性重启,你会从哪些维度分析?(硬件、电源、内存、内核、应用)

11. 解释一下 ELF 文件结构,以及程序从编译到运行的全过程(编译、链接、装载)。

12. 请结合实际项目,说明你如何进行系统级调试?使用过哪些工具?如何定位复杂问题?

二面通常会:

  • 更深入追问原理
  • 要求结合真实项目
  • 考察系统架构能力
  • 强调排查思维
  • 关注 Cache / DMA / 中断 / 内核同步
  • 看你是否真正理解底层机制

纯背八股基本不够,需要:

  • 能画流程
  • 能讲原理
  • 能说场景
  • 能结合代码或项目

嵌入式八股文专栏(全网最全面的嵌入式八股文专栏,包含大厂面试题):https://www.nowcoder.com/creation/manager/columnDetail/mPZ4kk

嵌入式八股文准备方法

分四个模块来准备,每个模块有侧重点:

C++ 基础:

  • 重点掌握内存模型(栈堆布局、对象生命周期)、智能指针原理、虚函数表机制、move 语义
  • volatile、const、inline、noexcept 这类关键字在嵌入式场景下的实际含义要能结合硬件说清楚
  • 不要只背语法,要能说出为什么,比如为什么析构函数要是虚函数,为什么 make_shared 更好

Linux 内核与驱动:

  • 内核模块、字符设备驱动、platform driver 框架至少要动手写过一个
  • 中断子系统(上下半部、tasklet、workqueue、threaded irq)、内存管理(虚拟内存、页表、mmap、kmalloc vs vmalloc)是必考方向
  • 设备树要能看懂基本结构,知道 compatible 属性如何匹配驱动,of_get_property 怎么用
  • 同步原语(spinlock、mutex、rwlock、RCU)要知道各自的使用限制,尤其是中断上下文不能睡眠这条规则

RTOS:

  • FreeRTOS 的任务调度、上下文切换、任务状态机要能画出来
  • 优先级反转和优先级继承是必考题,要能说清楚场景和解决方案
  • 信号量、互斥量、消息队列、事件组的区别和适用场景
  • 内存管理的五种 heap 方案(heap1~heap5)要了解基本差异

硬件接口与调试:

  • I2C、SPI、UART、CAN 的协议特点、时序、适用场景要熟
  • DMA 的工作原理、Cache 一致性问题(flush/invalidate 的时机)是嵌入式特有的高频考点
  • 调试工具:GDB + OpenOCD、逻辑分析仪、示波器的基本使用场景要能说
  • 偶发性 bug 的排查思路(看门狗复位原因、内存踩踏、栈溢出检测)要有系统性的方法论

备考节奏建议:先把 C++ 和 Linux 内核两块打扎实,这是所有嵌入式岗的基础盘,再根据目标公司偏 Linux 还是偏 MCU 决定 RTOS 和驱动的深度。地平线偏 Linux 和 SoC,FreeRTOS 了解即可,Linux 驱动和内

全部评论
好难😌
点赞 回复 分享
发布于 昨天 00:00 广东

相关推荐

前言 在之前推出的项目中,有很多粉丝私信我,到底什么是bootloader?什么是APP?是手机APP那种吗?有什么用?解决什么问题等等。因此,笔者再发一次详细版。1.为什么要用固件升级功能?我尽量一句话说清楚:目的就是为了产品发布以后想要对产品中的固件程序进行更新,那就需要重新烧录程序,但是产品一般都封装完好,不能拆开进行烧录调试,此时就需要IAP通过预留的通信接口(包括但不仅限于串口、IIC、SPI、CAN等通信方式),将所要更新的程序传入设备,以达到快速更新程序。比如汽车的OTA更新,如果不用OTA更新,只能去线下把汽车拆开再烧程序了,非常麻烦。其中,IAP全称是In Application Programing,即在程序中编程,意思就是说把需要更新的程序传入原来的程序中,原来的程序接收到了更新程序,就跳转到更新程序去执行。2 .什么是bootloader和APP程序(高频考点)?Bootloader叫做引导加载程序。在嵌入式系统上电复位后首先运行引导加载程序,它的功能主要是负责系统的上电自检、必要的硬件初始化、建立储存空间映射,并加载和启动操作系统。Bootloader一般储存在bootROM中,当前使用最多的类型是NOR flash rom,在大多数的嵌入式系统中,flash里边不仅储存了bootloader,还储存了用户程序代码。Bootloader有两种工作模式,一种是启动加载模式,另一种是下载模式;而提到的固件升级就属于bootloader的下载模式。比如博主的整个烟机项目就是一个巨大的bootloader程序,因为它能接收固件并进行跳转执行。3.为什么不做一个只有更新功能的bootloader,非要在bootloader里边实现如此多的功能呢?因为在产品中固件更新功能只是为了以防万一,有需要更新的时候才进行更新,不需要更新的时候用原来的功能就够了。接下来说一下什么是APP程序。APP指的就是需要传输的更新固件,不是手机APP,通常以.bin文件形式发送。又有粉丝问,那为什么要用bin文件,而不用hex文件呢?因为hex文件是包含地址信息的ASCII文本文件,可直接用于烧录;bin文件是纯二进制数据文件,不含地址信息,烧录时需要指定起始地址。刚好APP区域的划分是由我们自行划分的,起始地址只能自己指定,APP程序自然是要烧录到APP区域执行,因此需要未指定起始地址的bin文件。4. 固件升级的工作原理是什么?固件升级的工作原理实际上就是:先将整个Flash划分成boot区和APP区(前提为flash升级),boot区专门用于执行bootloader,APP区专门执行APP程序;然后将bootloader烧录到boot区,接下来通过上位机传入固件,此时bootloader接收固件并跳转到APP区域执行固件。上述这段话是一个总结,接下来从STM32的上电启动流程、bootloader到底干了什么以及APP程序如何跳转三个层面来进行具体分析。(1)STM32上电启动流程(以下是高频考点)当STM32发生复位时,此时硬件会强制PC寄存器指向一个固定地址0X00000000(或者是由boot引脚映射的0x08000000),该地址存放的是主堆栈指针(MSP)的初始值,内核会读取该值并进行堆栈初始化,以创建好C环境以及安全调用中断服务函数。其次,PC寄存器会执行到0x00000004地址,取出该地址存放的复位中断处理函数,并跳转过去执行;在复位函数中,首先完成系统时钟的初始化,其次调用__main函数,完成数据的初始化,如将Flash中的data段数据拷贝到RAM中,然后将未初始化的全局变量(bss段)清零。最后,__main函数调用main函数,进入到main函数执行。(2)bootloader程序在固件升级中到底干了什么?一句话说清楚这个问题。实际上,在固件升级功能中,bootloader就干了三件事情:1、接收上位机传输的固件保存到RAM中;2、将RAM上的固件拷贝到Flash;3、跳转到APP执行。(3)APP程序怎么跳转的?跳转APP程序操作实际上就一行代码--调用jump2app()。那为什么调用这个函数就行了呢?答案是jump2app是一个函数指针,直白点,它就是一个地址0x00000004+M(M是偏移量,或者说是boot区与APP区的分界线);这个地址看起来很熟悉对吧?因为才在上电启动流程里边见过,不同的是多了一个M,这代表的意思是在APP区里重新创建了一个新的中断向量表(依然0x00000000+M存放堆栈指针MSP、0x00000004+M存放复位向量)。理解了这行地址代表的含义之后,我们再来看jump2app()的含义。这实际上就是取地址操作(这里我不多解释了,如果你不明白,说明你C语言基础还要补),而这个地址里存放的是APP区的复位向量。因此,此处代表的意思就是取出复位向量并跳转执行,也就是执行到了APP区的复位中断服务函数中,然后再次执行系统时钟的初始化、调用__main函数初始化数据,最后调用APP的main函数执行。到此处,开始执行APP程序的main函数功能,跳转APP程序执行成功。
点赞 评论 收藏
分享
评论
点赞
4
分享

创作者周榜

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