原文地址:http://sacredlps.blog.163.com/blog/static/1641440292012299444505/
STM8S移植μC/OS-II
By GDOU Sacredlps
All Rights Reserved
μC/OS-II相信大家都很熟悉了,是由美国嵌入式系统专家JeanJ.Labrosse 一种可移植的,可植入ROM的,可裁剪的,抢占式的,实时多任务操作系统内核。它被广泛应用于微处理器、微控制器和数字信号处理器。包含了任务调度,任务管理,时间管理,内存管理和任务间的通信和同步等基本功能。μC/OS-II可移植到几乎所有微处理器上面允许,既有执行效率高、实时性强、任务切换快的特点,版本从2.00到2.85,下面就以移植2.85为例,在STVD编译环境下移植到最新的ST意法半导体公司生产的STM8SMCU。
STM8S基本特点:8位CPU内核,3级流水线的哈佛结构,内核有6个寄存器,并拥有16位指令,指令执行速率可达0.8Mips/Mhz以上,24位的PC寻址空间可达16M,16位的SP寻址空间可达64KB,拥有不可屏蔽的软中断,由于这些特点使得移值操作系统成为了可能。
缺点是CPU内核没有通用寄存器,使得很多运算都要暂存在RAM里边,RAM的划分变得复杂,在STVD编译环境下,采用的方法是利用堆栈来处理临时性变量,全局变量放在RAM的最低处,这种方法很巧妙,但会使得RAM的使用无规则,在IAR环境下,采用的是在RAM划分一个区域来充当通用寄存器使用。为了在STVD下移植μC/OS-II,不仅要清楚CPU的内部原理,还要认识STVD的编译原理。移植步骤如下:
第一:OS数据类型定义
typedef unsignedchar OS_STK;
typedef unsignedchar BOOLEAN;
typedef unsignedchar INT8U;
typedef signed char INT8S;
typedef unsignedint INT16U;
typedef signed int INT16S;
typedef unsignedlong INT32U;
typedef signed long INT32S;
typedef float FP32;
typedef double FP64;
#defineBYTE INT8S
#defineUBYTE INT8U
#defineWORD INT16S
#defineUWORD INT16U
#defineLONG INT32S
#defineULONG INT32U
第二步:定义与处理器有关的声明
#define OS_CRITICAL_METHOD 2
#if OS_CRITICAL_METHOD==1
#define OS_ENTER_CRITICAL() _asm("SIM");
#define OS_EXIT_CRITICAL() _asm("RIM");
#endif
#if OS_CRITICAL_METHOD==2
#define OS_ENTER_CRITICAL() save_cpusr();
#define OS_EXIT_CRITICAL() restore_cpusr();
#endif
#define OS_STK_GROWTH 1
#define OS_TASK_SW() _asm("TRAP");
第三步:编写底层函数之一【系统开始运行最高优先级的任务】
voidOSStartHighRdy(void)
{
OSTaskSwHook();
#asm
LDWX,[_OSTCBCur.W] //获取最高优先级的SP指针值
LDWSP,X
#endasm
OSRunning=TRUE;
EN_OS_CLK; //开定时器
#asm
IRET
#endasm
}
第四步:编写底层函数之二【上下文任务切换函数】.TRAP中断服务函数
@far@interruptvoidOSCtxSw(void)
{
#asm
LDWX,SP
ADDWX,#6
LDWSP,X
POPA
ANDA,#0XF7
PUSHA //堆栈指针调整
LDW[_OSTCBCur.W],X //保存堆栈指针
#endasm
OSTaskSwHook();
OSTCBCur=OSTCBHighRdy;
OSPrioCur=OSPrioHighRdy;
#asm
POPWX //堆栈调整
LDW0X07,X
POP0X0009
POPWX
LDW0X04,X
POP0X0006
LDWX,[_OSTCBCur.W] //获取堆栈指针
LDWSP,X
IRET
#endasm
}
第五步:编程底层函数之三【中断级任务切换函数】
voidOSIntCtxSw(void)
{
#asm
ADDWSP,#10
POPA
ANDA,#0XF7
PUSHA
LDWX,SP
LDW[_OSTCBCur.W],X //堆栈指针调整和保存
#endasm
OSTaskSwHook();
OSTCBCur=OSTCBHighRdy;
OSPrioCur=OSPrioHighRdy;
#asm
POPWX
LDW0X07,X
POP0X0009
POPWX
LDW0X04,X
POP0X0006
LDWX,[_OSTCBCur.W] //堆栈调整和或者堆栈指针
LDWSP,X
IRET
#endasm
}
第六步:编写底层函数之四【系统时钟函数】.使用定时器中断服务
@far@interruptvoidOSTickISR(void)
{
TIM2->SR1=0X00; //清除定时器标志位
OSIntEnter();
OSTimeTick();
OSIntExit();
}
第七步:编写底层函数之五【堆栈初始化函数】
OS_STK*OSTaskStkInit(void(*task)(void*p_arg),void*p_arg,OS_STK*ptos,
INT16U opt)
{
OS_STK*stk;
(void)opt;
stk =ptos;
*(stk) =(INT8U)((INT16U)task); //PCL
*(--stk)=(INT8U)((INT16U)task>>8); //PCH
*(--stk)=(INT8U)((INT32U)task>>16); //PCE
*(--stk)=0X07; //YL
*(--stk)=0X04; //YH
*(--stk)=0X03; //XL
*(--stk)=0X02; //XH
*(--stk)=0X01; //A
*(--stk)=0X20; //CC
(--stk);
return(stk);
}
第八步:编写临界保护函数【其中MY_CPUSR要在μC/OS-II.H中声明
的全局变量】
voidsave_cpusr(void)
{
(INT8U)MY_CPUSR;
_asm("PUSHCC\nSIM\nPOPA\n");
_asm("LD_MY_CPUSR,A");
}
voidrestore_cpusr(void)
{
_asm("LDA,_MY_CPUSR\nPUSHA\nPOPCC");
}
结束语:
由于STM8S的内核结构和STVD环境下的变量处理方式,在移植μC/OS-II难免会有点复制,需要调整和计算好堆栈指针,临界保护函数也正因为STVD处理临时变量使用的是堆栈所以没有使用μC/OS-II中定义的临时cpu_sr,而使用了全局变量。经过试验在用高频外部中断触发下可以很稳定的运行,也证明了系统的稳定性和安全性。
限于篇幅,移植源文件不再详解,读者可以直接移植这些与处理器有关的函数,并在μC/OS-II.h内声明外部函数便可。如果想要移植好的工程,可以留下邮箱。