# 1 MCU/MPU/CPU/SoC 有什么区别?
# 1.1 MCU
MCU(MicroControllerUnit)中文名称为微控制单元,又称单片微型计算机, 是指随着大规模集成电路的出现及其发展,将计算机的CPU、RAM、ROM、定时数器和多种I/O接口集成在 一片芯片上,形成芯片级的计算机,为不同的应用场合做不同组合控制。 MCU通常被用来控制简单的设备,如家用电器、车辆控制、传感器、嵌入式系统等。
# 1.2 MPU
即微处理器单元,通常代表功能强大的CPU,可理解为 增强型CPU ,但不是为任何已有的特定计算目的而设计的芯片。 这种芯片往往是计算机和高端系统的核心。MCU集成了片上外围器件而 MPU 没有集成片上外围器件。 例如嵌入式开发者最熟悉的 ARM 的 Cortex-A 芯片,他们都属于 MPU。
# 1.3 CPU
中央处理器,简称 CPU(Central Processing Unit),中央处理器主要包括两个部分, 即控制器、运算器,其中还包括高速缓冲存储器及实现它们之间联系的数据、控制的总线。 电子计算机三大核心部件就是CPU、内部存储器、输入/输出设备。 中央处理器的功效主要为处理指令、执行操作、控制时间、处理数据。 所谓的计算机的可编程性主要是指对CPU的编程。
CPU(中央处理器)是计算机系统的核心组件,负责执行程序指令和处理数据。它通常由以下几个主要组成部分构成:
控制单元(Control Unit):控制单元负责协调和控制CPU内部的各个部件,执行指令的获取、解码和执行操作。它包括程序计数器(Program Counter)来存储当前指令的地址,以及指令寄存器(Instruction Register)来存储当前指令。
算术逻辑单元(Arithmetic Logic Unit,ALU):ALU执行算术和逻辑操作,包括加法、减法、逻辑与、逻辑或等。它是处理数据的核心部分,用于执行各种数学和逻辑运算。
寄存器(Registers):寄存器是CPU内部的高速存储器,用于存储指令和数据。它包括通用寄存器(用于临时存储数据和中间结果)、程序计数器、指令寄存器等。寄存器的读写速度非常快,因此在CPU内部进行高速的数据传输和处理。
缓存(Cache):缓存是CPU内部的一种高速存储器,用于临时存储从主存(RAM)中读取的数据和指令。缓存的目的是减少对主存的访问次数,提高数据读取的速度。
总线(Bus):总线是连接CPU内部各个组件之间以及与其他系统组件之间进行数据传输的通道。它包括数据总线(用于传输数据)、地址总线(用于传输内存地址)、控制总线(用于传输控制信号)等。
除了上述主要组成部分外,现代CPU还可能包含其他辅助组件和功能,例如浮点运算单元(Floating-Point Unit,FPU)用于执行浮点运算、向量处理单元(Vector Processing Unit)用于高效地处理向量数据、分支预测单元(Branch Prediction Unit)用于预测分支指令的执行路径等。
需要注意的是,CPU本身并不包括存储器(如RAM或硬盘),它通过总线与外部存储器和其他系统组件进行数据交换。
# 1.4 SoC
SoC(System on Chip,整体的一个电路系统,完成一个具体功能的东西):指的是片上系统, MCU只是芯片级的芯片,而SoC是系统级的芯片,它既MCU那样有内置RAM、ROM 同时又像MPU那样强大,不单单是放简单的代码,可以放系统级的代码, SOC是一种高度集成的芯片,将多个功能模块(例如处理器、内存、外设等)集成到一个芯片上, 可以用于构建复杂的系统,如智能手机和平板电脑等。 MCU 是简单的 SoC,只能裸机或者运行 RTOS。
# 2 VCC/VSS/VDD/VEE/VBAT 有什么区别
# 2.1 VCC
C=circuit,表示电路的意思,即接入电路的电压。
# 2.2 VDD
D=device,表示器件的意思,即器件内部的工作电压。
# 2.3 VSS
S=series,表示公共连接的意思,通常指电路公共接地端电压。
# 2.4 VEE
负电压供电;场效应管的源极(S)
# 2.5 VBAT
battery,电池
当使用电池或其他电源连接到VBAT脚上时,当VDD 断电时,可以保存备份寄存器的内容和维持RTC的功能。如果应用中没有使用外部电池,VBAT引脚应接到VDD引脚上。
一般来说VCC=模拟电源,VDD=数字电源,VSS=数字地,VEE=负电源。
# 3 什么是上拉电阻和下拉电阻?
上拉电阻和下拉电阻是在数字电路中使用的两种电阻。 它们通常用于控制数字信号的电平。
- 上拉电阻是连接到信号线和正电源之间的电阻,用于将信号线上的电平拉高。
- 下拉电阻是连接到信号线和地之间的电阻,用于将信号线上的电平拉低。
在数字电路中,上拉电阻和下拉电阻通常用于控制输入信号的电平状态, 以确保正确的信号传输和处理。
# 4 晶振是什么?
晶振是一种用于产生稳定和精确的时钟信号的电子元件。它是由一块晶体和一些电路组成的。当晶体被电场激发时,它会产生一个固定频率的振荡信号,这个振荡信号被用来调节电子设备中各种电路的时序和节拍。晶振通常被用于计算机、通信设备、数字电视、智能手机等各种电子设备中。
# 5 单片机烧录方式有哪些?
# 5.1 mcu 地址映射
- ISP(In-System Programming)在系统编程,使用引导程序(Bootloader)加上外围UART/SPI等接口进行烧录。
- ICP (In-circuit programmer)在电路编程,使用SWD/JTAG接口。
- IAP(In-Application Programming)指MCU可以在系统中获取新代码并对自己重新编程,即用程序来改变程序。
Flash(Main memory)主存储区
通常编写的代码是放到主存储区的起始位置开始运行(0x08000000),烧录程序时直接将程序烧录到这里即可。
System memory 系统存储区
起始位置 0x1fff 0000,是 stm32 出厂时,由 ST 在这个区域内部预置了一段 Bootloader,也就是 ISP 程序,这是一块 ROM,出厂后无法修改。
# 5.2 启动方式选择
STM32有两个BOOT引脚,通过配置不同的高低电平,可以让单片机从不同的地址开始运行。
BOOT0 = 0,BOOT1 任意
从主闪存存储器(0x0800 0000)启动,这种情况,就是直接在这个地址烧录,烧录完直接在这个地址运行。
使用 JTAG/SWD 模式下载程序。
BOOT0 = 1,BOOT1 = 0
从系统存储器启动,这种情况,使用串口方式烧录程序,此时,单片机从系统存储器(0x1fff 0000)启动, 运行的是出场预置的 Bootloader 程序,接受串口发来的程序,并将其写入 main mermory (0x0800 0000) 烧录完成后,将 boot0 拉低,就可以运行烧录的程序了。
使用 ISP 串口烧录。
BOOT0=1,BOOT1=1
这种情况是从内存中启动,内置SRAM(也就是STM32的内存中),既然是SRAM,自然也就没有程序存储的能力了,这个模式一般用于程序调试。
# 6 volatile 有什么用?
避免编译器对变量进行优化。
violatile关键字通常用来修饰多线程共享的全局变量和IO内存。告诉编译器,不要把此类变量优化到寄存器中,每次都要老老实实的从内存中读取,因为它们随时都可能变化。
编译器对变量的优化有三个方面:
- 删除多余的语句。
例如:
a = 1;
a = 2;
a = 3;
2
3
优化的情况下,编译器会删除前面的两条语句。
- 可能会重新排列语句的顺序。
- 在多线程编程中,为了提高效率,可能将共享资源在每个线程中都保存一个备份到高速缓存中,造成同一个变量放在了两个高速缓冲区中,而对它们的读写操作就不是同一个内存,导致读写的不是同一个变量。
# 7 寄存器和内存、cache的区别
寄存器:寄存器是有触发器或锁存器组成,通常由触发器组成,寄存器拥有非常高的读写速度,所以在寄存器之间传递数据非常快
CPU 在一次时钟周期能访问一次寄存器。
内存:内存就是存储器,由半导体器件构成。
计算机的存储层次(memory hierarchy)之中,寄存器(register)最快,内存其次,最慢的是硬盘。
寄存器、内存和高速缓存都是计算机中的存储器件,但它们之间有以下区别:
寄存器:是位于CPU内部的最快速的存储器件,用于存储指令、数据和地址等。由于寄存器与CPU之间的距离非常近,所以访问速度非常快,但是容量非常有限,一般只有几十个字节。
内存:是计算机中存储数据和程序的主要存储器件,容量比寄存器大得多,可以存储大量的数据和程序。内存的读写速度比寄存器慢,但比较快,一般以纳秒为单位。
高速缓存:是一种介于寄存器和内存之间的存储器件,用于加速CPU访问内存的速度。高速缓存的容量比寄存器和内存都要小,但是它的读写速度比内存要快得多,一般以CPU时钟周期为单位。高速缓存通常分为多级,一级高速缓存离CPU最近,速度最快,容量最小,而二级、三级高速缓存离CPU越远,速度越慢,容量越大。
速度:register > L1 cache > L2 cache > memory > storage
# 8 总线是什么?
总线(bus)是计算机内部传输数据的通道,它是一组并行的电子线路或电气连接,通过这些线路或连接可以在计算机中的各个部件之间传输数据、地址和控制信息。总线在计算机体系结构中扮演着重要的角色,因为它们可以在不同的设备之间提供通信,并且协调计算机内部的所有活动。
总线的种类包括地址总线、数据总线和控制总线。地址总线用于传输内存地址,数据总线用于传输数据,控制总线用于传输控制信号,如时钟信号、读写信号等。不同类型的总线在计算机中承担不同的任务,并且它们的带宽和时序等方面的特性也会影响到计算机的性能。
# 9 AHB,APB 是什么?
AHP:高级高性能总线
APB指的是“高级外设总线”(Advanced Peripheral Bus),是ARM处理器的外设总线之一。APB总线是一个低速、低功耗的总线,主要用于连接低带宽的外设,如定时器、GPIO(通用输入/输出端口)、UART(通用异步收发器)等。APB总线通常被用作系统中的次要总线,因为它的数据传输速率比主总线(如AHB)慢,但是它可以在处理器和外设之间提供简单、灵活的通信。
APB总线和AHB总线一样,都是ARM体系结构中的标准总线,这些总线可以使处理器和外设之间进行快速、可靠的通信。在ARM处理器中,APB总线和AHB总线通常被组合使用,以提供处理器和外设之间的多层次连接,从而实现高效的数据交换和控制。
APB和AHB总线,类似于 PC 里的北桥和南桥总线。 南桥总线上挂接的都是鼠标、键盘这些慢速的设备,北桥上挂接显卡等高速设备。南桥频率低,北桥频率高。另外,南桥最后也要接到北桥上。 这些感觉都类似于APB和AHB。
# 10 ICode/DCode/System/DMA 总线/总线矩阵是什么?
# 10.1 ICode
该总线将CortexTM-M3内核的指令总线与闪存指令接口相连接。指令预取在此总线上完成。
ICode 中的I 表示Instruction,即指令。程序编译之后生成的二进制文件都是一条条指令,烧录后存放在FLASH中,内核要读取这些指令来执行程序就必须通过ICode 总线,它几乎每时每刻都需要被使用,它是专门用来取指的。
ICode连接M3内核与Flash接口。
# 10.2 DCode
该总线将CortexTM-M3内核的DCode总线与闪存存储器的数据接口相连接(常量加载和调试访问)。
DCode 中的D 表示Data,即数据,那说明这条总线是用来取数的。我们在写程序的时候,数据有常量和变量两种,常量就是固定不变的,用C 语言中的const 关键字修饰,是放到内部的FLASH 当中的,变量是可变的,不管是全局变量还是局部变量都放在内部的SRAM。因为数据可以被Dcode 总线和DMA 总线访问,所以为了避免访问冲突,在取数的时候需要经过一个总线矩阵来仲裁,决定哪个总线在取数。
# 10.3 system bus
System Bus是一个由多个总线组成的系统级总线,用于连接处理器核心和系统中其他设备和组件,例如内存、外设、DMA控制器、中断控制器等。
System Bus的主要功能是提供高带宽和低延迟的数据传输。它通常由多个独立的总线组成,包括数据总线、地址总线和控制总线。这些总线共同协作,实现处理器核心与其他系统组件之间的数据传输和控制信号的交互。
# 10.4 DMA 总线
DMA是把一个地址的数据搬运到另外一个地址,所以它需要控制地址,这些地址在处理器内部是AHB和APB总线矩阵管理的,所以DMA必须要挂到AHB和APB上面
DMA(Direct Memory Access)总线是一种用于高速数据传输的专用总线。它可以在不需要处理器的干预下,直接从外设设备中读取或写入数据到内存中。DMA总线通过减轻CPU的负担,提高数据传输的速度和效率,使系统更加高效和可靠。
# 10.5 总线矩阵
总线矩阵协调内核系统总线和DMA主控总线之间的访问仲裁,仲裁利用轮换算法。在互联型产品中,总线矩阵包含5个驱动部件(CPU的DCode、系统总线、以太网DMA、DMA1总线和DMA2总线)和3个从部件(闪存存储器接口(FLITF)、SRAM和AHB2APB桥)。在其它产品中总线矩阵包含4个驱动部件(CPU的DCode、系统总线、DMA1总线和DMA2总线)和4个被动部件(闪存存储器接口(FLITF)、SRAM、FSMC和AHB2APB桥)。
AHB外设通过总线矩阵与系统总线相连,允许DMA访问。
# 11 RCC 是什么?
Reset Clock Control,复位时钟控制,控制提供给各模块时钟信号的通断。
可开启或关闭各总线的时钟,在使用各外设功能必须先开启其对应的时钟,没有这个时钟内部的各器件就不能运行。 RTC是 STM32 内部集成的一个简单的时钟 (计时用),如果不用就关闭,用的话先要通过 RCC 配置其时钟源,可看作是一个外设器件。
# 12 为什么 32 位 cpu 地址总线一般不超过 32 ?
32 位的 CPU 数据总线宽度是 32 位,即 4 字节。
通常情况下,地址总线宽度要小于数据总线宽度,数据总线宽度决定了 CPU 的一个时钟周期内可以处理的数据量大小。 而数据总线宽度大小应该根据 CPU 支持的操作数大小来设计,通常地址总线宽度小于数据总线宽度,以便于 CPU 高效传输数据。
通常情况下,数据总线宽度与处理器架构所支持的最大数据宽度相匹配,以提供最佳的性能和效率。
增加地址总线宽度会增加芯片的复杂性和成本。因为需要更多的信号线和支持电路来传输和处理更多的地址位数。此外,处理器的寄存器也需要更多的位数来处理更大的地址,这会增加处理器的功耗和成本。
数据总线长度小于字长的话,会浪费 CPU 的处理能力,大于字长的话,地址数据 CPU 一次处理不完, 会影响效率,导致访存速度降低,寻址空间变大了,但是寻址速度变慢了,所以一般 数据总线的长度等于字长。
指针的长度一般等于地址总线的宽度。
# 13 UART 和 USART 有什么区别?
UART 通用异步收发器
USART 通用同步/异步收发器
# 14 RTC 和 RCC 的区别
RCC 是 stm32 的时钟控制器,RTC 是 stm32 内部集成的一个简单的时钟。
# 15 哈佛架构eh冯诺依曼架构的区别?
哈佛架构和冯诺依曼架构是两种不同的CPU设计思路,主要区别在于程序指令和数据是如何存储和传输的。
冯诺依曼架构认为CPU通过一组总线来分时获取指令和数据,指令和数据都存储在同一个存储器中,共享同一个地址空间。² 这种结构实现简单,成本低,但是也造成了信息流的传输瓶颈,影响了数据处理速度的提高。
哈佛架构认为CPU应该分别通过两组独立的总线来对接指令和数据,指令和数据分别存储在不同的存储器中,拥有不同的地址空间。¹² 这种结构可以使指令和数据有不同的数据宽度,同时取指和取数,提高了运算效率,但是也增加了复杂度和对外围设备的要求。
ARM是一种改进型的哈佛架构,它使用了内部缓存(cache)来存放指令和数据,而且指令缓存和数据缓存是分开的。¹ 这样既保留了哈佛架构的优点,又克服了冯诺依曼结构的缺点。
源: 与必应的对话, 2023/5/15 (1) ARM到底是冯诺依曼结构还是哈佛结构 - 知乎 - 知乎专栏. https://bing.com/search?q=%e5%93%88%e4%bd%9b%e6%9e%b6%e6%9e%84%e5%92%8c%e5%86%af%e8%af%ba%e4%be%9d%e6%9b%bc%e6%9e%b6%e6%9e%84%e7%9a%84%e5%8c%ba%e5%88%ab. (2) 哈佛结构和冯诺依曼结构 - 知乎 - 知乎专栏. https://zhuanlan.zhihu.com/p/85847486. (3) 冯诺依曼与哈佛结构的区别 - CSDN博客. https://blog.csdn.net/zhangwenchaochao/article/details/91047661. (4) ARM到底是冯诺依曼结构还是哈佛结构 - 知乎 - 知乎专栏. https://zhuanlan.zhihu.com/p/126269758. (5) 冯诺依曼结构和哈佛结构之间的区别 - 百度知道. https://zhidao.baidu.com/question/333521852.html.
# 16 哈佛架构和冯诺依曼架构的适用场景
哈佛架构和冯诺依曼架构的适用场景各有不同,主要取决于程序指令和数据的存储和访问需求。
冯诺依曼架构主要用于通用计算机领域,需要对存储器中的代码和数据频繁的进行修改,统一编址有利于节约资源。¹² 但是,这种结构也导致了指令和数据共享同一总线,造成了信息流的传输瓶颈,影响了数据处理速度的提高。
哈佛架构主要用于嵌入式计算机,程序固化在硬件中,有较高的可靠性、运算速度和较大的吞吐量。¹² 这种结构可以使指令和数据分别经由不同的存储空间和不同的总线,同时取指和取数,提高了运算效率,但是也增加了复杂度和对外围设备的要求。
ARM是一种改进型的哈佛架构,它使用了内部缓存(cache)来存放指令和数据,而且指令缓存和数据缓存是分开的。⁴ 这样既保留了哈佛架构的优点,又克服了冯诺依曼结构的缺点。⁴ ARM适用于需要高性能、低功耗、多任务处理的场景,如智能手机、平板电脑、物联网等。
源: 与必应的对话, 2023/5/15 (1) 哈佛结构&冯·诺依曼结构 - 知乎 - 知乎专栏. https://zhuanlan.zhihu.com/p/615523283. (2) 哈佛结构和冯诺依曼结构 - 知乎 - 知乎专栏. https://zhuanlan.zhihu.com/p/85847486. (3) 一套用了 70 年的计算机架构 —— 冯·诺依曼架构 - 知乎. https://zhuanlan.zhihu.com/p/581546247. (4) 哈佛结构还是冯诺依曼结构的特点有哪些 - 开发技术 - 亿速云. https://www.yisu.com/zixun/483127.html. (5) STM32属于哈佛结构还是冯诺依曼结构? - 知乎 - 知乎专栏. https://zhuanlan.zhihu.com/p/368910734.
# 17 看门狗是什么?
嵌入式看门狗是一种专门用于监测系统程序运行状态的芯片或程序,俗称"看门狗" (watchdog)。在嵌入式系统中,由于MCU常常会受到来自外界电磁场的干扰,造成程序跑飞而陷入死循环,无法继续工作,整个系统陷入停滞状态,发生不可预料的后果,所以出于对运行状态进行实时监测的考虑,便产生了一种专门用于监测系统程序运行状态的芯片或程序,俗称"看门狗" (watchdog) ¹。
希望这可以回答您的问题。如果您有其他问题,请随时问我!
源: 与必应的对话, 2023/5/15 (1) 嵌入式主板的“看门狗“功能是指什么 - 百度知道. https://bing.com/search?q=%e5%b5%8c%e5%85%a5%e5%bc%8f%e7%9c%8b%e9%97%a8%e7%8b%97%e6%98%af%e4%bb%80%e4%b9%88. (2) 看门狗原理_硬件看门狗的工作原理_kuniqiw的博客-CSDN博客. https://blog.csdn.net/kuniqiw/article/details/113098733. (3) 谈谈看门狗在嵌入式中的用法 - 简书. https://www.jianshu.com/p/cf6f6316565c. (4) 基于嵌入式系统中看门狗的原理与使用 - 电子发烧友网. https://www.elecfans.com/d/632710.html. (5) STM32 看门狗详解 - 知乎 - 知乎专栏. https://zhuanlan.zhihu.com/p/349094185. (6) 一篇文章搞定嵌入式看门狗watch dog概述与示例代码_看门狗代码_木头人i的博客-CSDN博客. https://blog.csdn.net/weixin_43332735/article/details/108862690.
# 18 integer operation result is out of range
GPIOC->CRL &= ~(0xff << 24);
编译后编译器报错:
integer operation result is out of range (61-D)
,经查资料是由于溢出所致,宏定义默认常量是有符号型,
当 0xff
左移 24 位时,常数就变成负数,编译器就会给出如上的警告信息解决办法是强制类型转换成无符号类型:
GPIOC->CRL &= ~((uint32_t)0xff << 24);
# 19 波特率和比特率
波特(Baud)即调制速率,指的是有效数据信号调制载波的速率,即单位时间内载波调制状态变化的次数。
它是对符号传输速率的一种度量,1波特即指每秒传输1个符号,而通过不同的调制方式,可以在一个码元符号上负载多个bit位信息。
“波特”(Baud)本身已是速率,所以不需要写成 Baud Rate(Rate 是赘字)。单位“波特”本身就已经是代表每秒的调制数,以“波特每秒”(Baud per second)为单位是一种常见的错误,但是在一般中文口语化的沟通上还是常以“波特率”来描述“波特”(Baud)
比特率:对信息传输速率(传信率)的度量
波特率:单位时间内传输符号的个数(传符号率)
如果在数字传输过程中,用0V表示数字0,5V表示数字1,那么每个码元有两种状态0和1. 每个码元代表一个二进制数字。此时的每秒码元数和每秒二进制代码数是一样的,这叫两相调制,波特率等于比特率。
如果在数字传输过程中,0V、2V、4V和6V分别表示00、01、10和11,那么每个码元有四种状态00、01、10和11. 每个码元代表两个二进制数字。此时的每秒码元数是每秒二进制代码数是一半的,这叫四相调制,波特率等于比特率一半。
1波特 = 1位/秒,1baud = 1 bit/s
两者关系
波特率与比特率的关系为:比特率=波特率X单个调制状态对应的二进制位数
I = S * log2N
# 20 中断和函数的区别
中断:
- 何时发生是不可预料的。
- 对于可剥夺型内核,完成中断调度后不是立刻返回原来的执行点执行,而是回到就绪态优先级最高的任务开始执行。
- 没有返回值。
- 不能传递参数。
函数:
- 何时发生是可以预料的。
- 完成函数调度后会返回原来的代码片段继续执行。
- 有返回值。
- 能传递参数。
相同点:
- 再执行调度之前,都会保存现场。
- 都是调用一个 subcode。
# 21 中断和事件的区别
从外部激励信号来看,中断和事件的产生源都可以是一样的.之所以分成2个部分,由于中断是需要CPU参与的,需要软件的中断服务函数才能完成中断后产生的结果;
但是事件,是靠脉冲发生器产生一个脉冲,进而由硬件自动完成这个事件产生的结果,当然相应的联动部件需要先设置好,比如引起DMA操作,AD转换等;
简单举例:外部I/O触发AD转换,来测量外部物品的重量;如果使用传统的中断通道,需要I/O触发产生外部中断,外部中断服务程序启动AD转换,AD转换完成中断服务程序提交最后结果;
要是使用事件通道,I/O触发产生事件,然后联动触发AD转换,AD转换完成中断服务程序提交最后结果;相比之下,后者不要软件参与AD触发,并且响应速度也更块;
要是使用事件触发DMA操作,就完全不用软件参与就可以完成某些联动任务了。
可以这样简单的认为,事件机制提供了一个完全由硬件自动完成的触发到产生结果的通道,不要软件的参与,降低了CPU的负荷,节省了中断资源,提高了响应速度(硬件总快于软件),是利用硬件来提升CPU芯片处理事件能力的一个有效方法。
# 22 什么时候需要开启 AFIO 时钟?
根据参考手册:
- 事件控制寄存器
- 复用重映射和调试 I/O 配置寄存器
- 外部中断配置寄存器1
- 外部中断配置寄存器2
- 外部中断配置寄存器3
- 外部中断配置寄存器3
只有需要用到重映射、时间寄存器、配置寄存器、外部中断时需要打开 AFIO 时钟,引脚复用时不用打开。
# 23 stm32 部分重映射和完全重映射有什么区别?端口复用和端口重映射有什么区别?
# 24 为什么内核里不能使用 printf?
printf是用户态的接口,其最终会依赖系统调用,内核不能使用用户态的接口。
内核中不能链接使用 libc 库,主要的原因是速度和大小,C 库效率太低,代码空间大。
但是大部分常用的 C 库都已经在内核里实现了。
# 25 为什么 linux 驱动程序里都是静态函数?
linux内核十分宠大,代码量超过百万行。对于C语言的函数和全局变量的作用空间都是
全局的,在另外一个文件中,使用extern关键字就可以实现对于其他文件中的全局变量
和函数的访问。因此,一旦源码中函数名称定义相同,就会出现编译出错。因此,需要
引入一些封装的特性,限制源码中函数和变量作用的空间。在前面添加static关键字,
其作用范围将缩小到仅仅为当前的文件,而不是整个系统。因此在平时写驱动时,如果
函数不需要被其他文件中引用,在前面添加static关键字是一个很好的习惯。
# 26 obj-m 和 obj-y 有什么区别?
obj-m表示把文件test.o作为"模块"进行编译,不会编译到内核,但是会生成一个独立的 "test.ko" 文件;
obj-y表示把test.o文件编译进内核;
# 27 为什么 linux 操作寄存器前要 ioremap?
linux 为了实现进程虚拟地址,在启用 MMU 后,内核中操作的是虚拟地址,内核访问不到物理地址。 如果操作了物理地址等于访问量非法地址,会导致内核奔溃。
# 28 字符设备和块设备的区别是什么?
系统中能够随机(不需要按顺序)访问固定大小数据片(chunks)的设备被称作块设备,这些数据片就称作块。最常见的块设备是硬盘,除此以外,还有软盘驱动器、CD-ROM驱动器和闪存等等许多其他块设备。注意,它们都是以安装文件系统的方式使用的——这也是块设备的一般访问方式。 另一种基本的设备类型是字符设备。字符设备按照字符流的方式被有序访问,像串口和键盘就都属于字符设备。如果一个硬件设备是以字符流的方式被访问的话,那就应该将它归于字符设备;反过来,如果一个设备是随机(无序的)访问的,那么它就属于块设备。 这两种类型的设备的根本区别在于它们是否可以被随机访问——换句话说就是,能否在访问设备时随意地从一个位置跳转到另一个位置。举个例子,键盘这种设备提供的就是一个数据流,当你敲入“fox” 这个字符串时,键盘驱动程序会按照和输入完全相同的顺序返回这个由三个字符组成的数据流。如果让键盘驱动程序打乱顺序来读字符串,或读取其他字符,都是没有意义的。所以键盘就是一种典型的字符设备,它提供的就是用户从键盘输入的字符流。对键盘进行读操作会得到一个字符流,首先是“f”,然后是“o”,最后是“x”,最终是文件的结束(EOF)。当没人敲键盘时,字符流就是空的。硬盘设备的情况就不大一样了。硬盘设备的驱动可能要求读取磁盘上任意块的内容,然后又转去读取别的块的内容,而被读取的块在磁盘上位置不一定要连续,所以说硬盘可以被随机访问,而不是以流的方式被访问,显然它是一个块设备。 内核管理块设备要比管理字符设备细致得多,需要考虑的问题和完成的工作相比字符设备来说要复杂许多。这是因为字符设备仅仅需要控制一个位置—当前位置—而块设备访问的位置必须能够在介质的不同区间前后移动。所以事实上内核不必提供一个专门的子系统来管理字符设备,但是对块设备的管理却必须要有一个专门的提供服务的子系统。不仅仅是因为块设备的复杂性远远高于字符设备,更重要的原因是块设备对执行性能的要求很高;对硬盘每多一分利用都会对整个系统的性能带来提升,其效果要远远比键盘吞吐速度成倍的提高大得多。另外,我们将会看到,块设备的复杂性会为这种优化留下很大的施展空间。 简单来讲,块设备可以随机存取,而字符设备不能随机存取,那裸设备又该如何解释呢? 难道裸设备,如磁盘裸设备也不能随机读取吗?那在数据库中用裸设备建一个2g的数据文件,为了存取最后一个数据块,难道ORACLE还要把前面的所有数据块都读一遍,显然不符合事实,如果这样解释呢,操作系统不能随机读取,并不意味着数据库也不能随机读取。 块设备通过系统缓存进行读取,不是直接和物理磁盘读取。字符设备可以直接物理磁盘读取。不经过系统缓存。(如键盘,直接相应中断)
https://blog.51cto.com/majesty/991565
# 29 ClearFlag()和ClearITPendingBit()的区别
ClearFlag():清除中断标志位
ClearITPendingBit():清除中断待处理位
标志位是事件发生与否的判断依据,用于支持函数的运行,如果事件发生, 则该位至1,但是这不一定会产生中断。
待处理位是控制中断发生的标志,如果该位置1(前提是相应标志位置1和中断已使能),则会产生中断,进入中断服务函数,而且在中断服务函数中必须手动将该位置0,否则程序会一直执行该中断。
这两个函数实现的功能其实是一样的,都是清除对应的标志位,但是标志位和中断位的含义不一样,不是所有的标志位都可以产生中断。
有的标志位不能产生中断, 标志位在程序中可以作为判定条件,支持程序的运行,中断则是跳转到中断函数执行。两个函数实现的功能是 一样的,在中断程序中可以用两个中的任一个。
# 30 什么是 MMU ?
MMU 全称为 Memory Management Unit,即 内存管理单元。在 带有MMU的嵌入式Linux 中,CPU 访问的地址都是 虚拟地址,而 MMU 负责将程序中 代码或数据 的 虚拟地址 翻译为 物理地址,以便程序访问内存。
在执行操作时,MMU 会自动转换 CPU发出的虚拟地址,无法人工进行操作,只需要配置好 MMU 相关属性即可。
虚拟地址 是在 编译和链接 时定义的,可以简单地理解为 由链接器和链接器脚本 指定虚拟地址。 除了 翻译虚拟地址,MMU 还可以配置 内存区域 的各项配置,如内存区域的访问权限,内存区域是否使能cache等功能。 总结 MMU 的功能,如下:
- 翻译虚拟地址
- 配置内存区域的相关属性
# 31 为什么无线频段都选择 2.4G 和 5G?
2.4GHz频段是无线电频谱中未经授权的ISM频段之一,用于工业、科学和医疗设备,包括微波炉和无线局域网(WLAN)等设备。
2.4GHz频段由于频率较低所以覆盖范围较广,并且拥有较强的穿透能力。
电话线路的带通是300--3KHz,HAYES先发明的 modem,所以用的2400HZ信号,对应波特率是2400。由于基本频率确定了,以后采用的提高通讯速率的方法都是在2400基础上倍频的,所以形成了9600,19200,115200 等。
波特率115200 = 115200 (位/秒)。
如果没有校验位,就应该除以 10,得到的是每秒字节数:波特率115200 = 115200 (位/秒) = 11520 (字节/秒)。
再除以 1024,就是每秒 KB 数:波特率115200 = 115200 (位/秒) = 11.25 (KB/秒)。如果有一位奇偶校验位,就应该除以 11,得到的是每秒字节数。
最后得出:波特率115200 = 115200 (位/秒) = 10.27 (KB/秒)。
# 32 为什么要有堆和栈?
为什么要有栈?
- 函数内部会定义局部变量,变量要占内存,由于位于同一函数中,很自然的想法是将其内存空间放在一起,有利于整体申请和释放。所以栈帧首先是一个容器。
- 一个函数一帧,多个函数多个帧。如何组织呢? PS: 是散列不行,所以选择了线性,队列不合适,选择了栈。
- 散列。一个函数的栈帧随意在内存中分配,栈帧地址与函数名建立关联关系 ==> 调用方与被调用方要保存对方的堆栈空间地址。
- 线性。又分为队列和栈两种结构。函数调用符合栈的特性,就用栈了。
为什么需要栈?为了支持函数。OS设计体现了对进程、线程的支持,直接提供系统调用创建进程、线程, 但就进程/线程内部来说,os 认为代码段是一个指令序列,最多jump几下,指令操作的数据都是事先 分配好的(数据段主要容纳全局变量,且是静态分配的),没有直接体现对函数的支持 (只是硬件层面上提供了栈指针寄存器,编译器实现函数参数、返回值压栈、出栈)。 没有函数,代码会重复,有了函数,才有局部变量一说,有了局部变量才有了数据的动态申请与分配一说。 函数及其局部变量 是最早的 代码+数据的封装。
为什么要有堆?
光有栈,对于面向过程的程序设计还远远不够,因为栈上的数据在函数返回的时候就会被释放掉, 所以无法将数据传递至函数外部。而全局变量没有办法动态地产生,只能在编译的时候定义, 有很多情况下缺乏表现力,在这种情况下,堆(Heap)是一种唯一的选择。
堆适合管理生存期较长的一些数据,这些数据在退出作用域以后也不会消失。
堆分配运行程序员按任意顺序分配/释放程序所需的数据结构——动态分配的数据结构可以脱离其调用者生命周期的限制。