目录
Os_InitializeVectorTable 的一般情况:
三、 驱动初始化(Driver Initialization)
七、BswM Start-up Two:启动 RTE 之前的最后一步
往期推荐
- 2025汽车行业新宠:欧企都在用的工具软件
- 【AUTOSAR高效开发神器】Davinci AutomationInterface帮你!
- ETAS工具链自动化实战指南<一>
- ETAS工具链自动化实战指南<二>
- ETAS工具链自动化实战指南<三>
- AUTOSAR工程师必读:Artop的核心功能
- Vector工具链自动化实战指南<一>
- isolar高手秘籍| ECU Configuration三分钟速成!
- 掌握核心步骤:RTA-BSW以太网配置全解析
- 一文详解TC399 CAN MCAL 配置
- LSL常见应用场景及示例<一>
- LSL常见应用场景及示例<二>
- LSL常见应用场景及示例<三>
- 为什么Autosar钟情arxml而非json?大揭秘!
- 深入浅出:SOME/IP-SD的工作原理与应用
- 【技术进阶】|一文掌握Autosar ComStack的精髓!
- Autosar培训笔记整理<一>
- 【AutoSAR进阶】|实战详解ETAS工具链UDS 0x2f服务核心配置!
- 实战详解ETAS工具链CanTp模块自动化配置
- 一文掌握5种常见的AUTOSAR 错误类型
- 【AUTOSAR工程师必备知识】一文搞懂AUTOSAR架构9种通信方式
- 实战干货|详解ETAS工具链之 intra-ECU通信的数据转换
在调试 ECU 启动问题时,你是否遇到过这些疑问:
为什么系统停在 EcuM_Init() 就不动了?
OS 启动后任务没跑起来是哪里没配置?
RTE 什么时候才真正开始调度?
BswM 的 Start-up One 和 Start-up Two 到底在干嘛?
本文带你完整梳理 AUTOSAR 中 ECU 的启动过程,从硬件复位到任务调度运行,逐步揭开 EcuM、OS、BswM、RTE 各阶段之间的调用逻辑。
一、从复位开始:ECU 启动的第一步
当 MCU 从复位向量(Reset Vector)跳转时,最先执行的是芯片特定的启动代码。这一步会初始化栈指针、准备内存空间,最终跳转到主应用入口点。
👉 ECU 应用层的第一个函数就是:
EcuM_Init();
它标志着 AUTOSAR 启动流程正式开始。
二、OS 初始化:让系统“有中断可用”
在 EcuM_Init() 中,系统会首先调用:
EcuM_AL_SetProgrammableInterrupts();
这一过程非常关键,因为内部会执行:
Os_InitializeVectorTable();
这是 OS 层的底层 API,用于准备中断向量表,让系统具备响应中断的能力。 但此时中断还未真正触发,只有在 StartOS() 调用之后,OS 才会开始接管中断。
📘 注意: 如果你的系统未正确调用 Os_InitializeVectorTable()
,ISR 将无法运行,OS 任务调度也会异常。
Os_InitializeVectorTable 的一般情况:
如上所述,在 RH850 端口中 Os_InitializeVectorTable() 的调用方式如下:
通常有两种情况:
-
在非 AUTOSAR 系统中,应在 Os_Main() 中调用;
-
在 AUTOSAR 系统中,应通过 EcuM 调用。
若两处均被配置并连续调用两次,实际上只是覆盖初始化,不会造成严重影响(只要在 OS 启动前完成)。
三、 驱动初始化(Driver Initialization)
接下来是 Driver Init Zero 和 Driver Init One 调用,这是 BSW 中最早的初始化调用之一。这两个初始化列表用于启动 MCAL 层驱动 和最底层的 Complex Device Drivers。
在 ISOLAR 中,这部分配置可在以下位置查看:
对应的生成代码位于:
通常每个模块会接收一个包含配置的结构体指针作为参数。某些目标平台上的非 AUTOSAR 兼容 MCAL 模块可能例外,具体请参考硬件厂商的生成代码或文档。
⏱ EcuM Startup Duration:
若想使用 EcuM_GetTicks() 函数,可通过设置相关配置参数为 true
启用。
当 EcuMRbStartupDuration = true
,系统将在每个驱动初始化列表的起始与结束处自动生成该函数调用。
⚠️ 注意: 应确保 EcuM_GetTicks() 关联的计时器在调用前已启动。例如,若该函数返回的计时器值来自 MCU 初始化的计时器,而 MCU 尚未初始化,则结果将无效。 集成方需确保逻辑合理。
四、启动 OS
在 EcuM_Init() 的最后一步是启动 OS:
此时 MCU 进入一个 while 循环,执行 Os_Cbk_Idle(),该函数始终返回 TRUE
,从而形成 while(1)
的空闲循环。
此时 OS 已启动,但调度表(Schedule Table)还没启动。只有当 RTE 启动后,任务调度才真正开始。
启动 OS 的调用也会触发所有配置为 Auto Start 的 OS 任务。在ETAS Starter Kit 中,唯一配置为自动启动的任务是InitTask,它不属于调度表,只在启动时执行一次。
⚙️ 多核系统中的 OS 启动:
在多核应用中,所有非主核最初均处于挂起状态。以 RH850 为例:
-
只有主核主动启动;
-
其他核通过 Os_AwaitStartup() 等待;
-
主核通过 OS 内部函数 Os_Cbk_StartCore() 唤醒从核;
-
所有核都会运行到 Os_Main(),并执行 EcuM_Init()。
💬 换句话说:在多核系统中,EcuM_Init() 需要在每个核心上都执行一次。
五、初始化任务(Init Task)
Init Task 阶段的主要目标是初始化并启动 BswM Init 列表:
其核心任务是初始化 BswM 模块 并触发第一个 Action List。,为后续启动阶段做准备。
🧩 旧版 BSW 的特别说明:
在 BSW ≤ 6.1.2 的版本中,由于 SchM 在 BswM 之前初始化,需要重新启动一次 SchM。 原因是 AUTOSAR 4.2.2 的启动流程在 BSW 6.1.2 中沿用,而从 6.1.3 开始,系统已适配 AUTOSAR 4.3.1。
旧版本的启动流程如下:
EcuM_StartupTwo() 会调用 BswM_Init(),当 BswM 初始化完成后,SchM_IModeInit 将触发 BswM Init List One。
六、BswM Start-up One:初始化记忆栈
在 ISOLAR 中以下位置中查看 BswM 用户回调列表:
Start-up One 的目标是:
-
初始化内存栈(Mem Stack);
-
执行 NvM_ReadAll();
-
触发 Start-up Two。
这两个操作是下一个动作列表(Action List)执行的触发条件。
七、BswM Start-up Two:启动 RTE 之前的最后一步
要激活 Start-up Two,必须满足以下两个条件:
-
NvM_ReadAll 完成;
-
Start-up One 完成。
在这一阶段,系统初始化剩余的 BSW 模块,其中最重要的是启动 RTE 的集成代码调用。
🔁 模块初始化顺序的变化:
RTA-BSW 版本 | 调用顺序 |
≤ 6.1.2 | SchM_Init() → BswM_Init() |
≥ 6.1.3 | BswM_Init() → SchM_Init() |
八、RTE 启动:让 ECU 真正“跑起来”
RTE 启动阶段是 ECU 启动序列中最关键的部分之一。调用 Rte_Start() 表示 ECU 几乎已完全启动。
当第一次调用 Rte_Start() 时,RTE 会:
-
启动 Schedule Table;此时 ECU 已接近完全运行状态
-
启动 Rte_TickCounter;
-
启用 GPT 通知,每 1ms 触发一次计数器自增。
当 GPT 定时器稳定运行时,ECU 就正式进入“正常运行模式”。 此时 ECU 基本已启动完成,最后一个 BswM 动作列表用于启用 ComM 通道 和 PduGroup,从而使通信模块运行起来。
九、调度表(Schedule Table)
RTE 根据 runnable 的周期生成 osNeeds.arxml,其中定义了调度表(Schedule Table)。
例如在在 Starter Kit 中:
-
BSW 任务:每 1ms 执行;
-
ASW 任务:每 10ms 执行。
当任务被激活后,从 Suspended 状态进入 Ready 状态; OS 会根据优先级调度高优先级任务进入 Running 状态; 执行完成后任务重新进入 Suspended 状态。
由于调度表配置为循环,最后一个 Expiry Point 执行完会回到第一个。因此 ASW 每 10ms 激活一次。
每当 Rte_TickCounter 增加一次,OS 就进入下一个 Expiry Point。
调试技巧:OS 与死循环问题
若系统在启动中陷入死循环,可在 ErrorHook 中添加断点或日志输出,用于捕获 OS 报错:
void ErrorHook(void) {
while(1); // 断点定位错误来源
}
如果代码进入了非预期的死循环,通常意味着启动过程中某个函数未获得期望的响应。例如,MCU 代码可能在等待 MCU_PLL_LOCKED 状态时无限阻塞。有些目标平台会在超时后进入错误钩子(ErrorHook),此时可通过错误信息进行调试。
总结:一条清晰的 ECU 启动主线
阶段 | 关键函数 | 说明 |
1 | EcuM_Init() | 启动入口 |
2 | Os_InitializeVectorTable() | 启动中断向量表 |
3 | Driver Init Zero/One | 初始化底层驱动 |
4 | StartOS() | 启动 OS 主循环 |
5 | Init Task | 初始化 BswM |
6 | BswM Start-up One | 读 NvM,准备下一阶段 |
7 | BswM Start-up Two | 启动 RTE |
8 | Rte_Start() | 启动调度表与任务调度 |
9 | GPT TickCounter | 驱动时间基准,系统稳定运行 |
📘 思考
EcuM 的启动过程其实就是“系统自举”过程的抽象: 从硬件 → OS → 驱动 → 服务 → 应用,每一层都为下一层提供运行条件。 理解启动顺序,能让我们更高效地排查启动异常、时序问题、乃至多核同步问题。