360公司嵌入式软件工程师电话技术面试
一、首相让做个人的技术栈介绍? 个人感觉真实展现就可以。 二、其次项目环节问答: 1.1 OTA项目介绍 1、是在NAND flash上还是在NOR flash上实现的? 首先需要我们理解这两种FLASH的区别? 目前Flash主要有两种NOR Flash和NADN Flash 。 接口差别: NOR Flash带有SRAM接口,有足够的地址引脚来寻址,可以直接和CPU相连,CPU可以直接通过地址总线对NOR Flash进行访问,可以很容易地存取其内部的每一个字节。
NAND Flash器件使用复杂的I/O口来串行地存取数据﹐只能通过I/O接口发送命令和地址,对NAND Flash内部数据进行访问。各个产品或厂商的方法可能各不相同。8个引脚用来传送控制、地址和数据信息。NAND Flash读/写操作采用512或2048字节的页。
NOR Flash是并行访问,Nand Flash是串行访问,所以相对来说,前者的速度更快些。
容量和成本
NOR Flash的成本相对高﹐容量相对小,常见的有128KB、256KB、1MB、2MB等;优点是读写数据时,不容易出错。所以在应用领域方面,NOR Flash比较适合应用于存储少量的代码。
NAND Flash的单元尺寸几乎是NOR Flash器件的一半,由于生产过程更为简单﹐也就相应是的数据。。容量比较大,由于价格便宜,更适合存储大量的数据。
因此STM32内部的flash是nor flash ,nand flash是不能直接运行代码的。。本项目是在nor flash上实现的。当时由于闹不清nor flash 和 nand flash 因此直接回答的是nand flash ,还不如直接回答是片上FLASH,败笔。因此,闹不清的概念,不要瞎说,从自己知道的角度回答也是个方法。 2、是属于差分的还是全量的升级? 属于全量的。 3、升级过程中的异常处理----断电的时候,如果正在覆盖的过程中发生了断电,是如何处理异常的? 搬运工作未完成这个异常是已知的,在重新上电后,在bootloader中会判断搬运是否完成了,如果未完成,会先完成搬运。 4、如何保证固件的合法性? 传输前会判断固件包的大小、名称、软件版本号、传输过程中会对每一帧数据进行校验,传输完成后会栈顶地址的值是否是合法的。 关于判断栈顶地址的合法性的理解?
if (((*(__IO uint32_t*)Application_Code_Address) & 0x2FFE0000 ) == 0x20000000)
对上述判断的理解: Application_Code_Address为APP的起始地址,从起始地址开始计算4个字节的值,存放的是栈顶地址的值。 对于主流STM32芯片,SRAM地址范围都是从 0x20000000处开始,128 Kbytes的SRAM 地址范围是 0x2000 0000 --0x2001 FFFF;堆栈指针(SP) 必须在 0x2000 0000 – 0x2001 FFFF 这块Region。因此所以 SP & 0x2FFE 0000 == 0x2000 0000,不去管SP的bit16 - 0,只检查bit27-17。 换句话讲,这句话通过判断栈顶地址值是否正确(是否在0x2000 0000 - 0x 2000 2000之间) 来推断是否应用程序已经下载了,由于应用程序的启动文件刚開始就去初始化化栈空间,假设栈顶值对了,说明应用程序已经下载了,启动文件的初始化也运行了。 对代码跳转这块儿的拓展理解:
JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
ApplicationAddress + 4 即为0x0800 3004 ,里面放的是中断向量表的第二项“复位地址” JumpAddress = (__IO uint32_t) (ApplicationAddress + 4); 因此,得到的JumpAddress 是复位地址。
typedef void (*pFunction)(void);
Jump_To_Application = (pFunction) JumpAddress;
pFunction是类型为void (*)(void) 的函数指针的别名。因此上述语句会使得Jump_To_Application 指向了复位函数所在的地址,因为它被强制类型转换为一个函数指针。
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();
Jump_To_Application()是把用户代码的复位地址付给PC指针,Jump_To_Application()这句代码debug的时候相应的汇编代码是 LDR r0,[pc,#12] ;相对PC的数据载入,去函数指针的地址 LDR r0,[r0,#00] ;R0做索引,无偏移,数据装载到R0,这个内容就是函数指针指向的内容,也就是函数的地址了,用户程序的起始地址; BLX r0 ;跳转
参考链接1 参考链接2
5、通讯协议制定,说一下帧的格式大概是什么样子的?帧头是个什么样的?有没有想过为什要用这种帧头,而不用0x01这种?制定通讯协议有没有遇到过什么问题? 通讯帧的格式主要是:
连续的16个bit数据,0xEB90是出现概率比较低的组合。 需要注意的问题:有助于进行二次开发,可扩展性强。
6、模块复用性强,是如何做到的? 将代码进行上下分层,上层实现和硬件无关的操作,比如下载超时判断、异常处理、数据帧接收处理等等。 下层实现硬件相关的操作,比如串口的初始化、FLASH的操作。 然后在分层的基础之上进行分离,将引脚号、串口号、波特率这些硬件信息资源再次进行一次分离封装。 这样做的好处是,当更换平台或者项目时,只需要更改相应的硬件资源信息,提高了代码的复用性,和开发效率。
7、问了一些岗位JD中比较相关的东西,设计到Camera、触摸屏的工作原理?等 回答的不是很理想。
1.2 xxx项目介绍 这里由于隐私问题,不展示项目名称。 1、起始问题问到项目是做什么的,自己的职责是什么? 当时简历中写的比较清楚了,自己只能又大概说了一遍。 2、各个板子彼此之间有通信吗?是什么通信方式? 3、简历中展现的用到的算法是什么算法? 4、简历中展现的解决的通讯帧错位问题是个什么问题?是如何解决的?
小结
面试官通过面试和简历展现的经历,总结到自己是主要做应用逻辑层偏多,底层驱动不是很多,这个我也做了肯定回答,然后问了下自己的一会技术上的职业规划。 整体下来,面试官给人的感觉很nice,沟通也很流畅。
|