AUTOSAR入门-EcuM模块与系统启动

原创 thatway 那路谈OS与SoC嵌入式软件 2022-06-22 07:30

AUTOSAR入门-EcuM模块与系统启动

“**日出而作,日落而息**”,  

白天要干活,晚上就要睡觉,两种状态的变化组成了很多人的生活。人的一生要经历生和死,也是状态的变迁,一个人从出生到童年、少年、青年、中年、老年,再到去世。
人的活动可以看成是很多状态的变迁,有活动就有状态,就会产生状态变迁,程序也是活动的,是人脑活动的延伸,模拟人脑的机制去自动运行,执行人脑设计的程序。典型的程序状态有:启动、运行、睡眠、唤醒、关机。这五种状态也可以描述我们要做的任何一件事情,可以帮助我们更加科学的去规划事情的发展。

下面进入正题,**EcuM**全称为(  

ECU State Management**顾名思义,指的就是ECU 的 状态管理,我们以 启动流程
为主来看分析一下AS代码:
https://github.com/thatway1989/as**。通过本篇文章可以让你了解到AS代码是怎么**启动**的,各个模块是怎么被**初始化**运行起来的,这在软件分析中是很重要的。好比我们说上帝创造了人,那我们要苦苦的去
寻找上帝
,问上帝你是怎么创造出来的人。

1. 状态机

上图中有  

五种状态Startup**ShutdownRUNSleep**Wakeup
的状态组成以及状态切换的过程,其中**OFFSleepRUN是稳态,而StartupWakeup**则是暂态


  • Startup
    阶段,同样按照
    Flexible
    模式中开启
    OS
    为界限,分为Startup I
    Startup II
    两个阶段;

  • 当唤醒事件能够控制
    CPU
    供电时,则需要进入
    Wakeup
    阶段验证
    Wakeup Event
    是否有效,相反如果不带电源控制,则直接进入
    RUN
    阶段。

  • 若进入到
    RUN
    阶段,可分为两个阶段:
    RUN II

    RUN III
    两个阶段。其中
    RUN II
    指的是正常运行阶段,
    RUN III
    则是
    SW-C
    为即将进入到
    ShutDown
    所需要做的前提准备。

  • 若进入到
    ShutDown
    阶段,首先会进入到
    PreShutDown
    阶段,然后按照
    Shutdown
    的目标不同,可以分为
    reset

    OFF

    Sleep
    三条路径。

  • 如果
    Target

    Sleep
    ,则进入到
    Go Sleep
    阶段,若在该阶段检测到唤醒事件,那么直接跳转至
    Wakeup Validation
    阶段。

  • 如果
    Target

    OFF

    Reset
    ,则需经历
    Go OFF I

    Go OFF II
    两个阶段,
    reset
    则会重新跳转至
    Startup
    阶段,而
    OFF
    则是直接关闭
    ECU

  • 若进入到
    Wakeup
    阶段,则需要进行四个阶段的唤醒源验证,主要分为
    Wakeup I

    Wakeup Validation

    Wakeup Reaction

    Wakeup II
    阶段;

  • 若进入到
    Sleep
    阶段,则可以分为两种
    Sleep
    模式:
    Sleep I

    Sleep II
    ,一般两者选其一。其中
    Sleep I
    阶段(
    Halt
    ),此阶段不运行代码,
    等待唤醒事件,然后跳转至
    Wakeup
    阶段;

  • 其中
    Sleep II
    阶段则为
    Polling
    阶段,这个阶段则会低功耗运行代码,并且等待唤醒事件,如果存在,则进入到
    Wakeup
    阶段。

2. 系统启动

上面EcuM的5种状态是概念还比较空洞
,下面就结合AS的代码
,来看下开机启动的过程。

ECU启动时,首先通过中断向量表运行引导程序(俗称BootLoader),Bootloader在满足一定条件下跳转至APP程序中的C_Init处并指向main函数
。Main()函数在

release/ascore/app/main.c
中定义:

在这个main()函数之前的代码是汇编写的,在BootLoader中,我们在编译的时候,见AUTOSAR入门-AS开源代码编译过程详解
2.5**生成TINIX.IMG:
生成的
TINIX.IMG**
有三部分:
boot.bin

loader.bin

x86

  • 》kernel.bin

boot.bin

loader.bin
的源码在:

as
/com/
as
.infrastructure/arch/x86/boot/

x86
就是我们用Scons编译出来的目标程序,都是c语言写的
,main入口函数就是上面说的release/ascore/app/main.c中定义。

进入EcuM_Init()函数后,首先启动第一阶段的初始化,之后启动OS,再进行第二启动阶段的初始化,最后就是进入StartPostOS阶段,如完成BswM模块的初始化,进而将控制权转交给BswM模块。

整个系统,BootLoader运行完成后,就有EcuM模块接管运行起来OS,初始化各种模块,到最后状态机的运行,都是有EcuM完成的。具体由EcuM_Init**()**
函数完成,在代码
com/as.infrastructure/system/EcuM/EcuM.c
中。

2.1 EcuM_StateType状态

首先就是设置ECU的状态,执行代码如下:

set_current_state(ECUM_STATE_STARTUP_ONE);

可以找到状态的定义如下:

typedef enum {
  ECUM_STATE_APP_RUN = 0x32,          //!< ECUM_STATE_APP_RUN
  ECUM_STATE_SHUTDOWN = 0x40,         //!< ECUM_STATE_SHUTDOWN
  ECUM_STATE_WAKEUP = 0x20,           //!< ECUM_STATE_WAKEUP
  ECUM_SUBSTATE_MASK = 0x0F,          //!< ECUM_SUBSTATE_MASK
  ECUM_STATE_WAKEUP_WAKESLEEP = 0x25, //!< ECUM_STATE_WAKEUP_WAKESLEEP
  ECUM_STATE_WAKEUP_ONE = 0x21,       //!< ECUM_STATE_WAKEUP_ONE
  ECUM_STATE_OFF = 0x80,              //!< ECUM_STATE_OFF
  ECUM_STATE_STARTUP = 0x10,          //!< ECUM_STATE_STARTUP
  ECUM_STATE_PREP_SHUTDOWN = 0x44,    //!< ECUM_STATE_PREP_SHUTDOWN
  ECUM_STATE_RUN = 0x30,              //!< ECUM_STATE_RUN
  ECUM_STATE_STARTUP_TWO = 0x12,      //!< ECUM_STATE_STARTUP_TWO
  ECUM_STATE_WAKEUP_TTII = 0x26,      //!< ECUM_STATE_WAKEUP_TTII
  ECUM_STATE_WAKEUP_VALIDATION = 0x22,//!< ECUM_STATE_WAKEUP_VALIDATION
  ECUM_STATE_GO_SLEEP = 0x49,         //!< ECUM_STATE_GO_SLEEP
  ECUM_STATE_STARTUP_ONE = 0x11,      //!< ECUM_STATE_STARTUP_ONE
  ECUM_STATE_WAKEUP_TWO = 0x24,       //!< ECUM_STATE_WAKEUP_TWO
  ECUM_STATE_SLEEP = 0x50,            //!< ECUM_STATE_SLEEP
  ECUM_STATE_WAKEUP_REACTION = 0x23,  //!< ECUM_STATE_WAKEUP_REACTION
  ECUM_STATE_APP_POST_RUN = 0x33,     //!< ECUM_STATE_APP_POST_RUN
  ECUM_STATE_GO_OFF_TWO = 0x4e,       //!< ECUM_STATE_GO_OFF_TWO
  ECUM_STATE_RESET = 0x90,            //!< ECUM_STATE_RESET
  ECUM_STATE_GO_OFF_ONE = 0x4d        //!< ECUM_STATE_GO_OFF_ONE
} EcuM_StateType;

2.2 EcuM_AL_DriverInitZero()

//
Initialize drivers that are needed to determine PostBuild configuration
 ASLOG(ECUM,
("!!!EcuM_AL_DriverInitZero!\n"));
 EcuM_AL_DriverInitZero();

初始化和启动Det(Default Error Tracer) 默认的错误追踪器,必须在最开始初始化

2.3 InitOS();

1.初始化全局变量sys_t os_sys,这个变量用于表示操作系统内部的状态信息

2.初始化计数器

3.初始化调度表

4.在ram中建立pcb,并把rom中的pcb解压到ram中,并串接成链。

2.4 Os_IsrInit()

建立中断表:

Os_IsrInit();-》Irq_Init();

2.5 EcuM_World全局变量

   AUTOSAR方法论中介绍:代码有一部分固定的代码和一部分配置代码组成。配置代码在AS中的主要形式就是全局变量,由scons studio工具生成,路径在:  

as/build/posix/x86/ascore/config

这些全局变量要生效就要加载到内存中,这里

//
Determine PostBuild configuration
EcuM_World.config = EcuM_DeterminePbConfiguration();
 就是加载各个模块配置的全局变量的,这些配置也叫PostBuild

configuration,就是说在编译后也可以改变的配置,这部分配置在内存中存在,可以被程序所修改。

 EcuM_World可以看作是ECU的控制块,它是一个EcuM_GobalType结构体,定义如下:  

EcuM_GlobalType EcuM_World;

```

typedef struct { boolean initiated; //是否已经启动 EcuM_ConfigType * config; //ECU上各个硬件部分的控制信息,如:Ecu Default Shutdown Target,Ecu Default Shutdown Mode, Ecu Default App Mode EcuM_StateType shutdown_target;

if (defined(USE_ECUM_FLEXIBLE))

EcuM_ShutdownCauseType    shutdown_cause;

endif

uint8                     sleep_mode;
AppModeType               app_mode;
EcuM_StateType            current_state;

if defined(USE_COMM) || (defined(USE_ECUM_COMM) && (ECUM_AR_VERSION < 40000))

uint32                                 run_comm_requests;

endif

uint32                                 run_requests;
uint32                                 postrun_requests;
/* Events set by EcuM_SetWakeupEvent */
uint32 wakeupEvents;

uint32 wakeupTimer;
uint32 validationTimer;
uint32 nvmReadAllTimer;
/* Events set by EcuM_ValidateWakeupEvent */
uint32 validEvents;
boolean killAllRequest;

} EcuM_GlobalType;

```

2.6 EcuM_AL_DriverInitOne()

完成无需OS支持的底层硬件驱动的初始化或者其他低水平的初始化,将这部分驱动的初始化称为Init Block 1;

```

if defined(USE_DEM)

// Preinitialize DEM                                                                                                                
NO_DRIVER(Dem_PreInit(ConfigPtr->DemConfigPtr)); 

endif

```

这里有DEM的预初始化。

初始化的模块:

  // Preinitialize DEM
  NO_DRIVER(Dem_PreInit());
  // Setup Port
  Port_Init(ConfigPtr->PortConfig);
  // Setup the GPT
  Gpt_Init(ConfigPtr->GptConfig);

  Wdg_Init(ConfigPtr->WdgConfig);

  NO_DRIVER(WdgM_Init(ConfigPtr->WdgMConfig));
  // Setup DMA
  Dma_Init(ConfigPtr->DmaConfig);
  // Setup ADC
  Adc_Init(ConfigPtr->AdcConfig);
  // Setup PWM
  Pwm_Init(ConfigPtr->PwmConfig);
  // Setup PWM
  Ipc_Init(&Ipc_Config);

  NO_DRIVER(VirtQ_Init(&VirtQ_Config));

  NO_DRIVER(RPmsg_Init(&RPmsg_Config));

  SHELL_Init();

2.7 KSM_INIT();

AUTOSAR入门-SoAd模块和TcpIp模块
3.3 TaskLwip**激活中,把**
KSM_Config
数组里面的任务轮询执行。

代码见:
build/posix/x86/ascore/config/ksm_cfg.c

2.8 StartOS(OSDEFAULTAPPMODE);

如果没有初始化正确,就进入了noooo()死循环,从而触发看门狗reset。

二是检查os_strat()是否被退出,如果退出,则会调用assert(0)从而引发可捕获的异常。

StratOS()这个系统API调用了os_start()内部函数,它在\system\kernel\init.c

这个函数首先获得处于ready队列优先级最高的任务,然后切换到该任务,其间又调用了用户的StartupHook(),启动Alarm、Counter和系统Tick。

首次任务切换后操作系统就开始正式运行,至此系统启动完毕。

EcuM_enter_run_mode();进入运行模式。

3.操作系统运行

操作系统的运行核心就在于如何组织任务抢占CPU的时间片。在OSEK OS中,任务被触发执行可能的情况有四种:

  1. 被其他任务、中断服务程序调用SetEvent()或ActivateTask()触发。任务还可以调用ChainTask()触发切换。

  2. 其他任务释放资源。

  3. 被报警器(Alarm)触发。

  4. 通信通知。

其中第3种情况是最为常见的,因为任务通常是以周期执行的形式体现。

含有RTE应用程序的操作系统可分为五个部分:内核、任务体、构件、RTE和基础软件,RTE在Arctic Core中是一个API的转换层,构件只能运行自己的算法或调用Rte中的函数,每一个项目都有用户自己定义的Rte模块将构件的调用转换为BSW的API。整个过程如下图所示:

3.1 Bsw启动

os启动后会执行任务,
com/as.infrastructure/system/SchM/SchM.c
中有任务列表

TASK(SchM_Startup){
EcuM_StartupTwo();
TerminateTask();

3.2 EcuM_StartupTwo()

在开启OS的初始化函数中调用EcuM_StartupTwo进行第二启动阶段的初始化,最后就是进入StartPostOS阶段,如完成BswM模块的初始化,进而将控制权转交给BswM模块。

// Initialize drivers that don't need NVRAM
data
EcuM_AL_DriverInitTwo(EcuM_World.config);
(void)Rte_Start();
EcuM_AL_DriverInitThree(EcuM_World.config);
EcuM_enter_run_mode(); //会就进入运行状态。

3.3 EcuM_AL_DriverInitTwo()

初始化不需要NVRAM数据的模块

```

if defined(USE_DCM) EcuM_CheckValidation

NO_DRIVER(Dcm_Init(ConfigPtr->DcmConfigPtr));   // Setup DCM                                                                        EcuM_CheckWakeup

endif


可以看到DCM的初始化  

## 3.4 EcuM_AL_DriverInitThree()  

初始化需要NVRAM数据的模块

```

5. EcuM其他几种状态分析

EcuM的AUTOSAR官方文档为:《  

AUTOSAR_SWS_ECUStateManager.pdf
》其他几种状态可以参考:

https://zhuanlan.zhihu.com/p/508403009

自己对照官方文档看一遍,这里偷懒
就不说明了。

后记:

最近比较忙些,每周一更还是要坚持,写点有用的东西,拓展嵌入式和汽车软件的知识。如果  

汽车软件
感兴趣的朋友,这里可以加我微信thatway1989
,备注进群
。然后拉你进本公众号的交流群:OS与AUTOSAR研究-交流群,可以讨论汽车软件最新技术,一起学习。

Talk

is cheap
,show me the code
,后续会继续更新,
纯干货
分析,无广告,不打赏,欢迎
转载
,欢迎
评论交流

往期见话题:
AUTOSAR入门

results matching ""

    No results matching ""