OpenEdv-开源电子网

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

在原子的ucos例程发现一个问题。

[复制链接]

38

主题

527

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1424
金钱
1424
注册时间
2011-11-27
在线时间
122 小时
发表于 2012-5-3 21:40:36 | 显示全部楼层 |阅读模式

原子的ALIENTEK MiniSTM32 UCOS实验 里面开关中断有个问题。

我在任务里使用OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()来保护全局变量时【OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()应该是成对使用的】

但当我把OS_EXIT_CRITICAL();注释掉的时候,程序还是正常运行,说明开关中断就没有起到作用。

于是,修改了一部分os_cpu_a.asm代码后,程序就死掉了【说明开关中断起作用了】,再打开注释程序可以正常运行。

是这样修改的:

(1)os_cpu_a.asm中斜体部分为修改的地方,其他没变

;/*********************** (C) COPYRIGHT 2010 Libraworks *************************
;* File Name: os_cpu_a.asm
;* Author: Librae
;* Version: V1.0
;* Date: 06/10/2010
;* Description: μCOS-II asm port
;*******************************************************************************/

  IMPORT  OSRunning               ; External references
        IMPORT  OSPrioCur
        IMPORT  OSPrioHighRdy
        IMPORT  OSTCBCur
        IMPORT  OSTCBHighRdy
        IMPORT  OSIntNesting
        IMPORT  OSIntExit
        IMPORT  OSTaskSwHook
          
        EXPORT  OSStartHighRdy              
        EXPORT  OSCtxSw
        EXPORT  OSIntCtxSw
  EXPORT  OS_CPU_SR_Save                                      ; Functions declared in this file
     EXPORT  OS_CPU_SR_Restore
      
        EXPORT  PendSV_Handler
         
    
NVIC_INT_CTRL    EQU     0xE000ED04  ; 中断控制寄存器
NVIC_SYSPRI2     EQU     0xE000ED20  ; 系统优先级寄存器(2)
NVIC_PENDSV_PRI  EQU     0xFFFF0000  ; 软件中断和系统节拍中断
                                        ; (都为最低,0xff).
NVIC_PENDSVSET   EQU     0x10000000  ; 触发软件中断的值.


  RESERVE8
  
  AREA    |.text|, CODE, READONLY
        THUMB
   
          

;********************************************************************************************************
;                                   CRITICAL SECTION METHOD 3 FUNCTIONS
;
; Description: Disable/Enable interrupts by preserving the state of interrupts.  Generally speaking you
;              would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then
;              disable interrupts.  'cpu_sr' is allocated in all of uC/OS-II's functions that need to
;              disable interrupts.  You would restore the interrupt disable state by copying back 'cpu_sr'
;              into the CPU's status register.
;
; Prototypes :     OS_CPU_SR  OS_CPU_SR_Save(void);
;                  void       OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
;
;
; Note(s)    : 1) These functions are used in general like this:
;
;                 void Task (void *p_arg)
;                 {
;                 #if OS_CRITICAL_METHOD == 3          /* Allocate storage for CPU status register */
;                     OS_CPU_SR  cpu_sr;
;                 #endif
;
;                          :
;                          :
;                     OS_ENTER_CRITICAL();             /* cpu_sr = OS_CPU_SaveSR();                */
;                          :
;                          :
;                     OS_EXIT_CRITICAL();              /* OS_CPU_RestoreSR(cpu_sr);                */
;                          :
;                          :
;                 }
;********************************************************************************************************

OS_CPU_SR_Save
    MRS     R0, PRIMASK                                         ; Set prio int mask to mask all (except faults)
    CPSID   I
    BX      LR

OS_CPU_SR_Restore
    MSR     PRIMASK, R0
    BX      LR


;/**************************************************************************************
;* 函数名称: OSStartHighRdy
;*
;* 功能描述: 使用调度器运行第一个任务
;*
;* 参    数: None
;*
;* 返 回 值: None
;**************************************************************************************/ 

OSStartHighRdy
        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, =OSRunning         ; OSRunning = TRUE
        MOV     R5, #1
        STRB    R5, [R4]

                                       ;切换到最高优先级的任务
        LDR     R4, =NVIC_INT_CTRL     ;rigger the PendSV exception (causes context switch)
        LDR     R5, =NVIC_PENDSVSET
        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

;/**************************************************************************************
;* 函数名称: 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                                       ; 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
PendSV_Handler_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

 end 

(2)os_cpu.h中,

#define  OS_CRITICAL_METHOD   4

#if OS_CRITICAL_METHOD == 4
  void OS_ENTER_CRITICAL (void);
     void OS_EXIT_CRITICAL (void);    
#endif

修改为:

#define  OS_CRITICAL_METHOD   3

#if OS_CRITICAL_METHOD == 3
#define  OS_ENTER_CRITICAL()  {cpu_sr = OS_CPU_SR_Save();}
#define  OS_EXIT_CRITICAL()   {OS_CPU_SR_Restore(cpu_sr);}
#endif

永远保持一颗学习的心态。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-5-3 23:28:49 | 显示全部楼层
OS_EXIT_CRITICAL();注释掉的时候,程序是可以正常运行的,只是不会执行任务切换了.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

38

主题

527

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1424
金钱
1424
注册时间
2011-11-27
在线时间
122 小时
 楼主| 发表于 2012-5-4 09:01:59 | 显示全部楼层
回复【2楼】正点原子:
OS_EXIT_CRITICAL();注释掉的时候,程序是可以正常运行的,只是不会执行任务切换了.
---------------------------------
两个led灯闪的任务,在其中一个任务中增加开关中断代码,如果把OS_EXIT_CRITICAL();注释掉就不会任务切换了,应该只有一个任务运行了,但是为啥两个灯还是正常闪烁。
永远保持一颗学习的心态。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-5-4 09:28:18 | 显示全部楼层
因为你调用了延时函数.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

38

主题

527

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1424
金钱
1424
注册时间
2011-11-27
在线时间
122 小时
 楼主| 发表于 2012-5-4 10:06:54 | 显示全部楼层
回复【4楼】正点原子:
因为你调用了延时函数.

---------------------------------
在开始任务里这样处理,任务照样切换(两led灯闪烁正常)。
//开始任务
void TaskStart(void * pdata)
{
pdata = pdata;
   OS_ENTER_CRITICAL();
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72);      //延时初始化 
uart_init(72,9600);  //串口初始化为9600
LED_Init();     //初始化与LED连接的硬件接口
SysTick_Configuration(); //初始化系统中断时钟
// OS_EXIT_CRITICAL();
OSTaskCreate(TaskLed, (void * )0, (OS_STK *)&TASK_LED_STK[LED_STK_SIZE-1], LED_TASK_Prio);
OSTaskCreate(TaskLed1, (void * )0, (OS_STK *)&TASK_LED1_STK[LED1_STK_SIZE-1], LED1_TASK_Prio);
OSTaskDel(OS_PRIO_SELF);
}
永远保持一颗学习的心态。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-5-4 12:38:14 | 显示全部楼层
 回复【5楼】科科1987: 
--------------------------------- 
OSTaskDel(OS_PRIO_SELF);  
这个函数应该会引起一次切换吧. 
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

38

主题

527

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1424
金钱
1424
注册时间
2011-11-27
在线时间
122 小时
 楼主| 发表于 2012-5-4 15:49:33 | 显示全部楼层
回复【6楼】正点原子:
 回复【5楼】科科1987: 
--------------------------------- 
OSTaskDel(OS_PRIO_SELF);  
这个函数应该会引起一次切换吧. 

---------------------------------
本来想关中断和开中断保护共享数据的,如果用的开关中断方法是不可嵌套的,那在打开中断(OS_EXIT_CRITICAL();)之前就已经开中断了。违背了当初的愿望。是不是例程里的OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()写的不合理。也许是我孤陋寡闻,没有见过OS_CRITICAL_METHOD == 4,貌似OS_CRITICAL_METHOD只有3种实现方法:
[1]   OS_CRITICAL_METHOD = 1:直接使用处理器的开关中断指令来实现宏
[2]   OS_CRITICAL_METHOD = 2:利用堆栈保存和恢复CPU的状态
[3]   OS_CRITICAL_METHOD = 3:利用编译器扩展功能获得程序状态字,保存在局部变量cpu_sr中


用下面的程序测试了一下,在关闭中断之后,串口中断照样可以接收数据。

//开始任务 
void TaskStart(void * pdata) 

pdata = pdata; 
   OS_ENTER_CRITICAL(); 
Stm32_Clock_Init(9); //系统时钟设置 
delay_init(72);      //延时初始化  
uart_init(72,9600);  //串口初始化为9600 
LED_Init();     //初始化与LED连接的硬件接口 
SysTick_Configuration(); //初始化系统中断时钟 
// OS_EXIT_CRITICAL(); 
OSTaskCreate(TaskLed, (void * )0, (OS_STK *)&TASK_LED_STK[LED_STK_SIZE-1], LED_TASK_Prio);
 OSTaskCreate(TaskLed1, (void * )0, (OS_STK *)&TASK_LED1_STK[LED1_STK_SIZE-1], LED1_TASK_Prio);
 OSTaskDel(OS_PRIO_SELF); 
}

//任务2
//控制DS1的亮灭.
void TaskLed1(void *pdata)
{
u8 t,len;
while(1)
{
if(USART_RX_STA&0x80)
{    
len=USART_RX_STA&0x3f;//得到此次接收到的数据长度
printf("\n您发送的消息为:\n");
for(t=0;t<len;t++)
{
USART1->DR=USART_RX_BUF[t];
while((USART1->SR&0X40)==0);//等待发送结束
}
printf("\n\n");//插入换行
USART_RX_STA=0;
}
LED1=!LED1;
OSTimeDlyHMSM(0,0,0,500);
}
}
永远保持一颗学习的心态。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-5-4 17:32:49 | 显示全部楼层
#if OS_CRITICAL_METHOD == 4
 void OS_ENTER_CRITICAL (void);
     void OS_EXIT_CRITICAL (void);     
#endif

这个是方法4定义的开关中断函数.
你的调用方法应该是有问题的.
你不要在调用OS_ENTER_CRITICAL();  之后再去调用可以引起任务切换,或者有开关中断的ucos函数.
你想测试就这样吧:
void TASK_X()
{
OS_ENTER_CRITICAL(); 
while(1)
{
     


}
你再看看还能引起调度不...

我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

38

主题

527

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1424
金钱
1424
注册时间
2011-11-27
在线时间
122 小时
 楼主| 发表于 2012-5-4 19:17:30 | 显示全部楼层

回复【8楼】正点原子:
---------------------------------
的确如原子所说,
void TaskLed(void *pdata)
{
while(1)
{
OS_ENTER_CRITICAL();
LED0=!LED0;
// OS_EXIT_CRITICAL();
// OSTimeDlyHMSM(0,0,0,300);
}
}
此时就不能调度了
永远保持一颗学习的心态。
回复 支持 反对

使用道具 举报

38

主题

527

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1424
金钱
1424
注册时间
2011-11-27
在线时间
122 小时
 楼主| 发表于 2012-5-4 19:31:05 | 显示全部楼层
由此看来,这种开关中断的方法是不可嵌套的吧
永远保持一颗学习的心态。
回复 支持 反对

使用道具 举报

38

主题

527

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1424
金钱
1424
注册时间
2011-11-27
在线时间
122 小时
 楼主| 发表于 2012-5-4 19:36:24 | 显示全部楼层

虽然程序考虑到了嵌套问题,使用了OSInterrputSum来统计嵌套数目,但貌似也没起到应有的作用。


;/***************************************************************************************
;* 函数名称: OS_ENTER_CRITICAL
;*
;* 功能描述: 进入临界区 
;*            
;* 参    数: None
;*
;* 返 回 值: None
;*****************************************************************************************/ 

OS_ENTER_CRITICAL
 
CPSID   I                       ; Disable all the interrupts
                                                                        
PUSH  {R1,R2}      

LDR  R1, =OSInterrputSum     ; OSInterrputSum++
LDRB  R2, [R1]
ADD    R2, R2, #1
STRB  R2, [R1]
POP     {R1,R2}
BX LR

;/***************************************************************************************
;* 函数名称: OS_EXIT_CRITICAL
;*
;* 功能描述: 退出临界区 
;*            
;* 参    数: None
;*
;* 返 回 值: None
;*****************************************************************************************/

OS_EXIT_CRITICAL
PUSH    {R1, R2}
LDR     R1, =OSInterrputSum     ; OSInterrputSum--
LDRB    R2, [R1]
SUB     R2, R2, #1
STRB    R2, [R1]
MOV     R1,  #0       
CMP     R2,  #0         ; if OSInterrputSum=0,enable 
                                        ; interrupts如果OSInterrputSum=0,
MSREQ  RIMASK, R1   
 OP    {R1, R2}
BX LR

永远保持一颗学习的心态。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-5-4 21:40:15 | 显示全部楼层
应该是后续代码也有调用
OS_ENTER_CRITICAL
和OS_EXIT_CRITICAL

所以就算你开始只调用了OS_ENTER_CRITICAL,但是后面的代码接着给你来个OS_ENTER_CRITICAL+OS_EXIT_CRITICAL,结果还是会调度的...
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

38

主题

527

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1424
金钱
1424
注册时间
2011-11-27
在线时间
122 小时
 楼主| 发表于 2012-5-5 16:18:10 | 显示全部楼层
回复【12楼】正点原子:
应该是后续代码也有调用
OS_ENTER_CRITICAL
和OS_EXIT_CRITICAL
所以就算你开始只调用了OS_ENTER_CRITICAL,但是后面的代码接着给你来个OS_ENTER_CRITICAL+OS_EXIT_CRITICAL,结果还是会调度的...
---------------------------------
所以这样OS_ENTER_CRITICAL和OS_EXIT_CRITICAL嵌套起来的话,这样就不合理嘛~~
隐患重重。我觉得还是按照OS_CRITICAL_METHOD = 3 (我测试了,这样就不会出现上面的打开中断的情况)合理一些。
永远保持一颗学习的心态。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

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

使用道具 举报

38

主题

527

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1424
金钱
1424
注册时间
2011-11-27
在线时间
122 小时
 楼主| 发表于 2012-5-5 16:45:59 | 显示全部楼层

因为我觉得原子例程中的开关中断的方法,这种方式虽然简单高效,但无法满足嵌套的情况。如果有两层临界区保护,在退出内层临界区时就会开中断,使外层的临界区也失去保护。虽然ucos的内核写的足够好,没有明显嵌套临界区的情况,但谁也无法保证一定没有,无法保证今后没有,无法保证在附加的驱动或什么位置没有。

参考网友的移植例程,修改了原子的例程中的os_cpu.h和os_cpu_a.asm两个文件,使用了第三种开关中断的方法,这样就允许了临界区嵌套的情况。由于本人是菜鸟,希望坛友们可以关于这方面进行讨论和指教:

(1)os_cpu.h:
/************************ (C) COPYLEFT 2010 Leafgrass ************k*************

* File Name : os_cpu_c.c 
* Author : Librae
* Date : 06/10/2010
* Description : μCOS-II在STM32上的移植代码C语言部分,
*   包括任务堆栈初始化代码和钩子函数等

******************************************************************************/

#ifndef __OS_CPU_H__
#define __OS_CPU_H__

#ifdef  OS_CPU_GLOBALS
#define OS_CPU_EXT
#else
#define OS_CPU_EXT  extern
#endif

/******************************************************************************
*                    定义与编译器无关的数据类型
******************************************************************************/

typedef unsigned char  BOOLEAN;
typedef unsigned char  INT8U; /* Unsigned  8 bit quantity       */
typedef signed   char  INT8S; /* Signed    8 bit quantity       */
typedef unsigned short INT16U; /* Unsigned 16 bit quantity       */
typedef signed   short INT16S; /* Signed   16 bit quantity       */
typedef unsigned int   INT32U; /* Unsigned 32 bit quantity       */
typedef signed   int   INT32S; /* Signed   32 bit quantity       */
typedef float          FP32; /* Single precision floating point*/
typedef double         FP64; /* Double precision floating point*/

typedef unsigned int   OS_STK; /* Each stack entry is 32-bit wide*/
typedef unsigned int   OS_CPU_SR; /* Define size of CPU status register*/

/*
*******************************************************************************
*                             Cortex M3
*                     Critical Section Management
*******************************************************************************
*/



/*
*******************************************************************************
*                          ARM Miscellaneous
*******************************************************************************
*/

#define  OS_STK_GROWTH        1      /* Stack grows from HIGH to LOW memory on ARM    */

#define  OS_TASK_SW()         OSCtxSw()

/*
*******************************************************************************
*                               ROTOTYPES
*                           (see OS_CPU_A.ASM)
*******************************************************************************
*/

#define  OS_CRITICAL_METHOD   3

#if OS_CRITICAL_METHOD == 3
#define  OS_ENTER_CRITICAL()  {cpu_sr = OS_CPU_SR_Save();}
#define  OS_EXIT_CRITICAL()   {OS_CPU_SR_Restore(cpu_sr);}
#endif

#if OS_CRITICAL_METHOD == 3                       /* See OS_CPU_A.ASM                                  */
OS_CPU_SR  OS_CPU_SR_Save(void);
void       OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
#endif

void       OSCtxSw(void);
void       OSIntCtxSw(void);
void       OSStartHighRdy(void);
void       OSPendSV(void);

OS_CPU_EXT INT32U OSInterrputSum;

#endif

(2) os_cpu_a.asm:
;/*********************** (C) COPYRIGHT 2010 Libraworks ********kee*****************
;* File Name : os_cpu_a.asm 
;* Author : Librae 
;* Version : V1.0
;* Date : 06/10/2010
;* Description : μCOS-II asm port
;*******************************************************************************/

IMPORT  OSRunning               ; External references
        IMPORT  OSPrioCur
        IMPORT  OSPrioHighRdy
        IMPORT  OSTCBCur
        IMPORT  OSTCBHighRdy
        IMPORT  OSIntNesting
        IMPORT  OSIntExit
        IMPORT  OSTaskSwHook
           
        EXPORT  OSStartHighRdy               
        EXPORT  OSCtxSw
        EXPORT  OSIntCtxSw
EXPORT  OS_CPU_SR_Save                                      ; Functions declared in this file
     EXPORT  OS_CPU_SR_Restore       
        EXPORT  endSV_Handler
        
     
NVIC_INT_CTRL    EQU     0xE000ED04  ; 中断控制寄存器
NVIC_SYSPRI14     EQU     0xE000ED22  ; 系统异常PendSV优先级寄存器地址
NVIC_PENDSV_PRI  EQU     0xFF        ; (PendSV中断的优先级为最低,255).                               
NVIC_PENDSVSET   EQU     0x10000000  ; 触发软件中断的值(位28为1).


PRESERVE8 

AREA    |.text|, CODE, READONLY
        THUMB 
    
           

;********************************************************************************************************
;                                   CRITICAL SECTION METHOD 3 FUNCTIONS
;
; Description: Disable/Enable interrupts by preserving the state of interrupts.  Generally speaking you
;              would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then
;              disable interrupts.  'cpu_sr' is allocated in all of uC/OS-II's functions that need to
;              disable interrupts.  You would restore the interrupt disable state by copying back 'cpu_sr'
;              into the CPU's status register.
;
rototypes:     OS_CPU_SR  OS_CPU_SR_Save(void);
;                  void       OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
;
;
; Note(s) : 1) These functions are used in general like this:
;
;                 void Task (void *p_arg)
;                 {
;                 #if OS_CRITICAL_METHOD == 3          /* Allocate storage for CPU status register */
;                     OS_CPU_SR  cpu_sr;
;                 #endif
;
;                       :
;                       :
;                     OS_ENTER_CRITICAL();             /* cpu_sr = OS_CPU_SaveSR();                */
;                       :
;                       :
;                     OS_EXIT_CRITICAL();              /* OS_CPU_RestoreSR(cpu_sr);                */
;                       :
;                       :
;                 }
;********************************************************************************************************

OS_CPU_SR_Save
    MRS     R0, RIMASK  ;读取PRIMASK到R0中,R0为返回值                                       ; Set prio int mask to mask all (except faults)
    CPSID   I  RIMASK=1,关中断(NMI和硬fault可以响应)
    BX      LR  ;返回

OS_CPU_SR_Restore
    MSR     RIMASK, R0  ;读取R0到PRIMASK中,R0为参数
    BX      LR  ;返回


;/**************************************************************************************
;* 函数名称: OSStartHighRdy
;*
;* 功能描述: 使用调度器运行第一个任务
;* 
;* 参    数: None
;*
;* 返 回 值: None
;**************************************************************************************/  

OSStartHighRdy
        LDR     R4, =NVIC_SYSPRI14      ; set the endSV exception priority
        LDR     R5, =NVIC_PENDSV_PRI
        STR     R5, [R4]

        MOV     R4, #0                 ; set the SP to 0 for initial context switch call
        MSR     SP, R4

        LDR     R4, =OSRunning         ; OSRunning = TRUE
        MOV     R5, #1    ; R1=1
        STRB    R5, [R4]    ; OSRunning = 1

        ;触发PendSV中断                ;切换到最高优先级的任务
        LDR     R4, =NVIC_INT_CTRL     ;rigger the endSV exception (causes context switch)
        LDR     R5, =NVIC_PENDSVSET
        STR     R5, [R4]

        CPSIE   I                      ;开中断
OSStartHang    ;死循环,应该不会到这里
        B       OSStartHang            ;should never get here

;/**************************************************************************************
;* 函数名称: OSCtxSw
;*
;* 功能描述: 任务级上下文切换         
;*
;* 参    数: None
;*
;* 返 回 值: None
;***************************************************************************************/
  
OSCtxSw
PUSH    {R4, R5}
        LDR     R4, =NVIC_INT_CTRL   ;触发PendSV异常 (causes context switch)
        LDR     R5, =NVIC_PENDSVSET
        STR     R5, [R4]
POP     {R4, R5}
        BX      LR

;/**************************************************************************************
;* 函数名称: OSIntCtxSw
;*
;* 功能描述: 中断级任务切换
;*
;* 参    数: None
;*
;* 返 回 值: None
;***************************************************************************************/

OSIntCtxSw
PUSH    {R4, R5}
        LDR     R4, =NVIC_INT_CTRL      ;触发PendSV异常 (causes context switch)
        LDR     R5, =NVIC_PENDSVSET
        STR     R5, [R4]
POP     {R4, R5}
        BX      LR


;/**************************************************************************************
;* 函数名称: 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                                       ; 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
PendSV_Handler_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
    END 
 

os_cpu_a.asm

7.51 KB, 下载次数: 310

os_cpu.h

2.89 KB, 下载次数: 314

永远保持一颗学习的心态。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-7-12 12:41:29 | 显示全部楼层
这个确实我的方法有些极端情况可能出问题.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

86

主题

417

帖子

0

精华

高级会员

Rank: 4

积分
781
金钱
781
注册时间
2013-2-20
在线时间
0 小时
发表于 2013-3-16 17:08:17 | 显示全部楼层
回复【15楼】科科1987:
---------------------------------
我下载了你的附件   替换了mini板里ucosii的文件  但发现不行啊编译报错

compiling test.c...
test.c(81): error:  #20: identifier "cpu_sr" is undefined
test.c(92): error:  #20: identifier "cpu_sr" is undefined
test.c(149): error:  #20: identifier "cpu_sr" is undefined
test.c(153): error:  #20: identifier "cpu_sr" is undefined
test.c - 4 Error(s), 0 Warning(s).
乐于思考,敢于请教;问人不累,诲人不倦!本人CSDN博客:http://blog.csdn.net/dcx1205 学习嵌入式的同学不要错过啊!
回复 支持 反对

使用道具 举报

38

主题

527

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1424
金钱
1424
注册时间
2011-11-27
在线时间
122 小时
 楼主| 发表于 2013-3-21 12:14:39 | 显示全部楼层
回复【17楼】可乐虎:
---------------------------------
任务代码中使用了开关中断:OS_ENTER_CRITICAL();和OS_EXIT_CRITICAL(); 在它里面使用了 cpu_sr = OS_CPU_SaveSR(),所以在任务中添加就行:

#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
    OS_CPU_SR     cpu_sr;
#endif
永远保持一颗学习的心态。
回复 支持 反对

使用道具 举报

86

主题

417

帖子

0

精华

高级会员

Rank: 4

积分
781
金钱
781
注册时间
2013-2-20
在线时间
0 小时
发表于 2013-4-16 09:59:08 | 显示全部楼层
谢咯 再看看
乐于思考,敢于请教;问人不累,诲人不倦!本人CSDN博客:http://blog.csdn.net/dcx1205 学习嵌入式的同学不要错过啊!
回复 支持 反对

使用道具 举报

50

主题

201

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
423
金钱
423
注册时间
2013-4-9
在线时间
1 小时
发表于 2013-4-17 12:05:35 | 显示全部楼层
看两位大神华山论剑 - -!看的云里雾里
回复 支持 反对

使用道具 举报

3

主题

32

帖子

0

精华

初级会员

Rank: 2

积分
83
金钱
83
注册时间
2011-5-10
在线时间
5 小时
发表于 2013-4-18 11:57:06 | 显示全部楼层
先MARK下
回复 支持 反对

使用道具 举报

0

主题

3

帖子

0

精华

新手入门

积分
23
金钱
23
注册时间
2014-3-27
在线时间
0 小时
发表于 2014-4-17 21:44:08 | 显示全部楼层
看两位大神的讨论,感觉受益不浅。。
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手上路

积分
23
金钱
23
注册时间
2014-1-31
在线时间
0 小时
发表于 2014-6-14 09:29:35 | 显示全部楼层
mark一下 
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-7-7 06:38

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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