OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 6536|回复: 1

都能看懂的简易嵌入式系统mini/OS揭秘(1)

[复制链接]

13

主题

42

帖子

0

精华

初级会员

Rank: 2

积分
128
金钱
128
注册时间
2011-8-16
在线时间
6 小时
发表于 2013-2-22 15:30:34 | 显示全部楼层 |阅读模式
 
mini/OS嵌入式系统内核揭秘(1)
以下贴出mini/OS汇编部分的代码:
;/*********************** (C) COPYRIGHT 2010 Libraworks *************************
;* File Name: os_cpu_a.asm
;* Author: Librae
;* Version: V1.0
;* Date: 06/10/2010
;* Description: μCOS-II asm port for STM32
;*******************************************************************************/
  IMPORT  OSCurTCB                    ; External references
  IMPORT  OSNewTCB
  IMPORT  OSTaskSwHook
                   
  EXPORT  OSStartTask
  EXPORT  OSCtxSw
  EXPORT  OSIntCtxSw
  EXPORT  OS_CPU_SR_Save                       ; Functions declared in this file
  EXPORT  OS_CPU_SR_Restore       
  EXPORT  PendSV_Handler 
    
NVIC_PENDSV_PRI  EQU     0xFFFF0000               ; PendSV priority value (lowest)
NVIC_PENDSVSET   EQU     0x10000000               ; value to trigger PendSV exception
NVIC_INT_CTRL    EQU     0xE000ED04               ; interrupt control state register
NVIC_SYSPRI2     EQU     0xE000ED20               ; system priority register (2)

  RESERVE8
  
  AREA    |.text|, CODE, READONLY
        THUMB
   
          
;********************************************************************************************************
;                                   CRITICAL SECTION METHOD 3 FUNCTIONS
;
;********************************************************************************************************
OS_CPU_SR_Save
    MRS     R0, PRIMASK   ;读取PRIMASK到R0,R0为返回值
    CPSID   I    RIMASK=1,关中断(NMI和硬件FAULT可以响应)
    BX      LR       ;返回
OS_CPU_SR_Restore
    MSR     PRIMASK, R0     ;读取R0到PRIMASK中,R0为参数;open interrupt
    BX      LR    ;返回

;/**************************************************************************************
;* 函数名称: OSStartTask
;*
;* 功能描述: 使用调度器运行第一个任务
;*
;* 参    数: None
;*
;* 返 回 值: None
;**************************************************************************************/ 
OSStartTask
        LDR     R4, =NVIC_SYSPRI2      ; set the PendSV exception priority
        LDR     R5, =NVIC_PENDSV_PRI
        STR     R5, [R4]
        MOV     R4, #0                 ; set the PSP to 0 for initial context switch call
        MSR     PSP, R4
                                       ;切换到最高优先级的任务
        LDR     R4, =NVIC_INT_CTRL     ;rigger the PendSV exception (causes context switch)
        LDR     R5, =NVIC_PENDSVSET    ;触发PendSV异常 (causes context switch)
        STR     R5, [R4]
        CPSIE   I                      ;enable interrupts at processor level
OSStartHang
        B       OSStartHang            ;should never get here
;/**************************************************************************************
;* 函数名称: OSCtxSw
;*
;* 功能描述: 任务级上下文切换        
;*
;* 参    数: None
;*
;* 返 回 值: None
;***************************************************************************************/
 
OSCtxSw
  USH    {R4, R5}
        LDR     R4, =NVIC_INT_CTRL   ;触发PendSV异常 (causes context switch)
        LDR     R5, =NVIC_PENDSVSET
        STR     R5, [R4]
  OP     {R4, R5}
        BX      LR
  NOP
;/**************************************************************************************
;* 函数名称: OSIntCtxSw
;*
;* 功能描述: 中断级任务切换
;*
;* 参    数: None
;*
;* 返 回 值: None
;***************************************************************************************/
OSIntCtxSw
  USH    {R4, R5}
        LDR     R4, =NVIC_INT_CTRL      ;触发PendSV异常 (causes context switch)
        LDR     R5, =NVIC_PENDSVSET
        STR     R5, [R4]
  OP     {R4, R5}
        BX      LR
        NOP
;/**************************************************************************************
;* 函数名称: OSPendSV
;*
;* 功能描述: OSPendSV is used to cause a context switch.
;*
;* 参    数: None
;*
;* 返 回 值: None
;***************************************************************************************/
PendSV_Handler
        CPSID   I                                           ; Prevent interruption during context switch
        MRS     R0, PSP                                     ; PSP is process stack pointer 如果在用PSP堆栈,则可以忽略保存寄存器,参考CM3权威中的双堆栈-白菜注
        CBZ     R0, PendSV_Handler_Nosave              ; Skip register save the first time
        SUBS    R0, R0, #0x20        
        STM     R0, {R4-R11}                             ; Save remaining regs r4-11 on process stack
        LDR     R1, =OSCurTCB   
        LDR     R1, [R1]
        STR     R0, [R1]                                    ; R0 is SP of process being switched out         
PendSV_Handler_Nosave
        PUSH    {R14}                                       ; Save LR exc_return value
        LDR     R0, =OSTaskSwHook                           ; OSTaskSwHook();
        BLX     R0
        POP     {R14}
        LDR     R0, =OSCurTCB                               ;OSCurTCB=OSNewTCB;    
        LDR     R1, =OSNewTCB
        LDR     R2, [R1]
        STR     R2, [R0]
        LDR     R0, [R2]                                    ; R0 is new process SP; SP = OSCurTCB;       
        LDM     R0, {R4-R11}                ; Restore r4-11 from new process stac
        ADD     R0, R0, #0x20
        MSR     PSP, R0            
        ORR     LR, LR, #0x04
  CPSIE   I                                  ; Exception return will restore remaining context
        BX      LR                  
  end 
仔细看汇编部分,是否就是ucos在stm32系统上移植的翻版?利用以上汇编部分代码,你就可以不管汇编部分,专心做c语言部分任务调度方面的事了。该任务调度时调用OSCtxSw(),传递不同任务的堆栈指针OSCurTCB,OSNewTCB就完成了新旧任务之间的切换。
再来看看OSCurTCB,OSNewTCB分别是什么。
typedef struct taskControlBlock
{
 /*当前的栈顶指针*/
 OS_STK     *pStackTop;  
 /*当前优先级*/
 RIO_TYPE    CurPriority; 
 /*任务状态*/
 uint8      TaskStat;
 /*等待时间片的个数*/
 int32     TCBDelay;
 
} TCB;
/*当前运行的任务*/
TCB   *OSCurTCB;
/*当前准备新运行的任务*/
TCB   *OSNewTCB;
/*当前OS中所有的任务*/
uint8  TaskNUM=0;
TCB   OSTCBTable[MAX_TASK_NUM];
可见OSCurTCB和OSNewTCB分别是当前运行任务的堆栈指针和要运行的新任务的堆栈指针。
下面关心的可能是任务的创建了,任务是如何创建的。每个任务都有自己的堆栈空间,就像是单独占用CPU一样,所以创建任务的一方面主要是完成任务堆栈的初始化。
以下是c语言写的任务堆栈的初始化函数,位于文件OS_CPU.c中,如果需要移植,除了汇编部分OS_CPU_A.asm文件修改外,OS_CPU.c和OS_TYPE.h等文件也需要修改。仅这几个文件,所以mini/OS移植很简单。
OS_STK实际上就是int32,因为stm32上堆栈指针就是32位长度。第一个参数是任务的地址,即函数的地址,第二个参数是任务的堆栈指针。
OS_STK *OSTaskStkInit (void (*task),OS_STK *ptos)
{
    OS_STK *stk;
// (void)PSR;                                    /* 'PSR' is not used, prevent warning                */
    stk    = ptos;                               /* 获取堆栈指针                                */
                                                 /* Registers stacked as if auto-saved on exception    */
    *(stk)    = (uint32)0x01000000L;             /* xPSR                                               */
    *(--stk)  = (uint32)task;                    /* Entry Point                                        */
    *(--stk)  = (uint32)0xFFFFFFFEL;             /* R14 (LR) (init value will cause fault if ever used)*/
    *(--stk)  = (uint32)0x12121212L;             /* R12                                                */
    *(--stk)  = (uint32)0x03030303L;             /* R3                                                 */
    *(--stk)  = (uint32)0x02020202L;             /* R2                                                 */
    *(--stk)  = (uint32)0x01010101L;             /* R1                                                 */
    *(--stk)  = (uint32)0;                       /* R0 : argument                                      */
                                                 /* Remaining registers saved on process stack         */
    *(--stk)  = (uint32)0x11111111L;             /* R11                                                */
    *(--stk)  = (uint32)0x10101010L;             /* R10                                                */
    *(--stk)  = (uint32)0x09090909L;             /* R9                                                 */
    *(--stk)  = (uint32)0x08080808L;             /* R8                                                 */
    *(--stk)  = (uint32)0x07070707L;             /* R7                                                 */
    *(--stk)  = (uint32)0x06060606L;             /* R6                                                 */
    *(--stk)  = (uint32)0x05050505L;             /* R5                                                 */
    *(--stk)  = (uint32)0x04040404L;             /* R4                                                 */
    return (stk);
}
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2013-2-22 16:44:46 | 显示全部楼层
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 23:04

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表