韦东山老师的从0写RTOS笔记

生产bin文件

fromelf --bin --output=led.bin Objects\led_c.axf

生产汇编文件

fromelf --text -a -c --output=led.dis Objects\led_c.axf

1.AAPCS函数调用规则

  1. R0-R3:传递参数
  2. R0:传递返回值
  3. SP(R13):栈指针
  4. LR(R14):函数返回地址
  5. PC(R15):程序执行地址
  • AAPCS规定函数调用过程不会破坏R4-R11寄存器
  • 函数中随意使用R0-R3寄存器,无需保存
  • 函数R4-R11,可以使用,但是用完以后需要恢复;

故意使用一个寄存器:

register int sum sam("r4");

在这里插入图片描述

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

进入add_val函数时需要保存R4,退出函数时需要还原R4

在这里插入图片描述

寄存器

一共16个寄存器,13个通用寄存器,3个特殊寄存器

在这里插入图片描述

R13 是栈指针,使用PUSH 或POP 实现存储的访问,物理上存在3个栈指针寄存器,一个是MSP,一个是PSP寄存器

R14是链接寄存器,用于函数和子程序程序调用时返回地址的保存,在异常处理期间,LR寄存器自动更新位特殊的数值,之后改数值将在异常处理结束时触发异常返回

R15程序计数器PC,读操作返回当前指令地址加4

异常和中断

中断也是一种异常

异常列表

在这里插入图片描述

中断列表
在这里插入图片描述

2.中断处理流程

1.进入中断保存现场

​ 硬件自动保存R0,R1,R,R3,R3,LR,返回地址,xPSR到栈中

返回地址:是中断的返回地址,这里LR仅仅是一个普通的寄存器而已(LR函数返回就是函数的返回地址)

在这里插入图片描述

2.调用处理函数

要确保R4-R11不变,软件需要将会把这些寄存器入栈保存,函数执行完成后,恢复R4-R11寄存器。

3.退出中断需要恢复现场

硬件从栈中恢复R0,R1,R,R3,R3,LR,返回地址,xPSR。

在这里插入图片描述

任务切换

C文件

void task_a(char *str)
{char buf[10] = "task a";volatile int i;puts(buf);while (1){i= 0;while (str[i])putchar(str[i]);i++;}
}void task_b(char *str)
{char buf[10] = "task b";volatile int i;puts(buf);while (1){i= 0;while (str[i])putchar(str[i]);i++;}
}

汇编文件

task_a0x08000410:    b51f        ..      PUSH     {r0-r4,lr};入栈0x08000412:    4604        .F      MOV      r4,r00x08000414:    4a0b        .J      LDR      r2,[pc,#44] ; [0x8000444] = 0x80004d00x08000416:    ca07        ..      LDM      r2,{r0-r2}0x08000418:    ab01        ..      ADD      r3,sp,#40x0800041a:    c307        ..      STM      r3!,{r0-r2}0x0800041c:    a801        ..      ADD      r0,sp,#40x0800041e:    f7ffffeb    ....    BL       puts ; 0x80003f80x08000422:    e00d        ..      B        0x8000440 ; task_a + 480x08000424:    2000        .       MOVS     r0,#00x08000426:    9000        ..      STR      r0,[sp,#0]0x08000428:    e003        ..      B        0x8000432 ; task_a + 340x0800042a:    9900        ..      LDR      r1,[sp,#0]0x0800042c:    5c60        `\      LDRB     r0,[r4,r1]0x0800042e:    f7ffffb5    ....    BL       putchar ; 0x800039c0x08000432:    9800        ..      LDR      r0,[sp,#0]0x08000434:    5c20         \      LDRB     r0,[r4,r0]0x08000436:    2800        .(      CMP      r0,#00x08000438:    d1f7        ..      BNE      0x800042a ; task_a + 260x0800043a:    9800        ..      LDR      r0,[sp,#0]0x0800043c:    1c40        @.      ADDS     r0,r0,#10x0800043e:    9000        ..      STR      r0,[sp,#0]0x08000440:    e7f0        ..      B        0x8000424 ; task_a + 20$d0x08000442:    0000        ..      DCW    00x08000444:    080004d0    ....    DCD    134218960$ti.task_btask_b0x08000448:    b51f        ..      PUSH     {r0-r4,lr}0x0800044a:    4604        .F      MOV      r4,r00x0800044c:    4a0b        .J      LDR      r2,[pc,#44] ; [0x800047c] = 0x80004dc0x0800044e:    ca07        ..      LDM      r2,{r0-r2}0x08000450:    ab01        ..      ADD      r3,sp,#40x08000452:    c307        ..      STM      r3!,{r0-r2}0x08000454:    a801        ..      ADD      r0,sp,#40x08000456:    f7ffffcf    ....    BL       puts ; 0x80003f80x0800045a:    e00d        ..      B        0x8000478 ; task_b + 480x0800045c:    2000        .       MOVS     r0,#00x0800045e:    9000        ..      STR      r0,[sp,#0]0x08000460:    e003        ..      B        0x800046a ; task_b + 340x08000462:    9900        ..      LDR      r1,[sp,#0]0x08000464:    5c60        `\      LDRB     r0,[r4,r1]0x08000466:    f7ffff99    ....    BL       putchar ; 0x800039c0x0800046a:    9800        ..      LDR      r0,[sp,#0]0x0800046c:    5c20         \      LDRB     r0,[r4,r0]0x0800046e:    2800        .(      CMP      r0,#00x08000470:    d1f7        ..      BNE      0x8000462 ; task_b + 260x08000472:    9800        ..      LDR      r0,[sp,#0]0x08000474:    1c40        @.      ADDS     r0,r0,#10x08000476:    9000        ..      STR      r0,[sp,#0]0x08000478:    e7f0        ..      B        0x800045c ; task_b + 20

产生中断时

  1. 硬件保存A现场:R0,R1,R,R3,R3,LR,返回地址,xPSR
  2. 调用处理函数systick_Handler
    1. 保存A现场R4-R11
    2. 取出任务B的现场
      1. 软件取出任务B的现场R4-R11
      2. 硬件恢复任务B的现场R0,R1,R,R3,R3,LR,返回地址,xPSR
  3. 中断返回

保存A的现场

  • 指令保存在在flash中,不需要保存
  • 全局变量不需要保存
  • 局部变量本来就在他自己的栈里,不破坏即可

在这里插入图片描述

创建任务

实质就是伪造现场

返回地址:就是任务函数的入口,R0即使任务的参数

在这里插入图片描述

创建任务的代码实现

创建任务:
实质就是伪造一个现场
0.调整栈指针,因为栈时向下生长的,先进先出的特性
1.首先伪造软件恢复的寄存器部分R4~R11
2.然后伪造硬件自动恢复的寄存器部分R0~R3,R12,LR,SP,PSR2.1 R0中保存的时任务参数2.2 R15(PC)中保存的时程序入口
3.最后将栈顶指针保存在任务管理数组中注意:这里没有伪造MSP或PSP寄存器的值
/**/
void create_task(task_function f, void *param, char *stack, int stack_len)
{int *top = (int *)(stack + stack_len);/* 伪造现场 */top -= 16;/* r4~r11 */top[0] = 0; /* r4 */top[1] = 0; /* r5 */top[2] = 0; /* r6 */top[3] = 0; /* r7 */top[4] = 0; /* r8 */top[5] = 0; /* r9 */top[6] = 0; /* r10 */top[7] = 0; /* r11 *//* r0~r3 */top[8]  = (int)param; /* r0 */top[9]  = 0; /* r1 */top[10] = 0; /* r2 */top[11] = 0; /* r3 *//* r12,lr */top[12] = 0; /* r12 */top[13] = 0; /* lr *//* 返回地址 */top[14] = (int)f; /* 任务入口 *//* PSR */top[15] = (1<<24); /* psr 使用thumb指令集 */	/* 记录栈的位置 */task_stacks[task_count++] = (int)top;
}

psr寄存器第24位标识使用哪个指令集

thumb指令 16位,消耗空间小,但是执行效率低

arm指令 32位 消耗空间大,但是执行效率高

启动任务

StartTask_asm PROC; 从任务的栈里把R4~R11读出来写入寄存器; r0 : 保存有任务的栈				; r1 : 保存有LR(特殊值)LDMIA r0!, { r4 - r11 }; 更新SPMSR MSP, R0;MOV SP, R0; 触发硬件中断返回: 它会把栈里其他值读出来写入寄存器(R0,R1,R2,R3,R12,PSR)BX R1ENDP

切换任务

  1. 硬件保存了一部分现场,并且让LR等于了一个特殊值
  2. 保存R4-R11
  3. 将LR传递给R0寄存器,讲SP
  4. 保存LR
  5. sp-4
  6. 保存老的任务栈,切换新的任务栈
  7. 恢复栈
  8. 返回
    在这里插入图片描述

韦老师的任务切换函数

SysTick_Handler_asm PROC; 在这里保存R4~R11STMDB sp!, { r4 - r11 }STMDB sp!, { lr }MOV R0, LR ; LR是一个特殊值ADD R1, SP, #4;这里保存了一个LR的值,所以需要做一个sp+4BL SysTick_Handler  ; 这个C函数保证不破坏R4~R11;经过测试以下部分代码根本不得执行LDMIA sp!, { r0 };拿出特殊的LR值LDMIA sp!, { r4 - r11 }BX R0ENDPEND

本人修改简化的任务切换

SysTick_Handler_asm PROC; 在这里保存R4~R11STMDB sp!, { r4 - r11 }MOV R0, LR ; LR是一个特殊值MOV R1, SP ; LR是一个特殊值BL SysTick_Handler  ; 这个C函数保证不破坏R4~R11ENDP

SysTick 中断处理函数

/**lr_bak:LR特殊值old_sp:老的栈
*/
void SysTick_Handler(int lr_bak, int old_sp)
{int stack;int pre_task;int new_task;SCB_Type * SCB = (SCB_Type *)SCB_BASE_ADDR;/* clear exception status */SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk;/* 如果还没有创建好任务, 直接返回 */if (!is_task_running()){return;  // 表示无需切换}/* 启动第1个任务或者切换任务 */if (cur_task == -1){/* 启动第1个任务 */cur_task = 0;/* 从栈里恢复寄存器 *//* 写汇编 */stack = get_stack(cur_task);StartTask_asm(stack, lr_bak);return ; /* 绝对不会运行到这里 */}/* 切换任务 */else{// 取出下一个任务pre_task = cur_task;new_task = get_next_task();if (pre_task != new_task){			/* 保存 pre_task: 在汇编里已经保存了 *//* 将上一个任务的栈保存起来,更新sp */set_task_stack(pre_task, old_sp);/* 切换 new_task */stack = get_stack(new_task);cur_task = new_task;StartTask_asm(stack, lr_bak);}}}

在这里插入图片描述

RTOS的本质

  1. 任务切换:本质就是保存A的栈,恢复B的栈
  2. 任务的休眠和唤醒

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

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

相关文章

用excel计算矩阵的乘积

例如&#xff0c;我们要计算两个矩阵的乘积&#xff0c; 第一个矩阵是2*2的&#xff1a; 1234 第2个矩阵是2*3的&#xff1a; 5697810 在excel中鼠标点到其它空白的地方&#xff0c;用来存放矩阵相乘的结果&#xff1a; 选择插入-》函数&#xff1a; 选中MMULT&#xff0c;…

Spring Cache

目录 1、简介 2、常用注解 3、使用RedisTemplate 4、使用springCache &#x1f343;作者介绍&#xff1a;双非本科大三网络工程专业在读&#xff0c;阿里云专家博主&#xff0c;专注于Java领域学习&#xff0c;擅长web应用开发、数据结构和算法&#xff0c;初步涉猎Python人…

MeterSphere 任意文件读取漏洞(CVE-2023-25814)

MeterSphere 任意文件读取漏洞&#xff08;CVE-2023-25814&#xff09; 免责声明漏洞描述漏洞影响漏洞危害网络测绘Fofa: title"MeterSphere" 漏洞复现1. 构造poc2. 发送数据包3. 查看文件 免责声明 仅用于技术交流,目的是向相关安全人员展示漏洞利用方式,以便更好地…

【LeetCode】挑战100天 Day10(热题+面试经典150题)

【LeetCode】挑战100天 Day10&#xff08;热题面试经典150题&#xff09; 一、LeetCode介绍二、LeetCode 热题 HOT 100-122.1 题目2.2 题解 三、面试经典 150 题-123.1 题目3.2 题解 一、LeetCode介绍 LeetCode是一个在线编程网站&#xff0c;提供各种算法和数据结构的题目&…

kubeadm部署k8s及高可用

目录 CNI 网络组件 1、flannel的功能 2、flannel的三种模式 3、flannel的UDP模式工作原理 4、flannel的VXLAN模式工作原理 5、Calico主要组成部分 6、calico的IPIP模式工作原理 7、calico的BGP模式工作原理 8、flannel 和 calico 的区别 Kubeadm部署k8s及高可用 1、…

Python读取csv文件并绘制曲线

前言 有时候我们的数据保存在csv文件中&#xff0c;但是想要更加直观的看出数据的好坏&#xff0c;最好利用matplotlib来画出曲线图 数据准备 我的数据格式如下&#xff1a; 在画图时&#xff0c;我需要把第一行去掉 # 去除第一个元素 xdata xdata.drop(xdata.index[0])…

Longhorn跨AZ实现存储高可用

Longhorn跨AZ实现存储高可用 longhorn基础组件功能及其作用这里就不做介绍了 方案一 Longhorn跨AZ的高可用的就是一个PVC的replicas 均匀打散的不同的AZ区域之间&#xff0c;这样当某个AZ挂掉后&#xff0c;engine会立即使用另外一个数据副本&#xff0c;并重建这个副本&…

Java TreeMap

TreeMap 是一个基于 key 有序的 key value 散列表。 map 根据其键的自然顺序排序&#xff0c;或者根据 map 创建时提供的 Comparator 排序不是线程安全的key 不可以存入null底层是基于红黑树实现的 TreeMap 的类结构图&#xff1a; 实现了 NavigableMap 接口&#xff0c;Na…

MATLAB的编程与应用,匿名函数、嵌套函数、蒙特卡洛法的掌握与使用

目录 1.匿名函数 1.1.匿名函数的定义与分类 1.2.匿名函数在积分和优化中应用 2.嵌套函数 2.1.嵌套函数的定义与分类 2.2.嵌套函数彼此调用关系 2.3.嵌套函数在积分和微分中应用 3.微分和积分 4.蒙特卡洛法 4.1.圆周率的模拟 4.2.计算N重积分&#xff08;均匀分布&am…

20道高频JavaScript面试题快问快答

※其他的快问快答&#xff0c;看这里&#xff01; 10道高频Qiankun微前端面试题快问快答 10道高频webpack面试题快问快答 20道高频CSS面试题快问快答 20道高频JavaScript面试题快问快答 30道高频Vue面试题快问快答 面试中的快问快答 快问快答的情景在面试中非常常见。 在面试过…

竞赛选题 深度学习疲劳驾驶检测 opencv python

文章目录 0 前言1 课题背景2 实现目标3 当前市面上疲劳驾驶检测的方法4 相关数据集5 基于头部姿态的驾驶疲劳检测5.1 如何确定疲劳状态5.2 算法步骤5.3 打瞌睡判断 6 基于CNN与SVM的疲劳检测方法6.1 网络结构6.2 疲劳图像分类训练6.3 训练结果 7 最后 0 前言 &#x1f525; 优…

idea 2023 设置启动参数、单元测试启动参数

找到上方的editconfigration&#xff0c; 如下图&#xff0c;如果想在启动类上加&#xff0c;就选择springboot&#xff0c;如果想在单元测试加&#xff0c;就选择junit 在参数栏设置参数&#xff0c;多个参数以空格隔开 如果没有这一栏&#xff0c;就选择就可以了。 然后&…

数字马力笔试面试复盘

笔试——10月9日19&#xff1a;00 单选&#xff1a;30题 16.如何获取AJAX 请求的响应状态码? A通过AJAX对象的 statusCode 属性获取 B通过AJAX对象的responseText 属性获取C通过AJAX对象的status 属性获取 D通过AJAX对象的responseCode属性获取 答案&#xff1a;可以通过AJAX…

回收站清空了怎么恢复?数据恢复的 6 种方法

众所周知&#xff0c;计算机中的回收站是一个存储空间&#xff0c;用于存储从计算机系统中删除的所有文件、文件夹或数据。它是大多数计算机系统&#xff08;包括Windows、Mac等&#xff09;上的必备功能。当从计算机中删除文件或文件夹时&#xff0c;它会在回收站中存储指定的…

京东数据分析:2023年Q3户外鞋服市场分析报告(冲锋衣行业销售数据分析)

从露营、骑行、徒步、桨板、垂钓、飞盘、滑雪到如今的city walk&#xff0c;近两年户外运动已经成为了年轻人新的生活方式。户外运动的爆发也刺激了人们对于鞋服在穿搭、场景化、专业性功能等方向的需求&#xff0c;户外鞋服市场迎来增长。 而全国性的降温则带给目前的户外鞋服…

七个优秀微服务跟踪工具

随着微服务架构复杂性的增加&#xff0c;在问题出现时确定问题的根本原因变得更具挑战性。日志和指标为我们提供了有用的信息&#xff0c;但并不能提供系统的完整概况。这就是跟踪的用武之地。通过跟踪&#xff0c;开发人员可以监控微服务之间的请求进度&#xff0c;从而使他们…

关于Android Studio 同步Gradle失败的解决方案

&#xff08;1&#xff09;打开Android Studio的Settings找到Gradle的目录 &#xff08;2&#xff09;打开本地文件目录&#xff0c;找到对应的gradle版本&#xff0c;可以通过Index of /gradle/ 下载gradle压缩包。把目录中gradle-7.0.2-bin\一堆字符\ 下 的.lck 和.part文…

MATLAB中Arrow 属性说明

目录 颜色和样式 位置 Arrow 属性是箭头的外观和行为。 Arrow 属性控制 Arrow 对象的外观和行为。通过更改属性值&#xff0c;可以修改箭头的特定方面。使用圆点表示法查询和设置属性。 ar annotation("arrow"); c ar.Color; ar.Color "red"; 颜色和…

SpringCloudGateway--Sentinel限流、熔断降级

目录 一、概览 二、安装Sentinel 三、微服务整合sentinel 四、限流 1、流控模式 ①直接 ②关联 ③链路 2、流控效果 ①快速失败 ②Warm Up ③排队等待 五、熔断降级 1、慢调用比例 2、异常比例 3、异常数 一、概览 SpringCloudGateway是一个基于SpringBoot2.x的…