Hello World

Hello World

H_Haozi Lv3

简单记录一下大家的面试内容

查漏补缺——————

龙晶石半导体 嵌入式软件 2025/9/28 2:30 LZ

  1. static的用法
  2. const的用法
  3. 介绍一下 STM32 的 .s 启动文件
  4. 介绍一下 STM32 的 .ld 文件
  5. 堆和栈的区别
  6. 获取内存数据类型字节数的方式
  7. 假设项目中 flash 过大,有初始化值为 0 的变量,删掉可以减少体积吗?
  8. SPI(什么时候读取数据,怎么设置)
  9. 介绍串口和 DMA 联合使用
  10. 串口和 DMA 实现接收可变长数据(并非有规定的协议)
  11. Mutex 和优先级继承
  12. 设备树的作用
  13. 字符设备在用户空间实现数据交换怎么实现(0 拷贝)
  14. 反问

哈罗普惠 嵌入式测试 2025/10/21 2:00 LZ

其实不要本科生–


统信软件 Linux-内核-操作系统 2025/10/21 2:00 LZ

全是内核知识,需要阅读源码才能有机会


齐昕科技 MCU底层固件-嵌入式 2025/10/30 2:45 CLH

面了24分钟,主要全问的是有关25年电赛的问题,从前期准备,到分工,再到具体实现逻辑和方案,以及遇到的问题


简单记录一下面试的时候可能会问的问题


Q1 有关GT911的屏幕驱动你是如何编写的,过程和遇到的问题?

首先gt911是IIC驱动的屏幕,所以我选择使用IIC的框架进行编写,同时考虑通过中断要上报坐标信息,所以需要Input子系统和中断申请,对于使用的IIC引脚中断引脚(上升沿触发)和复位引脚进行初始化

第一步是通过屏幕的数据手册以及板子的手册,查询对应的引脚以及初始化的时序和读取地址等,然后修改设备树:
主要需要设置引脚模式,电气属性,设置IIC配置的引脚和中断(上升沿触发)的相关配置(同时要屏蔽使用相同引脚的结点)

通过手册确认Gt911的IIC的总线编号和设备地址,中断引脚,复位引脚
确认IIC控制器的节点
添加GT911为IIC控制器的子节点
通过设置compatible 用于驱动匹配
设置reg 设置IIC地址
中断属性 指定引脚,同时配置为上升沿触发
复位引脚的GPIO定义
注意若这些引脚被其他模块占用,需要先屏蔽相关节点

第二步是编写驱动,首先注册一个IIC驱动,然后编写IIC驱动结构体,主要是probe和remove函数以及IIC的匹配表,通过IIC的匹配表查询对应的设备树节点吗,获取对应的引脚信息;
然后再probe函数里面对GPIO对中断引脚和复位引脚进行注册与初始化–通过一个固定的时序(ret int拉低 int拉高)进行初始化选择IIC的通讯地址,然后注册初始化IIC的设备,发送复位的指令进行软复位–然后注册INPUT触摸屏(还有初始化MT槽),注册初始化中断,然后当触发中断之后在中断的函数中进处理接收到的数据

解析设备树 获取IIC客户端 中断号 复位 GOIO等引脚资源
配置复位和中断引脚为输出模式,执行复位程序,配置完成之后再设置成运行的时候需要的模式
通过IIC读取GT911的ID,验证通信结果
创建Input设备,设置触摸、绝对坐标等事件
对于多点触摸,通过input_mt_init_slots初始化 MT 槽位,并设置 ABS_MT相关参数(如 X/Y 坐标范围、触点数量等)

第三步是测试中断,当初始化完基础的引脚后,触摸屏幕,如果中断程序中的打印函数正常工作说明中断测试成功,若没有成功可能原因为没有清除中断标志位或者屏幕的初始化时序有问题

因为IIC通信在中断处理函数中可能会引起休眠,所以不在上半部&&下半部的软中断和tasklet中进行IIC读取,而是选择工作队列或者中断线程中进行读取
申请和注册中断– 中断线程或者工作队列

第四步是通过IIC读取信息,通过Input子系统上报信息给内核 这里主要涉及上报流程(MT协议 选择槽位ID-> 槽位状态 -> 坐标X -> 坐标Y )&&中断的选择(这里使用中断线程化或者工作队列,因为IIC的通信中可能会阻塞,而软中断和Tasklet不能阻塞运行,会影响系统运行):

在中断线程中执行相关内容:
通过IIC读取GT911的状态寄存器和坐标数据包
解析数据,获取有效点数量、坐标、状态等
使用MT协议上报 1.硬件提供槽位ID 2.上报槽位状态 3.上报坐标 4.上报同步事件
向GT911写入命令,清除它的中断标志

补充一下上报的各种事件: 触摸事件 绝对坐标事件 上报结束的时候还有 同步事件 当然(如果是更高级的屏幕,还有压力时间,触摸方向事件等等)

对于中断线程化,即可以阻塞休眠的中断里面,对于信息维护,可以选择使用互斥锁或者自旋锁都可以,也可以在中断上下文中禁用中断
若我使用软中断或tasklet,则只能使用自旋锁,因为在软中断和tsaklet里面不能休眠(阻塞)

第五步验证是否上报成功,这里有两种方式:

首先可以使用 hexdump /dev/input/event2 来获取中断中上报的数据,也可以使用工具evtest来解析
使用开源工具: tslib工具进行测试

对于tslib,他也可以作为驱动层和应用层之间的适配层,提供滤波,去抖动或者坐标变换等功能

最后是期间遇到的问题:

  1. 首先是屏幕初始化的时序,需要查询数据手册,当时的时序和延时有问题,导致无法正常的读取信息
  2. gt911读取信息后,需要手动清除中断标志位(往特定寄存器写入0x00),否则无法继续读取
  3. 初始化设备树的时候需要屏蔽掉已经使用接口的节点,防止被二次初始化

Q2 对于linux的移植,整体的流程以及相关的

整体可以参考Linux移植相关概念

Uboot移植

参考NXP官方的源码(硬件设计参考的哪块官方板),然后以哪块板子的Uboot为基础

获取官方代码
编译官方代码,尝试运行,如果可以运行,观察哪些驱动有问题(这里主要检查SD卡,EMMC,LCD,网络),需要修改
创建新的板级配置,然后添加相关文件

修改驱动,对于imx6ull板子主要修改的驱动如下: LCD屏幕网络驱动

LCD: 分辨率,像素时钟,像素格式,LCD的panel环境变量(在uboot启动的配置模式中,通过setenv pannel TFT7016来设置)

网络驱动:因为6ull使用的网络芯片和官方不同,这里主要要适配网络芯片型号(PHY地址),以及正确的控制复位引脚

然后进行运行即可,同时通过set ipaddr/ethaddr/gatewayip/netmask/serverip…然后通过ping自己的虚拟机测试网络是否正确

这里强调bootcmd和bootargs环境变量
bootcmd是uboot倒计时结束之后执行的命令(比如后期的网络挂载就是通过在这里添加环境变量来实现的,注意,从网络中启动唯一目的是为了调试,为了防止频繁的往EMMC中烧录东西,这里使用的指令是tftp网络下载)
bootargs是uboot传递给linux内核的参数,比如控制的输出位置(我们默认的串口),根文件系统位置、文件系统的格式等等

内核编译成功之后会生成一个linux的镜像文件(uboot编译出来是一个bin文件,板子上电后通过固定偏移,开始运行uboot),我们将设备树文件和这个镜像文件保存到EMMC中,指定这个镜像文件和设备树的文件位置之后,uboot读取这两个文件进行启动,就是最终的从EMMC中启动

内核移植

在移植的时候,我们是可以使用图形化进行配置的,指令为make menuconfig,然后可以在图形化配置界面进行修改

这里主要涉及三个:

  1. CPU主频修改
  2. 修改EMMC的驱动模式,从4线修改为8线,更快; 修改供电,将默认的1.8V修改成3.3V
  3. 修改底层的网络驱动,因为芯片不同,部分引脚不同,同时要屏蔽别的使用了相关引脚IO的驱动
    (设备树中的PHY地址,网络驱动节点中的部分属性,复位和网络时钟引脚的驱动,这几个包括前两点都是设备树文件中修改,最后是在fec_main.c添加一个芯片复位之后的延时,要求复位之后要延时150ms,所以添加了一个延时)

然后重新编译之后,通过ifconfig进行测试网络

根文件系统的构建

使用BusyBox 构建根文件系统,主要修改两部分 添加编译器 添加中文支持,选择动态编译后编译 busybox,会得到一个基础的根文件系统(BusyBox的工作也就到此为止)
然后是向根文件系统中添加向根文件系统添加 lib 库(动态库,如果是静态编译则不用,但是静态库很占内存,并且可能导致dns不能使用)和一些基础文件目录(如 dev、proc、mnt、sys、tmp 和 root 等),这里的lib库通过交叉编译器工具中获取,并且没有裁剪

留言

有问题请指出,你可以选择以下方式:

  1. 在下方评论区留言
  2. 邮箱留言
  • Title: Hello World
  • Author: H_Haozi
  • Created at : 2024-09-01 08:05:00
  • Updated at : 2026-06-09 16:26:20
  • Link: https://blog.haozi-haozi.cn/2024/09/01/hello-world/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments