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

UCOSII - STC32G12K128 移植

[复制链接]

该用户从未签到

63

主题

703

回帖

1万

积分

荣誉版主

积分
10906
发表于 2023-9-13 13:28:43 | 显示全部楼层
C251_1.jpg

上面是楼主的程序,可以看到第1648行的任务切换程序位于第1638行与第1652行的临界区保护中了


点评

熊仔的分析是对的,我的这个回复中的说法是不对的,楼主移植版的任务调度发生在退出临界区保护之后。  详情 回复 发表于 2023-9-13 22:32
回复 支持 反对 送花

使用道具 举报

该用户从未签到

20

主题

575

回帖

1191

积分

荣誉版主

积分
1191
 楼主| 发表于 2023-9-13 15:16:17 | 显示全部楼层
杨老师: 你好, 感谢你回复我的贴子.
关于所贴代码, 在之前其实是想到过这个问题的, 但是我的观念却是和你不一样!
OS本来的意思是 用 OS_TASK_SW()来定义一条产生软中断的指令, 外国人还叫什么陷井来的.  这条指令(或许是一段代码)确实是在临界区的, 但正因为是在临界区, 所以此时不会发生中断, 接着按正常流程退出临界区, 然后就是任务切换了. 你说的那些 "任务在这就切走了,没有配对执行临界区了", 这些都只是你以为, 并没有真的发生.  又或者说用代码切换任务的移植确实会在这个时候切走,所以之后的代码需要补坑呀, 你们所说的会产生各种BUG,  现在需要各种细节操作, 可能就是因为此时你挖的这个坑,后期需要各种细节操作来弥补. 所以说嘛, 临界区还是那个临界区, 正常进入,正常退出. 任务切换还是任务切换, 两者是有些交集, 但并不矛盾。


51内核能运行UCOS, 我记得在很多年以前就见过相关的移植版本, 至少是十年前就有人移植过了吧. 最先移植的那位前辈, 确实大才, 他在51内核没有中断指令的前提下, 别出心栽的想到了用一段代码来模似这个过程. 当时我看到这些代码时, 很激动.
但是, 不管是UCOS本身, 还是那位前辈, 他们都很明白一件事, 临界区始终是临界区, 为什么这么说呢: 见过老版本的UCOS-C51移植的程序员, 应该知道最早的时候是使用直接开关中断来进入和退出临界区的, 那位前辈也知道自己这样做打断了临界区的代码,但人家补救了啊,在任务切换最后一步时, 他打开了中断, 也就是说, 他替临界段,完成了临界区未走完的最后一步. 做到了效果一至性.  其实为了不占用中断硬件资源, 这也是一种无奈之举, 并且通过一些其它的限制措施, 直接开关中断也是可行的, 当时可能就这么暂定下来了.  直接开关中断有些弊端(UCOS的介绍文档本身就提到过, 要小心的使用这种方式, 直白的来说就是这样用也可以, 但是你要自己排除掉那些可能引起错误的前提,或者说有些前提条件, 所以严格的来说, 这不算是BUG) 此话题不再详论, 所幸的是后期出了好多改善过的移植版本, 是值得肯定的. 比如熊仔那个版本, 确实还是挺好的, 细节做得很到位.
      另一点要提的是,许多处理器都会用代码而不是中断切换任务, 这里没有好坏之分, 只有哪种更适合的区别 . OSCtxSw() 本来是中断向量要指向的那个函数, 也就是任务切换的中断代码本身, 而OSIntCtxSw()和OSCtxSw()功能差不多, 但是因为各种处理器不同, OSIntCtxSw()可能需要一些额外的处理, 所以把他们区分开来了. 而用代码切换任务, 主要用是编辑这两个函数, 方法各种各样, 但其原理是不会变的, 或许你会因为某些特殊的需要面提前离开临界区, 但只要是保证了提前离开临界区后代码运行的正常逻辑就可以了, 毕竞是底动代码嘛, 灵活 变通都是常规操作. 但是无论你的操作有多么特殊, 再怎么别具一格 , 那也只能明是变通 ,  临界区的定义还是不会变的. 两回事, 不能以点概面.

另外有一点是, 杨老师说:达不到嵌套保套保护的目的, 这个嵌套是指哪个嵌套呢, 任务锁嵌套那是OS做好的了, 临界区我用的是模式3,支持嵌套使用. 如果说任务切换也会嵌套, 那我就又要犯迷糊了.


后来我想明白了, 理解不一样又有什么关系呢, 如果真的时学术问题, 或许还值得辩证一下, 但现在好像也并不是那么回事


回复 支持 反对 送花

使用道具 举报

该用户从未签到

20

主题

575

回帖

1191

积分

荣誉版主

积分
1191
 楼主| 发表于 2023-9-13 15:29:44 | 显示全部楼层
杨老师: 你好, 感谢你回复我的贴子.
关于所贴代码, 在之前其实是想到过这个问题的, 但是我的观念却是和你不一样!
OS本来的意思是 用 OS_TASK_SW()来定义一条产生软中断的指令, 外国人还叫什么陷井来的.  这条指令(或许是一段代码)确实是在临界区的, 但正因为是在临界区, 所以此时不会发生中断, 接着按正常流程退出临界区, 然后就是任务切换了. 你说的那些 "任务在这就切走了,没有配对执行临界区了", 这些都只是你以为, 并没有真的发生.  又或者说用代码切换任务的移植确实会在这个时候切走,所以之后的代码需要补坑呀, 你们所说的会产生各种BUG,  现在需要各种细节操作, 可能就是因为此时你挖的这个坑,后期需要各种细节操作来弥补. 所以说嘛, 临界区还是那个临界区, 正常进入,正常退出. 任务切换还是任务切换, 两者是有些交集, 但并不矛盾。


51内核能运行UCOS, 我记得在很多年以前就见过相关的移植版本, 至少是十年前就有人移植过了吧. 最先移植的那位前辈, 确实大才, 他在51内核没有中断指令的前提下, 别出心栽的想到了用一段代码来模似这个过程. 当时我看到这些代码时, 很激动.
但是, 不管是UCOS本身, 还是那位前辈, 他们都很明白一件事, 临界区始终是临界区, 为什么这么说呢: 见过老版本的UCOS-C51移植的程序员, 应该知道最早的时候是使用直接开关中断来进入和退出临界区的, 那位前辈也知道自己这样做打断了临界区的代码,但人家补救了啊,在任务切换最后一步时, 他打开了中断, 也就是说, 他替临界段,完成了临界区未走完的最后一步. 做到了效果一至性.  其实为了不占用中断硬件资源, 这也是一种无奈之举, 并且通过一些其它的限制措施, 直接开关中断也是可行的, 当时可能就这么暂定下来了.  直接开关中断有些弊端(UCOS的介绍文档本身就提到过, 要小心的使用这种方式, 直白的来说就是这样用也可以, 但是你要自己排除掉那些可能引起错误的前提,或者说有些前提条件, 所以严格的来说, 这不算是BUG) 此话题不再详论, 所幸的是后期出了好多改善过的移植版本, 是值得肯定的. 比如熊仔那个版本, 确实还是挺好的, 细节做得很到位.
      另一点要提的是,许多处理器都会用代码而不是中断切换任务, 这里没有好坏之分, 只有哪种更适合的区别 . OSCtxSw() 本来是中断向量要指向的那个函数, 也就是任务切换的中断代码本身, 而OSIntCtxSw()和OSCtxSw()功能差不多, 但是因为各种处理器不同, OSIntCtxSw()可能需要一些额外的处理, 所以把他们区分开来了. 而用代码切换任务, 主要用是编辑这两个函数, 方法各种各样, 但其原理是不会变的, 或许你会因为某些特殊的需要面提前离开临界区, 但只要是保证了提前离开临界区后代码运行的正常逻辑就可以了, 毕竞是底动代码嘛, 灵活 变通都是常规操作. 但是无论你的操作有多么特殊, 再怎么别具一格 , 那也只能明是变通 ,  临界区的定义还是不会变的. 两回事, 不能以点概面.

另外有一点是, 杨老师说:达不到嵌套保套保护的目的, 这个嵌套是指哪个嵌套呢, 任务锁嵌套那是OS做好的了, 临界区我用的是模式3,支持嵌套使用. 如果说任务切换也会嵌套, 那我就又要犯迷糊了.


后来我想明白了, 理解不一样又有什么关系呢, 如果真的时学术问题, 或许还值得辩证一下, 但现在好像也并不是那么回事
回复 支持 反对 送花

使用道具 举报

该用户从未签到

20

主题

575

回帖

1191

积分

荣誉版主

积分
1191
 楼主| 发表于 2023-9-13 15:49:01 | 显示全部楼层
杨为民 发表于 2023-9-13 13:08
楼主的问题“临界区切换任务? 这个确实没想过, 不过我很好奇的是, 什么时候需要在临界区切换任务.  ”
我 ...

话不能说的太满啊, 你看看我的那个代码, 中断切换任务, 在中断函数代码里, 就是没有全程设为临界区, 只是在访问全局变量时暂时进出临界区. 除此之外别的代码都是不保护的. 如果有高优先级中断, 是允许发生的, 我这对个有把握. 理由:除了自身外, 别的中断代码都是当普通的中断, 他们可以打断我, 但是他们返回我到这时, 一定会替我恢得上下文(编绎器会完成的, 不用担心). 这样就简化了中断的设计. 或许你还有个问题, 那高级中断里的代码要切换任务怎么办, 当然是设置中断标志罗, 又没有真的切换, 你怕什么. 那是不是重复设置了中断标志呢, 是的, 但是没关系, 无非是多切换一次, 你是最高优先级任务, 再切换一次又怎么样, 该是你的还是你的

点评

(1)根据熊仔前面的分析,楼主的移植版的任务切换确实是在临界区外进行的。 (2)因此:“楼主移植版的任务切换是一个可以被打断的过程”。楼主的回复也说明了这一点。 (3)但是按照正规操作系统的要求:“OS中  详情 回复 发表于 2023-9-13 23:52
回复 支持 反对 送花

使用道具 举报

该用户从未签到

11

主题

331

回帖

886

积分

荣誉版主

积分
886
发表于 2023-9-13 22:04:26 | 显示全部楼层
本帖最后由 熊仔 于 2023-9-13 22:06 编辑

uCOS源码在楼主这种触发一个中断切换任务方式是正确的。内核源码是没有bug的。
OSCtxSw或者OSIntCtxSw的作用只是人为把定时器4的溢出中断标志置位。

任务真正切换是在退出临界区(OS_EXIT_CRITICAL();)后,开启中断。然后进入定时器4中断服务函数切换任务。
这种方式就是参考了ARM cortex的pendSV方式。


如果使用代码直接切换的任务方式,uCOS内核源码确实存在bug,这个也是我在解决临界区保护方法3为啥不能工作的时候发现的。一开始为了不修改内核源码,在切换函数里面处理入栈的数据。后面为了解决任务切换能嵌套,不得已才修改内核源码。又修改了2次。第一次提前执行OS_EXIT_CRITICAL();发现不完美,开启了中断,有很大问题;
第二次弄了一个OS_EXIT_CRITICAL_NOT_INT()宏。OS_EXIT_CRITICAL_NOT_INT()的作用是执行了退出临界区的部分代码,但是不开启中断。执行完毕任然是关中断的。这个方案还是挺满意。

















点评

熊仔的分析是对的,我的上个回复中的说法是不对的,楼主移植版的任务调度发生在退出临界区保护之后。  详情 回复 发表于 2023-9-13 22:33
回复 支持 反对 送花

使用道具 举报

该用户从未签到

63

主题

703

回帖

1万

积分

荣誉版主

积分
10906
发表于 2023-9-13 22:32:50 | 显示全部楼层
杨为民 发表于 2023-9-13 13:28
上面是楼主的程序,可以看到第1648行的任务切换程序位于第1638行与第1652行的临界区保护中了

熊仔的分析是对的,我的这个回复中的说法是不对的,楼主移植版的任务调度发生在退出临界区保护之后。
回复 支持 反对 送花

使用道具 举报

该用户从未签到

63

主题

703

回帖

1万

积分

荣誉版主

积分
10906
发表于 2023-9-13 22:33:55 | 显示全部楼层
熊仔 发表于 2023-9-13 22:04
uCOS源码在楼主这种触发一个中断切换任务方式是正确的。内核源码是没有bug的。
OSCtxSw或者OSIntCtxSw的作 ...

熊仔的分析是对的,我的上个回复中的说法是不对的,楼主移植版的任务调度发生在退出临界区保护之后。
回复 支持 反对 送花

使用道具 举报

该用户从未签到

63

主题

703

回帖

1万

积分

荣誉版主

积分
10906
发表于 2023-9-13 23:52:41 | 显示全部楼层
tzz1983 发表于 2023-9-13 15:49
话不能说的太满啊, 你看看我的那个代码, 中断切换任务, 在中断函数代码里, 就是没有全程设为临界区, 只是 ...

(1)根据熊仔前面的分析,楼主的移植版的任务切换确实是在临界区外进行的。
(2)因此:“楼主移植版的任务切换是一个可以被打断的过程”。楼主的回复也说明了这一点。


(3)但是按照正规操作系统的要求:“OS中任务切换是一个不能够被打断的过程”,原因是如果被打断,就可能产生异常的任务调度,产生错误的后果。
(4)下面用楼主的目前的移植版为例来说明任务切换过程被打断后可能的后果。假设当前任务为C,是最低优先级,准备切换到的新任务为B,任务B优先级比任务C高。
下图是楼主的任务切换程序:

Fig_01_任务切换.jpg

假设“T4IF=1”后,任务切换程序开始执行。任务切换程序从第98行执行到第112行时是在保存任务C的寄存器现场和TCB,然后第115行进入临界区保护,第119行退出临界区保护。
(5)程序中的第128行到第137行是开始恢复任务B的寄存器现场,最后第140行切换到任务B执行。
(6)假设上面程序在执行到第128行到第137行之间时发生了一个优先级比定时器4(任务切换中断PendSvIsr)高的新中断使得任务A就绪,假设任务A的优先级比任务B高(比如是系统中断,任务A休眠倒计时结束了;又比如是一个外部中断发生,检测到有异常事件发生需要任务A来处理),新中断就暂停当前任务切换去执行新的中断ISR,当新中断ISR中的中断任务切换程序再次设置“T4IF=1”后退出新中断,上面的程序继续执行(不是从头执行),直到第140行切换到任务B继续执行。
(7)在执行第140行的“RETI”中断返回指令时,STC单片机硬件自动设置“T4IF=0”。这时大家可以发现,就绪任务优先级最高的任务A被忽略了,任务被切换到任务B执行,这是一个极大的错误。
(8)结论:从理论上说,如果任务切换不在临界区保护中连续进行,就有可能被打断,就有可能产生异常结果。当然也许这种事件实际发生的可能性只有亿万分之一。
不知楼主是否赞同我的这个结论

回复 支持 反对 送花

使用道具 举报

该用户从未签到

20

主题

575

回帖

1191

积分

荣誉版主

积分
1191
 楼主| 发表于 2023-9-14 09:22:50 | 显示全部楼层
杨老师, 这是为何呢?  不怪我说话比较刻薄啊. 讲个故事吧, 我初学51单片机的时候, 书上说中断函数后加上关键字 using x 指定寄存器组, 会节约一些入栈的时间, 于是我就喜欢每次都指定. 后来有一次不对劲了, 原因是我在中断函数中调用了另一个函数, 而被调用的函数没有指定寄存器组, 所以产生了错误 , 但是当时不知道原因啊, 于是我就拼命的查, 代码查不到, 那就仿真, 跟踪, 查汇编, 终于发现了是寄存器组用错了,  当时我高兴啊,  但高兴的不是我找到原因了, 而是"我以为我自己找到了编译器的BUG" , 只是后来才知道, 人家本来的设定就是被调用的函数也需要指定寄存器组. (原来小丑是自己)
     说正题吧, STC单片机硬件自动设置“T4IF=0, 这是对的, 但时机可以不在执行RETI的时候哦,  而是在进入中断的时候, 所以你说的那些, 还是不可能存在的.  执行RETI不会清除中断标志, 是一贯的用法, 否则: 不管有没有用OS , 丢失中断标志是一定会发生的. 为此我还特意去验证了一下.

    如果真的指出了我程序中的不足, 我会很高兴, 对广大网友也是一种帮助, 但连续几次了啊, 先是说不在临界区切换任务, 后来又说不能嵌套, 再后来又说任务切换一定是中临界区. 再到后来, 熊仔承认了, 我切换任务是在临界区外的. 都是些子虚乌有的东西. 并且刚开始时还能够感觉到态度有些傲慢: 没有直接指出我的问题, 反而是要我去看他的代码. 当然了, 这些都没关系, 我自己也承认自己说话比较傲, 没给别人面子, 这些问题我自己以后慢慢克服.

再说UCOS 熊仔所谓的 "BUG" 吧, 可能上一段回复你还是没有看懂,  三个关键点: OS_TASK_SW(),  OSCtxSw(),  OSIntCtxSw()  这三个东西是移植者需要做的东西 ,
原本对应关系是:
OS_TASK_SW()  ------ 中断指令

OSCtxSw()   -----------中断代码(切换任务的专用中断)

OSIntCtxSw()--------------如果你直接从别的中断直接返回, 需要比OSCtxSw() 增加一些操作. 这些东西人家都是放开的, 让你们自己来做的.

现在是你改变了原本的"真意"->就是用代码模似中断过程, 然后返回, 这个方法可以啊, 但是首先是你改变了别人的那点东西, 然后, 顺其自然, 接下来可能出现的问题当然是要你自己去解决了. 这样做是可以的, 如果做好了, 也是最适合51内核的做法, 但是, 因在你, BUG是果, 那你不能由此来说人家有"BUG"呀.  

可能就是惯性思维吧, 也可能是因为你刚接触时用的就是51内核, 所以误以为本来就应该是这样的.  柳白说: "身前一尺是他的世界", 此处无敌.  而我却说, 一尺之外, 更有大千世界, 走出来吧, 外面世界很精彩, 我从来都是认同你们的成果的, 但是也请你们不要排外

最后感谢杨老师和熊仔, 这次是真感谢, 由于你们提出的问题, 我确实找到了我中断代码中的一个BUG, 但和杨老师说的不一样,  在我的中断代码中, 如果在开临界段前发生了别的中断, 在别的地方就有可能改变EA的状态(当然这种可以仍然是比较小的), 我程序中这段代码是直接开关中断的, 所以会有问题. 之前的想法是,本身就是中断代码, 即然能运行到这, EA一家是开的, 所以不用保存, 直接开关即可.  但是现在发现了不行. 还是直接用OS临界段模式3来替代吧, 不相差那一点时间















点评

“杨老师, 这是为何呢? ”——你的意思其实是:我为什么盯着你不停地说,口气又不好,而且经常说的还不对。首先点赞你的好脾气,然后我来解释一下。 (1)RTOS是下一步STC单片机应用的重点方向,但是对RTOS,了解的  详情 回复 发表于 2023-9-14 15:01
回复 支持 反对 送花

使用道具 举报

该用户从未签到

11

主题

331

回帖

886

积分

荣誉版主

积分
886
发表于 2023-9-14 10:57:23 | 显示全部楼层
本帖最后由 熊仔 于 2023-9-14 11:07 编辑

杨老师的意思是下面这段代码会被中断

截图202309141053091369.jpg

解决方法:应该把EA=1弄到RETI前面。

楼主没有把EA=0放中断跳转后第一条,可能考虑更高优先级嵌套。其实没必要,都到这里了,直接切换就好,。
把EA=0弄第一条,妥妥的。也不需要方法3这么复杂。


这个触发设定最低优先级中断方式也是挺好的,流程简单。代码是自己用的,好用就行。
回复 支持 反对 送花

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-18 02:08 , Processed in 0.079427 second(s), 72 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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