FreeRTOS ARM简明架构

1 关键寄存器详解

1.1 R13 (SP) 栈指针寄存器

功能说明:

复制代码
栈指针 (Stack Pointer):指向当前堆栈的顶部
ARM CortexM 处理器有两个独立的栈指针:
  1. MSP (Main Stack Pointer):主栈指针
     用于异常处理程序(中断、异常)
     操作系统内核代码使用
  2. PSP (Process Stack Pointer):进程栈指针
     用于普通应用程序代码
     每个任务可以有自己的PSP

在FreeRTOS中的应用:

复制代码
; 在任务切换时保存和恢复PSP
mrs r0, psp           ; 读取当前任务的PSP到r0
; ... 保存任务上下文 ...
msr psp, r0           ; 恢复新任务的PSP

栈操作示例:

复制代码
; 压栈操作(Push)
push {r0-r3, lr}   ; 将r0、r1、r2、r3和lr寄存器的值依次压入栈中
                   ; 作用:保存函数调用前的寄存器状态,lr存储返回地址

; 出栈操作(Pop)
pop {r0-r3, pc}    ; 从栈中依次恢复r0、r1、r2、r3的值,并将原lr的值写入pc
                   ; 作用:恢复寄存器状态,同时通过pc跳回原调用地址(实现函数返回)

1.2 R14 (LR) 链接寄存器

功能说明:

复制代码
链接寄存器 (Link Register):存储函数调用的返回地址
调用子程序时,处理器自动将返回地址保存在LR中
从子程序返回时,可以使用 BX LR 指令返回

特殊用法:

复制代码
1. 异常处理中的LR:
   进入异常时,LR被设置为特殊的EXC_RETURN值
   EXC_RETURN指示返回时应使用的堆栈指针和处理器模式

2. EXC_RETURN值:
   CortexM3/M4 EXC_RETURN值
   0xFFFFFFF9  返回线程模式,使用MSP
   0xFFFFFFFD  返回线程模式,使用PSP
   0xFFFFFFF1  返回Handler模式,使用MSP

使用示例:

复制代码
; 调用函数
bl function_name      ; 1. 将下一条指令地址存入LR
                      ; 2. 跳转到function_name

; 函数返回
bx lr                ; 跳转到LR中的地址,返回调用者

; 嵌套调用时保护LR
push {lr}            ; 保存LR到栈中
bl another_function
pop {lr}             ; 从栈中恢复LR
bx lr                ; 返回

1.3 R15 (PC) 程序计数器

功能说明:

复制代码
程序计数器 (Program Counter):存储下一条要执行的指令地址
正常执行时,PC自动递增(ARM状态+4,Thumb状态+2)
通过修改PC的值可以跳转到任意地址执行

特殊性质:

复制代码
1. 读取PC:读取PC时,返回当前指令地址+4(ARM)或+2(Thumb)
2. 修改PC:写入PC会立即跳转到新地址执行
3. 对齐要求:PC值必须对齐到指令长度(Thumb为2字节对齐)

使用示例:

复制代码
; 直接跳转
ldr pc, =0x08001000  ; 跳转到绝对地址

; 相对跳转
add pc, pc, 0x100   ; PC相对跳转

; 条件跳转
cmp r0, 10
beq target_label     ; 如果相等则跳转

2 ARM汇编指令详解

2.1 内存访问指令

LDR (Load Register) 加载寄存器

复制代码
; 基本语法:LDR{条件} Rd, [Rn, offset]
LDR R0, [R1]         ; 从R1指向的地址读取4字节到R0
LDR R0, [R1, 4]      ; 从R1+4的地址读取4字节到R0
LDR R0, [R1, 4]!     ; 从R1+4读取,然后R1=R1+4(前变址)
LDR R0, [R1], 4      ; 从R1读取,然后R1=R1+4(后变址)
LDR R0, [R1, R2]     ; 从R1+R2的地址读取
LDR R0, [R1, R2, LSL 2]  ; 从R1+(R2<<2)的地址读取

STR (Store Register) 存储寄存器

复制代码
; 基本语法:STR{条件} Rd, [Rn, offset]
STR R0, [R1]         ; 将R0的4字节写入R1指向的地址
STR R0, [R1, 4]      ; 将R0的4字节写入R1+4的地址
STR R0, [R1, 4]!     ; 写入R1+4,然后R1=R1+4
STR R0, [R1], 4      ; 写入R1,然后R1=R1+4

批量加载/存储指令

复制代码
; LDM/STM指令格式:op{条件}{模式} Rn{!}, reglist{^}
; 模式:IA(后递增)、IB(前递增)、DA(后递减)、DB(前递减)

LDMIA R0!, {R1-R3}    ; 从R0读取到R1,R2,R3,R0每次增加4
STMIA R0!, {R1-R3}    ; 将R1,R2,R3写入R0,R0每次增加4

; 在FreeRTOS任务切换中的应用
STMFD SP!, {R0-R12, LR}  ; 保存所有寄存器到栈(全递减)
LDMFD SP!, {R0-R12, PC}  ; 从栈恢复所有寄存器并返回

2.2 算术运算指令

ADD (Addition) 加法

复制代码
; 语法:ADD{条件}{S} Rd, Rn, Operand2
ADD R0, R1, R2       ; R0 = R1 + R2
ADD R0, R1, 0xFF     ; R0 = R1 + 255
ADD R0, R0, 1        ; R0++,相当于R0=R0+1
ADDS R0, R1, R2      ; 加法并更新标志位

SUB (Subtraction) 减法

复制代码
; 语法:SUB{条件}{S} Rd, Rn, Operand2
SUB R0, R1, R2       ; R0 = R1 - R2
SUB R0, R1, 0xFF     ; R0 = R1 - 255
SUB R0, R0, 1        ; R0,相当于R0=R0-1
SUBS R0, R1, R2      ; 减法并更新标志位

其他算术指令

复制代码
MUL R0, R1, R2        ; 乘法:R0 = R1 × R2
AND R0, R1, R2        ; 逻辑与:R0 = R1 & R2
ORR R0, R1, R2        ; 逻辑或:R0 = R1 | R2
EOR R0, R1, R2        ; 逻辑异或:R0 = R1 ^ R2
MOV R0, R1            ; 移动:R0 = R1
MOV R0, 0x100         ; 立即数移动:R0 = 256

2.3 比较和跳转指令

CMP (Compare) 比较

复制代码
; 语法:CMP{条件} Rn, Operand2
; 实际执行:Rn  Operand2,结果不保存,只更新标志位

CMP R0, 10           ; 比较R0和10

B (Branch) 无条件跳转

复制代码
; 语法:B{条件} label
B main                ; 无条件跳转到main标签
BEQ label1            ; 如果相等(Z=1)则跳转到label1
BNE label2            ; 如果不相等(Z=0)则跳转到label2
BGT label3            ; 如果大于(有符号)则跳转到label3

BL (Branch with Link) 带链接的跳转

复制代码
; 语法:BL{条件} label
; 功能:1. 将下一条指令地址存入LR
;       2. 跳转到label

BL function_name      ; 调用函数
; 调用后LR = 返回地址
; 函数中应该使用BX LR返回

BX (Branch and Exchange) 跳转并切换指令集

复制代码
; 语法:BX{条件} Rm
; 功能:跳转到Rm指定的地址,并根据Rm[0]决定使用ARM还是Thumb状态

BX LR                 ; 返回到LR中的地址(常用)
BX R0                 ; 跳转到R0中的地址

2.4 特殊指令

MRS/MSR 状态寄存器访问

复制代码
; 读取状态寄存器到通用寄存器
MRS R0, CPSR          ; 读取当前程序状态寄存器
MRS R0, SPSR          ; 读取保存的程序状态寄存器(异常模式)
MRS R0, APSR          ; 读取应用程序状态寄存器
MRS R0, MSP           ; 读取主栈指针
MRS R0, PSP           ; 读取进程栈指针

; 写通用寄存器到状态寄存器
MSR CPSR, R0          ; 写当前程序状态寄存器
MSR PSP, R0           ; 写进程栈指针

数据传送指令

复制代码
; LDR伪指令  加载任意32位常数
LDR R0, =0x12345678   ; 加载32位立即数
LDR R0, =label        ; 加载标签地址

; MOV/MVN  移动和取反移动
MOV R0, 0x100        ; R0 = 256
MVN R0, 0xFF         ; R0 = ~0xFF = 0xFFFFFF00

3 常用指令组合模式

4.1 函数调用标准序言/尾声

复制代码
; 函数序言(保存寄存器)
PUSH {R4R11, LR}      ; 保存被调用者保存的寄存器和返回地址
SUB SP, SP, LOCAL_SIZE ; 为局部变量分配栈空间

; 函数尾声(恢复寄存器)
ADD SP, SP, LOCAL_SIZE ; 释放局部变量空间
POP {R4R11, PC}       ; 恢复寄存器并返回(直接将返回地址弹出到PC)

4.2 原子操作实现

复制代码
; 使用LDREX/STREX实现原子操作
atomic_increment:
    LDREX R1, [R0]     ; 独占加载
    ADD R1, R1, 1     ; 递增
    STREX R2, R1, [R0] ; 尝试独占存储
    CMP R2, 0         ; 检查是否成功
    BNE atomic_increment ; 失败则重试
    BX LR              ; 返回

4.3 循环和条件判断

复制代码
; 简单的for循环
    MOV R0, 0         ; i = 0
loop_start:
    CMP R0, 10        ; 比较i和10
    BGE loop_end       ; 如果i>=10,跳出循环
    
    ; 循环体代码...
    
    ADD R0, R0, 1     ; i++
    B loop_start       ; 继续循环
loop_end:
相关推荐
维构lbs智能定位2 小时前
人员定位软件系统从核心架构、关键功能、主流技术、典型应用与选型要点详解
架构
国科安芯2 小时前
RISC-V架构抗辐照MCU在航天器载荷中的SEU/SEL阈值测试与防护策略
单片机·嵌入式硬件·安全·架构·安全威胁分析·risc-v
郑州光合科技余经理2 小时前
源码部署同城O2O系统:中台架构开发指南
java·开发语言·后端·架构·系统架构·uni-app·php
阿波罗尼亚2 小时前
Java框架中的分层架构
java·开发语言·架构
猫猫的小茶馆2 小时前
【Linux 驱动开发】三. 应用程序调用驱动过程分析
linux·arm开发·驱动开发·stm32·单片机·嵌入式硬件·pcb工艺
liulanba2 小时前
AI Agent技术完整指南 第四部分:Transformer架构与实践
人工智能·架构·transformer
roman_日积跬步-终至千里2 小时前
【架构-选型逻辑】如何让业务逻辑与开源项目核心逻辑精准对齐——从功能匹配到逻辑对齐的思维转换
架构·开源
Jia ming3 小时前
ARM多核处理器缓存一致性全解析
arm开发·缓存
码农三叔3 小时前
(4-1)机械传动系统与关节设计:关节驱动方式对比
人工智能·架构·机器人·人形机器人