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

STC单片机 uC/OS-II核心技术(8):中断外任务切换方法

[复制链接]
  • TA的每日心情
    开心
    7 小时前
  • 签到天数: 147 天

    [LV.7]常住居民III

    39

    主题

    887

    回帖

    4126

    积分

    荣誉版主

    积分
    4126
    发表于 2023-10-7 10:33:46 | 显示全部楼层
    熊仔 发表于 2023-10-7 10:24
    OSIntExit() 函数,必须是可重入的,莫非你没有看过代码?

    看过, 没关心去记位~~~

    那肯定 不管多少次 嵌套, 都不会出问题(堆栈溢出除外)
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    11

    主题

    331

    回帖

    886

    积分

    荣誉版主

    积分
    886
    发表于 2023-10-7 10:40:14 | 显示全部楼层
    LAOXU 发表于 2023-10-7 10:23
    像 老杨 上次举了一个 例子, 两个任务分别调用 printf 函数, 当发生嵌套时, 被打断的  printf 函数, 无法恢 ...

    对于特殊资源,互斥访问都是必要的。操作系统都有考虑。现在的操作系统都很完善了,临界区,互斥锁==资源的使用。
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    11

    主题

    331

    回帖

    886

    积分

    荣誉版主

    积分
    886
    发表于 2023-10-7 12:28:20 | 显示全部楼层
    本帖最后由 熊仔 于 2023-10-7 12:29 编辑

    (5)在uC/OS-II中,具体实现中断外任务切换的函数是上面第1651行的“OS_TASK_SW()”宏函数。
    在首次引入中国的uC/OS-II的原始版本中,这个宏函数是利用80x86 CPU的软中断指令“INT”实现的。由于80x86软中断指令“INT”不受第1641行uC/OS-II进入临界区保护时关闭总中断的影响,在第1651行处产生一个真正的“软中断”,实现任务切换。在完成任务切换退出“软中断”之后,单片机继续执行第1655行的退出临界区保护程序,打开总中断,至此uC/OS-II系统才脱离临界区。

    对于杨老师第五点。我有不同观点。
    在完成任务切换退出“软中断”之后,单片机继续执行第1655行的退出临界区保护程序,打开总中断,至此uC/OS-II系统才脱离临界区。通过分析这很不正确。
    int指令执行过程
    1)取中断类型码n;
    2)标志寄存器入栈(pushf),IF=0,TF=0(重置中断标志位);
    3)CS、IP入栈;
    4)查中断向量表, (IP)=(n*4),(CS)=(n*4+2)。
    INT软中断后,OSCtxSw这个中断服务函数是立即执行的。OSCtxSw函数执行后,肯定是切换到新的任务去了,所以不会返回到断点。





    点评

    “肯定是切换到新的任务去了,所以不会返回到断点。” 很好,阅读很仔细,思考很到位,其实这也正是uC/OS-II原始架构设计的一个高光亮点! (1)这是uC/OS-II中断里任务调度函数: [attachimg]23170[/attachimg]  详情 回复 发表于 2023-10-7 14:46
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    63

    主题

    703

    回帖

    1万

    积分

    荣誉版主

    积分
    10906
     楼主| 发表于 2023-10-7 13:50:05 | 显示全部楼层
    tzz1983 发表于 2023-10-7 10:08
    杨老师: 呵呵, 实际上还是不会的, 要不你自己去想?  只有自己想出来的, 才会理解的.
    给您几个提示吧:
    1.无 ...

    1.无论你给多少次 T4IF=1, T4IF最终都是等于1, 绝对不会等于2.
    2.无论任务切换过程中被其它中断打断过多少次(可以是嵌套), 中断都是会返回原来的断点, 因为别的中断在执行OSIntExit()时, 如果有切换任务的需求, 只是会做一个 T4IF=1的动作, 除PendSv外, 所有其它的中断都不会真的做任务切换, 它们就是普通的中断, 从哪里来, 回哪里去. 其它的中断切换任务的需求由PendSv中断代劳.
    3.在多级嵌套中断里, 由于OSIntNesting++的存在, T4IF=1这个动作也会没有, 只有在最后一级中断(PendSv除外)退出时, 才有T4IF=1的动作

    (1)如果“T4IF=1”可能被设置多次(这代表有多个任务切换请求发生 在任务切换中断执行之前),那么CosyOS就考虑的比你全面,他用队列来解决这个问题,并且还按优先级进行处理。对于这种情况你的和熊仔的方案有漏洞。

    如果“T4IF=1”不可能被设置多次(这代表不可能有多个任务切换请求发生 在任务切换中断执行之前,那么CosyOS的考虑就是多余的,那么他用队列来解决这个问题就是多此一举

    (2)“在多级嵌套中断里, 由于OSIntNesting++的存在, T4IF=1这个动作也会没有”,如果这句话成立,那么““T4IF=1”不可能被设置多次”,上面的结论你和熊仔的方案是正确的,但是这句话对于你和熊仔的方案不成立。按照STC32G单片机中断和中断退出(RETI)的工作机制,除非你们的“OSIntNesting++”是中断矢量开始的头一两条指令,“OSIntNesting--”是“RETI”之后的头一两条指令,否则就没有对中断实现完整的保护,对于你和熊仔的方案“T4IF=1”就可能被设置多次!
    (3)“只有在最后一级中断(PendSv除外)退出时, 才有T4IF=1的动作”,所以我在挑战者x51的第一篇帖子了将“EA=0”放在你的模拟软中断(PendSv)的第一行程序,将“EA=1”放在模拟软中断“RETI”之前的最后一行程序,把你这除外的漏洞补掉了!你还颇有微词,嫌遮住你的关键部位遮多了!(熊仔的现在还露在外面没有遮住)。
    (4)我个人认为,对于CosyOS由于它没有中断嵌套保护的功能(比如OSIntNesting++这种招数),所以对于CosyOST4IF=1”肯定可能被设置多次,所以他用队列来解决这个问题不是多此一举,而是必须的。
    (5)谈到了就介绍一下在我的“天山x51-uCOSII”的STC8H单片机RTOS中是如何进行中断嵌套保护的,供大家参考。在中断矢量处程序是这样的
    中断嵌套保护_01.jpg

    中断ISR发生的第一条指令就是“INC     TSX51_BIOS_INTNESTING_COUNTER”,肯定被执行,不可能被跳过。这样每个中断一发生就进入中断嵌套保护了
    (6)在中断ISR处的程序是这样的:
    中断嵌套保护_02.jpg

    这样STC8H单片机的每一个中断都被天山x51的“BIOS”系统统一保护起来了,用户只需要填写每个中断的用户ISR函数就行了。然后所有的中断都从同一个出口程序“TSX51_BIOS_BOOT_INT151_EXIT”退出中断,实现统一管理。
    (7)中断出口程序“TSX51_BIOS_BOOT_INT151_EXIT”的代码如下:
    中断嵌套保护_03.jpg

    其中第136行到第138程序为中断返回指令建立了一个堆栈,第139行的“RETI”指令既发布了硬件中断结束信号结束中断,也将程序转移到第117行处。由于这是RETI指令发布后的第一条指令,因此“DEC     TSX51_BIOS_INTNESTING_COUNTER”指令肯定得到执行,甚至避免将这条指令放在“RETI”指令前的漏洞。这样每个中断从开始直到退出的整个过程都被完整地中断嵌套保护了
    (8)玩家版的程序通常只考虑一般C语言级别不出现漏洞,而产品版则必须在汇编语言级别堵住每一个可能发生的漏洞来保证RTOS系统的高可靠性。






    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    20

    主题

    576

    回帖

    1195

    积分

    荣誉版主

    积分
    1195
    发表于 2023-10-7 14:19:07 | 显示全部楼层
    本帖最后由 tzz1983 于 2023-10-7 14:22 编辑
    杨为民 发表于 2023-10-7 13:50
    “1.无论你给多少次 T4IF=1, T4IF最终都是等于1, 绝对不会等于2.
    2.无论任务切换过程中被其它中断打断过 ...

    杨老师啊, 和你说明一个东西真的很难啊, 如果, 我说如果"你是我的学生, 我都可能会放弃你", 太难搞了.

    1. TF4=1会不会多次被设置, 这和熊仔搞论的OSIntNesting++是否可能来不及加就发生了更高的优先级嵌套有关, 在这里并不是重点, 重点想表达的意思是, 即便是执行了多次, 也只会有一次切换, 不会发生错误.  (正常情况下多次嵌套只会设置一次)
    2.为什么不会发生错误呢, 因为OS核心参数是在临界段段内读写的, 核心参数不会出错, 在最后一次任务切换时(哪怕是嵌套时重复两次最高优先级任务切换), 也一定会毫无错误的正确的切换到最高优先级那个任务. (举个简单的例子, 多次嵌套中断里有3个任务被激活, 那到最后也只是需要切换一次, 而不是三次, 剑只要指向最高的任务优先级就可以了, 我说的TF4=1被多次设置也不会出错, 也不会进行多次切换, 就是这个意思)
    3.这里同时也说明了读写OS核心参数时, 为什么一定要在临界段内操作.

    再说明一下, 你要在切换任务时全程关中断, 我没有反对你, 那是你的选择, 你这样做也是可以的, 不会发生错误.  但是我不会这样选择, 原因不多说了.

    如果我还是没说明白, 那证明我的口才太差了, 接下看看熊仔能不能给您解释一下
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    20

    主题

    576

    回帖

    1195

    积分

    荣誉版主

    积分
    1195
    发表于 2023-10-7 14:41:30 | 显示全部楼层
    本帖最后由 tzz1983 于 2023-10-7 15:59 编辑

    即然说到了OSIntNesting++, 那就再多说一点, 之前和熊仔讨论时, 熊仔已经明了, 用中断切换任务时,
    其实OSIntNesting的作用被消弱了-> 即使真的有一次没有加到, 因为硬件自动嵌套的原因, 也不会发生切换错误, 这就是为什么我为认中断切换任务的方法比代码切换任务更加健壮的原因

    其2是, 用代码切换任务时, 熊仔认为OSIntNesting++不放在向量口也行的, 原因是三级流水线, 发生中断后仍有两条指令可以执行
    但是我不认同这种看法, 硬件产生中断, 如果本身就算一条指令的话(比如以前的书箱解释为LCALL), 向量口跳转也算一条指令, 那么OSIntNesting++就是第三条指令了.
    但是这些硬件细节其实我是不怎么确定的. 所以不知道, 就不要去否定别人.  
    结论是:
    1.用代码切换任务时, OSIntNesting++放在向量口, 比放在中断代码第一句更可靠.
    2.用中断切换任务时, 无所谓放在哪, 都可以

    点评

    请问阁下,你的“OSIntNesting--”指令放在哪里了?别顾头不顾腚!  详情 回复 发表于 2023-10-7 14:49
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    63

    主题

    703

    回帖

    1万

    积分

    荣誉版主

    积分
    10906
     楼主| 发表于 2023-10-7 14:46:25 | 显示全部楼层
    熊仔 发表于 2023-10-7 12:28
    (5)在uC/OS-II中,具体实现中断外任务切换的函数是上面第1651行的“OS_TASK_SW()”宏函数。在首次引入中 ...

    肯定是切换到新的任务去了,所以不会返回到断点。

    很好,阅读很仔细,思考很到位,其实这也正是uC/OS-II原始架构设计的一个高光亮点!
    (1)这是uC/OS-II中断里任务调度函数:
    uCOSII_01_中断任务切换.jpg

    这是uC/OS-II中断外任务调度函数:

    uCOSII_02_非中断任务切换.jpg

    它们的共同点是任务切换函数完成后的紧跟着的语句是第732行或者第1729行的“OS_EXIT_CRITICAL();”退出临界保护区语句
    (2)假设原来优先级高的任务A被挂起来后又就绪了(比如说用“OSTimeDly”休眠到期了),切换是从当前优先级较低的任务B切换到任务A,这就是说:整个RTOS系统在任务B进入了临界区保护后(第700行或者第1708行),在没有退出当前任务B的临界区保护的情况下执行了第721行或者第1725行的任务切换程序,将任务切换到了任务A,这时整个RTOS仍然处于临界区保护中!
    (3)然后任务A从上次任务挂起点的下一行程序开始执行,执行第732行或者第1729行的“OS_EXIT_CRITICAL();”的退出临界保护区语句,这时整个RTOS系统才在任务A中退出临界区保护。
    (4)因此我的(5)点应该改为
    在完成任务切换退出“软中断”之后,单片机继续执行“新任务”的(非被切换的老任务的)第1655行的退出临界区保护程序,打开总中断,至此uC/OS-II系统才在新任务中脱离临界区
    (5)临界区保护的C语言程序行虽然写在不同的任务函数里,但是关闭总中断(EA)进行临界区保护是整个单片机RTOS的行为,根据上面的代码流程分析:除了定义临界区保护的宏是空定义的方法0情况,在本论坛的所有不使用模拟软中断的uC/OS-II范例中,任务切换都是在临界区保护中进行的。


    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    63

    主题

    703

    回帖

    1万

    积分

    荣誉版主

    积分
    10906
     楼主| 发表于 2023-10-7 14:49:31 | 显示全部楼层
    tzz1983 发表于 2023-10-7 14:41
    即然说到了OSIntNesting++, 那就再多说一点, 之前和熊仔讨论时, 熊仔已经明了, 用中断切换任务时,
    其实OSI ...

    请问阁下,你的“OSIntNesting--”指令放在哪里了?别顾头不顾腚!
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    20

    主题

    576

    回帖

    1195

    积分

    荣誉版主

    积分
    1195
    发表于 2023-10-7 15:17:21 | 显示全部楼层
    本帖最后由 tzz1983 于 2023-10-7 15:25 编辑
    杨为民 发表于 2023-10-7 14:49
    请问阁下,你的“OSIntNesting--”指令放在哪里了?别顾头不顾腚!

    应该在OSIntExit()内吧, 我没有你们这么执着, 并没有回去看原代码.
    OSIntNesting--完了后会TF4=1,这在中断切换任务中不会出错, 而代码切换任务, 如果少加了就会出错.
    接下来下午我不能再这么陪聊了, 要干点活了. 杨老师您再研究研究

    补充一下, 我的意思不是可以故意不加, 而是"可能"由于硬件机制导致的非常低的机率的少加 , 还有, 不用担心OSIntNesting--会减成负数, 能执行到OSIntExit() OSIntNesting就一定能减

    点评

    “应该在OSIntExit()内吧, 我没有你们这么执着, 并没有回去看原代码.” 玩家移植版的作者通常不需要了解RTOS整个工作原理和全部流程,产品移植版的维护者不但要了解RTOS整个工作原理和全部流程,而且必须要深入研究  详情 回复 发表于 2023-10-7 15:59
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    7 小时前
  • 签到天数: 147 天

    [LV.7]常住居民III

    39

    主题

    887

    回帖

    4126

    积分

    荣誉版主

    积分
    4126
    发表于 2023-10-7 15:32:24 | 显示全部楼层
    捕获111.JPG


    老杨厉害, 超人也, 回贴已经领先到 12月份了 ?!  
    回复 支持 反对 送花

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2024-5-18 15:52 , Processed in 0.081813 second(s), 71 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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