问题描述:在GD32F450中移植FreeRTOS后,设置相关参数如下:
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
其作用如下:
FreeRTOS对任务的调度采用基于时间片(time slicing)的方式。时间片,顾名思义,把一段时间等分成了很多个时间段,在每一个时间段保证优先级最高的任务能执行,同时如果几个任务拥有相等的优先级,则它们会轮流使用每个时间段占用CPU资源。调度器会在每个时间片结束的时候通过周期中断(tick interrupt)执行一次,调度器根据设置的抢占式还是合作式模式选择哪个任务在下一个时间片会运行。
时间片的大小由configTICK_RATE_HZ这个参数设置。如果configTICK_RATE_HZ设置为10HZ,则时间片的大小为100ms。configTICK_RATE_HZ的值由应用需求决定,通常设为100HZ(时间片大小相应为10ms)。
当使用vTaskdelayUntill 函数设置任务运行周期时,发现设置的周期数并不能够与实际时间一致。
例如,设置10ms周期,实际周期为12ms。实际周期比设定的多2ms。
其它地方暂时未发现异常,修改上面的宏定义至500后,在设置4ms以上,2ms的整数倍周期时,实际时间与设定的一致。
但是设定2ms周期时,实际周期为约3.11ms。
将宏定义改回1000后,设定1ms周期时,同样实际周期约为3.11ms。
我猜,这就是导致设定1000的configTICK_RATE_HZ时,实际周期与设定周期不一致的原因。更深层次的原因还没有分析出来。
———————–分割线————————-
通过将任务中的函数注释后,无论设置configTICK_RATE_HZ为1000还是500。均能够将任务按照预定的周期调用。
由于变量xTickCount可能会溢出,所以程序必须检测各种溢出情况,并且要保证延时周期不得小于任务主体代码执行时间。这很好理解,不可能出现每5毫秒执行一个需要20毫秒才能执行完的任务。
测试任务内的函数运行一次所需的时间为:3.11ms ,因此这里解释了为什么最小任务周期是3.11ms。
———————–分割线————————-
任务周期为3.11ms,configTICK_RATE_HZ为1000(systick为1ms)时,设置任务周期为10ms,为什么会出现实际与设定不符合呢?
taskENTER_CRITICAL();
...
taskEXIT_CRITICAL();
在任务中执行函数时,为了保证代码执行过程中不被打断,因此将代码段放入了临界保护区内,而临界保护区的作用如下:
The taskENTER_CRITICAL() and taskEXIT_CRITICAL() macros provide a basic critical section implementation that works by simply disabling interrupts, either globally, or up to a specific interrupt priority level. See the vTaskSuspendAll() API function for information on creating a critical section without disabling interrupts.
简单翻译: 宏taskENTER_CRITICAL()和宏taskEXIT_CRITICAL()提供了一个基本的临界区实现,它通过简单地禁用中断来工作,无论是全局的,还是特定的中断优先级级别。请参阅vTaskSuspendAll() API函数了解如何在不禁用中断的情况下创建临界区。
Critical sections must be kept very short, otherwise they will adversely affect interrupt response times. Every call to taskENTER_CRITICAL() must be closely paired with a call to taskEXIT_CRITICAL().
简单翻译:临界区必须保持很短,否则会对中断响应时间产生不利影响。对taskENTER_CRITICAL()的每次调用必须与对taskEXIT_CRITICAL()的调用紧密配对。
当把整个函数段放入临界区后,由于长时间的中断,GD32F450的systick中断一直无法进入,导致周期发生延时,这是个非常不好的结果。
解决办法应该是,尽量减少临界区的使用。
以上分析,请多多交流。