MC9S12G128模块化分层化软件架构之十——TaskSchedule任务调度

修改历史

内容

1        overview

1.1        目的

1.2        综述

2        question

3        软件实现

3.1        Coding Rule

3.2        中间件module层修改

3.2.1        增加mdsys_cfg.h

3.2.2        修改mdrti.c

3.2.3        增加mdsys_time.c

3.2.4        修改mdtask_cfg.c

3.2.5        修改mdtask_cfg.h

3.2.6        修改mdtask.c

3.2.7        修改mdio.c

3.3        common公共文件夹

3.3.1        新建math.c

4        基础内容

4.1        缩略语

4.2        TimingEvent activated runnables

4.3        Autosar: Activation Offset for RunnableEntity

5        软件测试及调试

5.1        任务调用

5.2        task monitor配置错误

5.3        task monitor runtime错误

5.4        task monitor cycle time错误

6        实物展示

 

上一期源码MC9S12G128_RTIAndClock.zip下载地址:

https://download.csdn.net/download/Sure_gengjia/13126844

1      overview

1.1    目的

本文档用于起点开发板的TaskSchedule周期任务调度模块软件说明。

不局限于硬件功能的实现,着眼于实现高质量、优美的软件

                     

1.2    综述

1. 引入功能安全策略,增加任务运行时间和调用周期时间的监控;

2. 引入AUTOSAR timing event方法,周期调用不同任务;

3.实现任务可配置化,配置与底层代码分离.

2       question

1.       如何理解offset?

2.        

3       软件实现

3.1     CodingRule

具体可在源码的 ..\Sources\code_rules.txt中可见。

3.2    中间件module层修改

3.2.1         增加mdsys_cfg.h

包括中间层module层放的周期,和一些宏开关。

3.2.2         修改mdrti.c

3.2.2.1          修改mdrti_1ms_hander()

增加mdsys_timer计时器。

注意:这里不需要对mdsys_timer限制最大值,加满UINT32_MAX溢出到0,该值用于测量测试checkpoint之间的时间差。

3.2.3         增加mdsys_time.c

把mdsys_poweron_time_ms和mdsys_poweron_time_s移到本文件,增加mdsys_timer变量。

增加mdsys_time_get_since_ms()来获取时间差,单位为ms。

3.2.4         修改mdtask_cfg.c

change log:

3.2.4.1          修改mdtask_config[]任务配置数组

修改结构体配置参数:

周期任务需要的参数:

①       执行周期;

②     为了避免在同一时刻一个任务中执行的可运行实体(runnable,实际是一个个处理不同任务的函数,他们的运行周期一样),给每一个在同一个task中运行的实体增加偏移量,具体留到后面的优化中实现;

③      任务函数指针;

④      任务运行时间的最大阈值;

⑤      任务的调用周期的最小阈值;

⑥      任务的调用周期的最大阈值;

⑦      计算平均运行时间和平均调用周期时间的滤波个数;(多少个值的和算平均值)

3.2.4.2          增加mdtask_basic_2ms_period()

这时module中间层的2ms周期任务,一般用于调用实时性要求很高,但任务量又小的任务,如IO采样;

3.2.4.3          增加mdtask_basic_4ms_period()

中检测module层4毫秒周期任务,一般用于调用实时性次于IO采样的任务,如SPI采样。如果AD要求实时性高,也可以放在2毫秒任务中。

3.2.4.4          增加mdtask_basic_5ms_period()

中间层5毫秒周期任务,可用于调用CAN通信处理任务,ADC采样任务;

3.2.4.5          增加mdtask_basic_10ms_period()

中间层module层10毫秒周期任务,可用于调用实时性一般的任务,如诊断任务;

3.2.4.6          增加mdtask_appl_4ms_period()

用于处理应用层实时性要求高的任务,电机控制,(甚至可以增加2毫秒任务处理,要与AD采样周期一致,保证每次处理的是新的数据,此处不使用,不增加,)这里的LED流水灯任务可以改为10毫秒任务;

3.2.4.7          增加mdtask_appl_5ms_period()

3.2.4.8          增加mdtask_appl_10ms_period()

3.2.5         修改mdtask_cfg.h

3.2.5.1          增加任务周期宏定义

3.2.5.2          增加采集配置表中所有周期任务信息结构体

采集的信息包括:

①       上一次的采样时间点;

②      运行时间runtime最小时间;

③      运行时间runtime最大时间;

④      运行时间filter_count次平均之后的时间;

⑤      周期时间cycle_time最大时间;

⑥      周期时间cycle_time最小时间;

⑦      周期时间cycle_time平均时间;

⑧      运行时间的错误类型;

⑨      周期时间的错误类型;

3.2.5.3          增加时间的错误类型枚举

3.2.5.4          增加taskID

如果要增加task,需要在该枚举中增加taskID。

3.2.6         修改mdtask.c

changelog:

3.2.6.1          修改mdtask_init()

该函数可用于任务调度时,计算所有任务的周期数的最小公倍数。

首先,当系统时间计时器(mdrti_1ms_counter)能整除每个任务的周期数时,该任务会被执行。但是mdrti_1ms_counter的最大值应当为任务的周期数的最小公倍数的2n倍或者UINT16_MAX,一般在设置任务周期时最好是1ms, 2ms, 4ms, 5ms, 10ms, 20ms, 50ms, 100ms,1000ms。

3.2.6.2          新增mdtask_calculate_lcm_peiod ()

用于计算所有周期的最小公倍数的2n倍。

3.2.6.3          增加mdtask_report_task_start()

如果使用任务监控功能(MDTASK_MONITOR_TIME == 1u),该函数应该在每个周期任务一开始的地方调用,这样才能监控的运行时间长度和调用周期才能准确。

主要用于监控调用周期的实际时间,第一次的调用该函数和下一次调用该函数的时间差即为该任务的实际调用周期,并检查该任务的调用周期是否在配置范围内。

但是在mdsys_time_get_since_ms()函数中不能实现微秒级的时间参数,所以该功能不能准确检测出任务执行的微秒级的时间,只能检测数毫秒级的时间。

3.2.6.4          增加mdtask_report_task_run()

如果使用任务监控功能(MDTASK_MONITOR_TIME == 1u),该函数应该在每个周期任务最后结束的地方调用,这样才能监控的运行时间长度才能准确。

3.2.6.5          修改mdtask_schedule()

注意:这里一定要用uint16 tick_count =mdtask_get_tick();获取当前的mdrti_1ms_counter,因为这个全局变量是一直在变的,如果在判断task开始是否开始执行时该全局变量增加了,下一个task就会错过本次执行的机会。例如,taskA的周期是5ms,offset是1,taskB的周期是10ms秒,offset是1,此时mdrti_1ms_counter为11。

此时((mdrti_1ms_counter % period_of_taskA) ==offset_of_taskA),所以taskA可以执行,但是taskA的运行时间runtime为2ms,当taskA结束后,mdrti_1ms_counter为13,本来没有执行taskA时,(mdrti_1ms_counter % period_of_taskB) == offset_of_taskB是成立的,但是因为taskA执行时间过长,导致taskB不能执行。而如果使用局部变量获取tick_count= mdtask_get_tick()就会避免由于某一个task执行时间过长导致其他其他task无法执行的问题。

3.2.7         修改mdio.c

去掉mdio_input_sample()中的对周期的判断,因为改为了周期调用mdio_input_sample(),不需要函数内部自己判断。

3.3    common公共文件夹

3.3.1         新建math.c

3.3.1.1          新增calculate_least_common_multiple_u16()

4       基础内容

4.1     缩略语

runable activation

runnable的激活与RTEEvent有关。RTEEvent决定runnable的执行与否。RTEEvent定义为事件。例如, a timing event,当定时器到时,对应的runnable被激活。

 
   
   
   
   

4.2    TimingEventactivated runnables

TimingEvent:用于启动RunnableEntity的事件。

TimingEvent用于在RunnableEntity中执行重复动作。简单来说就是每次TimingEvent发生时触发RunnableEntity的执行。

4.3     Autosar: Activation Offset forRunnable Entity

In order to allow optimizations(smooth cpu load, mapping of runnableentitysand BswSchedulableEntitys with different periods in the same task to avoid datasharing, etc), the RTE has to handle the activation offset information from atask shared reference point only for tim trigger RannableEntitys and BswSchedulableEntitys.The maximum period of a task can be calculated automatically as the greatestcommon divisor(GCD) of all runnables period and offset. It is assumed that therunnables worst case execution is less than the GCD. In case of the worst caseexecution is greater than the GCD, the behavior becomes undefined.

为了让CPU负载更加平均分布,为了避免在同一个task中但有不同的周期的runnableentity共享数据,对于那些时间触发的runnableentitys并且共享同一个时间参考点的runnableEntitys,RTE应当处理好激活时偏移量参数。该任务的周期应当为所有runnable周期和偏移量的最大公约数(GCD)。最差情况是runnable执行时间少于最大公约数(GCD)。如果执行时间查过最大公约数,系统表现无法确定。

翻译的很晦涩难懂,不过可以图解不断含义。

例1:

一个task中有3个runnable,每个activation offset定义如下:

Runnable

Period

ActivationOffset

R1

100ms

20ms

R2

100ms

60ms

R3

100ms

100ms

runnable R1, R2和R3都在T1任务中调用,T1的周期为20ms,20ms是3个runnable周期和激活偏移量(activationoffset)的最大公约数。

①      参考时间为0ms时,任务T1开始运行,当前没有runnable应当被执行;

②      参考时间为20ms时(0和20ms之间任务T1不会被执行),任务T1开始运行,当前的offset为20ms,R1被执行;

③      参考时间为40ms时,任务T1开始运行,当前没有runnable应当被执行;

④      参考时间为60ms时,任务T1开始运行,当前offset为60ms,R2被执行;

⑤      参考时间为80ms时,任务T1开始运行,当前没有runnable应当被执行;

⑥      参考时间为100ms时,任务T1开始运行,当前offset为100ms,R2被执行;

例2:

4个runnable在同一个task中被调用,激活偏移量和任务中的调用位置定义如下:

Runnable

Period

Position in task

Activation Offset

R1

50ms

1

0ms

R2

100ms

2

0ms

R3

100ms

3

70ms

R4

50ms

4

20ms

runnable R1,R2和R3在同一个任务T1中被调用,任务T1的周期为10ms,10ms是4个runnable周期和激活偏移量的最大公约数(GCD)。

5       软件测试及调试

当前配置参数:

5.1    任务调用

例:

当mdtask_old_tick_count不等于mdrti_1ms_counter时,此时tick_count整除mdtask_config[]中mdtask_appl_4ms_period ()任务周期APPL_TASK_4MS_PERIOD,如下图在mdtask_appl_4ms_period ()设置断点,mdrti_1ms_counter为22016,整除4。

5.2    task monitor配置错误

将mdtask_appl_4ms_period最大cycle time阈值设置为3,最小cycle time阈值设置为4,应该是报MdtaskCycletimeError_WrongConfig。

5.3    taskmonitorruntime错误

在mdtask_appl_4ms_period ()中增加mdsys_delay_ms(4u)延时4ms,mdtask_appl_4ms_period ()runtime就会大于4ms,mdtask_config[]中配置mdtask_appl_4ms_period ()最大runtime阈值为2ms,此时应当报MdtaskRuntimeError_OverMaxTime。

5.4    taskmonitorcycletime错误

在mdtask_appl_4ms_period ()中增加mdsys_delay_ms(6u)延时6ms,mdtask_appl_4ms_period ()runtime就会大于6ms,会影响mdtask_appl_4ms_period ()下一个激活点,导致跳过一个周期,会导致时序混乱。mdtask_config[]中配置mdtask_appl_4ms_period ()最大cycletime阈值为5ms,此时应当报MdtaskCycletimeError_OverMaxTime。

 

6       实物展示

 

 

更多精彩内容请关注公众号: 激活未来。

 

ONGOING!

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值