ucos-ii嵌入式操作系统任务调度(二)----任务切换瞬间cpu做了什么以及任务任务切换函数OS_TASK_SW
先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,股票基金定投,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题,二维码如下:
一 概述
在上一篇文章《ucos-ii嵌入式操作系统任务调度(一)----任务调度的过程及实现原理》中,我们分析了任务调度过程中的步骤,但是在最后结尾处,我们留了一个小疑问:任务是如何实现切换的呢?在切换的瞬间cpu发生了什么?汇编函数OSCtxSw实现原理又是什么?
在分析这个疑问之前,先看如下几个问题:
- CPU的栈是什么?
- CPU在执行代码,调用函数的过程中,如何传递函数参数?如何正确返回被调用函数的?
- CPU发生中断/异常时,如何响应中断/异常,响应完之后,又是如何跳转回发生异常/中断的地方,继续执行代码的
先看第一个问题
栈:首先从物理意义上来看,它就是位于芯片内部的一端RAM内存(**当然这个说法不一定准确,我理解的是外部sdram是不是也可以作为栈区域,不一定是芯片内部的RAM内存,在我的印象中,会在linker file指定栈地址,欢迎各位大佬不吝赐教 **)。其次从软件代码操作的角度来看,它是仅在表头进行插入和删除操作的线性表,也就说对于码农来说,我们只能在一端读取/写入栈。根据芯片架构的不同,又分为两种栈,栈空间地址向上增长和栈空间地址向下增长。
这个栈是sp指针实时指向的栈。
再看第二个问题
如何实现函数调用时,参数传递?
针对ARM平台,其指令集规定,当参数不超过4个时,我们使用cpu内部的R0~R3来传递参数,如果函数参数超过4个,比如说对于printf函数,我们使用栈来传递参数。
再看第三个问题
cpu发生中断、异常时,会先进行现场保护,把当前cpu各个寄存器的值保存在栈中(R0~R15寄存器,当然就包括了sp指针,pc指针),保存完之后,就会调转到中断,异常处执行,执行完成之后,就会从栈中恢复当前的状态,并继续运行。
上面三个问题,在这里也是粗浅的做了一些说明,在此就不展开来详细说明,读者可以自行查阅资料
二 过程分析
有了上面的基础认识之后,我们现在来看一下,ucos任务切换的瞬间,发生了什么。
首先任务切换,是通过调用宏OS_TASK_SW(),即汇编函数OSCtxSw实现的,OSCtxSw函数如下:
OSCtxSwLDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)LDR R1, =NVIC_PENDSVSETSTR R1, [R0]BX LR
该汇编函数的目的,就是将寄存器NVIC_INT_CTRL设置为NVIC_PENDSVSET,查阅cortex-m系列内核手册可知,就是使能了PendSV异常,也就是说在这里软件触发了一次异常。
既然这个时候,软件触发了一次异常,根据我们上面的知识,可以知道,在响应异常处理时,cpu会自动先进行现场保存,也就是会将当前cpu各个寄存器的值写入到栈中(这个栈是cpu指针真正指向的栈,也就是我们在linker file中指定的内存区域),保存完之后,就会响应异常处理了,异常处理函数如下:
PendSV_HandlerCPSID I ; Prevent interruption during context switchMRS R0, PSP ; PSP is process stack pointerCBZ R0, OS_CPU_PendSVHandler_nosave ; Skip register save the first timeSUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stackSTM R0, {R4-R11}LDR R1, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP;LDR R1, [R1]STR R0, [R1] ; R0 is SP of process being switched out
逐句分析
CPSID I ;关闭中断,防止切换期间被打扰,在切换期间有可能产生新的中断,更新堆栈中的信息
MRS R0, PSP ;将cpu的堆栈指针psp送给R0,此时R0也指向栈顶
CBZ R0, OS_CPU_PendSVHandler_nosave ;如果 R0 = 0,跳到OS_CPU_PendSVHandler_nosave,即不保存上下文;如果R0 != 0,则继续往下执行;为什呢?因为首次调用时,是没有上文的,我们只需要切换到下文即可
;保存上文 (如果是第一次切换,则不执行下面的语句,直接执行OS_CPU_PendSVHandler_nosave)
SUBS R0, R0, #0x20 ;因为寄存器是32位的,4字节对齐,自动压栈的寄存器有8个,所以偏移为8*0x04=0x20
STM R0, {R4-R11} ;除去自动压栈的寄存器外,需手动将R4-R11压栈
LDR R1, =OSTCBCurLDR R1, [R1] STR R0, [R1] ;这里为什么是三行?ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令,先让R1=OSTCBCur(注意这里R1存放的是一个地址),然后将这个地址指向的值赋值给R1,最后再将R1中的值付给R0,其实最终目的就是将R0寄存器值,写入到当前用户分配的堆栈中去
接着就是切换到下文了,如下:
OS_CPU_PendSVHandler_nosavePUSH {R14} ; Save LR exc_return valueLDR R0, =OSTaskSwHook ; OSTaskSwHook();BLX R0POP {R14}LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy;LDR R1, =OSPrioHighRdyLDRB R2, [R1]STRB R2, [R0]LDR R0, =OSTCBCur ; OSTCBCur = OSTCBHighRdy;LDR R1, =OSTCBHighRdyLDR R2, [R1]STR R2, [R0]LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;LDM R0, {R4-R11} ; Restore r4-11 from new process stackADDS R0, R0, #0x20MSR PSP, R0 ; Load PSP with new process SPORR LR, LR, #0xF4 ; Ensure exception return uses process stackCPSIE IBX LR ; Exception return will restore remaining context
同样,逐句分析
PUSH {R14} ; LR压栈,下面要调用C函数,调用C函数时,将用来保存返回的函数地址
LDR R0, =OSTaskSwHook ; 调用OSTaskSwHook();
BLX R0 ; 调用OSTaskSwHook()结束并返回
POP {R14} ; 恢复 LR 寄存器,与前面对应
LDR R0, =OSPrioCur ; 置OSPrioCur = OSPrioHighRdy;
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0]
LDR R0, =OSTCBCur ; 置OSTCBCur = OSTCBHighRdy;
LDR R1, =OSTCBHighRdy
LDR R2, [R1]
STR R2, [R0]
LDR R0, [R2] ; R0中的值为新任务的SP; SP = OSTCBHighRdy->OSTCBStkPtr;
LDM R0, {R4-R11} ; 堆栈中的值手动弹出到寄存器:R4-R11
ADDS R0, R0, #0x20
MSR PSP, R0 ; PSP = 新任务SP,将SP的指针指向堆栈的顶端
ORR LR, LR, #0x04 ; 确保异常返回后使用PSP
CPSIE I ; 重新打开中断,与开始关闭中断对应
BX LR ; 退出异常,从PSP自动弹出xPSR,PC,LR,R0-R3,进入新任务运行
ucos-ii嵌入式操作系统任务调度(二)----任务切换瞬间cpu做了什么以及任务任务切换函数OS_TASK_SW相关推荐
- 基于STM32的简易示波器的UCOS II嵌入式实时操作系统实现
基于STM32的简易示波器的UCOS II嵌入式实时操作系统实现 在基于STM32的示波器的实现的基础上,在STM32上移植UCOS II嵌入式实时操作系统. 在UCOS II操作系统中将各个功能分发 ...
- 优先级调度算法实现_一篇讲透嵌入式操作系统任务调度
进互联网公司操作系统和网络库是基础技能,面试过不去的看,这里基于嵌入式操作系统分几章来总结一下任务调度.内存分配和网络协议栈的基础原理和代码实现. 处理器上电时会产生一个复位中断,接下来会执行复位中断 ...
- 从0到1写嵌入式操作系统---------------------------4尝试两个任务的切换
上次我们创建了两个任务task1与task2,这次我们来实现tsak1与task2两个任务的切换.先了解下CM3内核的一些常用指令,不一定非要记住,只需要熟能生巧!先来看MSR和MRS指令. MRS ...
- RTOS ---嵌入式操作系统之时钟节拍下的任务切换
嵌入式操作系统之时钟节拍下的任务切换 嵌入式操作系统如FreeRTOS.FreeRTOS 中任务切换的过程, 提到触发任务切换的两种情况 : 高优先级任务就绪抢占和同优先级任务时间共享(包括提前挂起) ...
- 基于嵌入式操作系统VxWorks的多任务并发程序设计(3)――任务调度
基于嵌入式操作系统VxWorks的多任务并发程序设计(3) ――任务调度 作者:宋宝华 e-mail:[email]21cnbao@21cn.com[/email] 出处:软件报 VxWorks支持 ...
- 51单片机中使用ucos ii的优缺点(好文)
摘要:近年来,在单片机系统中嵌入操作系统已经成为人们越来越关心的一个话题.本文通过对一种源码公开的嵌入式实时操作系统ucos ii的分析,以51系列单片机为例,阐述了在单片机中使用该嵌入式操作系统的优 ...
- 嵌入式操作系统µCOS-II及应用编程
点击打开链接 嵌入式操作系统µCOS-II及应用编程 µCOS-II是一个嵌入式实时操作系统,广泛的应用于控制系统中.µCOS-II有Micrium公司提供,是一个可移植.可固化的.可裁剪的.抢占式多 ...
- 嵌入式操作系统复习——详细
嵌入式操作系统 绪论 嵌入式系统 嵌入式操作系统 嵌入式系统硬件和软件基础 嵌入式硬件系统基本组成 嵌入式微处理器 嵌入式系统总线 嵌入式系统存储结构 嵌入式软件体系结构 嵌入式操作系统体系结构 操作 ...
- 自制嵌入式操作系统 DAY1
遥想当年刚学习操作系统的时候,很难理解教科书中关于线程/进程的描述.原因还是在于操作系统书上的内容太过抽象,对于一个没有看过内核代码的初学者来说,很难理解各种数据结构的调度.后来自己也买了一些造轮子的 ...
最新文章
- 论机器学习领域的内卷
- 如何改变eclipse控制台编码
- 重构-改善既有代码的设计:重构原则(二)
- leetcode-832-Flipping an Image
- BrnShop开源网上商城第二讲:ASP.NET MVC框架
- mysql 1033 frm_MySQL ERROR 1033 (HY000): Incorrect information in file. 处理一例
- linux c自写时钟,关于internal_add_timer函数(linux/kernel/timer.c中定义的)的一个问题
- 看地形地貌下载什么地图?看地形地貌软件介绍
- 关于Git这一篇就够了
- asp.net知识共享平台
- java 实现搜索附近人功能
- 计算机网络未识别网络,电脑网络出现未识别的网络,无Internet访问的解决办法...
- 图片太大导致 imageView无法显示
- stc89c52rc转移到面包板,使用oled屏
- [USACO18JAN] Lifeguards S
- 关于如何开启本地代理隐藏本地ip
- linux服务器端 postfix+php邮件发送+发件人代发修改配置
- redistemplete请求spring security /oauth/token 报401错误,表示没有权限
- 光线投射与光线跟踪算法归纳
- 解决Could not determine artifacts for XXXX: Skipped due to earlier error
热门文章
- 智启联云GPS定位平台二次开发接口,支持808/1078设备接入
- 中国工业经济-污染与经济增长面板数据熵值法计算教程
- Chilledwindouws电脑病毒
- 写一个自由曲面光学透镜设计文章的提纲,要比较具体
- 从蒙娜丽莎到战争机器 — 达芬奇大师科学展
- mybatis基本操作流程
- 西门子atch指令详解_西门子PLC指令表-技术中心-智慧矿山-煤矿自动化,煤矿自动化系统,煤矿综合自动化,科达自控—煤矿生产无人值守的推动者,践行者和领导者...
- MATLAB绘图有锯齿
- 简历中尽量不要出现精通_“熟练”“精通”,这些词在简历中要慎用 | 求职干货记...
- java 四则运算_java四则运算