找回密码
 立即注册
楼主: 杨***

STC单片机uC/OS-II移植记(3):整理移植源

[复制链接]

该用户从未签到

11

主题

332

回帖

895

积分

荣誉版主

积分
895
发表于 2023-8-1 13:10:08 | 显示全部楼层
杨为民 发表于 2023-8-1 10:19
在范例程序中使用两个定时器除了准确测量任务切换时间,还有以下的目的:
(1)给出规范的RTOS中断ISR写 ...

杨老师回答的 很详细,受益匪浅。谢谢。
回复 支持 反对 送花

使用道具 举报

该用户从未签到

11

主题

332

回帖

895

积分

荣誉版主

积分
895
发表于 2023-8-1 13:29:38 | 显示全部楼层
本帖最后由 熊仔 于 2023-8-1 20:21 编辑
杨为民 发表于 2023-8-1 09:55
(1)我压根不赞同给单片机RTOS的任务函数设置上面输入参数,所以不高兴保存它,我自己写的RTOS的任务函 ...

关于1,解决方法,通用指针通过R3,R2,R1传参。保存下就好。当然杨老师不喜欢传参不处理也行,或许有人跟着其他资料实验测试,用到传参的例子,会有问题调试半天。
  1. {
  2.     OS_STK *stk;
  3.     p_arg = p_arg;
  4.     opt          = opt;                                                /* opt没被用到,保留此语句防止警告产生                         */
  5.     stk          = (OS_STK *)ptos;                        /* 任务堆栈最低有效地址                                                 */
  6.     *stk++ = 15;                                                /* 任务堆栈长度                                                                 */
  7.     *stk++ = (INT16U)task & 0xFF;                /* 任务代码地址低8位                                                         */
  8.     *stk++ = (INT16U)task >> 8;                /* 任务代码地址高8位                                                         */
  9.     /* 处理器是按特定的顺序将寄存器存入堆栈的,所以用户在将寄存器存入堆栈的时候也要依照这一顺序 */
  10.     *stk++ = 0x00;                                        /* PSW                                                                                         */
  11.     *stk++ = 0x0A;                                        /* ACC                                                                                         */
  12.     *stk++ = 0x0B;                                        /* B                                                                                         */
  13.     *stk++ = 0x00;                                        /* DPL                                                                                         */
  14.     *stk++ = 0x00;                                        /* DPH                                                                                         */
  15.     *stk++ = 0x00;                                        /* R0                                                                                         */
  16.     *stk++ = (INT16U)p_arg & 0xFF;  /* R1                                                                                         */
  17.     *stk++ = (INT16U)p_arg >> 8;        /* R2                                                                                         */
  18.     *stk++ = (INT32U)p_arg >> 16;        /* R3                                                                                         */
  19.     *stk++ = 0x04;                                        /* R4                                                                                         */
  20.     *stk++ = 0x05;                                        /* R5                                                                                         */
  21.     *stk++ = 0x06;                                        /* R6                                                                                         */
  22.     *stk++ = 0x07;                                        /* R7                                                                                         */
  23.     /* 不用保存SP,任务切换时根据用户堆栈长度计算得出                                                                     */
  24.     *stk++ = (INT16U)(ptos + opt) >> 8;        /* ?C_XBP 仿真堆栈指针高8位 opt传入任务堆栈大小   */
  25.     *stk++ = (INT16U)(ptos + opt) & 0xFF;        /* ?C_XBP 仿真堆栈低8位 opt传入任务堆栈大小   */
  26.     return ((void *)ptos);        /* 返回最低地址,这里不用弹出栈顶指针是为了提高计算效率     */
  27. }
复制代码


关于2,系统(中断)级别切换任务 里面调用了两次OSTaskSwHook 钩子函数,我还特意查了下移植到Ix86L处理器的版本。








OSTaskSwHook 函数总共出现3次调用情况。3个任务切换都是只调用一次,后面两个任务切换基本都是在;OSTCBCur = OSTCBHighRdy之前调用的。
所以_?OSIntCtxSw: 这个系统切换函数里面应该删除一个。






回复 支持 反对 送花

使用道具 举报

该用户从未签到

11

主题

332

回帖

895

积分

荣誉版主

积分
895
发表于 2023-8-1 15:28:45 | 显示全部楼层
本帖最后由 熊仔 于 2023-8-1 15:35 编辑
杨为民 发表于 2023-8-1 09:38
(1)一个事件发生后,又发生了另一个事件,两个事件未必关联,也未必有是因果关系。就像大哥先生了个儿 ...

找到问题了, 任务休眠进入的任务切换。
优先级较高,中断抢占调度,之后翻转IO马上就进入休眠引起一次任务调度。

点评

这个解释是不对的。我专门在本版块发了个新帖,你试着用“孤立疗法”来研究一下,那个出现那个现象的原因是什么  详情 回复 发表于 2023-8-1 17:46
回复 支持 反对 送花

使用道具 举报

该用户从未签到

83

主题

1132

回帖

1万

积分

荣誉版主

积分
12251
 楼主| 发表于 2023-8-1 17:46:54 | 显示全部楼层
熊仔 发表于 2023-8-1 15:28
找到问题了, 任务休眠进入的任务切换。
优先级较高,中断抢占调度,之后翻转IO马上就进入休眠引起一次任 ...

这个解释是不对的。我专门在本版块发了个新帖,你试着用“孤立疗法”来研究一下,那个出现那个现象的原因是什么
回复 支持 反对 送花

使用道具 举报

该用户从未签到

11

主题

332

回帖

895

积分

荣誉版主

积分
895
发表于 2023-8-1 19:51:23 来自手机 | 显示全部楼层
本帖最后由 熊仔 于 2023-8-1 20:15 编辑

我特意在os延时函数之前加了个普通延时,P23的高电平脉冲就隔开了延迟的时间。当然重点是因为有就绪任务才能进入软件级调度。
如果没有就绪任务,即便执行os延时函数,也是不会出现P23的高电平脉冲。

点评

方法正确,见我下面的回复  详情 回复 发表于 2023-8-2 00:57
回复 支持 反对 送花

使用道具 举报

该用户从未签到

83

主题

1132

回帖

1万

积分

荣誉版主

积分
12251
 楼主| 发表于 2023-8-2 00:57:58 | 显示全部楼层
熊仔 发表于 2023-8-1 19:51
我特意在os延时函数之前加了个普通延时,P23的高电平脉冲就隔开了延迟的时间。当然重点是因为有就绪任务才 ...

方法正确,见我下面的回复
回复 支持 反对 送花

使用道具 举报

该用户从未签到

83

主题

1132

回帖

1万

积分

荣誉版主

积分
12251
 楼主| 发表于 2023-8-2 01:02:23 | 显示全部楼层
本帖最后由 杨为民 于 2023-8-2 01:04 编辑

本帖子前面提到的关于瑕疵问题:
Fig01.jpg
其中的“重要瑕疵,如果当前有任务调度,会导致随后任务级OSCtxSw 任务切换函数执行”不存在。并且按照用户程序设计的次序,从时间次序上P23脉冲发生在P21脉冲前面。

1)通过孤立疗法,将3个任务依次注释掉,可以看到这个现象出现在“任务C”中。因此将程序进一步修改为研究程序,只运行任务C
Fig02.jpg
Fig03.jpg
其中将任务C的第74行注释掉,使该任务无限循环执行。然后用P25夹住“uCx51_Task_SleepMS”休眠函数。这样从时间次序上为:P25=0-->休眠-->睡醒-->P25=1

这样我们就可以看到该现象被“孤立”出来,唯一而重复第发生了,这样就便于我们研究查找问题了:
Fig04.jpg
2)将单次的事件放大:
Fig05.jpg
1)图中可以看到当程序执行到第70行的T1时刻,P25=0,然后开始执行第71行程序,访问休眠函数。
2)在休眠函数中,经过14.875微秒,程序设置好延时计数,挂起本任务后,T2时刻开始进行非中断的任务切换,将任务切换给空闲任务,图中呈现出P23的正脉冲。
3)经过100毫秒的休眠后,由RTOS的“_?OSTimeTick 系统节拍处理程序唤醒任务C,由“_?uCx51_IntSched”中断任务切换函数将任务执行权切换给任务C。但是按照时间顺序这个切换过程的P21通道正脉冲位于图的右面,在本图中是看不到的。本图上显示的P21通道正脉冲是上一个程序循环的。
4)当任务C被唤醒后,程序从第72P25=1开始执行,继续从第68行执行到第70行,实现下一个循环。图中P25的正脉冲代表了执行这一段用户程序的过程。
3)结论。对于任何一个RTOS的休眠函数,都将产生两次关联的任务切换,第一次是将本任务挂起,进入休眠状态,由非中断任务切换函数将任务控制权切换给其他任务,第2次是休眠时间到后,有中断任务切换函数将任务控制权切换回本函数,从休眠函数的下一行程序开始执行。
两者从时间上非中断切换在线,中断切换在后,但不是因果关系。休眠函数是因,两者皆是果。
4)任务切换函数是uC/OS-II原有的,本移植并未改变,因此uC/OS-II的任务切换函数没有错误。在这里仍然要谢谢熊仔坛友的这次的抛砖引玉,经这一轮的讨论使得我们大家加深了对RTOS的认识。



回复 支持 反对 送花

使用道具 举报

该用户从未签到

11

主题

332

回帖

895

积分

荣誉版主

积分
895
发表于 2023-8-2 12:45:28 | 显示全部楼层
本帖最后由 熊仔 于 2023-8-2 12:46 编辑

杨老师回答很详细。
我也把uC/OS-II优化了一遍,把遇到的瑕疵都改了。

还有2点需要讨论的:
讨论1,原版移植的作者对中断的处理,进出需要开关中断,算是正确的,不算瑕疵。因为他是照顾  LCALL _?OSIntEnter        ;通知内核进入中断函数调用,这个函数调用前需要关中断。


当然,函数介绍的说明2也提示用户可以直接OSIntNesting++ 操作。已经声明了全局变量。
所以这个时候有更优化的方案。
方案1 ,就是杨老师的方案,但是改动较大。
方案2,我现在用的方案 。OS_EXT  INT8U      DF_DATA       OSIntNesting;  // 用data声明变量 可以直接在中断入口++操作(INC  OSIntNesting )。这个和杨老师的方案一致。
考虑到原函数是有对OSRunning 判断,系统启动了才进行++或者--操作。
如果用户在没有启动系统的时候,就把EA打开。会进入中断 OSIntNesting ++。但是LCALL _?OSIntExit        ;通知内核退出中断    这个不能--,导致出问题。所以需要改造这个函数。
把OSIntNesting--;部分移动出来,在if (OSRunning == OS_TRUE)之前。
另外if (OSIntNesting > 0u)没必要,成对出现的,不会小于0的情况。
OSIntExit函数改造后这样:


下面是中断函数:



讨论2,是否规定用户只用寄存器组0.  因为用上系统后,中断函数需要系统管理,不能使用C51自带的C语言中断函数。
我认为统一用工作寄存器0。这样还可以更加优化对寄存器组的进出堆栈。
直接用绝对地址方式出入栈。不然要使用相对地址,需要通过ACC出入栈,效率慢了一倍。如果使用其他寄存器组速度反而慢了,没意思。
下面是绝对地址操作寄存器组出入栈:

                PUSH AR0
                PUSH AR1
                PUSH AR2
                PUSH AR3
                PUSH AR4
                PUSH AR5
                PUSH AR6
                PUSH AR7




                POP        AR7
                POP        AR6
                POP        AR5
                POP        AR4
                POP        AR3
                POP        AR2
                POP        AR1
                POP        AR0


回复 支持 反对 送花

使用道具 举报

该用户从未签到

83

主题

1132

回帖

1万

积分

荣誉版主

积分
12251
 楼主| 发表于 2023-8-2 13:20:33 | 显示全部楼层
熊仔 发表于 2023-8-2 12:45
杨老师回答很详细。
我也把uC/OS-II优化了一遍,把遇到的瑕疵都改了。

你能够“我也把uC/OS-II优化了一遍,把遇到的瑕疵都改了。”,说明你已经深入地研究过了。依我对你的了解,你有能力自己独立移植一个uC/OS-II的版本,但是缺一点点勇气。你是时候推出一个你自己的RTOS移植版本了。不必顾忌我已经写的那些。我只是一个老师,只是一个给你引路的,说的也未必都正确。因此你就根据你已经提出的关于不等长堆栈、关于中断任务保护以及在堆栈中保存寄存器现场等等观点,移植一个你自己的版本,勇敢地迈这一步
回复 支持 反对 送花

使用道具 举报

该用户从未签到

11

主题

332

回帖

895

积分

荣誉版主

积分
895
发表于 2023-8-2 15:45:19 | 显示全部楼层
杨为民 发表于 2023-8-2 13:20
你能够“我也把uC/OS-II优化了一遍,把遇到的瑕疵都改了。”,说明你已经深入地研究过了。依我对你的了解 ...

好的,忙完,抽空把移植的记录写下来,另发一个帖子。
我优化后的切换任务函数时间缩短到11.4us,原来是14.多us左右
回复 支持 反对 送花

使用道具 举报

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

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2024-11-1 07:45 , Processed in 0.230496 second(s), 77 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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