DIY简单的RTOS(一)

2023-11-17

说明

在看了很多关于RTOS的文章,一直想做一个简单的RTOS,苦于现有资料非常少,在看了很多关于现有RTOS的底层实现,再结合相关文章,完成一个简单的RTOS demo。代码难免有不合理之处,仅当个人学习做笔记使用。

项目代码



什么是RTOS

实时操作系统(RTOS)是指当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统做出快速响应,调度一切可利用的资源完成实时任务,并控制所有实时任务协调一致运行的操作系统。提供及时响应和高可靠性是其主要特点。




PenSV异常

在RTOS内核中,一个任务可通过手动触发PendSV异常,在PendSV异常服务函数中实现任务切换(切换到下一个任务)

我们从相关手册找到设置PendSV异常的寄存器中断及状态控制寄存器ICSR

在这里插入图片描述
只需要将该寄存器的28位置1即可。
若当前没有更高的优先级中断,则会进入到PendSV异常处理函数中;否则等待中断完成进入到异常处理函数。


设置PendSV的优先级
在这里插入图片描述
通常来说,PendSV的优先级都没有中断的优先级高,因此设置PendSV优先级最低,从而避免在外部中断服务函数中产生任务切换。
可以设置成0-255的优先级,这是设置成0xFF。




相关汇编指令

import:翻译为进口或引入,表明要调用的函数为外部文件定义

export:翻译为出口或输出,表明该符号可以被外部模块使用,类似于C中的extern功能。

这里使用IMPORT导入C语言中的变量。


LDR{条件} 目的寄存器 <存储器地址>
作用:将存储器地址所指地址处连续的4个字节(1个字)的数据传送到目的寄存器中。

  • LDR R0, = blockPtr //把blockPtr表示的值加载到R0寄存器中
  • LDR R0,[R0] //将存储器地址为R0的字数据读入寄存器R0

如果blockPtr是一个地址,如数组的首地址,那么首先R0中存储的就是数组的首地址,接着把地址R0的字数据读入R0,相当于R0中保存的是数组的第一个元素的值。

stmdb(地址先减而后完成操作)和ldmia指令一般配对使用,stmdb用于将寄存器压栈,ldmia用于将寄存器弹出栈,作用是保存使用到的寄存器。


指令:stmdb sp!,{r0-r12,lr}
含义:sp = sp - 4,先压lr,sp = lr(即将lr中的内容放入sp所指的内存地址)。sp = sp - 4,再压r12,sp = r12。sp = sp - 4,再压r11,sp = r11…sp = sp - 4,最后压r0,sp = r0。


LDMIA , LDMIA R0!,{R1,R2}
是指将R0指向的单元中的数据读出到R1,R2中(R0自动加1)



相关代码

main.c

#define NVIC_INT_CTRL 			0xE000Ed04	//寄存器地址
#define NVIC_PENDSVSET 		  0x10000000
#define NVIC_SYSPRI2			  0xE000ED22	//寄存器地址
#define NVIC_PENDSV_PRI		  0x000000FF

#define MEM32(addr)				*(volatile unsigned long *)(addr)
#define MEM8(addr)				 *(volatile unsigned char *)(addr)
void triggerPendSVC(void){
	//设置pendsv优先级最低和置1.
	MEM8(NVIC_SYSPRI2) = NVIC_PENDSV_PRI;
	MEM32(NVIC_INT_CTRL) = NVIC_PENDSVSET;
}
typedef struct _BlockType_T{
	unsigned long *stackPtr;
}BlockType_t;
BlockType_t *blockPtr;
unsigned long stackBuffer[1024];
BlockType_t block;
block.stackPtr = &stackBuffer[1024];	//指向最后一个单元
blockPtr = &block;

switch.c

/**
 * 保存R4-R11寄存器
 * 内嵌汇编
*/
__asm void PendSV_Handler(void){
    //映射到pendsv_handler中
    IMPORT blockPtr
    LDR R0, = blockPtr
    LDR R0, [R0]
    LDR R0, [R0]//获取stackPtr的值

    STMDB R0!,{R4-R11}   //批量写寄存器(高-低)
    
    LDR R1,=blockPtr
    LDR R1,[R1]
    LDR R0,[R1]

    //测试代码
    ADD R4,R4, #1
    ADD R5,R5, #1

    //恢复寄存器
    LDMIA R0!,{R4-R11}
    //退出异常
    BX LR
}

创建一个.c文件即可,开头是__asm指明是汇编操作,因为C语言无法完成对寄存器的操作。




代码说明

在汇编代码中,我们连续用了3条LDR指令,其中有两条是重复的。
在main.c文件中,首先获取blockPtr的地址送到R0,接着读取地址R0对应的值(也是地址),接着读取地址R0的值(数组地址)。
例:
在这里插入图片描述

  1. 把blockPtr的地址(0x20000000)保存到R0
  2. 取地址对应的值(0x20000008) 保存到R0
  3. 取地址对应的值(0x20001024) 保存到R0

stackPtr的值时0x20001024,指向数组stackBuffer第1025个元素(1开始算起)的地址。


接着保存R11-R4寄存器的内容到R0指向的内容中。 此时R0指向第1025个元素的地址,而我们的数组大小才1024个,在STMDB指令中,地址先自减,在存储对应的寄存器的值。

接着把R0的值仍然设置为0x20001024(数组第1025个元素地址)
R4 = R4 +1
R5 = R5 + 1

使用LDMIA 指令做测试,把R0的值存储到寄存器R4-R11中。

在这里插入图片描述
地址自增32/4 = 8个寄存器(R4-R11),且R4和R5寄存器的值被修改成0(这里做测试使用)。




运行说明

这里基于ARMCM3仿真实现,以后会在单片机上运行。仿真的时候我们看是否跳入到了PendSV服务函数中,是否保存了相应的数据。任务的切换关键在于上下文的保存,可通过压栈和出栈来实现。
在这里插入图片描述




参考

汇编:stmdb和ldmia指令

参考01课堂:从0到1实现RTOS

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

DIY简单的RTOS(一) 的相关文章

  • msys2 修改国内源加速pacman

    1 msys2 修改国内源加速pacman 清华大学 etc pacman d mirrorlist mingw32 Server https mirrors tuna tsinghua edu cn msys2 mingw i686 1
  • netty源码分析之LengthFieldBasedFrameDecoder

    http www jianshu com p a0a51fd79f62 hmsr toutiao io utm medium toutiao io utm source toutiao io 拆包的原理 关于拆包原理的上一篇博文 netty
  • 五一节假期结束给团队开会,快速进入工作状态

    大家好 五一的假期大家过的都还开心吧 五一长假已经结束了 更开心的事情马上又要来了 再坚持10天 又要发工资了 再坚持上3天班又可以缓冲一下休息一天了 打工人 上班快乐 伴随着这些开心在这里我请大家尽快从自由松散的假期状态中走出来 重整旗鼓
  • Mac VS Code 如何去除右边的预览功能

    取消选中Minimap即可
  • Scala中的高阶函数

    1 定义 当一个函数 func1 中的 参数列表 传入的是函数 那么函数func1 就是高阶函数 上边几个函数可以 提炼出为一个高阶函数 因为 他们只是 黄线标志的部分不同 我们可以 定义一个 函数作为作为参数传递进去 来提取为 一般规律
  • opencv+nvcodec实现视频硬解码

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 系统配置 前言 一 NVCODEC是什么 二 OpenCV编译 1 安装Driver CUDA 2 编译OpenCV 总结 系统配置 操作系统 Ubuntu18 0
  • SpringMVC的拦截器

    SpringMVC的拦截器 SpringMVC的拦截器 SpringMVC的拦截器 01 SpringMVC拦截器 拦截器的作用 理解 02 SpringMVC拦截器 interceptor和filter区别 理解 记忆 03 Spring
  • style-components的熟练运用

    安装 首先下一个包 npm install save styled components 使用 创建组价以及根据属性加样式 import React Component from react import styled from style
  • driver.get_screenshot_as_file()没有保存图片的原因

    部分代码如下 cur time time strftime Y m d H M S filename os path dirname os path abspath screenshot cur time png driver get sc
  • JavaScript:实现简易计算功能

    JavaScript 实现简易计算功能 body部分
  • 数据结构:手撕图解单链表---phead的多种传参方式对比和辅助理解

    文章目录 为什么要引入链表 单链表 单链表的定义和原理 单链表的头插 对于指针的深层次理解 链表的尾插 封装malloc函数 尾删 头删 查找 链表中元素的插入 在某节点前插入 在某节点后插入 链表中元素的删除 删除pos位置的值 删除po
  • umi学习总结

    文章目录 umi介绍 umi是什么 umi的特性 开发环境 Node js 依赖管理工具 目录结构 路由 配置路由 页面跳转 Link组件 路由组件参数 路由动态参数 query信息 样式 使用css样式 dva 为什么需要状态管理 umi
  • Qt弹出窗口

    Qt弹出Widget窗口置顶 1 需求 Widget每次都弹出且为非模态窗口 2 老版代码 if widget NULL widget new QWidget widget gt show 想象 弹出窗口后 如果发生窗口切换 再次点击时 弹
  • Go语言常用的标准库

    文章目录 打印日志 系统调用命令 json的序列化和反序列化 base64 压缩和解压 标准输入 文件操作 目录操作 init函数 包的可见性 数学库 生成随机数 时间函数 打印日志 package main import log os f
  • Java内存回收机制

    C C 等语言中 内存的分配和释放由程序代码来完成 容易出现由于程序员漏写内存释放代码引起的内存泄露 最终导致系统内存耗尽 Java代码运行在JVM中 由JVM来管理 堆Heap 内存的分配和回收 Garbage Collection 把程
  • 接口如何处理重复请求?

    本文主要来源于 处理重复请求的三种方式 服务端如何高效的处理重复请求 对其整理和总结 用于学习记录 重复请求常用的处理方式就是幂等性处理 幂等性可以理解为 无论执行了多少次重复请求 数据只会处理一次 在数据库里也只会有一条数据 和数据库的唯
  • 以太坊智能合约各方法对应的签名编码

    erc20智能合约常见方法对应的签名编码 常见例如交易 transfer address uint256 编码为 web3 sha3 transfer address uint256 substring 0 10 gt 0xa9059cbb
  • Solidity合约中Merkle Root验证的一点实践

    背景 在上一篇文章 Solidity合约中签名验证的一点实践 中提到过 白名单机制一般有两种 除了签名验证的方式外 就是本文讲述的Merkle Root验证的方式 主要做法是在服务端对白名单地址列表整体构建Merkle树 计算出树的root

随机推荐

  • 解决Hbase报错java.lang.IllegalStateException: The procedure WAL relies on the ability to hsync for....

    完整报错为 java lang IllegalStateException The procedure WAL relies on the ability to hsync for proper operation during compo
  • set的使用

    创建集合 set 1 2 3 4 转化为列表list 1 如果我要在许多列表中找出相同的项 那么用集合是最好不过的了 用集合只用一行就可以解决 x y z 交集 2 去重 gt gt gt lst 1 2 3 4 1 gt gt gt pr
  • 毕业那天我们一起失恋

    毕业那天我们一起失恋 原载 婚姻家庭 VOL 1大四快开学了 我提前了几天来学校 俗话说 磨刀不误砍柴功 我提早来学校 把床铺好 把蚊帐挂起来 把厕所弄干净 把寝室打扫一下 寝室里只有我做这种打扫的事情 寝室有三个人 我一个 丸子一个 还有
  • 【翻译】对计算机未来的10个预测或;我们的首席科学家的无稽之谈

    TLDR WASM将无处不在 编译目标 部署目标 物联网 插件生态系统 这已经在发生了 1 5年 Rust将继续流行 根据RedMonk的指数 在未来几年将超过Go 2 4年 将出现一个严重的Kubernetes的对手 如果它使用WASM并
  • 写个爬虫吧

    import requests url https image baidu com search acjson tn resultjson com ipn rj ct 201326592 is 0 2C0 fp detail logid 1
  • 03-MySQL数据类型

    一 数值类型 整数 MySQL 主要提供的整数类型有 TINYINT SMALLINT MEDIUMINT INT BIGINT 浮点数 浮点类型有两种 分别是单精度浮点数 FLOAT 和双精度浮点数 DOUBLE 定点类型 只有一种 就是
  • 记录一次 JS 解密去混淆的经历 -- 如何破解加密的 JS 代码(一)

    写在前头 昨天发了一个 某JS最牛加密脱壳解密破解去混淆工具 有朋友说上代码不如讲一下思路 于是今天准备捋一下这个思路 顺便当整理复习了 需要直接解密代码的请看上一篇文章 这里只有思路与过程 阅读此文默认你有一定的 JavaScript 基
  • vscode工作区同时显示多个文件

    有时候安装的vscode打开一个文件又打开另一个文件只会保存新的文件 旧的文件别替换 这样做项目比较难受 所以用下面方法可以打开多个文件 workbench editor showTabs true
  • 【E2E】Tesseract5+VS2017+win10源码编译攻略

    一 记录我目前在win10 X64和VS2017的环境下成功编译Tesseract5 0的方式 二 记录在VS2017 C 工程中调用Tesseract4 0的方法 三 记录编译和调用Tesseract4 0过程中踩到的坑和相应的解决方案或
  • IMU立大功:有效减小建筑工人高空坠落风险

    尽管建筑行业不断努力改善工作场所安全 但它仍然是全球最危险的行业之一 建筑行业的工作死亡或致命工伤比例为25 在这些致命伤害中 大约36 是由高空坠落造成的 这是建筑行业从业者意外死亡的主要原因之一 其他国家 包括澳大利亚 中国和韩国 也因
  • 使用eclipse创建JAVA项目

    打开eclipse软件 选择好工作区域 就是项目的储存地址 后登陆 File New Project 选择 Java Project 输入项目名称 点击Finish SRC是专门放java源代码的文件夹 就是你在IDE里编写的各个java类
  • C语言上机实验思路分享9

    实验项目名称 实验十 C 文件基本操作 实验目的及要求 1 掌握文件和文件指针的概念以及文件的定义方法 2 了解文件打开和关闭的概念和方法 3 掌握有关文件操作的函数 实验内容 方法和步骤 1 文件 stu info1 txt 包含学生的基
  • 模板型模板参数报错,无法调试通过,---《深入实践c++模板》例子

    include
  • 迪杰斯特拉算法求图的某个顶点到其他顶点的最短路径问题

    迪杰斯特拉算法 使用图的广度优先遍历算法 比如先从G点出发 找到能与G直接连接的顶点 然后才从与G最近的A出发 找到与A相邻的节点 通过比较G到每个顶点的距离大小 筛选出到每个点的最短路径 代码 迪杰斯特拉算法球最短路径问题 public
  • hdu 3966 Aragorn's Story

    Problem acm hdu edu cn showproblem php pid 3966 Reference 树链剖分 树链剖分原理 树链剖分详解及模板 HDU3966 树链剖分 Meaning 一棵 n 个点的树 每给结点有个值 三
  • BERT、BART、T5 等法学硕士的比较分析

    探索语言模型 介绍 在这篇博文中 我将讨论 BERT BART 和 T5 等大型语言模型 到 2020 年 法学硕士领域取得的重大进展包括这些模型的开发 BERT和T5是Google开发的 BART是Meta开发的 我将根据这些型号的发布日
  • css实现水平居中

    代码示例 div class box div class box1 div div 1 弹性布局 推荐 display flex 这些要添加在父级的 是父级的属性 父级添加display flex 父级添加justify content c
  • Zookeeper 基本操作

    Zookeeper 基本操作 文章目录 Zookeeper 基本操作 1 查看zk的运行状态 2 客户端连接zk 3 ls 查看 4 get 获取节点数据和更新信息 5 stat 获得节点的更新信息 6 ls2 ls命令和stat命令的整合
  • java localdate mysql_如何使用JDBC从java.sql.Date获取LocalDateTime对象?

    Java8的java time包提供了一个名为LocalDateTime的类 用于获取本地日期和时间的当前值 除日期和时间值外 还可以使用此字段来获取其他日期和时间字段 例如 一年中的某天 一周中的某天和一年中的某周 将java sql D
  • DIY简单的RTOS(一)

    说明 在看了很多关于RTOS的文章 一直想做一个简单的RTOS 苦于现有资料非常少 在看了很多关于现有RTOS的底层实现 再结合相关文章 完成一个简单的RTOS demo 代码难免有不合理之处 仅当个人学习做笔记使用 项目代码 什么是RTO