这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 国产MCU » 最新版本uC-OS2-2.93.01已移植到STC最新的1T8051,STC8H

共3条 1/1 1 跳转至

最新版本uC-OS2-2.93.01已移植到STC最新的1T8051,STC8H8K64U上

菜鸟
2023-08-22 10:12:25     打赏

最新版本uC-OS2-2.93.01已移植到STC最新的 1T 8051, STC8H8K64U
===适用于STC8系列所有型号
===解决了网络上不同移植版本潜在的bug

===鼓励大家在STC官网 www.STCAIMCU.com 帮忙查错, 200元/每条错误感谢, 大家一起前行
许可改成 APACHE 2.0 也就是可以商业使用不用授权。具体可以查看APACHE 2.0内容。

声明:本移植版本参考了陈是知移植版本和STC网站上的原网友版, 另外测试例子使用杨为民老师移植的版本
一,提升速度
  1. 重要的变量使用data修饰
  2. 结构体指针变量使用xdata修饰
  3. 使用DPTR自增方式
      注意,使用DPTR自增方式,这部分代码不能硬件仿真,单独调试,可以全速运行。


os_cpu_a.A51文件,有测试信号。
P20    测试OSIntExit       运行时间  (有任务切换4us)(无任务2.83us)
P21    测试OSIntCtxSw  系统级切换任务时间    (8.6us)
P23    测试OSCtxSw       任务级切换任务时间    (8.7us)
P26    测试滴答定时器中断全过程时间 (有任务24.3us)   (无任务13us)
P27    测试OSTimeTick  运行时间      (有任11.2us)(无任务9.3us)

以上测试,选择 STC8H8K64U 工作时钟是 40MHz

os_cpu_a.A51文件,有测试信号。

P20    测试OSIntExit     运行时间  (有任务切换4us)(无任务2.83us)
P21    测试OSIntCtxSw  系统级切换任务时间  (8.6us)
P23    测试OSCtxSw      任务级切换任务时间    (8.7us)

P26    测试滴答定时器中断全过程时间     (有任务24.3us)   (无任务13us)
P27    测试OSTimeTick  运行时间     (有任11.2us)(无任务9.3us)
以上测试,选择工作时钟是40MHz


二,允许任务堆栈空间任意大小
修改了OSTaskCreate,增加stk_size入口


  • INT8U  OSTaskCreate (void   (*task)(void *p_arg),

  •                      void    *p_arg,

  •                      OS_STK  *ptos,

  •                      INT16U   stk_size,

  •                      INT8U    prio) large reentrant

  1. OS_STK  *OSTaskStkInit (void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT16U opt)

  2. 对 OSTaskStkInit函数利用 opt 传入任务堆栈大小 实现不等长任务堆栈

    三 ,临界区保护方法,支持方法2和方法3

  • #if OS_CRITICAL_METHOD==2

  • //执行OS_ENTER_CRITICAL()时,先将中断状态保存到堆栈,然后关中断;

  • //执行OS_EXIT_CRITICAL()时,再从堆栈中恢复原来的中断开/关状态。这种方法不会改变中断状态,避免前面的问题。

  • //但是,当用户使用的处理器有堆栈指针相对寻址模式时,可能出现严重错误。

  • //问题分析:OS_ENTER_CRITICAL()时导致中断切换任务的时候硬件堆栈多入了一个_push_(IE),

  • //解决方法:OSIntCtxSw()函数调整SP的时候应该多减1,原来SP=SP-4改为SP=SP-5

  • #include <intrins.h>

  • #define OS_ENTER_CRITICAL()do{_push_(IE);EA = 0;}while(0)   /* 利用堆栈保存中断状态,再关中断  */

  • #define OS_EXIT_CRITICAL()do{ _pop_ (IE);}while(0)          /* 将IE从堆栈弹出,恢复IE值    */

  • #endif


  • #if OS_CRITICAL_METHOD==3

  • //获取当前中断状态的值,并将其保存在C函数局部变量之中

  • //问题分析:可重入函数的局部变量cpu_sr会入仿真栈。导致中断切换任务的时候,仿真堆栈出问题。

  • //解决方法:OSIntCtxSw()函数执行时需要对仿真堆栈指针++操作。

  • #define OS_ENTER_CRITICAL() do{ cpu_sr=IE;EA = 0;}while(0)

  • #define OS_EXIT_CRITICAL()  do{ IE = cpu_sr; }while(0)

  • #endif

  1. 四,支持软件定时器
    之前移植的版本没有适配软件定时器功能。OS_VERSION >= 281 支持软件定时器。
    移植过程中遇到一个困难,就是回调函数,函数指针问题。重点是指针ptmr需要加上xdata修饰。

typedef  void (code *OS_TMR_CALLBACK)(void xdata*ptmr, void *parg) large reentrant;

五,解决RET和RETI混用问题
OSIntCtxSw 是在中断中调用的,需要调用RETI返回
OSStartHighRdy 运行第一个任务,应该用RET返回
OSCtxSw  在任务中调用的,应该用RET返回

这三个函数最后部分的代码都一样。之前移植的版本统一用RETI返回,导致混用。
本移植提供2个解决方法,原则是OSIntCtxSw 函数提前退出中断,统一用RET返回

  • ;方法1:直接把  OSIntCtxSw_in函数地址入栈,由RETI中断返回,跳转到OSIntCtxSw_in函数,共6T

  •         MOV DPTR,#OSIntCtxSw_in

  •         PUSH DPL

  •         PUSH DPH

  •         RETI


  •          ;方法2:;巧妙的利用函数返回RETI执行了中断完毕,跳转到下一条语句。这样任务可以无忧使用RET作为返回,共9T。

  •         LCALL    RE_RETI

  •         LJMP OSIntCtxSw_in

  • RE_RETI:        RETI

显然方法1更优秀
当然还有方法3,3个函数独立,不要共同出口。这里不推荐,浪费代码空间。


六,关于中断嵌套的做法
提供了2个中断例子:
定时器1 中断演示允许中断嵌套
定时器3 中断演示禁止中断嵌套

  • ; ==== 定时器1 中断服务程序 =============

  • ;演示允许中断嵌套

  • EXTRN CODE  (_?Timer1_Handler)

  • Timer1_ISR:

  •         USING 0        ;工作寄存器0

  •         CLR EA  ;调用OSIntEnter之前先关中断

  • ;SETB P20

  •         PUSHALL            ;现场保护

  •         LCALL _?OSIntEnter        ;通知内核进入中断     

  •         SETB EA  ;允许中断嵌套

  •         

  •         LCALL _?Timer1_Handler

  •         

  •         LCALL _?OSIntExit   ;通知内核退出中断

  •         POPALL      ;恢复现场   

  • ;CLR P20

  •         RETI

  •         

  •         

  • ; ==== 定时器3 中断服务程序 =============

  • ;演示禁止中断嵌套

  • EXTRN CODE  (_?Timer3_Handler)

  • Timer3_ISR:

  •         USING 0        ;工作寄存器0

  • ;SETB P20;

  •         CLR EA      ;禁止中断嵌套

  •         PUSHALL            ;现场保护


  •         LCALL _?Timer3_Handler


  •         POPALL      ;恢复现场   

  • ;CLR    P20

  •         SETB  EA   ;中断函数执行完毕,重新允许中断

  •         RETI


对于OSIntEnter 还有更优秀的做法,在中断里面直接OSIntNesting++,我之前另一帖子有讲,需要改动源码。
推荐使用OSIntEnter 函数。


七,堆栈初始化函数,对void *p_arg正确做法

    //R3、R2、R1用于传递任务参数p_arg,其中R3代表存储器类型,R2为高字节偏移,R1为低字节位移。
    *stk++ = (INT16U)p_arg & 0xFF;          // R1
    *stk++ = (INT16U)p_arg >> 8;            // R2
    *stk++ = (INT32U)p_arg >> 16;           // R3   存储器类型有code(0xFF),xdata(0x01),data(0x00),idata(0x00),pdata(0xFE)

八,统一用寄存器组0,加快出入栈速度
汇编使用 USING 0

  • ;定义压栈出栈宏

  • PUSHALL    MACRO

  •         PUSH PSW

  •         PUSH ACC

  •         PUSH B

  •         PUSH DPL

  •         PUSH DPH

  •         PUSH AR0

  •         PUSH AR1

  •         PUSH AR2

  •         PUSH AR3

  •         PUSH AR4

  •         PUSH AR5

  •         PUSH AR6

  •         PUSH AR7

  •         ENDM

  •    

  • POPALL    MACRO

  •         POP  AR7

  •         POP  AR6

  •         POP  AR5

  •         POP  AR4

  •         POP  AR3

  •         POP  AR2

  •         POP  AR1

  •         POP  AR0

  •         POP  DPH

  •         POP  DPL

  •         POP  B

  •         POP  ACC

  •         POP  PSW

  •         ENDM

九,修复一个隐藏很深的bug,任务堆栈总空间需要分配很大系统才能运行。
折腾很长时间,最后跟踪代码发现OSTCBFreeList指针指向xdata 地址0,空指针作怪。
任务堆栈总空间比较少的时候OSTCBTbl[OS_MAX_TASKS + OS_N_SYS_TASKS];数组从地址0开始存放。

初始化的时候OSTCBFreeList           = &OSTCBTbl[0]; 导致OSTCBFreeList指针指向xdata 地址0,分配到一个空指针。
解决方法。xdata地址0声明一个null变量占用了该地址。

修改后测试,任务堆栈空间分配32字节,也能顺利运行。

源码:
最新版本uC/OS-II源码在本贴的附件中,也可以如下链接下载
https://github.com/weston-embedded/uC-OS2

uCOSII-STC8-V1.00-20230821.zip

演示程序.rar

TM$[K0]J}(6VYN[NUV7[51B.jpg












关键词: uC-OS2-2.93.01     STC8H8K64U    

专家
2023-08-22 14:34:55     打赏
2楼

我个人认为。器件是否有用,和“流行”两个字从来就没有任何关系。对于很多电子爱好者而言,入门单片机的开发,是从51系列单片机开始的。现在有了国产的32位51单片机,对有51基础的开发者而言,肯定是是一件愉快的事情。能适应uC-OS系统,了不起了。有时间我要去试试这款单片机。



专家
2023-09-05 10:20:09     打赏
3楼

这个厉害了,话说我51 学的是真烂


共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]