By using this site you agree to the use of cookies for analytics Learn More

案例研究|EcuM(ECU状态管理)模块及AUTOSAR程序启动/关闭/唤醒流程解析(Classic AUTOSAR基础篇)

案例研究|EcuM(ECU状态管理)模块及AUTOSAR程序启动/关闭/唤醒流程解析
(Classic AUTOSAR基础篇)

如不做特别说明,本文介绍的内容基于规范的21-11版本。

简介

EcuM模块作为基础模块之一,管理ECU状态,包括但不限于:
  • 初始化/反初始化OS,SchM,BswM以及一些其他基础软件模块
  • 当有请求时,配置ECU进入到睡眠或关闭状态
  • 管理ECU所有的唤醒事件
EcuM模块还提供唤醒验证的功能,来识别“正确的”唤醒事件。并且还有这些功能:
  • ECU部分/快速启动,仅包含有限功能,之后由应用决定其他功能启动顺序
  • ECU以最快速度仅启动必须功能并运行RTE执行某些SWC的功能,然后再启动其他BSW模块以及其他SWC
  • 除了一般意义上定义的RUN状态(完全操作),还可以定义其他状态
  • 多核ECU:ECU所有核之间启动,关闭,睡眠,唤醒状态的协同操作
对于ECU的状态管理,还需要和RTE模块(以及其SchM功能),和BswM模块一同工作,管理并控制状态的切换以及具体实现。

EcuM模块的阶段

启动(STARTUP)阶段持续到模式管理运行起来。一般地,启动阶段包括最小运行需求,例如初始化底层驱动,启动OS,初始化BSW调度表以及BswM模块,这样才能满足最低需求以进行模式管理。关闭(SHUTDOWN)阶段的操作则与之相反。

运行(UP)阶段包括所有未强调的状态,在这个阶段中,根据集成工程师定义的状态机,ECU从一个状态(State)迁移到另一个状态,或是从一个模式(Mode)转移到另一个模式。

当然,这里会有一个疑问——这个State和Mode怎么理解。一般来说,当我们提到State时,是指BSW模块内部的状态,可以构成BSW的状态机,这些状态对于应用来说是不可见的。而Mode,则是包括但不仅限于EcuM等状态机的一组状态,和应用或者整车直接相关(PS. AP的EM/SM有类似的概念)。

运行阶段也可能会包含一些前置睡眠状态,比如还未完全进入睡眠状态时,提前使能唤醒源。

启动阶段

下图展示了ECU启动时的动作,当EcuM_Init被调用时,EcuM模块开始接管ECU的启动过程。

main函数执行之前的启动代码本文暂不进行详细说明,一般都是MCU的栈初始化,变量初始化等,满足代码能够执行的条件即可。

当调用到EcuM_Init()时,EcuM开始接管ECU启动过程,并进行StartPreOS的操作:

StartPreOS阶段

进入到StartPreOS阶段时,会执行以下动作:

StartPreOS是来给OS初始化做准备的阶段,应当尽可能保证最短过程。在这个过程当中,不应当使用中断,如果一定需要使用,只允许一类中断。驱动以及硬件抽象模块初始化并不严格地由EcuM模块定义,可以在上述的Block 0和Block 1中执行。例如,Block 0中初始化Det模块,Block 1中初始化其他相关模块:

有了这些,我们就可以开始放心地启动OS了。

当EcuM调用StartOS()时,EcuM会短暂释放控制权给到OS的启动。集成工程师需要实现一个OS任务能够被自动启动,并将EcuM_StartTwo作为它的第一个执行动作。

StartPostOS阶段

执行到EcuM_StartupTwo后,开始了StartPostOS过程。
首先,需要启动BSW调度表,然后初始化BswM模块,初始化BSW调度表,最后开启调度表计时器,开始执行BSW或者SWC的周期事件。

运行阶段

当BSW调度表启动,BswM_Init被调用,我们可以认为进入了运行阶段。不过此时内存管理模块还没有初始化,也没有启动通信协议栈,RTE和SWC也仍未启动。从EcuM的角度来说,ECU已经是运行状态,然而,接下来还会由BswM模块进行模式仲裁以及更多的BSW模块初始化,启动RTE,开始运行SWC。以Elektrobit产品提供的demo为例,执行完EcuM_StartupTwo后,会初始化各个模块(例如通信协议栈模块,状态管理模块,内存管理模块等),并请求BswM进入到Startup Two A的状态:

BswM_RequestMode(EB_INTGR_BSWM_BSWM_SM,EB_INTGR_BSWM_STARTUP_TWO_A);

接下来,BswM会根据我们配置的Action List执行响应动作,例如读取NvM,启动Rte等,

此后,由于还请求了Startup Two B,因此会接着执行其他模块的初始化,例如ComM,Dem,Xcp模块等。

既然Dem模块初始化了,此时我们可以开始启动Operation Cycle状态了,例如:

Dem_SetOperationCycleState(DEM_OPCYC_POWER,DEM_CYCLE_STATE_START)

设置通信允许动作:

然后,请求Run Two状态: 

BswM_RequestMode(0,EB_INTGR_BSWM_RUN_TWO)

并且我们还可以在BswM模块里设置了将模式切换通知到Rte的动作(实际上之前每一次状态切换都有设置对应的通知动作):

Rte在获取到对应模式状态时,根据系统设计时定义好的Mode Switch Event,执行相应的Runnable:

FULL COMMUNICATION的问题

上周发布过的一篇文章:案例研究 | ComM — Communication Manager 通信管理模块(Classic AUTOSAR基础篇)
里面有提到:

当SWC初始化时,由于后续SWC中runnable有通信的需求,所以这里进行了ComM_RequestComMode的调用。

似乎本文到此为止都还没有提到这个,很高兴地祝贺你,你对通信启动的过程已经非常熟悉。

由于项目需求的不同,并不限定一定用何种方式请求通信。无论是在ComM文章里提到的那样,由SWC去主动调用请求ComM User的接口,

/* request full communication mode */
(void)Rte_Call_UR_ComMUser_0_RequestComMode(FULL_COMMUNICATION);

还是你期望等待总线上消息唤醒的方式,(注:此处代码为模拟设置唤醒事件的代码)

FUNC(void,ECUM_APPL_CODE)CanTrcv_Callout_SimulatedWakeup(void)

{

/* Set wakeup event as real external hardware driver for wakeup by bus */     

           EcuM_SetWakeupEvent(1U<<EcuMConf_EcuMWakeupSource_ECUM_WKSOURCE_CAN);

}

都可以。

当然,别忘了设置进入FULL COMMUNICATION状态时,还要使能对应的Pdu Group。

SHUTDOWN阶段

当ECU需要关闭或者重启的时候,EcuM会进入到SHUTDOWN阶段。

我们以Dcm模块0x11服务请求reset为例,我们会设置EcuM Shutdown Target为RESET以及请求进入prepare-shutdown的call-out:

BswM_RequestMode(0,EB_INTGR_BSWM_PRP_SHUTDOWN);

当进入到Prepare Shutdown的状态,此时你需要通知Rte这个状态的变化,停止Dem Operation Cycle,关闭(de-init) Dem模块,停止Rte,写入NvM数据等,并请求进入offPreOS的状态。

在OffPreOS状态,根据规范,你需要做这些事情:

OS关闭之后,会调用hook函数(需要在EB tresos中开启对应功能,或者集成代码中实现对应函数),

在这个hook函数当中,会首先调用EcuM_OnGoOffTwo(),内容由项目需求决定。

再然后根据之前选择的shutdown target来判断执行下一个动作,重启或者关闭:

   if (EcuM_ShutdownTarget == ECUM_STATE_RESET)
   {
     EcuM_AL_Reset(EcuM_ResetMode);
   }
   else
   {
     EcuM_AL_SwitchOff();

   }

SLEEP阶段

当ECU不需要通信时,可以进入睡眠模式以低功耗模式运行,此时需要设置EcuM Shutdown Target为SLEEP,

此时也需要设置条件,也能进入Prepare Shutdown状态,通知Rte这个状态的变化,停止Dem Operation Cycle,关闭(de-init) Dem模块,停止Rte,写入NvM数据等。

直到选择Go Down还是Go Poll前,操作都和刚才说明的关闭操作一样,由于我们现在选择的shutdown target是sleep,所以会执行EcuM_GoPoll或者EcuM_GoHalt函数。

上图红框即我们接下来要执行的动作,

首先进行Go Sleep操作,简单来说就是状态通知以及打开唤醒源。

再然后,进入死循环,执行需要在睡眠状态执行的其他动作,并不停地检测唤醒事件:

while

(
     (CoreInstance->WakeupStatus.Pending == 0U) &&
     (CoreInstance->WakeupStatus.Validated == 0U)
)
{
     /* Invoke the callout function. */
     EcuM_SleepActivity();

    /* Check the enabled wakeup sources. */ 

    EcuM_CheckWakeup(EcuM_SleepModeConfigList[CoreInstance>SleepMode].wakeupSource&ECUM_WKSMASKALL);

 }

一旦检测到(有效)唤醒事件,则退出循环,并开始执行唤醒操作。

唤醒过程

接着上一节,我们继续了解一下退出上述的循环后,唤醒过程中的动作。规范中对于唤醒时的动作是这样定义的,

首先设置MCU状态为normal状态,然后关闭唤醒源,如果有设置唤醒时需要重新初始化的驱动,则会调用EcuM_AL_DriverRestart()。

最后解锁调度表,其他任务可以再次执行起来。

多核中的EcuM

不同于每一个Partition都需要有一个BswM实体,每个core上有一个Partition上跑OS和EcuM就可以了。

多个核中有一个是主核,主核上的EcuM初始化后,接着启动其他核上的“卫星”EcuM。每一个EcuM都会启动本地的OS以及对应的BswM实体。

如果每个核上运行的是同一个EcuM,那么EcuM在执行时需要知道它运行在哪个核上,做出相应的逻辑动作。

 if (ECUM_CORE_ID_MASTER == ECUM_GET_CORE_ID())
 {
   EcuM_StartPreOS();
 }
 if (ECUM_CORE_ID_INITIAL == ECUM_GET_CORE_ID())
 {
   EcuM_StartAllCores();
 }

初始化动作和之前说明的几乎一样,只是主核上的EcuM还需要启动其他核。

 

 

相关产品:

经典 AUTOSAR基础软件、汽车操作系统和量身定制的工具环境: EB tresos

 

下载评估版:

免费试用EB tresos配置符合 AUTOSAR 标准的软件(支持Infineon AURIX TC38XQ和Renesas RH850/F1KM)

 

相关培训:

AUTOSAR和软件架构培训

 

成功案例:

 

相关新闻:

 

 

 

作者:

陈谦

Elektrobit中国团队的软件工程师

专注于Classic AUTOSAR