Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

修正rt_thread_delay_until时间不准问题 #4329

Merged
merged 2 commits into from
Mar 11, 2021

Conversation

liruncong
Copy link
Contributor

@liruncong liruncong commented Feb 9, 2021

拉取/合并请求描述:(PR description)

[
rt_thread_delay_until存在以下问题:

  1. 延时时间不准
    已在cortex-a8开发板测试.
    ]

以下的内容不应该在提交PR时的message修改,修改下述message,PR会被直接关闭。请在提交PR后,浏览器查看PR并对以下检查项逐项check,没问题后逐条在页面上打钩。
The following content must not be changed in the submitted PR message. Otherwise, the PR will be closed immediately. After submitted PR, please use a web browser to visit PR, and check items one by one, and ticked them if no problem.

当前拉取/合并请求的状态 Intent for your PR

必须选择一项 Choose one (Mandatory):

  • 本拉取/合并请求是一个草稿版本 This PR is for a code-review and is intended to get feedback
  • 本拉取/合并请求是一个成熟版本 This PR is mature, and ready to be integrated into the repo

代码质量 Code Quality:

我在这个拉取/合并请求中已经考虑了 As part of this pull request, I've considered the following:

  • 已经仔细查看过代码改动的对比 Already check the difference between PR and old code
  • 代码风格正确,包括缩进空格,命名及其他风格 Style guide is adhered to, including spacing, naming and other styles
  • 没有垃圾代码,代码尽量精简,不包含#if 0代码,不包含已经被注释了的代码 All redundant code is removed and cleaned up
  • 所有变更均有原因及合理的,并且不会影响到其他软件组件代码或BSP All modifications are justified and not affect other components or BSP
  • 对难懂代码均提供对应的注释 I've commented appropriately where code is tricky
  • 本拉取/合并请求代码是高质量的 Code in this PR is of high quality

@Guozhanxin
Copy link
Member

@KyleChenjh please take a look.

@KyleChenjh
Copy link

@liruncong 你好,关于第一个符号类型的问题,我觉得无符号数据进行比较是正确的,如果转成有符号的话,数据范围会发生变化,同时还会造成溢出的问题,举个例子unsigned char 的0x80 (10进制表示为128)数据,转成signed char 就会变成-128,拿这样的数据进行比较显然不合理。而源代码中直接 rt_tick_get() - *tick < inc_tick 进行比较,应该加一些限制,类似与线程定时器计算超时时间做 (timer->init_tick < RT_TICK_MAX / 2) 比较完善些。

关于第二个问题,tick的修改应该不够完备,原因有两点:

rt-thread/src/thread.c

Lines 601 to 625 in 302f179

if ((rt_int32_t)(cur_tick - *tick) < (rt_int32_t)inc_tick)
{
rt_tick_t left_tick;
*tick += inc_tick;
left_tick = *tick - cur_tick;
/* suspend thread */
rt_thread_suspend(thread);
/* reset the timeout of thread timer and start it */
rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &left_tick);
rt_timer_start(&(thread->thread_timer));
/* enable interrupt */
rt_hw_interrupt_enable(level);
rt_schedule();
/* clear error number of this thread to RT_EOK */
if (thread->error == -RT_ETIMEOUT)
{
thread->error = RT_EOK;
}
}

  1. 首先是进入这个if判断时候,tick值被直接更新为一个*tick += inc_tick ,这个值就不对了,应该再减去cur_tick才对(就是因为不知道tick到cur_tick之间过了多久才用 rt_thread_delay_until 函数的),要不然每次进入这个if 判断中都是一个固定值(+=inc_tick)如果直接加的话为什么不用rt_thread_mdelay() 函数。
  2. 该函数在最后执行了 rt_schedule操作,如果有调度发生,tick也就随之变化了,所以这个tick值再拿来做参考也是没有价值的,所以在最后退出时候才又做了一次rt_tick_get操作。

@liruncong
Copy link
Contributor Author

liruncong commented Mar 2, 2021

@KyleChenjh 第1个问题,当时没仔细考虑,确实这里无符号比较更合适。
第2个问题,“*tick += inc_tick”, 是把tick更新为定时器到达时的tick值,这个我觉得没问题啊。"rt_schedule();"调用后,经过left_tick时间后,理论tick值应该就是前面更新的tick值(注:“*tick += inc_tick”). 然后从"rt_schedule();"下一行继续运行.
此外,tick每次增加inc_tick,目的就是要让该线程在每inc_tick周期调度任务,解决部分硬实时任务问题。rt_thread_mdelay()是无法达到这个目的的,因为其调度的周期=线程执行周期+延时周期,并且线程本身执行周期还不是固定的。
注: 对于硬实时应用,硬实时任务必定会在inc_tick周期内完成,每次必须固定间隔inc_tick调用

@KyleChenjh
Copy link

@liruncong 感谢您的回复。这个函数是延时从tick的时间直到inc_tick的时间为止(但是不是绝对的,是至少要这么长时间,因为有调度发生,所以不是固定的),因此理论值就没意义了,或者是在调度之后再加个 rt_get_tick() 看下实际和理论的差别。函数最后加rt_tick_get操作是合理的。

@liruncong
Copy link
Contributor Author

@KyleChenjh 既然可以改为固定的,为什么不改为固定呢?这在硬实时系统上是必须的。而且非硬实时系统中更改后照样可以使用。调度之后rt_get_tick()时,如果在调度后,rt_get_tick()前,发生中断,获取的tick将与理论tick有偏差,这将无法应用于硬实时系统

@KyleChenjh
Copy link

@liruncong 不是能改为固定而不改为固定,是这个固定值只是理论值是无意义的。😰

@Guozhanxin
Copy link
Member

@KyleChenjh 既然可以改为固定的,为什么不改为固定呢?这在硬实时系统上是必须的。而且非硬实时系统中更改后照样可以使用。调度之后rt_get_tick()时,如果在调度后,rt_get_tick()前,发生中断,获取的tick将与理论tick有偏差,这将无法应用于硬实时系统

@liruncong 您好,可以把您针对这个函数的使用场景说一下吗,拿这个值做什么用?

@liruncong
Copy link
Contributor Author

@KyleChenjh 比如控制电机时,要求每2ms给电机发一个速度,发速度的线程500us以内完成,如果不准时给驱动器速度,电机运行不平稳。再比如数控系统中插补控制,必须固定周期内完成插补计算,插补速度输出给驱动器,不能说这回4ms,下次5ms吧, 驱动器一个周期没收到速度,那么将认为0,电机就震动了。

@Guozhanxin
Copy link
Member

@KyleChenjh 比如控制电机时,要求每2ms给电机发一个速度,发速度的线程500us以内完成,如果不准时给驱动器速度,电机运行不平稳。再比如数控系统中插补控制,必须固定周期内完成插补计算,插补速度输出给驱动器,不能说这回4ms,下次5ms吧, 驱动器一个周期没收到速度,那么将认为0,电机就震动了。

@liruncong 那么在这些场景下,你会怎么使用这个api呢,更具体的说,你会怎么用 tick 这个变量呢?

@liruncong
Copy link
Contributor Author

liruncong commented Mar 3, 2021

@KyleChenjh 大概按下面的示例使用:

void PeriodTask() {
    ......
}

void MyThread() {
    uint32_t tickInc = 4; // 4ms. 假如1个tick 1ms
    uint32_t tick = rt_tick_get();
    while (true) {
        rt_thread_delay_until(&tick, tickInc);
        PeriodTask();
    }
}

@Guozhanxin
Copy link
Member

我搜索了一下,这个函数的用途应该和 FreeRTOS 的 vTaskDelayUntil 函数一样。我感觉楼主这么修改应该是合理的。

https://blog.csdn.net/xy6zzz/article/details/49762021

@Guozhanxin
Copy link
Member

@liruncong 楼主你把第一个修改 "rt_tick_get() - *tick < inc_tick"无符号数比较错误,应该用有符号进行比较 再改回来吧。

@KyleChenjh
Copy link

@liruncong 嗯嗯,按照上面的使用场景,这样改是合理的,可以保证时间间隔。楼主你把第一个修改无符号数再改回来吧。

@liruncong liruncong changed the title 修正rt_thread_delay_until时间不准问题,及错误使用无符号比较问题 修正rt_thread_delay_until时间不准问题 Mar 4, 2021
@liruncong
Copy link
Contributor Author

@KyleChenjh 已更改

@Guozhanxin Guozhanxin added the +1 Agree +1 label Mar 9, 2021
@BernardXiong BernardXiong merged commit ca80560 into RT-Thread:master Mar 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
+1 Agree +1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants