|
本帖最后由 钟山风雨起苍黄 于 2023-8-22 09:55 编辑
最新版本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
复制代码 OS_STK *OSTaskStkInit (void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT16U opt)
对 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
复制代码
四,支持软件定时器
之前移植的版本没有适配软件定时器功能。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
源码从这下载:
https://www.stcaimcu.com/forum.php?mod=viewthread&tid=3934&page=1&extra=#pid26085
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|