1. 从零拆解:Autosar 与 Simulink 联合开发的真实痛点
搞过汽车电子嵌入式开发的人都知道,Autosar 架构和 Simulink 模型开发这两件事单独拎出来都不算太难,但把它们捏在一起做,问题就成倍冒出来了。我最早接触这套组合是在一个车身控制器项目上,当时团队决定用 Simulink 做应用层逻辑建模,底层走 Autosar Classic Platform 的标准栈,工具链用的是 MATLAB/Simulink 加 Embedded Coder,目标芯片是英飞凌 TC3xx 系列。听起来很标准的方案对吧?结果光是把模型生成的代码和 Autosar RTE 对接这一件事,就折腾了将近三周。
这篇文章想聊的就是这些实际踩过的坑。不是那种教科书式的“Autosar 架构介绍”,也不是“Simulink 入门教程”,而是当你真的要把一个 Simulink 模型塞进 Autosar 工程里时,会遇到的配置问题、代码生成问题、接口匹配问题、以及那些文档里不会写的细节。适合已经有基本 Simulink 使用经验、正在往 Autosar 方向转型的嵌入式工程师,也适合做域控制器应用层开发的同行参考。
核心关键词就三个:Autosar、Simulink、模型。围绕这三个词,我会把从模型架构设计到代码集成、从 ECUC 配置到 OS 任务映射的完整链路拆开来讲,每个环节都配上我实际用过的参数和配置方法。
2. 整体设计思路:为什么 Autosar 和 Simulink 的配合这么别扭
2.1 两套思维方式的根本冲突
Autosar 的核心思路是“标准化接口 + 分层解耦”。应用层软件组件(SWC)不直接碰硬件,所有通信通过 RTE(Runtime Environment)走,底层驱动由 BSW(Basic Software)统一管理。这套逻辑的好处是复用性强、换芯片不用重写应用层,但代价是配置复杂度极高,光一个 ECUC 模块的参数就能让人看花眼。
Simulink 的核心思路是“基于模型的设计(MBD)”,你在图形化界面里搭逻辑,仿真验证通过后自动生成 C 代码。它的优势是开发效率高、可视化强、早期就能做 MIL/SIL 测试。但 Simulink 默认生成的代码是“裸”的 C 函数,它不知道什么是 RTE、什么是 SWC、什么是 Runnable Entity。
这两套东西碰在一起,核心矛盾就一个:Simulink 生成的代码怎么变成 Autosar 能识别的 SWC 实现。解决这个矛盾的方式,就是通过 Embedded Coder 的 Autosar 目标支持包,让 Simulink 按照 Autosar 的规范来生成代码和 ARXML 描述文件。
2.2 工具链选型的几个关键决策
在实际项目中,工具链的选择直接决定了后面踩坑的数量。我整理了一个对比表,是我用过的几种方案:
| 方案 | 工具组合 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 方案A | Simulink + Embedded Coder + Autosar Blockset | 原生支持 ARXML 导出,SWC 描述自动生成 | 对 Simulink 版本要求高,R2020b 以下支持不完善 | 新建项目,应用层全用 Simulink 开发 |
| 方案B | Simulink + 手动编写 RTE 接口 | 灵活度高,不依赖特定工具箱 | 工作量大,容易出错,维护困难 | 小规模项目或已有大量手写代码 |
| 方案C | Simulink 生成代码 + 第三方 Autosar 工具链配置 | 可配合达芬奇等配置工具 | 工具间兼容性问题多,ARXML 导入导出容易丢信息 | 团队已有成熟 Autosar 工具链 |
我个人的建议是:如果是新项目,直接上方案A,用 Autosar Blockset 做 SWC 建模和 ARXML 导出。虽然前期学习曲线陡,但后面省事。如果是已有项目改造,方案C 更现实,但要做好 ARXML 反复导入导出的心理准备。
2.3 模型架构的分层原则
在 Autosar 框架下,Simulink 模型不应该是一个大杂烩。我的做法是严格按照 SWC 的粒度来拆分模型:
- 应用层 SWC 模型:纯逻辑,不含任何硬件相关代码,输入输出通过 RTE 端口
- 传感器/执行器 SWC 模型:包含信号预处理和后处理,但不直接操作寄存器
- 服务层 SWC 模型:如 NVM 管理、诊断服务等,通过标准 Autosar 接口调用 BSW
每个 SWC 对应一个独立的 Simulink 模型文件,通过模型引用(Model Reference)的方式组合。这样做的好处是代码生成时可以按 SWC 粒度分别生成,方便和 Autosar 工程做集成。
注意:不要把所有逻辑塞进一个模型里生成一个巨大的 C 文件,后期和 RTE 对接时会非常痛苦。按 SWC 拆分模型,每个模型生成的代码量控制在 2000 行以内比较合适。
3. 核心配置细节:从 Simulink 模型到 Autosar SWC
3.1 Autosar Blockset 的环境配置
第一步是把 Simulink 的 Autosar 支持包装好。在 MATLAB 的 Add-On Explorer 里搜索 “Autosar Blockset”,安装完成后还需要配置 Embedded Coder 的目标语言为 C(不是 C++),因为 Autosar Classic Platform 的标准接口都是 C 语言。
配置路径在 Simulink 的 Configuration Parameters 里:
- 打开Configuration Parameters(快捷键 Ctrl+E)
- 左侧选择Code Generation
- System target file选择
autosar.tlc - Language选择
C - Toolchain根据你的编译器选择,比如
GNU gcc或Tasking
这里有个坑:autosar.tlc这个 target file 只有在安装了 Autosar Blockset 之后才会出现。如果你在列表里找不到它,说明支持包没装好或者 license 不包含这个工具箱。
3.2 SWC 接口的建模方法
在 Simulink 里建 SWC 接口,核心是用Function-Call Subsystem和Simulink Function来定义 Runnable Entity。具体操作:
- 每个 Runnable 对应一个 Function-Call Subsystem,触发方式选择
Function-Call - 输入输出端口用Inport/Outport模块,然后在 Autosar 属性里映射为
SenderReceiverInterface或ClientServerInterface - 如果是 NVM 读写,用Data Store Memory配合 Autosar 的
NvDataInterface
我实际项目中的一个典型配置是这样的:一个车窗控制 SWC,包含三个 Runnable——Init、Run_10ms、Run_100ms。Init 在 ECU 启动时执行一次,Run_10ms 是周期任务,Run_100ms 处理慢速逻辑。每个 Runnable 在 Autosar 里对应一个RunnableEntity,通过SwcInternalBehavior描述。
3.3 ARXML 导出与 ECUC 配置对接
模型建好后,通过Code Generation生成代码和 ARXML。关键配置在Autosar选项卡里:
- XML Options:选择导出的 ARXML 版本,一般选
AUTOSAR_4.2.2或AUTOSAR_4.4.0,要和你的 Autosar 工具链版本匹配 - SWC Name:填写 SWC 的名称,比如
Swc_WindowControl - Component Type:选择
ApplicationSwComponentType
生成的 ARXML 文件包含了 SWC 的描述信息,包括端口、接口、Runnable、数据类型等。这个文件需要导入到 Autosar 配置工具(比如达芬奇 Configurator 或 EB Tresos)里,和 BSW 的 ECUC 配置做集成。
实操心得:ARXML 导入导出时最容易丢的是数据类型映射。Simulink 里的
uint8、uint16到了 Autosar 里需要映射为uint8、uint16的ImplementationDataType。如果映射不对,RTE 生成时会报类型不匹配的错误。建议在 Simulink 里就用 Autosar 标准数据类型(在 Autosar Blockset 的 Data Type 包里定义),不要用 Simulink 默认的double。
4. 代码生成与集成:那些让人抓狂的细节
4.1 代码生成配置的必改项
Simulink 默认的代码生成配置是针对通用嵌入式系统的,直接用来生成 Autosar 代码会有一堆问题。以下是我每次新建模型都会改的配置项:
| 配置项 | 默认值 | 建议值 | 原因 |
|---|---|---|---|
| System target file | grt.tlc | autosar.tlc | 必须用 Autosar 目标才能生成符合规范的代码 |
| Language | C++ | C | Autosar Classic 标准接口是 C |
| Generate reusable code | off | on | 多个 SWC 可能共用函数,开启复用减少代码量 |
| Code packaging | Modular | Compact | Compact 模式生成更少的文件,方便集成 |
| Mat-file logging | on | off | 量产代码不需要 mat 文件日志 |
| Infinite loop | on | off | Autosar 的 Runnable 不能有无限循环 |
还有一个容易忽略的:Code Generation > Interface > Advanced Parameters里的Single output/update function要勾上,这样每个 Runnable 只生成一个函数,方便和 RTE 的Rte_Runnable_xxx对接。
4.2 RTE 接口的匹配问题
Simulink 生成的代码里,Runnable 的函数名默认是模型名加子系统名,比如Swc_WindowControl_Run_10ms。但 Autosar RTE 生成的接口函数名是Rte_Runnable_Swc_WindowControl_Run_10ms。这两个名字对不上,链接就会报错。
解决方法有两种:
- 在 Simulink 的Autosar配置里,把 Runnable 的名称手动改成和 RTE 一致
- 在 RTE 配置里,把 Runnable 的名称改成和 Simulink 生成的一致
我一般用第一种,因为 Simulink 这边改起来更方便。具体在Code Generation > Autosar > Runnable里,把Runnable Name改成 RTE 期望的名称。
4.3 数据类型和端口的对齐
这是最容易出问题的地方。Simulink 里的信号线有数据类型,Autosar 的端口也有数据类型,两边必须严格对齐。我遇到过的情况:
- Simulink 里用了
boolean,Autosar 里定义的是boolean,但底层实现是uint8,导致 RTE 生成时类型不匹配 - Simulink 里用了
fixdt(1,16,2^-4)这种定点类型,Autosar 里没有对应的ImplementationDataType,需要手动创建 - 端口方向搞反了,Simulink 的 Inport 在 Autosar 里应该是
RequirePort,Outport 是ProvidePort
避坑技巧:在 Simulink 里建模时,所有信号线都显式指定数据类型,不要用
Inherit: auto。在 Autosar 配置工具里,先定义好所有的ImplementationDataType,再导入 Simulink 的 ARXML,这样类型映射的成功率最高。
4.4 代码集成到 Autosar 工程的步骤
代码生成后,集成到 Autosar 工程的流程大致如下:
- 把 Simulink 生成的
.c和.h文件拷贝到 Autosar 工程的src目录下 - 把生成的 ARXML 导入到 Autosar 配置工具,生成 SWC 描述
- 在 ECUC 配置里,把 SWC 的 Runnable 映射到 OS Task
- 配置 RTE,生成 RTE 代码
- 编译整个工程,解决链接错误
第3步的 OS Task 映射是个关键点。Autosar OS 的任务周期和 Simulink 里 Runnable 的采样周期必须一致。比如 Simulink 里Run_10ms的采样周期是 0.01s,那 OS Task 的周期也必须是 10ms。如果对不上,要么逻辑执行频率不对,要么 RTE 报错。
5. 常见问题与排查技巧实录
5.1 代码生成报错:找不到 autosar.tlc
这个错误通常出现在刚装好 Autosar Blockset 但没配置好的时候。排查步骤:
- 确认 MATLAB 版本是否支持 Autosar Blockset(R2018b 以上)
- 在 MATLAB 命令行输入
ver查看已安装的工具箱列表,确认 Autosar Blockset 在列 - 输入
which autosar.tlc查看文件路径,如果返回空,说明路径没配好 - 检查 license 是否包含 Autosar Blockset
5.2 ARXML 导入后端口丢失
这个问题我遇到过好几次,原因是 Simulink 里的端口没有正确映射为 Autosar 接口。检查方法:
- 在 Simulink 里选中 Inport/Outport 模块,打开Block Parameters
- 确认Autosar选项卡里的
Port Name和Interface已经填写 - 如果
Interface为空,需要先在 Autosar 字典里定义SenderReceiverInterface
5.3 RTE 生成报错:Runnable 未映射到 Task
这个错误说明 ECUC 配置里漏了 Runnable 到 Task 的映射。在达芬奇或 EB Tresos 里:
- 找到
EcuC模块下的EcucPartition - 在
SwcInternalBehavior里找到对应的RunnableEntity - 把
RunnableEntity的CanBeInvokedConcurrently设为false(除非确实需要并发) - 在
OsTask配置里,把 Runnable 添加到 Task 的Activation列表
5.4 编译链接报错:undefined reference to Rte_xxx
这是典型的接口不匹配问题。排查思路:
- 检查 Simulink 生成的函数名和 RTE 生成的函数名是否一致
- 检查头文件包含路径是否正确
- 检查 RTE 的
Rte_xxx.h是否被正确包含在 Simulink 生成的代码里
我整理了一个常见问题速查表:
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| 代码生成报错 autosar.tlc 找不到 | 工具箱未安装或路径未配置 | 重装 Autosar Blockset,检查 license |
| ARXML 导入后端口丢失 | 端口未映射为 Autosar 接口 | 在 Simulink 里配置 Port 的 Autosar 属性 |
| RTE 报 Runnable 未映射 | ECUC 配置缺少 Task 映射 | 在 OS 配置里添加 Runnable 到 Task |
| 链接报 undefined reference | 函数名不匹配 | 统一 Simulink 和 RTE 的 Runnable 命名 |
| 数据类型不匹配 | Simulink 用了非标准类型 | 用 Autosar 标准数据类型建模 |
| 任务周期不对 | OS Task 周期和 Runnable 采样周期不一致 | 对齐两者的周期参数 |
5.5 实操心得:版本兼容性是最大的坑
我踩过最深的坑是 MATLAB 版本和 Autosar 工具链版本的兼容性。MATLAB R2020b 的 Autosar Blockset 导出的 ARXML 是 4.4.0 版本,但项目用的达芬奇 Configurator 只支持到 4.2.2,导入时直接报版本不兼容。后来是把 MATLAB 降到 R2019b 才解决。
所以我的建议是:在项目启动前,先确认 MATLAB 版本、Autosar Blockset 版本、Autosar 配置工具版本、目标芯片的 MCAL 版本,这四个版本的兼容性。不要等到模型都建好了才发现导出的 ARXML 用不了。
6. 模型仿真与测试:MIL/SIL/PIL 的落地方法
6.1 MIL 仿真:在 Simulink 里验证逻辑
MIL(Model-in-the-Loop)是最基础的验证方式,就是在 Simulink 里直接跑模型,用 Signal Builder 或 From Workspace 模块给输入激励,用 Scope 观察输出。这个阶段不需要考虑 Autosar 的任何东西,纯粹验证逻辑正确性。
我的习惯是每个 SWC 模型都配一个独立的测试 harness,用Signal Editor模块定义测试用例。测试用例覆盖正常工况、边界条件和异常工况。比如车窗控制的模型,测试用例包括:正常上升、正常下降、防夹触发、堵转保护、开关抖动等。
6.2 SIL 仿真:验证生成代码的正确性
SIL(Software-in-the-Loop)是把 Simulink 生成的 C 代码编译成可执行文件,在 PC 上跑,和 Simulink 的仿真结果做对比。这个阶段能发现代码生成引入的问题,比如定点运算的精度损失、代码优化的副作用等。
配置 SIL 的步骤:
- 在 Configuration Parameters 里,把Code Generation > Verification > SIL打开
- 选择Create SIL block,Simulink 会自动生成一个 SIL 模块替换原来的模型
- 运行仿真,对比 SIL 输出和 MIL 输出
注意:SIL 仿真时,如果模型里用了 Autosar 的 NVM 接口或服务接口,需要提供 stub 实现,否则编译会报错。我一般用
#ifdef SIL_TEST宏来隔离这些硬件相关代码。
6.3 PIL 仿真:在目标硬件上验证
PIL(Processor-in-the-Loop)是把生成的代码下载到目标芯片上跑,通过串口或 CAN 和 Simulink 通信,做实时验证。这个阶段能发现编译器差异、芯片特性导致的问题。
PIL 的配置比 SIL 复杂,需要:
- 目标板的调试接口(JTAG/SWD)
- 通信接口(串口或 CAN)
- Simulink 的 PIL 支持包(比如 TI C2000 或 STM32 的 PIL 支持包)
我实际项目里,PIL 主要用于验证浮点运算和中断响应的实时性。如果 PIL 结果和 SIL 结果差异大,通常是编译器优化等级或者芯片的 FPU 配置问题。
6.4 测试覆盖率与代码质量
Autosar 项目对代码质量要求高,通常需要做代码覆盖率分析。Simulink 的Simulink Coverage工具可以做模型覆盖率分析,包括:
- Decision Coverage:判断分支是否都覆盖到
- Condition Coverage:条件表达式的每个子条件是否都覆盖到
- MCDC:修正条件判定覆盖,汽车行业常用
覆盖率目标一般是 100% Decision Coverage 和 100% MCDC。如果达不到,需要补充测试用例。我通常会在模型里加一些Test Point模块,方便观察内部信号。
7. 进阶话题:多模型集成与 J1939 通信
7.1 多 SWC 模型的集成策略
一个 ECU 里通常有多个 SWC,每个 SWC 对应一个 Simulink 模型。集成方式有两种:
- 模型引用(Model Reference):一个主模型引用多个子模型,代码生成时分别生成每个子模型的代码
- 子系统(Subsystem):所有逻辑在一个模型里,用子系统划分
我推荐用模型引用,因为:
- 每个 SWC 可以独立开发和测试
- 代码生成时可以按 SWC 粒度生成,方便和 Autosar 工程集成
- 模型引用支持增量编译,改一个 SWC 不用重新生成所有代码
7.2 J1939 通信的模型实现
J1939 是商用车常用的 CAN 通信协议,在 Autosar 里通过CanIf、PduR、Com模块实现。在 Simulink 里,可以用CAN Pack/Unpack模块处理 J1939 报文,或者用 Autosar Blockset 的SenderReceiverInterface直接映射到 J1939 的 PGN。
我做过的一个项目里,J1939 报文的发送周期是 100ms,接收是事件触发。在 Simulink 里,发送用Function-Call Subsystem触发,接收用Simulink Function处理。关键是要把 J1939 的 PGN 和 SPN 映射到 Autosar 的ISignal和IPdu。
实操心得:J1939 的报文长度可能超过 8 字节,需要用到传输协议(TP)。Simulink 里处理 TP 比较麻烦,建议在 BSW 层用
CanTp模块处理,应用层只处理完整的 PGN 数据。
7.3 NVM 数据管理的模型实现
Autosar 的 NVM 模块负责非易失性数据的存储和读取。在 Simulink 里,通过NvDataInterface定义 NVM 数据块,通过ServicePort调用 NVM 服务。
配置步骤:
- 在 Autosar 字典里定义
NvDataInterface,指定数据块的大小和默认值 - 在 Simulink 模型里用
Data Store Memory模块映射到 NVM 数据块 - 在 ECUC 配置里,配置
NvMBlockDescriptor,指定存储位置和读写周期
NVM 读写在模型里通常是异步的,需要处理NvM_ReadBlock和NvM_WriteBlock的返回状态。我一般用一个状态机来管理 NVM 操作,避免在 Runnable 里阻塞等待。
8. 工具链协同:达芬奇配置与 Simulink 的配合
8.1 达芬奇 Configurator 的 ECUC 配置要点
达芬奇是国内常用的 Autosar 配置工具,ECUC 配置是它的核心功能。和 Simulink 配合时,重点配置以下几个模块:
- EcuC:定义 ECU 的总体配置,包括分区、时钟、内存映射
- Os:定义 Task、Alarm、Event,和 Simulink 的 Runnable 映射
- Rte:定义 RTE 的生成选项,包括端口、接口、Runnable 映射
- Com:定义通信矩阵,和 Simulink 的端口映射
- NvM:定义 NVM 数据块,和 Simulink 的 NVM 接口映射
8.2 ARXML 的导入导出流程
Simulink 生成的 ARXML 需要导入到达芬奇里,流程如下:
- 在达芬奇里新建一个工程,选择对应的 Autosar 版本
- 导入 BSW 的 ARXML(通常由芯片厂商提供)
- 导入 Simulink 生成的 SWC ARXML
- 在 ECUC 配置里,把 SWC 的端口和 BSW 的端口做连接
- 生成 RTE 代码和 OS 配置代码
导入时最常见的问题是命名冲突。Simulink 生成的 SWC 名称如果和已有的 SWC 重名,导入会失败。解决方法是在 Simulink 里给 SWC 加项目前缀,比如PrjA_Swc_WindowControl。
8.3 版本管理与团队协作
Autosar 项目的 ARXML 文件通常很大,用 Git 管理时容易冲突。我的做法是:
- ARXML 文件按模块拆分,每个 SWC 一个文件
- 用
.gitattributes配置 ARXML 的 diff 策略 - 定期做 ARXML 的合并和校验
团队协作时,Simulink 模型和 ARXML 的版本要同步。我一般用 Git LFS 管理.slx文件,用普通 Git 管理.arxml文件。
9. 我个人的经验总结与建议
写了这么多,最后分享几个我在实际项目中总结出来的经验,都是踩坑换来的:
第一,不要试图在 Simulink 里做所有事。Autosar 的分层架构是有道理的,应用层逻辑用 Simulink 建模,底层驱动和通信栈用 BSW 配置,各司其职。我见过有人试图在 Simulink 里直接操作 CAN 寄存器,结果代码生成后完全跑不通。
第二,数据类型一定要从源头统一。在项目启动时,先定义好所有的ImplementationDataType,然后在 Simulink 里用这些类型建模。不要等到代码生成时才去映射类型,那时候改起来工作量巨大。
第三,版本兼容性检查要前置。MATLAB 版本、Autosar Blockset 版本、配置工具版本、MCAL 版本,这四个的兼容性矩阵一定要在项目启动前确认。我吃过亏,MATLAB R2020b 导出的 ARXML 在达芬奇 4.2.2 里导入失败,最后只能降版本。
第四,测试要趁早。MIL 测试在模型建好后马上做,SIL 测试在代码生成后做,PIL 测试在硬件可用后做。不要等到集成阶段才发现逻辑错误,那时候排查成本高十倍。
第五,ARXML 要当代码一样管理。每次修改都提交 Git,写清楚修改内容。ARXML 的冲突解决比 C 代码麻烦得多,好的版本管理习惯能省很多时间。
这个领域的内容还有很多可以展开,比如多核 ECU 的 SWC 分区、功能安全相关的模型配置、AUTOSAR Adaptive 和 Simulink 的配合等。后面有机会再单独写。如果你也在做类似的项目,欢迎交流踩坑经验。