?? arm_00_os_taskswitch.c
字號:
/**********************************************************************************************
本程序只供學習使用,不得用于其它任何用途,否則后果自負。
ARM_00_OS_TaskSwitch.c file
注意:該文件必須設置為ARM模式。
作者:Computer-lov
建立日期:2006-5-1
修改日期:2006-5-16
版本:V1.0
版權所有,盜版必究。
任何技術問題可到我的博客上留言: http://computer00.21ic.org
Copyright(C) Computer-lov 2006-2016
All rights reserved
**********************************************************************************************/
#include <ADuC7027.H>
#include "My_type.h"
#include "LED.H"
#include "UART.H"
#include "KEYS.H"
#include "interrupt.h"
#include "ARM_00_OS_Core.H"
#include "ARM_00_OS_TaskSwitch.H"
/**********************************************************************************************
功能:禁止中斷。
入口參數1:DisEnabledBit。即CPSR中對應的I位和Q位。
頭文件中有定義,#define OS_I_Bit 0x80 #define OS_F_Bit 0x40
關IRQ中斷時,使用OS_I_Bit,關FIQ中斷時,使用OS_F_Bit。
兩個都關時,將兩者按位或,即 OS_I_Bit | OS_F_Bit
返回:無。
使用資源:使用軟中斷號0。
備注:使用了內嵌的ARM指令,該函數所在的文件必須設置為ARM模式。
**********************************************************************************************/
void DisEnableInterrupt(uint32 DisEnableBit) __swi(0)
{
__asm LDMIA SP!,{R8} //堆棧中保存的是SPSR寄存器(參看SWI_VEC.s文件),將其彈出至R8中。
__asm ORR R8,R8,R0,LSL #0 //R8中的值,跟傳遞進來的DisEnableBit(被放在R0中)相或。{}
__asm STMDB SP!,{R8} //將設置好的SPSR寄存器,壓回堆棧
DisEnableBit=0; //防止編譯器警告。請不要刪除該語句。如果刪除該語句,編譯器可能會刪除某些語句
//從而導致程序運行錯誤
}
//////////////////////////////////End of function//////////////////////////////////////////////
/**********************************************************************************************
功能:使能中斷。
入口參數1:EnabledBit。即CPSR中對應的I位和Q位。
頭文件中有定義,#define OS_I_Bit 0x80 #define OS_F_Bit 0x40
關IRQ中斷時,使用OS_I_Bit,關FIQ中斷時,使用OS_F_Bit。
兩個都關時,將兩者按位或,即 OS_I_Bit | OS_F_Bit
返回:無。
使用資源:使用軟中斷號1。
備注:使用了內嵌的ARM指令,該函數所在的文件必須設置為ARM模式。
**********************************************************************************************/
void EnableInterrupt(uint32 EnableBit) __swi(1)
{
__asm LDMIA SP!,{R8} //堆棧中保存的是SPSR寄存器(參看SWI_VEC.s文件),將其彈出至R8中
__asm MVN R0,R0 //EnableBit(被放在R0中)取反
__asm AND R8,R8,R0 //R8中的值,跟R0相與{}
__asm STMDB SP!,{R8} //將設置好的SPSR寄存器,壓回堆棧
EnableBit=0; //防止編譯器警告。請不要刪除該語句
}
//////////////////////////////////End of function//////////////////////////////////////////////
/**********************************************************************************************
功能:啟動操作系統。
入口參數1:AddrOfSystemIdle。必須設置為系統空閑任務的入口地址。系統啟動后,從系統空閑任務開始運行。
入口參數2:Mode。系統空閑任務代碼的模式。可以選擇ARM_MODE或者THUMB_MODE。
返回:無。
使用資源:使用軟中斷號2。
備注:使用了內嵌的ARM指令,該函數所在的文件必須設置為ARM模式。系統啟動后,進入系統空閑任務。
**********************************************************************************************/
void OSStart(uint32 AddrOfSystemIdle,uint32 Mode) __swi(2)
{
__asm ADD SP,SP,#20 //{}調整SP,使其指向返回地址的前一個字
__asm STMDB SP,{R0} //將入口地址壓入堆棧中的返回地址處
__asm SUB SP,SP,#20 //{}將堆棧指針調回
__asm LDMIA SP!,{R8} //將SPSR彈出,放入R8中
Mode|=~(0x20); //將傳遞進來的Mode其它位設置為1,只保留T位
__asm ORR R8,R8,#0x20 //將SPSR中的T位設置為1{}
__asm AND R8,R8,R1 //將SPSR的值與Mode相與。從而T位跟Mode的T位相同{}
__asm STMDB SP!,{R8} //將SPSR壓回棧中
OSCurrentPcb=&OSSystemIdlePcb; //當前任務為系統空閑任務
AddrOfSystemIdle=0; //防止編譯器警告。請不要刪除該語句
}
//////////////////////////////////End of function//////////////////////////////////////////////
/**********************************************************************************************
功能:保存堆棧指針。堆棧指針被保存在當前任務的TaskSP成員中。
入口參數1:sp。當前任務堆棧指針的地址值。
返回:無。
備注:sp由R0寄存器傳入。
**********************************************************************************************/
void OSSaveSP(uint32 sp)
{
OSCurrentPcb->TaskSP=sp; //保存當前堆棧指針
}
//////////////////////////////////End of function//////////////////////////////////////////////
/**********************************************************************************************
功能:恢復堆棧指針。將當前任務的堆棧指針恢復。
入口參數1:無。
返回:堆棧指針的地址值。被保存在R0中。
備注:無。
**********************************************************************************************/
uint32 OSResumeSP(void)
{
return OSCurrentPcb->TaskSP; //將堆棧指針的地址值返回
}
//////////////////////////////////End of function//////////////////////////////////////////////
/**********************************************************************************************
功能:設置堆棧。任務創建時,要設置好其堆棧,使其看起來,就像任務剛被切換的任務一樣。
入口參數1:StackAddr。32位的堆棧入口地址值,堆棧是往下生長的,所以入口地址應該是堆棧區的最高地址。
入口參數2:TaskEntryAddr。32位的任務入口地址值。
入口參數3:Mode。被創建任務代碼的模式。可選擇為OS_ARM_MODE或者OS_THUMB_MODE。
返回:32位的堆棧地址。被壓入堆棧后,堆棧指針會更新。
使用資源:使用軟中斷號4。
備注:無。
**********************************************************************************************/
uint32 OSSetStack(uint32 StackAddr,uint32 TaskEntryAddr,uint32 Mode) __swi(4)
{
#define PushedBytes (16*4) //壓入了16個字,共64字節
//R0中保存的是堆棧入口地址
__asm MOV R12,R0 //{}StackAddr傳進時,被放在了R0中。將R0轉存至R12中。
__asm STMDB R12!,{R3} //入口地址被TaskEntryAddr被編譯器轉移至R3中。將R3壓棧
__asm MOV R8,#0 //{}R8清零
__asm STMDB R12!,{R8} //該位置保存的是R3。將其清0。
__asm STMDB R12!,{R8} //該位置保存的是R2。將其清0。
__asm STMDB R12!,{R8} //該位置保存的是R1。將其清0。
__asm STMDB R12!,{R8} //該位置保存的是R0。將其清0。
__asm LDMIA SP,{R8} //將剛壓入的SPSR(見SWI_VEC.S文件)出棧至R8中。
Mode|=~(0x20); //將Mode的其它位置1,只保留T位。
__asm ORR R8,R8,#0x20 //將SPSR中的T位置1。
__asm AND R8,R8,R2 //將SPSR的值與Mode相與。從而T位跟Mode的T位相同{}
__asm STMDB R12!,{R8} //將SPSR壓棧。任務被調度時,SPSR將被返回至CPSR。
__asm MOV R8,#0 //R8清0{}
__asm STMDB R12!,{R8} //該位置保存的是用戶模式下的R14。將其清0。
__asm STMDB R12!,{R8} //該位置保存的是R12。將其清0。
__asm STMDB R12!,{R8} //該位置保存的是R11。將其清0。
__asm STMDB R12!,{R8} //該位置保存的是R10。將其清0。
__asm STMDB R12!,{R8} //該位置保存的是9。將其清0。
__asm STMDB R12!,{R8} //該位置保存的是R8。將其清0。
__asm STMDB R12!,{R8} //該位置保存的是R7。將其清0。
__asm STMDB R12!,{R8} //該位置保存的是R6。將其清0。
__asm STMDB R12!,{R8} //該位置保存的是R5。將其清0。
__asm STMDB R12!,{R8} //該位置保存的是R4。將其清0。
TaskEntryAddr=0; //防止編譯器警告。請不要刪除該語句。
return StackAddr-PushedBytes; //返回堆棧指針
}
//////////////////////////////////End of function//////////////////////////////////////////////
/**********************************************************************************************
功能:切換任務。任務被切換到優先級最高的就緒態任務。
入口參數:無。
返回:無。
使用資源:使用軟中斷號3。
備注:該函數為任務切換函數,修改這里的代碼是要注意,可能會導致跑飛。
**********************************************************************************************/
void OSTaskSwitch(void) __swi(3)
{
//將用戶模式下的堆棧地址裝入到R8中
__asm MOV R8,SP //{}特權模式下的堆棧指針暫時放到R8{}
__asm STMDB R8!,{R13}^ //將用戶模式下的堆棧指針R13放入到特權模式下的堆棧中{}
__asm NOP //插入一個NOP指令,在訪問用戶模式下的寄存器后,后面不能緊跟訪問備份寄存器的指令,所以插入一個NOP指令{}
__asm MOV SP,R8 //剛剛是借用R8來訪問堆棧的,R8被更新后,應該將其寫回SP中{}
__asm LDMIA SP!,{R8} //將剛壓入的用戶堆棧地址彈出至R8
__asm ADD SP,SP,#20 //{}調整SP的值,使SP指向堆棧內的返回地址。堆棧的結構:返回地址,R12,R8,R3,SPSR,R14。當前的SP指向R14
//調整后,SP指向返回地址
__asm LDMDA SP!,{R12} //{}將返回地址彈出至R12
__asm STMDB R8!,{R12} //將返回地址壓入用戶棧
__asm STMDB R8!,{R0-R3} //將R0-R3壓入用戶棧
__asm LDMDA SP!,{R3} //彈出R12放入到R3中
__asm LDMDA SP!,{R2} //彈出R8放入到R2中
__asm SUB SP,SP,#4 //跳過被壓入的R3,這里未用到{}
__asm LDMDA SP!,{R1} //彈出SPSR放入到R1中
__asm MOV R0,R8 //R8是堆棧地址,轉存到R0{}
__asm STMDB R0!,{R1} //{}R1在SPSR中,將其壓入用戶堆棧中
__asm STMDB R0!,{R14}^ //將用戶模式下的R14壓入用戶堆棧中
__asm MOV R8,R2 //R2中保存的是R8,將其放入R8中{}
__asm MOV R12,R3 //R3中保存的是R12,將其放入R12{}
__asm STMDB R0!,{R4-R12} //將R4-R12壓入用戶堆棧中
__asm BL OSSaveSP //保存堆棧指針{}
if(TimeOfTaskStart<T0VAL) //T0VAL是計數器0的值。T0VAL的值是減小的。如果T0VAL大于上一次的值,則說明已經溢出
{
OSCurrentPcb->RunTimeInThisRefreshPeriod+=TimeOfTaskStart+MaxOfTimer0+1-T0VAL; //計算時間差
}
else //否則
{
OSCurrentPcb->RunTimeInThisRefreshPeriod+=TimeOfTaskStart-T0VAL; //計算時間差
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -