【FreeRTOS】ARM架构汇编实例

目录

  • ARM架构简明教程
    • 1. ARM架构
      • 电脑的组成
      • 1.2 RISC
      • 1.2 提出问题
      • 1.3 CPU内部寄存器
      • 1.4 汇编指令
    • 2. C函数的反汇编


学习视频
【FreeRTOS入门与工程实践 --由浅入深带你学习FreeRTOS(FreeRTOS教程 基于STM32,以实际项目为导向)】 https://www.bilibili.com/video/BV1Jw411i7Fz/?p=9&share_source=copy_web&vd_source=8af85e60c2df9af1f0fd23935753a933


ARM架构简明教程

1. ARM架构

电脑的组成

电脑的组成

对于单片机,叫SoC system on chip,在芯片上有完整的系统

芯片集成了CPU 内存 硬盘(flash)

内存:读出数据,写入数据

计算都是在CPU内完成的

1.2 RISC

ARM芯片属于精简指令集计算机(RISC:Reduced Instruction Set Computing),它所用的指令比较简单,有如下特点:

① 对内存只有读、写指令
② 对于数据的运算是在CPU内部实现
③ 使用RISC指令的CPU复杂度小一点,易于设计

在这里插入图片描述

对于上图所示的乘法运算a = a * b,在RISC中要使用4条汇编指令:

① 读内存a
② 读内存b
③ 计算a*b
④ 把结果写入内存

1.2 提出问题

问题:在CPU内部,用什么来保存a、b、a*b ?

回答:寄存器 R0、R1、R2……

1.3 CPU内部寄存器

在这里插入图片描述

无论是cortex-M3/M4,

还是cortex-A7,

CPU内部都有R0、R1、……、R15寄存器;

它们可以用来“暂存”数据。

在这里插入图片描述

对于R13、R14、R15,还另有用途:

R13:别名SP(Stack Pointer),栈指针

R14:别名LR(Link Register),用来保存返回地址

R15:别名PC(Program Counter),程序计数器,表示当前指令地址,写入新值即可跳转

1.4 汇编指令

  • 读内存:Load

    # 示例
    LDR  R0, [R1, #4]  ; 读地址"R1+4", 得到的4字节数据存入R0
    

Load R 读 四个字节,读R1+4的地址,读入的数据保存到R0里
其他指令:LDRB\LDRH
LDRB 读取一个字节 1Byte,LDRH 读取Half,2Bytes

  • 写内存:Stroe

    # 示例
    STR  R0, [R1, #4]  ; 把R0的4字节数据写入地址"R1+4"
    

写内存 4个字节STR 把R0的4字节数据写到R1+4
写其他字节数
STRB 1byte
STRH half - 2bytes

读写指令经常用到,一定要掌握这两条指令

  • 加减

    ADD R0, R1, R2  ; R0=R1+R2
    ADD R0, R0, #1  ; R0=R0+1
    SUB R0, R1, R2  ; R0=R1-R2
    SUB R0, R0, #1  ; R0=R0-1
    
  • 比较

    CMP R0, R1  ; 结果保存在PSR(程序状态寄存器)
    

结果保存到程序状态寄存器里

  • 跳转

    B  main  ; Branch, 直接跳转
    BL main  ; Branch and Link, 先把返回地址保存在LR寄存器里再跳转
    

跳转
B main; PC/R15=main的地址

BL main; 分为两个步骤
LR/R14=返回地址
PC/R15=main的地址

2. C函数的反汇编

C函数:

int add(volatile int a, volatile int b)
{volatile int sum;sum = a + b;return sum;
}

这段代码里用volatile int a,不要让编译器优化我们的程序

把这个函数复制,随便我们工程的放到一个地方

修改如下部分
在这里插入图片描述

void OLED_Test(void)
{int OLED_Count = 0;OLED_Init();// 清屏OLED_Clear();while (1){// 在(0, 0)打印'A'OLED_PutChar(0, 0, 'A');// 在(1, 0)打印'Y'OLED_PutChar(1, 0, 'Y');// 在第0列第2页打印一个字符串"Hello World!"OLED_PrintString(0, 2, "Hello World!");OLED_PrintSignedVal(6, 4, OLED_Count);OLED_Count = add(OLED_Count, 1);    //OLED_Count ++ 看反汇编代码}
}

让Keil生成反汇编:

选择 魔术棒-uesr 示例图片
在这里插入图片描述

  • 为例方便复制,制作反汇编的指令如下:
fromelf  --text  -a -c  --output=xxx.dis  xxx.axf

上面语句的作用是 用 xxx.axf 输出 xxx.dis 的反汇编

  • 为了方便复制粘贴,先做好我自己的这行代码,自己的路径自己粘贴,方法在如下
  • 在linker的窗口下,往下翻,就能找到linker的路径,复制粘贴到对应的位置即可

在这里插入图片描述
结合起来就是

fromelf  --text  -a -c  --output=test.dis  01_freertos_template\01_freertos_template.axf

用01_freertos_template\01_freertos_template.axf ,输出test.dis的反汇编

粘贴到对应的位置

在这里插入图片描述

编译 看输出结果
在这里插入图片描述
这里很直观的看到输出了.dis文件

找到这个文件,用文本文档打开

在这里插入图片描述

OLED_Test0x08002a00:    2400        .$      MOVS     r4,#00x08002a02:    f7ffff01    ....    BL       OLED_Init ; 0x80028080x08002a06:    f7fffeea    ....    BL       OLED_Clear ; 0x80027de0x08002a0a:    2100        .!      MOVS     r1,#00x08002a0c:    2241        A"      MOVS     r2,#0x410x08002a0e:    4608        .F      MOV      r0,r10x08002a10:    f7ffff9c    ....    BL       OLED_PutChar ; 0x800294c0x08002a14:    2259        Y"      MOVS     r2,#0x590x08002a16:    2100        .!      MOVS     r1,#00x08002a18:    2001        .       MOVS     r0,#10x08002a1a:    f7ffff97    ....    BL       OLED_PutChar ; 0x800294c0x08002a1e:    a208        ..      ADR      r2,{pc}+0x22 ; 0x8002a400x08002a20:    2102        .!      MOVS     r1,#20x08002a22:    2000        .       MOVS     r0,#00x08002a24:    f7ffff79    ..y.    BL       OLED_PrintString ; 0x800291a0x08002a28:    4622        "F      MOV      r2,r40x08002a2a:    2104        .!      MOVS     r1,#40x08002a2c:    2006        .       MOVS     r0,#60x08002a2e:    f7ffff35    ..5.    BL       OLED_PrintSignedVal ; 0x800289c0x08002a32:    2101        .!      MOVS     r1,#10x08002a34:    4620         F      MOV      r0,r40x08002a36:    f000fa7f    ....    BL       add ; 0x8002f380x08002a3a:    4604        .F      MOV      r4,r00x08002a3c:    e7e5        ..      B        0x8002a0a ; OLED_Test + 10
add0x08002f38:    b503        ..      PUSH     {r0,r1,lr}0x08002f3a:    b081        ..      SUB      sp,sp,#40x08002f3c:    e9dd0101    ....    LDRD     r0,r1,[sp,#4]0x08002f40:    4408        .D      ADD      r0,r0,r10x08002f42:    9000        ..      STR      r0,[sp,#0]0x08002f44:    bd0e        ..      POP      {r1-r3,pc}
i.main
main0x08002f46:    f7fdfe77    ..w.    BL       HAL_Init ; 0x8000c380x08002f4a:    f7fffe0f    ....    BL       SystemClock_Config ; 0x8002b6c0x08002f4e:    f7fffa1d    ....    BL       MX_GPIO_Init ; 0x800238c0x08002f52:    f7fffac3    ....    BL       MX_I2C1_Init ; 0x80024dc0x08002f56:    f7fff9cf    ....    BL       MX_ADC1_Init ; 0x80022f80x08002f5a:    f7fffadf    ....    BL       MX_SPI1_Init ; 0x800251c0x08002f5e:    f7fffc1f    ....    BL       MX_USB_PCD_Init ; 0x80027a00x08002f62:    f7fffaff    ....    BL       MX_TIM1_Init ; 0x80025640x08002f66:    f7fffb65    ..e.    BL       MX_TIM2_Init ; 0x80026340x08002f6a:    f7fffbc1    ....    BL       MX_TIM3_Init ; 0x80026f00x08002f6e:    f7fffbfb    ....    BL       MX_USART1_UART_Init ; 0x80027680x08002f72:    f000f813    ....    BL       osKernelInitialize ; 0x8002f9c0x08002f76:    f7fff9e7    ....    BL       MX_FREERTOS_Init ; 0x80023480x08002f7a:    f000f82b    ..+.    BL       osKernelStart ; 0x8002fd40x08002f7e:    e7fe        ..      B        0x8002f7e ; main + 56

搜索add,要区分大小写!
在这里插入图片描述

C函数add

int add(volatile int a, volatile int b)
{volatile int sum;sum = a + b;return sum;
}

C函数add的反汇编代码如下:

    i.addadd0x08002f34:    b503        ..      PUSH     {r0,r1,lr}0x08002f36:    b081        ..      SUB      sp,sp,#40x08002f38:    e9dd0101    ....    LDRD     r0,r1,[sp,#4]0x08002f3c:    4408        .D      ADD      r0,r0,r10x08002f3e:    9000        ..      STR      r0,[sp,#0]0x08002f40:    bd0e        ..      POP      {r1-r3,pc}

在这里插入图片描述
add函数里的cnt参数保存在r0里,1保存在r1里,局部变量保存在栈里

在这里插入图片描述

对于单片机来说,在FLASH的地址上,保存这些数据

在这里插入图片描述
cpu会读取FLASH地址,得到对应的机器码,在cpu内部执行机器码,
cpu会读取FLASH地址,得到对应的机器码,在cpu内部执行机器码,
cpu会读取FLASH地址,得到对应的机器码,在cpu内部执行机器码,
……

在这里插入图片描述

从栈里把数值POP到R1R2R3,
仅仅是为了后面把LR的值POP到PC寄存器,仅
仅是为了恢复栈

以上可以看出,对于汇编代码,本质上,大多数汇编代码都是读取内存,写入内存,加加,减减,跳转

看起来很高大上的C语言的函数,在汇编里都是如此,读内存,写内存,加加,减减,跳转~

韦老师说这节课看不懂没关系,后面课程还会讲的

学习视频
【FreeRTOS入门与工程实践 --由浅入深带你学习FreeRTOS(FreeRTOS教程 基于STM32,以实际项目为导向)】 https://www.bilibili.com/video/BV1Jw411i7Fz/?p=9&share_source=copy_web&vd_source=8af85e60c2df9af1f0fd23935753a933

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/27548.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity制作背包的格子

1.新建一个面板 2.点击面板并添加这个组件 3.点击UI创建一个原始图像,这样我们就会发现图像出现在了面板的左上角。 4.多复制几个并改变 Grid Layout Group的参数就可以实现下面的效果了

GraogGNSSLib学习

GraogGNSSLib学习 程序编译环境版本项目编译结果问题 程序编译 GraphGNSSLib 环境版本 程序开源是在ubuntu16.04-kinetic环境跑通的,但是我的环境是UBUNTU20.04,所以,先进行了ROS的安装,因为我的系统是ubuntu20.04所以&#xf…

Linux--MQTT(一)简介

一、简介 MQTT ( Message Queuing Telemetry Transport,消息队列遥测传输), 是一种基于客户端服务端架构的发布/订阅模式的消息传输协议。 与 HTTP 协议一样, MQTT 协议也是应用层协议,工作在 TCP/IP 四…

MOS开关电路应用于降低静态功耗

本文主要讲述MOS开关电路的应用,过了好久突然想整理一下,有错误的地方请多多指出,在做电池类产品,需要控制产品的静态功耗,即使让芯片进入休眠状态,依旧功率很大,所以在电路中加一组软开关,防止…

HTML静态网页成品作业(HTML+CSS)—— 零食商城网页(1个页面)

🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,未使用Javacsript代码,共有1个页面。 二、作品演示 三、代…

LeetCode 230.二叉搜索树中第K小的元素

各位看官们,大家好啊,今天这个题我用的方法时间复杂度比较高,但也是便于便于理解的一种方法,大家如果觉得的好的话,就给个免费的赞吧,谢谢大家了^ _ ^ 题目要求如图所示: 题目步骤: 1.我们可以一维数组来接…

使用Unsloth微调Llama3-Chinese-8B-Instruct中文开源大模型

微调Llama3-Chinese-8B-Instruct 微调是指在大规模预训练的基础模型上,使用特定领域或任务数据集进行少量迭代训练,以调整模型参数,提升其在特定任务上的表现。这种方法可以充分利用预训练模型的广泛知识,同时针对特定应用进行优化,达到更精准高效的效果。 Llama-3-Chinese-8B-…

刷题记录(240613)

aliyun0512 1. 小红定义一个数组是好数组,当且仅当所有奇数出现了奇数次,所有偶数出现了偶数次。现在小红拿到了一个数组,她希望取一个该数组的非空子序列(可以不连续),使得子序列是好数组。你能帮小红求出子序列的方案数吗?由于…

【深度学习】stable-diffusion-3,SD3生图体验

stabilityai/stable-diffusion-3-medium 代码地址: https://huggingface.co/stabilityai/stable-diffusion-3-medium 可在这里体验: https://huggingface.co/spaces/ameerazam08/SD-3-Medium-GPU

并查集C++

并查集的原理 并查集(Union-Find Set)。可以把每个连通分量看成一个集合,该集合包含了连通分量中的所有点。这些点两两连通(连通性),而具体的连通方式无关紧要,就好比集合中的元素没有先后顺序之…

【ARM Cache 及 MMU 系列文章 1.3 -- 如何判断 L2 Cache 是否实现?】

请阅读【ARM Cache 及 MMU/MPU 系列文章专栏导读】 及【嵌入式开发学习必备专栏】 文章目录 CPU Configuration Register代码实现CPU Configuration Register 在 Armv9 架构中,我们可以通过arm 提供的自定义寄存器IMP_CPUCFR_EL1 来判断当前系统中是否实现了 L2 Cache, 如下所…

SpringBoot 实现 阿里云语音通知(SingleCallByTts)

目录 一、准备工作1.开通 阿里云语音服务2.申请企业资质3.创建语音通知模板,审核通过4.调用API接口---SingleCallByTts5.调试API接口---SingleCallByTts 二、代码实现1.导入依赖 com.aliyun:aliyun-java-sdk-dyvmsapi:3.0.22.创建工具类,用于发送语音通知…

我用AI绘画Stable Diffusion 一个月后,竟然能做出惊艳所有人的效果!

大家好,我是设计师阿威 如今要拍摄一组写真,需要服装、道具、灯光、场地、布景、拍摄、后期等过程。整个过程需要统一才能形成好的写真效果。现在有了AI绘图技术,我们可以实现通过AI绘图,只用计算机计算就得到一组接近真实的写真照…

什么是微前端

什么是微前端? 微前端 这个名词,第一次被提出还是在2016年底,那是在 ThoughtWorks Technology Radar。这个概念将微服务这个被广泛应用于服务端的技术范式扩展到前端领域。现代的前端应用的发展趋势正在变得越来越富功能化,富交互…

vue富文本wangeditor加@人功能(vue2 vue3都可以)

依赖 "wangeditor/editor": "^5.1.23", "wangeditor/editor-for-vue": "^5.1.12", "wangeditor/plugin-mention": "^1.0.0",RichEditor.vue <template><div style"border: 1px solid #ccc; posit…

Stable-Baseline3 x SwanLab:可视化强化学习训练

Stable Baselines3 (SB3) 是一个强化学习的开源库&#xff0c;基于 PyTorch 框架构建。它是 Stable Baselines 项目的继任者&#xff0c;旨在提供一组可靠且经过良好测试的RL算法实现&#xff0c;便于研究和应用。StableBaseline3主要被应用于机器人控制、游戏AI、自动驾驶、金…

Django DetailView视图

Django的DetailView是一个用于显示单个对象详情的视图。下面是一个使用DetailView来显示单个书籍详情的例子。 1&#xff0c;添加视图 Test/app3/views.py from django.shortcuts import render# Create your views here. from django.views.generic import ListView from .m…

BGP学习

BGP是一种矢量协议&#xff0c;使用TCP作为传输协议 ,目的端口号是179.是触发式更新&#xff0c;不是周期性更新 BGP的重点是策略路由的选路&#xff0c;能对路由进行路由汇总。运行BGP的路由器被称为BGP发言者&#xff0c;两个建立BGP会话的路由器互为对等体 IBGP和EBGP的区…

STM32项目分享:OV7670将图片上传电脑

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 1.PCB图 2.PCB板及元器件图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; https://www.bilibili.c…

调用华为API实现车牌识别

目录 1.作者介绍2.华为云车牌识别2.1车牌识别技术2.2华为云OCR 3.实验过程3.1获取API密钥3.2Python代码实现3.3实验结果 参考链接 1.作者介绍 袁明懿&#xff0c;男&#xff0c;西安工程大学电子信息学院&#xff0c;2023级研究生 研究方向&#xff1a;机器视觉与人工智能 电子…