μCOS-II移植 - 基于CortexM3

μCOS-II是一个经典的RTOS。

任务切换对于RTOS来说是最基本也是最核心的部分,除此之外还有任务调度算法。

先来看看基于stm32f107的任务切换代码:

;********************************************************************************************************
;                                          START MULTITASKING
;                                       void OSStartHighRdy(void)
;
; Note(s) : 1) This function triggers a PendSV exception (essentially, causes a context switch) to cause
;              the first task to start.
;
;           2) OSStartHighRdy() MUST:
;              a) Setup PendSV exception priority to lowest;
;              b) Set initial PSP to 0, to tell context switcher this is first run;
;              c) Set the main stack to OS_CPU_ExceptStkBase;
;              d) Set OSRunning to TRUE;
;              e) Trigger PendSV exception;
;              f) Enable interrupts (tasks will run with interrupts enabled).
;********************************************************************************************************

OSStartHighRdy
    LDR     R0, =NVIC_SYSPRI14                                  ; Set the PendSV exception priority
    LDR     R1, =NVIC_PENDSV_PRI
    STRB    R1, [R0]

    MOVS    R0, #0                                              ; Set the PSP to 0 for initial context switch call
    MSR     PSP, R0

    LDR     R0, =OS_CPU_ExceptStkBase                           ; Initialize the MSP to the OS_CPU_ExceptStkBase
    LDR     R1, [R0]
    MSR     MSP, R1    

    LDR     R0, =OSRunning                                      ; OSRunning = TRUE
    MOVS    R1, #1
    STRB    R1, [R0]

    LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]

    CPSIE   I                                                   ; Enable interrupts at processor level

OSStartHang
    B       OSStartHang                                         ; Should never get here

;********************************************************************************************************
;                               PERFORM A CONTEXT SWITCH (From task level)
;                                           void OSCtxSw(void)
;
; Note(s) : 1) OSCtxSw() is called when OS wants to perform a task context switch.  This function
;              triggers the PendSV exception which is where the real work is done.
;********************************************************************************************************

OSCtxSw                                  
    LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]
    BX      LR

;********************************************************************************************************
;                             PERFORM A CONTEXT SWITCH (From interrupt level)
;                                         void OSIntCtxSw(void)
;
; Notes:    1) OSIntCtxSw() is called by OSIntExit() when it determines a context switch is needed as
;              the result of an interrupt.  This function simply triggers a PendSV exception which will
;              be handled when there are no more interrupts active and interrupts are enabled.
;********************************************************************************************************

OSIntCtxSw                                  
    LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]
    BX      LR

;********************************************************************************************************
;                                         HANDLE PendSV EXCEPTION
;                                     void OS_CPU_PendSVHandler(void)
;
; Note(s) : 1) PendSV is used to cause a context switch.  This is a recommended method for performing
;              context switches with Cortex-M3.  This is because the Cortex-M3 auto-saves half of the
;              processor context on any exception, and restores same on return from exception.  So only
;              saving of R4-R11 is required and fixing up the stack pointers.  Using the PendSV exception
;              this way means that context saving and restoring is identical whether it is initiated from
;              a thread or occurs due to an interrupt or exception.
;
;           2) Pseudo-code is:
;              a) Get the process SP, if 0 then skip (goto d) the saving part (first context switch);
;              b) Save remaining regs r4-r11 on process stack;
;              c) Save the process SP in its TCB, OSTCBCur->OSTCBStkPtr = SP;
;              d) Call OSTaskSwHook();
;              e) Get current high priority, OSPrioCur = OSPrioHighRdy;
;              f) Get current ready thread TCB, OSTCBCur = OSTCBHighRdy;
;              g) Get new process SP from TCB, SP = OSTCBHighRdy->OSTCBStkPtr;
;              h) Restore R4-R11 from new process stack;
;              i) Perform exception return which will restore remaining context.
;
;           3) On entry into PendSV handler:
;              a) The following have been saved on the process stack (by processor):
;                 xPSR, PC, LR, R12, R0-R3
;              b) Processor mode is switched to Handler mode (from Thread mode)
;              c) Stack is Main stack (switched from Process stack)
;              d) OSTCBCur      points to the OS_TCB of the task to suspend
;                 OSTCBHighRdy  points to the OS_TCB of the task to resume
;
;           4) Since PendSV is set to lowest priority in the system (by OSStartHighRdy() above), we
;              know that it will only be run when no other exception or interrupt is active, and
;              therefore safe to assume that context being switched out was using the process stack (PSP).
;********************************************************************************************************

OS_CPU_PendSVHandler
    CPSID   I                                                   ; Prevent interruption during context switch
    MRS     R0, PSP                                             ; PSP is process stack pointer
    CBZ     R0, OS_CPU_PendSVHandler_nosave                     ; Skip register save the first time

    SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack
    STM     R0, {R4-R11}

    LDR     R1, =OSTCBCur                                       ; OSTCBCur->OSTCBStkPtr = SP;
    LDR     R1, [R1]
    STR     R0, [R1]                                            ; R0 is SP of process being switched out

                                                                ; At this point, entire context of process has been saved
OS_CPU_PendSVHandler_nosave
    PUSH    {R14}                                               ; Save LR exc_return value
    LDR     R0, =OSTaskSwHook                                   ; OSTaskSwHook();
    BLX     R0
    POP     {R14}

    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 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
    LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack
    ADDS    R0, R0, #0x20
    MSR     PSP, R0                                             ; Load PSP with new process SP
    ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack
    CPSIE   I
    BX      LR                                                  ; Exception return will restore remaining context

OSPendSV()是 PendSV Handler 的中断处理函数(的名称),它实现了上下文切换。这种实现
方式对于 ARM Cortex-M3 来说是强烈推荐的。这是因为对于任何异常,ARM Cortex-M3 可以
自动的保存(进入异常)和恢复上下文(退出异常)的 一部分内容。因此 PendSV handler 只
需要保存和恢复 R4-R11 和堆栈指针这些剩余的上下文。使用了 PendSV 的异常机制,意味
着,无论是由任务触发还是由中断或异常触发的上下文切换都可以用同一种方法实现。
置 注意你必须在异常向量表的位置 14  处设置一个指针指向 OSPendSV()。
PendSV handler 的伪代码如下:

OSPendSV:
if (PSP != NULL) { (1)
Save R4-R11 onto task stack; (2)
OSTCBCur->OSTCBStkPtr = SP; (3)
}
OSTaskSwHook(); (4)
OSPrioCur = OSPrioHighRdy; (5)
OSTCBCur = OSTCBHighRdy; (6)
PSP = OSTCBHighRdy->OSTCBStkPtr; (7)
Restore R4-R11 from new task stack; (8)
Return from exception; (9)

(0) 注意当 OSPendSV 被 CPU 运行,CPU 会自动地保存 xPSR、PC、LR、R12 和 R0-R13 到
任务的堆栈。当将部分上下文保存到相应的任务的堆栈后,CPU 要切换堆栈指针了,
转而使用 SP_main 来运行剩下的中断程序。
(1) 这里我们检查 SP_process 堆栈指针是否为 NULL。重申:OSStartHighRdy()函数将
SP_process 置 NULL 来达到避免当运行第一个任务时保存任务的上下文的目的。
(2) 如果 PendSV()确实被触发来实现一个完整的任务切换,则我们简单的保存上下的寄
存器的值(R4-R11)
(3) 一旦正在被切换的任务的上下文被保存,我们简单的保存任务的堆栈指针
(SP_process)到正在被切换的任务的 OS_TCB。
(4) 接下来我们调用 UCOS 上下文切换的钩子函数(参见 OS_CPU_C.C)。
(5) 像其他硬件平台上移植 UCOS 的做法一样,我们需要赋值新的高优先级的任务的指
针到当前的任务的指针。
(6) 同上,我们需要复制 OSTCBHighRdy 进 OSTCBCur。
(7) 接下来,我们恢复我们希望切换的那个任务的当前栈顶指针。重申,栈顶指针保存
在变量 OSTCBHighRdy->OSTCBStkPtr 中。方便起见,UCOS 总是将.OSTCBStkPtr 放在结
构体 OS_TCB 的开头,这样避免了去查找 SP 的 offset,offset 总是 0。
(8) 我们从任务的堆栈结构中恢复任务的上下文,为任务的执行做准备。
(9) 实现一个异常的返回,这将促使 ARM Cortex-M3 自动从相应的任务堆栈结构中恢复
R3-R12、LR、PC 和 xPSR 寄存器的值。至此便正在运行新任务了。
注意:PendSV Handler 是不可抢占的是不可被中断的,以此保证上下文自动切换。如果上下
文切换时发生中断,则新任务恢复后(上下文切换完毕后)立即执行相应的中断服务程序。

OSStartHighRdy将PSP置零,设置并触发了PendSV,在OS_CPU_PendSVHandler中,会跳过PSP和r4-r11的压栈,这是因为是第一次执行任务切换,之前没有有意义的任务需要保存。

同时可以发现任务级别的切换和中断级别的切换是一样的。

对于移植μCOS-II,基本需要专为操作系统而生的SYSTICK提供的OS心跳、任务切换和禁止使能中断就可以了。

时间: 2024-07-29 18:52:00

μCOS-II移植 - 基于CortexM3的相关文章

Cstyle的札记,Freertos内核详解,基于cortex-m3,第0篇

Freertos是一个硬实时内核,支持众多的微处理器架构,我们可以从它的官网(www.freertos.ort)下载它的sourcecode,同时也可以看出它支持了几十种的微处理器架构,这些就不罗嗦了.之所以选择研究这个,是应为窥探RTOS内核的内幕一直每一个做底层软件开发人员的心愿,选择过好几种RTOS但他们有的是需要收费,有的不太成熟也不够系统,有的虽然比较成熟但是系统太大不太适合研究.而freertos就不同了,它除了包含RTOS所需要的基本的东西之外最大的特点就是开源+简单并且支持了非常

emWin 移植 - 基于红牛开发板

一直想利用所学的东西自己设计一个精致一些的作品,手头正好有一块红牛开发板,就先用它来写一些软件,熟悉一下过程和一些想法的可行性.首先当然是选择一个操作系统了,对比了几种之后选择了emWin.那就移植一下吧. 这里首先要感谢一下http://www.openedv.com/posts/list/0/27697.htm 这篇帖子.我的思路基本是照着这个帖子做的.感谢楼主把辛苦的研究成果贡献出来,让我这个菜鸟能够快些入门. STemWin下载地址: http://www.st.com/web/en/c

STM32固件库3.5+uCOS2.86移植(转自暴走的工程师)

考了很多移植的资料和代码,终于移植好了...应该是完美移植吧~~哈哈哈~~ 编译环境是IAR 工程适用于STM32F10X大容量产品,如果不是,请自行修改启动文件和工程配置 编译器优化等级最高...这个你们根据需要自己调整吧... ############################################################################### 1.Jean J.Labrosse与μCOS—II μCOS—II是一个实时可剥夺型操作系统内核,该操作系统

Cortex-M3

大家听说过Cortex-M3吗?在嵌入式处理器的世界,cortex-M3是一位人见人爱的后生.它的成本和功耗低,可配置性很高.如今,很多ARM的工程师加入了cortex-M3的学习与开发中,WIZnet一直都是行业的领先者,即将上市的新产品W7200正是加入了cortex-M3处理器的全硬件TCP/IP协议栈芯片,通过利用它的优势,相信会得到更多客户的青睐.下面,广大的嵌入式爱好者可以跟随我们一起来了解cortex-M3,加入到基于这一先进的32位处理器的嵌入式开发学习. Cortex-M3 学

六轴加速度传感器MPU6050官方DMP库到瑞萨RL78/G13的移植

2015年的电赛已经结束了.赛前接到器件清单的时候,看到带防护圈的多旋翼飞行器赫然在列,又给了一个瑞萨RL78/G13的MCU,于是自然联想到13年的电赛,觉得多半是拿RL78/G13做四旋翼的主控,虽然事后证实我的猜测是错的,但是在赛前我还是完成了相关代码的准备,这其中就包括了MPU6050的DMP库移植.在移植前我大概搜了一下,发现网上还没有相关的源代码.一起准备电赛的同学还买过一份RL78/G13的飞控代码,虽然也是使用MPU6050进行姿态获取,但是对MPU6050的读取并不是通过DMP

uC/OS-II在STM32F103上的移植

uc/os工程的创建和移植 先在官方下载uc/os的源代码,下载链接如下,注册之后即可以下载: https://www.micrium.com/download/micrium_stm32xxx_ucos-ii/ 注意IAR和MDK的区别,IAR版汇编的在MDK上汇编不兼容,改动会比较多. 然后在Keil中新建一个uCOS的工程,选择板子为STM32F103C8,选择CMSIS下的CORE和Device下的Startup,以及Device下的StdPeriph Drivers下的Framewor

系统移植的四大步骤

最近在学习系统移植的相关知识,在学习和调试过程中,发现了很多问题,也解决了很多问题,但总是对于我们的开发结果有一种莫名其妙的感觉,纠其原因,主要对于我们的开发环境没有一个深刻的认识,有时候几个简单的命令就可以完成非常复杂的功能,可是我们有没有想过,为什么会有这样的效果?如果没有去追问,只是机械地完成,并且看到实验效果,这样做其实并没有真正的掌握系统移植的本质. 在做每一个步骤的时候,首先问问自己,为什么要这样做,然后再问问自己正在做什么?搞明白这几个问题,我觉得就差不多了,以后不管更换什么平台,

将 Android* Bullet 物理引擎移植至英特尔® 架构

简介 由于目前的移动设备上能够使用更高的计算性能,移动游戏现在也可以提供震撼的画面和真实物理(realistic physics). 枪战游戏中的手雷爆炸效果和赛车模拟器中的汽车漂移效果等便是由物理引擎所提供,其核心是物理模拟. 一般而言,物理模拟决定了游戏引擎的性能. 一款游戏成功与否通常取决于物理引擎计算物理模型的速度和准确度. 本文将介绍如何构建 Android 版 Bullet 物理引擎并将其移至到基于英特尔? 凌动 SoC 的平台. Bullet 物理 Bullet 物理库是一个实时物

RT-Thread 在stm小内存系列产品的nano+msh完整移植教程

本教程基于CUBE-MX,搭建环境方便快捷,把更多精力用在移植的实现上. ps:本次移植基于stm32l151, 理论上和F1系列通用, 和F4系列区别开来. ps:纯手工搭建环境也是可以,在一个可以输出hello world的demo上进行移植. ps: 基于官方移植思路,简单快捷,但是要调整一些小细节. 源地址: https://www.rt-thread.org/document/site/tutorial/nano/mdk/an0031-nano-mdk/ https://www.rt-