uCOS-II中的OS_CPU.h,OS_CPU_A.s,OS_CPU.c

2024-02-26 17:48
文章标签 ii cpu os ucos

本文主要是介绍uCOS-II中的OS_CPU.h,OS_CPU_A.s,OS_CPU.c,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

μC/OS-Ⅱ的移植集中在OS_CPU.h,OS_CPU_A.s,OS_CPU.c这三个文件上,下面分别详细介绍三个文件中的函数和需要修改或者编写的代码。


1. OS_CPU.h的移植

该文件定义了和处理器及编译器相关的定义及一些全局函数声明。由于ARM7 处理器字长为32位,半字长为16位,字节为8位,因此在OS_CPU.h文件修改与编译器相关的定义如下:

typedef unsigned char BOOLEAN;

typedef unsigned char INT8U;

typedef signed char INT8S;

typedef unsigned short INT16U;

typedef signed short INT16S;

typedef unsigned long INT32U;

typedef signed long INT32S;

typedef float FP32;

typedef double FP64;

typedef unsigned long OS_STK;

 

#define OS_CRITICAL_METHOD 2

#define OS_ENTER_CRITICAL() ARMDisableInt()

#define OS_EXIT_CRITICAL() ARMEnableInt()

#define OS_STK_GROWTH 1

#define OS_TASK_SW OSCtxSw

 

extern void OSCtxSw(void);

extern void OSIntCtxSw(void);

extern void ARMDisableInt(void);

extern void ARMEnableInt(void);

extern void OSTickISR(void);

2. OS_CPU_C.C文件

移植OS_CPU_C.C文件时,需要编写的是任务堆栈初始化函数OSTaskStkInit和时钟节拍中断服务钩子函数OSTimeTickHook。

在μC/OS-II中,每一个任务都有自己的任务堆栈,当发生任务切换或者中断时,其CPU使用权被剥脱,为了任务能被再次运行,那么这个被打断的任务所用到的处理器的寄存器内容均应得到保存,按照ARM7 处理器的压栈和入栈指令的特点,设计任务堆栈如下图2:


CPSR


R0

R1

……

R12

LR(R14)

PC(R15)


图2 任务堆栈的结构

根据任务堆栈结构示意图,OS_STK函数编写如下:

#define SVCMODE 0x13

OS_STK * OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt){

OS_STK *stk;

opt = opt;

stk = (OS_STK) ptos;

*--stk = (OS_STK) task;

*--stk = (OS_STK) task;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = 0;

*--stk = (INT32U) pdata;

*--stk = (SVC32MODE|0x40);

return ((OS_STK *)stk);

}

说明:用户创建任务时,OSTaskCreat()会调用OSTaskStkInit函数初始化该任务的堆栈,并把返回的堆栈指针保存到该任务的TCB结构中的最前面的参数OSTCBStkPtr中,当该任务要被恢复时,任务切换函数从其TCB块中取得其任务堆栈指针,依次将堆栈内容弹到处理器对应的 CPSR、r0,r1,…,r12,lr,pc的寄存器中,完成现场的恢复和程序指针PC的返回。

另一个需要编写的函数是OSTimeTickHook,该函数被时钟节拍中断服务函数OSTickISR中的OSTimeTick函数调用,用来清除时钟节拍中断发生设备的请求。本移植方案使用S3C44B0X处理器的RTC模块的tick中断作为时钟节拍中断,该函数编写如下:

void OSTimeTickHook(void){

rI_ISPC =((INT32U)0x01) << 20;

}

注意:用户也可不修改此函数,但是必须在OSTickISR中执行清除发生节拍中断的设备的中断请求标志,为便于说明,本文将利用内核提供给用户的OSTimeTickHook函数来完成清中断的任务。

另外几个hook函数不必去改它们。至此,OS_CPU.C编写完成。

3. OS_CPU_A.S文件的移植

该文件是移植过程中唯一需要用汇编语言来实现的文件,也是移植的重点和难点所在。在这个文件里,需要编写的函数有OSStartHighRdy,OSCtxSW,OSIntCtxSW,OSTickISR,ARMDisableInt,ARMEnableInt几个。

下面先结合us/os的任务切换的过程分析一下这几个函数的作用。

1)OSStartHighRdy()函数

当程序执行内核的OSStart函数时,表示多任务系统开始启动, OSStart函数将调用OSStartHighRdy函数从最高优先级任务的TCB块中获得该任务的堆栈指针,通过该指针,依次从该任务的任务堆栈中恢复CPU的现场。由于任务在堆栈初始化时,已经设定了弹出到程序指针寄存器PC的是该任务函数的入口地址,因此,OSStartHighRdy函数只需依次弹出任务栈内容到处理起寄存器,该任务便将得以运行。

2)OSCtxSw()函数

该函数是任务级的上下文切换函数,当任务被阻塞而主动请求CPU开始任务调度时执行,其过程是将当前任务的的CPU现场保存到该任务堆栈中去,然后从 OSTCBHighRdy中获得更高优先级任务的堆栈指针,再从该指针指向的堆栈中恢复此任务的CPU现场,使之继续执行,从而完成一次任务级别的切换。表2为OSCtxSw函数的伪代码。

void OSCtxSw(void) {

保存处理器寄存器;

OSTCBCur->OSTCBStkPtr = sp;

OSTCBCur = OSTCBHighRdy;

SP = OSTCBHighRdy->OSTCBStkPtr;

恢复该任务的现场();

执行中断返回指令;

}

表2 OSCtxSw函数的伪代码

3) OSIntCtxSw() 函数

该函数用于中断级的上下文切换。由于CPU响应时钟节拍中断后,处理器从svc进入了irq模式,并进入时钟节拍中断服务函数OSTickISR, OSTickISR函数发现若有高优先级任务需要运行,则系统不返回中断前的任务,而直接调度就绪的高优先级任务使之尽快得到执行,以保证实时性能。但是由于OSTickISR函数一开始已经保存过任务中断前的CPU现场,因此OSIntCtxSW()不需要再进行类似的操作。当OSTickISR调用 OSIntExit函数找出需要运行的更高优先级任务后,OSIntExit会将该任务的TCB指针放在OSTCBHighRdy中,然后 OSIntExit在最后调用OSIntCtxSW函数来从OSTCBHighRdy中获取堆栈指针然后恢复该高优先级任务的现场,使得其继续执行,并不再返回时钟节拍中断服务程序。显然,OSIntCtxSW函数的过程和OSCtxSW函数的后半部分操作相同,因此,OSCtxSW可以借用 OSIntCtxSW的代码。

4) OSTickISR()函数

在 CPU响应时钟节拍中断后,程序指针PC发生跳转后进入该函数,由于OSTickISR调用OSTimeTick函数使得所有的延时节拍不为0的任务延时节拍数减1,并调用OSIntExit函数来找出就绪的高优先级任务,若需要切换,则最后由OSIntCtxSw来完成新任务的调度,否则仍然返回到被时钟节拍中断的任务。OSTickISR函数的伪码和注释见表3。

5) ARMDisableInt和ARMEnableInt函数

ARMDisableInt 是用来暂时禁止FIQ及IRQ中断的函数,ARMEnableInt则是恢复ARMDisableInt执行前的中断使能状态,二者成对使用,用来保护临界段代码不被中断破坏。本移植使用方式2,即在进入临界段代码前关中断,完成后恢复先前的中断使能状态。

void OSTickISR(void) {

保存处理器寄存器;

调用OSIntEnter();

给产生中断的设备清中断;

调用OSTimeTick();

调用OSIntExit();

恢复处理器寄存器;

执行中断返回指令;

}

表3 OSTickTime函数的伪码

下面给出OS_CPU_A.S的全部内容和注释。


; *****OS_CPU_A.S文件汇编代码开始*****

AREA |subr|, CODE, READONLY ;声明为代码段


;***** OSStartHighRdy代码开始*****

     EXPORT OSStartHighRdy ;关键词EXPORT表示声明此函数被其他文件使用,下同

     IMPORT OSTaskSwHook ;关键词IMPORT声明此函数/参量在其他文件中定义,下同

     IMPORT OSTCBHighRdy

     IMPORT OSRunning

OSStartHighRdy ; 使就绪表中任务最高的优先级的任务开始运行

         BL OSTaskSwHook ; 调用用户的Hook函数,空函数

         LDR r4,=OSRunning ; 将OSRunning置1,声明多任务OS开始运行

         MOV r5, #1

         STRB r5, [r4]

         LDR r4, =OSTCBHighRdy ; 伪指令,取得存储OSTCBHighRdy的地址

         LDR r4, [r4] ; 得到最高优先级任务的任务堆栈地址

         LDR sp, [r4] ; 切换到新任务的堆栈

         LDMFD sp!, {r4} ;从新任务堆栈中读取第一个参数(CPSR)到(r4)

         MSR cpsr_cxsf, r4 ;再传给cpsr,堆栈中的CPSR弹出到CPU的cpsr寄存器

         LDMFD sp!, {r0-r12,lr,pc} ;依次恢复该任务r0~r12,lr,pc,切换到该任务


; *****下面开始OSCtxSw函数,完成任务级的任务切换*****

     EXPORT OSCtxSw

     IMPORT OSPrioCur

     IMPORT OSPrioHighRdy

     IMPORT OSTCBCur

     IMPORT OSTaskSwHook

     IMPORT OSTCBHighRdy;该变量指向任务切换后即将运行的任务的OS_TCB

OSCtxSw

         STMFD sp!, {lr} ; OSCtxSw是被调用的,lr的值就是调用前的PC值,入栈

         STMFD sp!, {r0-r12,lr} ; 将lr和其他寄存器入栈

         MRS r4, cpsr ;通过MRS指令将cpsr入栈

         STMFD sp!, {r4} ; 被挂起的当前任务的寄存器保存完毕,下面接着保存该

                                ;任务的堆栈指针,以便下次恢复时,可以找到其堆栈指针,便可恢复其寄存器

         LDR r4, =OSTCBCur ; 得到当前TCB块的地址,传给r4

         LDR r5, [r4] ; 将OSTCBCur中的值传给r5,注意OSTCBCur存的是指针

         STR sp, [r5] ; 将当前任务的sp传到OSTCBCur存的指针中去


; *****下面OSCtxSw准备恢复优先级更高的就绪任务,这部分可共用OSIntCtxSw的代码*****

; *****OSIntCtxSw函数开始*****

     EXPORT OSIntCtxSw

     IMPORT OSTaskSwHook

OSIntCtxSw ;准备任务切换

         BL OSTaskSwHook ;调用Hook函数,此为空函数

         LDR r4, =OSTCBHighRdy

         LDR r4, [r4] ;将高优先级的任务栈顶指针存到r4中

         LDR r5, =OSTCBCur

         STR r4, [r5] ; OSTCBCur = OSTCBHighRdy

         LDR r6, =OSPrioHighRdy;取出高优先级

         LDRB r6, [r6] ;优先级,字节传送

         LDR r5, =OSPrioCur

         STRB r6, [r5] ; OSPrioCur = OSPrioHighRdy

         LDR sp, [r4] ;从r4中取得要恢复的任务的栈顶指针

         LDMFD sp!, {r4} ;弹出任务栈中的第一个参数,即cpsr

         MSR cpsr_cxsf, r4 ;首先开始恢复cpsr

         LDMFD sp!, {r0-r12,lr,pc} ;依次恢复r0~r12,lr,pc,任务切换


; *****OSTickISR开始*****

     EXPORT OSTickISR

     IMPORT OSIntEnter

     IMPORT OSTimeTick

     IMPORT OSIntExit


     LINK_SAVE DCD 0 ;用来保存时钟节拍中断前的lr,以便计算出pc而使之入栈

     PSR_SAVE DCD 0 ;用来保存中断前的spsr,中断产生时,svc模式下的cpsr存到spsr

OSTickISR ;时钟节拍中断服务程序入口,需要用户在主函数中安装

         STMFD sp!, {r4} ;因为r4下面要使用,故先保存r4到irq模式的堆栈中

         LDR r4, =LINK_SAVE ; 准备保存LR,SPSR,以便得到中断前的pc和cpsr_svc

         STR lr, [r4] ; LINK_SAVE = lr_irq,此时lr=PC(中断发生前)+4

         MRS lr, spsr ;lr已保存,用lr取得spsr(保存的是中断前的cpsr)

         STR lr, [r4, #4] ; PSR_SAVE = spsr_irq

         LDMFD sp!, {r4} ;恢复r4

         ORR lr, lr, #0x80 ;在上下文切换前,屏蔽irq中断。注意lr存的是中断前的cpsr

         MSR cpsr_cxsf, lr ;中断产生前是svc模式,故必须要切换到此模式下保存现场

         SUB sp, sp, #4 ;按任务栈结构,空一个空间预留给PC

         STMFD sp!, {r0-r12,lr} ; 依次保存lr、r12~r0

         LDR r4, =LINK_SAVE ;准备保存pc,取得存svc模式下发生中断前lr的地址

         LDR lr, [r4, #0]

         SUB lr, lr, #4 ;中断前的pc = LINK_SAVE - 4,此前lr为异常前pc+4的值

         STR lr, [sp, #(14*4)];保存pc到任务栈中预留的空间

         LDR r4, [r4, #4] ;开始保存cpsr,r4 = PSR_SAVE,即中断前的cpsr_svc

         STMFD sp!, {r4} ;保存svc模式下任务的cpsr,寄存器保护完毕

         LDR r4, =OSTCBCur ;下面开始将该堆栈指针传给OSTCBCur所指向的指针

         LDR r4, [r4] ;便于OSIntExit函数判断是否当前任务优先级最高

         STR sp, [r4] ;在OSTCBCur->OSTCBstkptr保存被中断的任务的栈顶指针

         BL OSIntEnter ;异常前的上下文保存好之后,开始准备中断服务,将OSIntNesting++

         BL OSTimeTick ;将所有延时节拍不为1的任务的节拍数都减1,并清中断标志

         BL OSIntExit ;将OSIntNesting--,并判断是否有高优先级任务就绪,若有,则调

                           ;用OSIntCtxSw()调度该任务并不再返回; 若没有则返回到这里

         LDMFD sp!, {r4} ;这里sp存的仍是调用OSIntEnter前的sp,即被中断的任务栈顶指针

         MSR cpsr_cxsf, r4 ;从堆栈中恢复中断前任务的cpsr,注意此时irq才被重新允许

         LDMFD sp!, {r0-r12,lr,pc} ;恢复中断前任务的 r0-r12,lr和pc,返回被中断的任务


;******OSTickISR函数代码完成,下面是临界段代码前后开关中断的函数******

     EXPORT ARMDisableInt

ARMDisableInt

         MRS r0, cpsr ;由于任务和内核都运行在svc模式下,因此可方便地操作cpsr

         STMFD sp!, {r0} ; 保存当前的cpsr

         ORR r0, r0, #0xc0 ;屏蔽FIQ,IRQ中断

         MSR cpsr_c, r0 ;回写cpsr,只屏蔽IRQ中断

         MOV pc, lr ;返回

         EXPORT ARMEnableInt

         ARMEnableInt ;必须和ARMDisableInt成对使用

         LDMFD sp!, {r0} ;弹出在ARMDisableInt中被保存的cpsr

         MSR cpsr_c, r0 ;恢复关中断前的cpsr

         MOV pc, lr ;返回

         END ;汇编代码结束

;*****OS_CPU_A.S文件结束******

这篇关于uCOS-II中的OS_CPU.h,OS_CPU_A.s,OS_CPU.c的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/749658

相关文章

使用Python检查CPU型号并弹出警告信息

《使用Python检查CPU型号并弹出警告信息》本教程将指导你如何编写一个Python程序,该程序能够在启动时检查计算机的CPU型号,如果检测到CPU型号包含“I3”,则会弹出一个警告窗口,感兴趣的小... 目录教程目标方法一所需库步骤一:安装所需库步骤二:编写python程序步骤三:运行程序注意事项方法二

AI基础 L9 Local Search II 局部搜索

Local Beam search 对于当前的所有k个状态,生成它们的所有可能后继状态。 检查生成的后继状态中是否有任何状态是解决方案。 如果所有后继状态都不是解决方案,则从所有后继状态中选择k个最佳状态。 当达到预设的迭代次数或满足某个终止条件时,算法停止。 — Choose k successors randomly, biased towards good ones — Close

从0到1,AI我来了- (7)AI应用-ComfyUI-II(进阶)

上篇comfyUI 入门 ,了解了TA是个啥,这篇,我们通过ComfyUI 及其相关Lora 模型,生成一些更惊艳的图片。这篇主要了解这些内容:         1、哪里获取模型?         2、实践如何画一个美女?         3、附录:               1)相关SD(稳定扩散模型的组成部分)               2)模型放置目录(重要)

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 图一 图二 示例 1:(图一)输入:head = [1,1,2]输出:[1,2]示例 2:(图

Java程序到CPU上执行 的步骤

相信很多的小伙伴在最初学习编程的时候会容易产生一个疑惑❓,那就是编写的Java代码究竟是怎么一步一步到CPU上去执行的呢?CPU又是如何执行的呢?今天跟随小编的脚步去化解开这个疑惑❓。 在学习这个过程之前,我们需要先讲解一些与本内容相关的知识点 指令 指令是指导CPU运行的命令,主要由操作码+被操作数组成。 其中操作码用来表示要做什么动作,被操作数是本条指令要操作的数据,可能是内存地址,也

LeetCode:3177. 求出最长好子序列 II 哈希表+动态规划实现n*k时间复杂度

3177. 求出最长好子序列 II 题目链接 题目描述 给你一个整数数组 nums 和一个非负整数k 。如果一个整数序列 seq 满足在下标范围 [0, seq.length - 2] 中 最多只有 k 个下标i满足 seq[i] != seq[i + 1] ,那么我们称这个整数序列为好序列。请你返回 nums中好子序列的最长长度。 实例1: 输入:nums = [1,2,1,1,3],

代码训练营 Day26 | 47.排序II | 51. N-皇后 |

47.排序II 1.跟46题一样只不过加一个树层去重 class Solution(object):def backtracking(self,nums,path,result,used):# recursion stopif len(path) == len(nums):# collect our setresult.append(path[:])return for i in range(

Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.B

一个bug日志 FATAL EXCEPTION: main03-25 14:24:07.724: E/AndroidRuntime(4135): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.syyx.jingubang.ky/com.anguotech.android.activity.Init

代码随想录训练营day37|52. 携带研究材料,518.零钱兑换II,377. 组合总和 Ⅳ,70. 爬楼梯

52. 携带研究材料 这是一个完全背包问题,就是每个物品可以无限放。 在一维滚动数组的时候规定了遍历顺序是要从后往前的,就是因为不能多次放物体。 所以这里能多次放物体只需要把遍历顺序改改就好了 # include<iostream># include<vector>using namespace std;int main(){int n,m;cin>>n>>m;std::vector<i

win10不用anaconda安装tensorflow-cpu并导入pycharm

记录一下防止忘了 一、前提:已经安装了python3.6.4,想用tensorflow的包 二、在pycharm中File-Settings-Project Interpreter点“+”号导入很慢,所以直接在cmd中使用 pip install -i https://mirrors.aliyun.com/pypi/simple tensorflow-cpu下载好,默认下载的tensorflow