(嵌入式八股)No.3 STM32(1)

1.1 了解即可:MCU/MPU/SOC/FPGA/DSP/NPU

嵌入式处理芯片主要根据集成度和应用场景分为 MCU、MPU 和 SoC。

- MCU (微控制器) 就像‘全能单身公寓’,集成了 CPU、RAM、Flash 和外设,没有 MMU,主要运行裸机或 RTOS,用于低功耗实时控制(如 STM32)。

- MPU (微处理器) 就像‘高性能引擎’,计算能力强但需要外挂 DDR 和存储,拥有 MMU,可以运行 Linux 等大型系统(如早期 ARM9)。

- SoC (片上系统) 则是现代主流的‘摩天大楼综合体’,它在 MPU 的基础上进一步集成了 GPU、NPU、WiFi 等专用模块,适合高性能计算和多媒体应用(如 RK3588)。

此外,还有专攻数学运算的 DSP、硬件逻辑可编程的 FPGA 以及专攻 AI 加速的 NPU,它们常作为协处理器配合 SoC 使用。”

1.2 STM32启动流程(熟悉)

注:如果觉得八股还是不太了解,后续可以去结合 OTA 升级再巩固巩固

先了解一下什么是MSP和PSP

MSP(Main Stack Pointer)主堆栈指针​

•用途:默认堆栈指针,用于处理模式(Handler Mode),即中断、异常处理等系统级操作。

•特点:​

◦系统复位后自动启用;​

◦所有异常处理(如中断服务程序)都必须使用MSP;​

◦始终在特权模式下使用;

◦是全局共享的堆栈指针,系统内核使用它来处理紧急事务。

PSP(Process Stack Pointer)进程堆栈指针​

◦用途:用于线程模式(Thread Mode)下的应用程序代码(如用户任务)。​

◦特点:​

需要显式配置,常用于多任务系统(如RTOS);不同任务切换的时候PSP指针就会指向不同的任务,这个在RTOS调试中也会用到!

每个任务可拥有独立的PSP,实现堆栈隔离;

▪可在特权或非特权模式下使用(取决于配置);​

▪若某个任务发生堆栈溢出,不会影响其他任务或系统内核。

启动流程(熟悉)

1️⃣硬件复位序列(芯片自动完成)​

上电/外部复位​(POR/PDR 电路释放后就是重启之后,内核处于已知状态):​

◦PC = 0x0000 0000​

◦所有寄存器为默认值,Flash 等待周期按出厂设定。​

取第一个字——主堆栈顶(MSP)​

内核从 0x0000 0000 读出 32 位数值(也就是4个字节),装入 MSP。

(该值实际存放在 Flash 0x0800 0000,通过地址别名映射到 0x0000 0000。)​

取第二个字——复位向量​

从 0x0000 0004 读出 Reset_Handler 地址,跳转到该地址,开始执行用户代码。

2️⃣启动文件运行(startup_stm32xxxx.s)​

4. 建立 C 运行环境​

•把 Flash 中的 .data 常量拷贝到 RAM(已初始化全局变量)​

•把 .bss 段全部清零(未初始化全局变量)

•可选:把 _estack 重新装入 MSP,确保栈顶对齐​

系统级初始化​

◦调用 SystemInit():使能 FPU、配置 RCC 时钟树、重映射中断向量表(写 SCB->VTOR)​

◦调用 __libc_init_array():为 C++ 全局对象调用构造函数(纯 C 工程亦会执行)​

进入用户世界​

◦bl main(这个是BL是汇编指令,先记下返回地址(把下一条指令地址写入 LR 寄存器),再跳转到目标函数。)​

从此开始执行用户 main(),启动流程结束。​

3️⃣总结:​

上电/复位​

→ 硬件自动:取 MSP → 取 Reset_Handler → 跳转​

→ 软件汇编:copy .data / zero .bss → SystemInit() → __libc_init_array()​

→ main()

1.3 ARM架构(了解即可,寄存器务必掌握)

入门了解即可

Cortex‐M3 的一个简化视图

ARM 架构的

在嵌入式开发领域,ARM架构的处理器占了90%以上的市场份额, 大多数人学习嵌入式都是从ARM开始的。如果时间足够的话可以去学习一下简单的汇编指令。如果时间不够的话就深入了解ARM体系结构和工作流程。

ARM 即 Advanced RISC Machines 的缩写,在嵌入式开发领域,ARM 架构的处理器占了 90%以上的市场份额, 大多数人学习嵌入式都是从 ARM 开始的。如果时间足够的话可以去学习一下简单的汇编指令。如果时间不够的话就深入了解 ARM 体系结构和工作流程。

ARM 有三种不同系列的处理器,分为 ARM 三种系列,同时有多种架构,比如 ARMv6ARMv7ARMv8

  • M 系列处理器主要是低性能芯片,应用于单片机领域,我们常说的 STM32F103、STM32F407、STM32H750 都是 M 内核的,分别对应 M3/M4/M7 内核。
  • A 系列处理器主要是高性能芯片,跑 Linux 系统,比如 imx6ull、STM32MP15x 等。
  • R 系列处理器实时性较强,芯片性能高于 M 系列,主要应用于工业领域

ARM 从 v6 版本开始转变设计理念,最终在 v7 版本中正式将内核架构划分为 A、R、M 三大系列,分别针对不同的应用场景。

架构演进:ARMv7 与 ARMv8

  1. 核心区别
  • ARMv7:32 位架构,确立了 A/R/M 三大分系。
  • ARMv8:引入了 64 位支持(AArch64),并在 M 系列中引入了硬件级安全特性。
  1. Cortex-M 系列的演进 (v7-M vs v8-M)

ARMv7-M (如 M3/M4/M7)

  • 传统的扁平内存模型。
  • 安全性依赖软件或 MPU 进行简单的区域保护。

ARMv8-M (如 M23/M33):

  • TrustZone 技术:最大的升级点。将硬件资源物理隔离为 安全域 (Secure World) 和 非安全域 (Non-secure World)。
  • 应用价值:在物联网设备中保护密钥和核心启动代码,防止通过非安全应用窃取核心数据。

Cortex-M3/M4 /M7 均基于 ARMv7-M 架构,具备以下核心硬件特性: 务必熟悉

流水线与总线架构

  • 三级流水线:取指 (Fetch) \rightarrow\解码 (Decode) \rightarrow\执行 (Execute)。支持分支预测。
  • 哈佛架构 (Harvard Architecture):指令总线 (I-Code) 和 数据总线 (D-Code) 分离,可同时进行指令读取和数据访问。
  • 统一编址:尽管总线分离,但指令和数据共享同一个 4GB 线性地址空间 (0x00000000 ~ 0xFFFFFFFF)。
  • AMBA 总线标准:基于 AHB-Lite (高速) 和 APB (外设) 总线协议,支持高吞吐量操作。

存储与位操作

  • 位带操作 (Bit-banding):支持对两个特定存储器区域(SRAM 和 外设区)进行位寻址。通过访问“别名区”的一个字,实现对“位带区”某个位的原子操作(读-改-写)。
  • MPU (存储器保护单元):可选组件。提供硬件级的内存访问权限控制(如设置某区域为只读、不可执行),增强系统健壮性。(M7 会带)

中断与系统控制

  • NVIC (嵌套向量中断控制器):紧耦合于内核,低延迟(12 个周期)。支持 中断嵌套。支持 8~256 个 中断优先级。支持最多 240 个外部中断请求。
  • 双堆栈机制 (Shadow Stack Pointer):MSP (主堆栈指针):用于 OS 内核和中断服务程序。PSP (进程堆栈指针):用于用户应用程序。作用:实现 OS 内核与用户任务的堆栈隔离,提高安全性。
  • 低功耗支持:支持睡眠模式 (Sleep) 和深度睡眠 (Deep Sleep),配合 WFI/WFE 指令。

总结

ARM处理器的工作模式:(了解)

  • 应用程序正常运行时,ARM 处理器工作在用户模式(User mode),当程序运行出错或有中断发生时,ARM 处理器就会切换到对应的特权工作模式。
  • 用户模式属于普通模式,有些特权指令是运行不了的,需要切换到特权模式下才能运行。在 ARM 处理器中,除了用户模式是普通模式,剩下的几种工作模式都属于特权模式。
  • 目的是为了实现代码隔离和安全保护。
  • 在 CM3 中取消了 FIQ 的概念(v7 前的 ARM 都有这个 FIQ,快中断请求),这是因为有了更新更好的机制——中断优先级管理以及嵌套中断支持,它们被纳入 CM3 的中断管理逻辑中。

两种操作模式 (Operation Modes)

用于区分“普通代码”和“异常代码”。

  • 处理者模式 (Handler Mode):谁在用:所有的 中断服务例程 (ISR) 和 异常处理函数。特点:永远处于特权级。中断发生时,处理器自动进入此模式;中断返回时,自动退出。
  • 线程模式 (Thread Mode):谁在用:普通的 主应用程序 (main 函数及后台任务)。特点:复位后默认进入此模式。它可以是特权级,也可以是用户级。

两种特权级 (Privilege Levels)

用于提供内存访问保护机制。

  • 特权级 (Privileged Level):权限:上帝视角。可以访问所有内存地址(包括系统控制寄存器 NVIC, SCB 等),执行所有指令。默认:系统复位后,默认处于 特权级。
  • 用户级 (User Level):权限:受限视角。不能访问系统关键寄存器(如 NVIC, SYSTICK)。不能访问被 MPU 保护的特权内存区。这些区域通常是操作系统的区域。试图访问受限资源会触发 HardFault 或 BusFault。目的:运行不受信任的程序或普通的 OS 任务,防止它们把系统搞崩。

总结

Handler 模式专管中断,永远是特权的;

Thread 模式跑应用程序,复位是特权的,但可以切成用户级;

特权用户很简单(改寄存器),用户想回特权必须通过 SVC 系统调用(异常)。

寄存器及其作用(务必掌握)

Cortex-M3 处理器内部包含两类核心寄存器:一是 通用寄存器 (R0-R15),其中 R0-R7 (低组) 可被所有指令(包括 16 位 Thumb)访问,而 R8-R12 (高组) 主要由 32 位 Thumb-2 指令访问,R13-R15 则有特定用途(SP, LR, PC);二是 特殊功能寄存器(如 xPSR, PRIMASK, CONTROL),它们负责保存处理器状态和控制运行模式,且必须通过专用的系统指令(MSR/MRS)才能访问。

寄存器组

a.通用寄存器

R0-R12(通用寄存器)​

  • R0~R3 通常用来传递函数参数,所以函数形参一般不超过 4 个!
  • R4~R11 用来保存程序运算的中间结果或函数的局部变量等(一般都是硬件自动保存)
  • R12 常用来作为函数调用过程中的临时寄存器。
  • 但是注意:绝大多数 16 位 Thumb 指令只能访问 R0‐R7,而 32 位 Thumb‐2 指令可以访问所有寄存器。

R13(栈指针,SP)

  • 物理寄存器:通用寄存器 R13 被用作堆栈指针。
  • 主堆栈指针(MSP):或写作 SP_main。这是缺省的堆栈指针,它由 OS 内核、异常服务例程以及所有需要特权访问的应用程序代码来使用。
  • 进程堆栈指针(PSP):或写作 SP_process。用于常规的应用程序代码(不处于异常服用例程中时)。
  • 用途:永远指向当前堆栈的栈顶(Stack Top)。
  • 操作:在函数调用(保存现场)和中断处理时,负责利用 PUSH(入栈)和 POP(出栈)指令管理内存数据。
  • 对齐规则:SP 的最低两位永远是 0。这意味着堆栈地址必须是 4 字节对齐 的(Word Aligned)。例如:SP 可以是 0x20001000 或 0x20001004,但绝不可能是 0x20001001。

▪特点:在函数调用和中断处理中,栈指针用于管理栈的入栈(PUSH)和出栈(POP)操作。​

R14(链接寄存器,LR)

▪用途:存储函数调用返回地址。​

▪特点:在函数调用时,ARM处理器会将返回地址存储到LR寄存器中。在函数返回时,从LR寄存器中获取返回地址。

R15(程序计数器,PC)

▪用途:存储当前指令的地址。​

▪特点:PC寄存器始终指向当前正在执行的指令的地址。每次指令执行后,PC会自动更新到下一条指令的地址。CPU一条一条不停地取指令,程序也就源源不断地一直运行下去。

举个🌰:比如我们运行函数的时候他是怎么运行的呢?可以理解为是把函数的地址加载到了 PC 指针上,然后就会运行 PC 指针指向的这个函数(这个地方再去复习一下函数指针)

b.特殊功能寄存器

  • 程序状态字寄存器组(PSRs)
  • Application PSR (APSR)
  • Execution PSR (EPSR)
  • Interrupt PSR (IPSR)
  • 中断屏蔽寄存器组(PRIMASK, FAULTMASK, BASEPRI) 只有在特权级下,才允许访问这 3 个寄存器PRI-MASK、FAULT-MASK 和 BASE-PRI 寄存器主要用于异常或者中断的屏蔽。每一个异常都有一个优先级的属性。

要访问 PRIMASK, FAULTMASK 以及 BASEPRI,同样要使用 MRS/MSR 指令,如:

MRS R0, BASEPRI ;        读取 BASEPRI 到 R0 中 
MRS R0, FAULTMASK ;        似上
MRS R0, PRIMASK ;        似上 
MSR BASEPRI, R0 ;        写入 R0 到 BASEPRI 中 
MSR FAULTMASK, R0 ;        似上 
MSR PRIMASK, R0 ;        似上

c.控制寄存器(CONTROL)

    CONTROL 寄存器用于定义特权级和堆栈指针的选择,仅能通过特殊指令 (MRS/MSR) 访问:

  • CONTROL[1] (堆栈选择位): 决定线程模式使用 MSP(0) 还是 PSP(1)。限制:Handler 模式下该位恒为 0(强制使用 MSP)。只有在特权级下才允许修改此位。
  • CONTROL[0] (特权级位): 0 为特权级,1 为用户级。单向限制: 特权级可直接写 1 切换到用户级;但用户级禁止写此位,想返回特权级必须触发异常(如 SVC),在异常服务例程中修改。
MRS <gp_reg>, <special_reg> ;读特殊功能寄存器的值到通用寄存器 
MSR <special_reg>, <gp_reg> ;写通用寄存器的值到特殊功能寄存器

d.状态寄存器(了解)​

CPSR(当前程序状态寄存器)​

•用途:存储当前处理器的状态信息,包括条件标志、中断屏蔽位等。​

•主要字段:​

◦N(负标志)表示结果为负。​

◦Z(零标志):表示结果为零。​

◦C(进位标志):表示有进位或借位。​

◦V(溢出标志):表示有溢出。​

◦I(IRQ中断屏蔽位):1表示禁止IRQ中断,0表示允许IRQ中断。​

◦F(FIQ中断屏位):1表示禁止FIQ中断,0表示允许FIQ中断。​

◦M(模式位):表示当前处理器的工作模式(如用户模式、中断模式等)。​

SPSR(保存的程序状态寄存器)​

•用途:在中断或异常处理时,保存当前的CPSR值。​

•特点:当处理器进入中断或异常处理模式时,CPSR的值会被保存到SPSR中。在中断或异常处理结束时,从SPSR中恢复CPSR的值。

指令集(了解 Thumb‐2)

Thumb‐2 指令集为编程带来了更多的灵活性。许多数据操作现在能用更短的代码搞定,这意味着 Cortex‐M3 的代码密度更高,也就对存储器的需求更少。

历史痛点 (ARM7 时代)

在 Cortex-M3 之前的处理器(如 ARM7TDMI),必须在两种互斥的状态间切换:开发者需要混合编程,处理器需要在运行时进行状态切换(Switching Overhead),既浪费时间又增加软件管理的复杂度。

- ARM 状态 :执行 32 位指令。性能强,但代码体积大。

- Thumb 状态 :执行 16 位指令。代码密度高(省 Flash),但性能弱(功能是 ARM 的子集)。

M3 的突破 (Thumb-2)

Cortex-M3 只支持 Thumb-2 指令集 ,彻底抛弃了传统的 ARM 指令集。

- 水乳交融 :Thumb-2 允许 16 位指令 和 32 位指令 在同一个指令流中混合使用,无需手动切换状态。取指都按 32 位处理。同一周期最多可以取出两条指令,留下了更多的带宽给数据传输。

- 自动识别 :处理器自动判断指令长度。

- 双重优势 :既拥有 Thumb 的高代码密度,又拥有 ARM 的高性能。

优点:

消灭切换开销:不再需要在 32 位/16 位 状态间跳来跳去,节省了执行时间和指令空间。

中断响应更快:以前中断必须在 ARM 状态下处理,现在直接在 Thumb-2 下处理,无需切换,响应更迅速。

开发更简单:不需要再考虑哪个文件用 ARM 编译、哪个用 Thumb 编译,统一汇编器 (Unified Assembler) 搞定一切。

#八股##满分简历要如何准备?#
泻湖花园嵌入式Offer指南 文章被收录于专栏

从入门到上岸,一站式搞定求职! 本硕纯机械,无竞赛无论文,后转行嵌入式软件开发(因为课题组师哥转嵌入式拿到30Woffer之后狠狠心动),秋招最终收获35W+offer可以为27届或者28届的的UU们提供参考,可以关注一下!!!

全部评论
启动流程mark
点赞 回复 分享
发布于 03-03 22:45 山东
点赞 回复 分享
发布于 03-03 22:45 山东

相关推荐

02-11 14:29
已编辑
字节跳动_QA
Edgestr:这种的写代码最狠了
点赞 评论 收藏
分享
评论
6
9
分享

创作者周榜

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