硬件驱动
1.CPU内部结构
- 算术逻辑单元(ALU):这是CPU用于执行算术和逻辑运算的核心部分。无论是加法、减法、乘法、除法等基本算术运算,还是逻辑运算如与、或、非等,都是由ALU来完成的。
- 控制单元(CU):控制单元负责管理和控制CPU的运行过程。它接收来自指令寄存器的指令,并对指令进行译码,然后发出相应的控制信号,指挥全机各个部件自动、协调地工作。
- 寄存器:寄存器是CPU中的小容量高速存贮部件,它们用来暂存指令、数据和地址。寄存器的存取速度很快,可与CPU的速度相匹配。
- 缓存(Cache):缓存是CPU中的一个高速缓冲存储器,用于存储CPU经常需要访问的数据和指令。当CPU需要数据时,它会首先尝试从缓存中查找,如果找到则直接读取,否则再去主存中查找。这种机制可以大大提高CPU的数据访问速度。
- 总线:总线是CPU内部各部件之间以及CPU与外部设备之间进行数据传送的通路。它负责将CPU的指令和数据传送到各个部件,同时也将各个部件的工作状态和数据传送到CPU。
2.Cortex-M3和M4可以同时支持小端模式和大端模式吗
是的,Cortex-M3和Cortex-M4处理器同时支持小端模式和大端模式的存储器系统。
小端模式(Little-endian)和大端模式(Big-endian)是两种不同的数据存储和读取方式,在小端模式下,数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,而在大端模式下,数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这两种模式的选择主要取决于具体的硬件设计和系统需求。
Cortex-M3和Cortex-M4处理器在复位时会确定存储器系统的端配置,即选择小端模式或大端模式。一旦设置好后,存储器的端配置在下次复位前都不会改变。这种设计使得处理器能够适应不同的硬件平台和应用场景,提高了系统的灵活性和兼容性。
3.CPU、内存、虚拟内存、硬盘的关系
CPU是从内存或者缓存中拿到指令,放入寄存器,并对指令译码分解成一系列微操作,然后发出控制命令,执行微操作;
CPU并不能直接调用存储在硬盘上的系统、程序和数据,所以必须先将硬盘上的数据、内容存储在内存中,这样才能被CPU读取,所以内存是硬盘和CPU的中转站;
内存一般是比较小的,当内存超出额度之后,就会把硬盘上的部分空间模拟成内存——>虚拟内存,将暂时不用的数据或程序保存到虚拟内存,等到需要的时候再调用。
总结:CPU是工厂,内存是中转站,硬盘是仓库,虚拟内存是临时中转站。
4.ARM结构处理器分类
1.嵌入式微处理器 —> 具有32位以上的处理器
2.嵌入式微控制器 —> 单片机,以某种微处理器内核为核心,芯片内部集成ROM,RAM等功能
3.嵌入式DSP处理器 —> 擅长数字信号处理
5.嵌入式MCU、MPU和DSP有什么区别
MCU,即微控制器,是一种集成了中央处理器核心、内存、外设接口等功能于一体的芯片。它通常用于控制嵌入式系统的操作,如家用电器、汽车控制系统等。MCU注重功耗、成本和尺寸的优化,特别适用于资源要求较低的应用场景。其内部存储器通常较小,且任务类型单一,主要执行过程控制、辅助功能以及简单的传感器数据采集等任务。
MPU,即微处理器,是一种具有强大计算和数据处理能力的芯片,它集成了CPU、内存、外设控制器和总线接口等功能。MPU通常具有较高的主频和大容量存储器,能够完成各种复杂的计算任务和数据处理操作。它适用于需要高性能计算和复杂算法处理的系统,如嵌入式系统和计算机领域。与MCU相比,MPU更注重处理能力和运算速度,能够运行复杂的操作系统和大型程序。
DSP,即数字信号处理器,是一种专门用于数字信号处理的微处理器。它具有特殊的硬件结构和指令集,能够高效地处理数字信号,如音频、视频、图像处理等。DSP的内部采用程序和数据分开的哈佛结构,具有专门的硬件乘法器,广泛采用流水线操作,提供特殊的DSP指令。与MCU和MPU相比,DSP更注重数字信号处理的性能和效率,适用于通信、音频处理、雷达等领域。
综上所述,嵌入式系统中的MCU、MPU和DSP在应用场景、优化方向和性能特点上存在差异。MCU适用于低功耗、资源有限的嵌入式系统控制任务;MPU适用于需要高性能计算和复杂算法处理的系统;而DSP则专注于数字信号处理领域的高效运算处理。
6.ROM、RAM和缓存
ROM(只读存储器)
ROM是一种非易失性存储器,意味着即使计算机关闭,ROM中的数据也会保留。ROM中存储的数据在制造过程中被编程,并且之后不能被修改,因此被称为“只读”。ROM通常用于存储计算机启动时需要的基本输入输出系统(BIOS)或固件,以及其他不需要改变的重要信息。
RAM(随机存取存储器)
RAM是一种易失性存储器,意味着当计算机关闭或重启时,RAM中的数据会被清除。RAM允许数据被读取和写入,并且数据的访问时间与存储位置无关,因此被称为“随机存取”。RAM是计算机主存的主要组成部分,用于存储当前正在运行的程序和数据,以便CPU能够快速访问。
缓存(Cache Memory)
缓存是一种高速缓冲存储器,位于CPU和主存之间,用于存储最近被CPU访问过的数据或指令。由于CPU的运算速度远高于主存的访问速度,因此引入缓存可以减少CPU等待主存响应的时间,提高计算机的整体性能。缓存通常使用静态RAM(SRAM)实现,这种存储器的访问速度非常快。
区别与联系
- 功能:ROM主要用于存储固定不变的数据和程序,RAM用于存储临时数据和程序,而缓存则用于加速CPU对主存的访问。
- 性能:ROM和RAM的访问速度相对较慢,而缓存的访问速度非常快。
- 可修改性:ROM中的数据是不可修改的,RAM中的数据可以随意读写,缓存中的数据会根据CPU的需要动态更新。
- 容量:ROM的容量通常较小,RAM的容量相对较大,而缓存的容量通常很小但速度极快。
7.常见的CPU指令集
CISC,即复杂指令集计算,其特点是指令集非常丰富且多样化,包含了许多复杂和专门的指令。CISC架构的处理器能够执行更多种类的操作,对于特定任务可能更加高效。然而,这种架构也带来了一些挑战,比如指令长度不固定,执行速度可能较慢,因为处理器需要解析更复杂的指令。此外,CISC架构的处理器通常需要更多的硬件支持来实现这些复杂指令。
RISC,即精简指令集计算,旨在通过精简指令集来提高处理器的效率。RISC指令集通常较小,指令长度固定,且每个指令的执行时间都很短。这种设计使得RISC处理器能够实现更高的执行速度和更低的功耗。由于指令集简单且统一,RISC处理器的设计也相对简单,从而降低了制造成本。然而,RISC架构可能需要更多的指令来完成某些复杂任务,这可能导致代码体积增加。
8. CPU的流水线工作原理
CPU执行一条指令时,也分为几个步骤,如
指令取指(instruction fetch)—> 指令译码(Instruction decode)—> 指令执行(execute)—> 访存(memory access)—> 写回(write back),
重点:CPU并不会等一条指令完全执行完才执行下一条指令,而是像流水一样
9.嵌入式流水线工作有什么不同?
嵌入式CPU为了提高效率,采用超流水线结构,我们知道,CPU执行一条指令被分成5个步骤,每个步骤可能都需要1ns,但是有个长指令,被分成5个步骤时,指令执行这个步骤却需要2ns,那么整个时间就被限制了
为了提高效率,我们可以把指令执行(Execute)这个步骤再拆分成两组(寄存器+组合逻辑),每组执行时间为1ns,这样我们的普通流水线成了六级流水线了,这就是超流水线
10.uboot启动过程做了什么事
U-Boot(Universal Boot Loader)是一个开源的、通用的引导加载程序,它支持多种处理器架构和嵌入式系统。U-Boot的启动过程可以分为两个阶段,每个阶段都有其特定的任务。
第一阶段(Stage1)主要完成以下工作:
- 硬件设备初始化:这包括设置CPU的速度、时钟频率及中断控制寄存器等,确保硬件处于正确的状态。
- 加载U-Boot第二阶段代码到RAM:为了加快启动速度和提供更大的灵活性,U-Boot的第二阶段代码通常存储在Flash等非易失存储器中,并在第一阶段被加载到RAM中执行。
- 设置好栈(Stack):为后续的C语言代码执行做好准备。
- 跳转到第二阶段代码入口:完成第一阶段的初始化工作后,跳转到第二阶段代码的入口点。
第二阶段(Stage2)则主要完成以下工作:
- 初始化本阶段要使用的硬件设备:这可能包括内存、网络接口、显示设备等,具体取决于目标系统的配置。
- 检测系统内存映射:确定系统的内存布局,以便后续的内存分配和管理。
- 从Flash等设备读取并加载内核到RAM中:为内核的启动做好准备。
- 为内核设置启动参数:这些参数可能包括内存布局、根文件系统位置等,供内核在启动时使用。
- 调用内核:最后,U-Boot将控制权交给内核,由内核完成系统的后续初始化工作并启动用户空间程序。
总的来说,U-Boot的启动过程是一个复杂的序列,涉及硬件初始化、代码加载、内存管理等多个方面,这个过程确保了嵌入式系统在加电后能够正确地加载并运行操作系统和应用程序。
11.说一说Bootloader
Bootloader是在嵌入式系统或计算机启动时的第一段代码,它的主要任务是负责系统的初始化和加载操作系统的核心模块。具体来说,Bootloader会首先进行硬件设备的初始化,包括CPU、内存、总线等核心硬件,确保它们处于正确的状态。接着,Bootloader会建立内存空间映射图,为最终调用操作系统内核准备好正确的环境。
常见的Bootloader有Redboot、ARMboot、U-Boot、Blob等,其中U-Boot(Universal Boot Loader)是一个开源的、通用的引导加载程序,支持多种处理器架构和嵌入式系统。U-Boot的启动过程包括硬件初始化、加载内核等操作,确保系统能够正确地加载并运行操作系统。
总的来说,Bootloader是嵌入式系统或计算机启动时的关键组成部分,它确保了系统在加电后能够正确地加载并运行操作系统和应用程序。
12.中断和异常
中断是指,停止当前的工作,转去执行另个任务,执行完成后发回继续执行
异常是指,由于指向内部指令引起的错误
区别:中断由外因引起,异常由CPU本身原因引起。
13.DMA和中断的区别
DMA不需要CPU参与,就可以进行数据的传输,大大提高数据传输时CPU的效率,而对于中断来说,必须要CPU的参与。
DMA的工作模式有两种,一种要求原地址和目标地址都必须是连续,另一种就没有这样的要求。
14.中断函数的注意
1.中断函数应该遵循快进快出,把比较消耗时间的任务放到中段下文处理,比如tasklet,工作队列;
2.中断函数的返回值,应该使用内核定义的宏,而不是自定义;
3.中断不能有阻塞,不能让中断进入睡眠,比如中不能有信号量。
15.为什么要向内核传参
因为内核并不是对于所有的开发板都是完美适配的,内核对于开发板的环境是一无所知的,所以要想启动内核,就需要通过传参告诉内核当前的环境。
16.如何向内核传参
uboot传的是R0,R1,R2参数,R0默认是0,R1存放的就是CPU的型号,R2里面存放的是些基地址,比如内存的起始地址,内存大小,根文件系统的信息,
数据结构是struct tag
该结构体有两部分组成,结构体tag_header和联合体tag_data。
17.uboot为什么要关闭caches?
caches是CPU的2级缓存,主要作用是将常用的指令和数据存在cpu内部,刚上电CPU还不能管理caches,指令caches可以关闭,也可以不关闭,但是数据caches必须关闭,否则可能由于刚开始的代码到caches里面取数据的时候,由于caches还没准备好,会导致数据异常。
18.说一说AD转换
AD转换,即模拟信号到数字信号的转换,其原理是将连续变化的模拟信号转换为离散的数字信号,以便于数字电路进行处理和存储。这个过程一般分为三个主要步骤:采样、量化和编码,有时也包括保持。
- 采样:采样是把时间连续的模拟信号转换成时间离散、幅度连续的信号。换句话说,采样是用每隔一定时间间隔的信号样本值序列,代替原来在时间上连续的信号,也就是在时间上将模拟信号离散化。
- 量化:量化是将幅度上连续取值(模拟量)的每一个样本转换为离散值(数字量)表示。也就是用有限数量的近似原来连续变化的幅度值,把模拟信号的连续幅度变为数量有限、有一定间隔的离散值。
- 编码:编码则是按照一定的规律,把量化后的离散值用二进制数码表示,这样便于计算机的存储、处理和传输。
通过以上三个步骤(或四个步骤,如果包括保持的话),可以完成模拟信号到数字信号的转换。AD转换在电子设备中有着广泛的应用,比如音频设备、通信系统、传感器接口等,它实现了模拟信号在数字系统中的处理和传输,大大提高了信号处理的灵活性和可扩展性。
19.驱动申请内存的函数
在操作系统中,特别是像Linux这样的系统,内存管理是一个核心功能。驱动程序,作为操作系统的一部分,经常需要动态地申请和释放内存。在Linux内核中,有几个主要的函数用于内存的申请。
- kmalloc():
- 这是内核态下常用的内存申请函数。
- 它使用slab分配器,因此申请的内存是物理连续的。
- kmalloc()申请的内存位于内核空间中的直接映射区,通常用于分配小块内存。
- 需要指定所需内存的大小以及分配标志(如GFP_KERNEL)。
- vmalloc():
- vmalloc()也是内核态下的内存申请函数。
- 与kmalloc()不同,vmalloc()申请的内存并不保证物理连续,但它可以在需要时分配大块内存。
- vmalloc()申请的内存位于内核空间的动态映射区。
- 由于其分配的内存可能不是物理连续的,因此性能上可能不如kmalloc(),但在需要大块连续虚拟内存空间时非常有用。
此外,在用户态程序中,常用的内存申请函数是malloc()、calloc()和realloc(),这些函数通过C库提供,并依赖于操作系统的动态内存管理机制。这些函数申请的内存位于用户空间,并通过指针来访问和管理。在使用完内存后,应使用free()函数来释放它。
20.说一说Linux驱动开发和Linux应用开发以及Qt开发
Linux驱动开发、Linux应用开发和Qt开发是软件开发中的三个不同领域,每个都有其特定的目标和工具集。下面是对这三个领域的简要介绍:
Linux驱动开发
Linux驱动开发涉及为Linux内核编写软件,以便与硬件设备(如打印机、摄像头、网络设备、存储设备等)进行交互,驱动程序是操作系统与硬件设备之间的桥梁,它使得操作系统能够识别和控制硬件。
主要特点:
- 需要深入了解Linux内核、硬件架构以及设备的工作原理。
- 使用C语言和内核提供的API进行开发。
- 涉及中断处理、内存管理、并发控制等底层概念。
- 需要处理硬件相关的复杂性和不确定性。
开发工具:
- 文本编辑器或集成开发环境(IDE)如Vim, Emacs, Eclipse等。
- 交叉编译器,用于将代码编译成可在目标硬件上运行的二进制文件。
- 调试工具如gdbserver, kgdb等,用于远程调试内核代码。
Linux应用开发
Linux应用开发是指在Linux操作系统上编写用户空间的应用程序。这些程序可以是命令行工具、图形用户界面(GUI)应用程序、网络服务、数据库应用等。
主要特点:
- 使用高级编程语言如C, C++, Python, Java等。
- 利用Linux系统提供的库和API,如glibc, POSIX线程库等。
- 可以利用多种开发工具和框架,如GCC, CMake, Qt, GTK+等。
- 通常不涉及直接的硬件交互,而是通过系统调用来访问底层资源。
开发工具:
- 文本编辑器或IDE,如VSCode, Eclipse, CLion等。
- 编译器和构建系统,如GCC, CMake等。
- 调试工具,如gdb, valgrind等。
- 性能分析工具,如perf, gprof等。
Qt开发
Qt是一个用于开发跨平台应用程序和用户界面的框架。它提供了丰富的GUI组件、网络编程接口、多线程支持等,使得开发者能够高效地创建复杂的应用程序。
主要特点:
- 使用C++作为主要编程语言,但也支持其他语言如Python和QML。
- 提供了丰富的GUI组件和布局管理器,使得界面开发变得简单而高效。
- 支持多线程和网络编程,使得开发复杂的应用程序成为可能。
- 提供了强大的信号和槽机制,用于处理事件和消息。
开发工具:
- Qt Creator是一个专门为Qt设计的IDE,提供了代码编辑、编译、调试和性能分析等功能。
- Qt的库和工具集,包括QtCore, QtGui, QtWidgets等,用于构建应用程序的各个部分。
- 第三方库和插件,用于扩展Qt的功能和兼容性。
总的来说,Linux驱动开发、Linux应用开发和Qt开发都是软件开发的重要组成部分,它们在不同的层次和领域发挥着各自的作用。驱动开发关注于硬件和操作系统的交互,应用开发关注于实现特定的功能和服务,而Qt开发则提供了一个高效的跨平台开发框架。