
很多人一提到AutoSar架构第一个反应就是Configurator工具里那一大堆ECUC参数或者是生成出来的一堆.c和.h文件。我刚开始啃这块时也是这个状态打开DaVinci Configurator每个标签页里几十个参数看过就忘完全不知道自己到底在配什么。学了一阵子之后我才意识到真正难住的不是“某一个参数填什么”而是把整条链路想明白一个信号从应用层发到总线上要经过哪些模块掉电之后数据为什么还能保持控制器之间是怎么一起醒、一起睡的。这篇笔记就是我梳理AutoSar架构核心链路的过程适合刚接触车载软件、被各种模块缩写绕晕的同行。1. 先搞明白AUTOSAR到底解决了什么问题1.1 没有AUTOSAR的年代ECU软件长什么样在讲架构之前先聊一段背景。早期ECU软件开发基本上是“一个项目一套代码”。应用逻辑、硬件寄存器操作、CAN收发逻辑、存储逻辑全搅在一起。换一颗MCU整个底层驱动重写换一个传感器应用层也得跟着改。硬件平台和软件功能高度耦合导致项目之间没法复用工程师的精力大量耗在“移植”而不是“功能”上。AUTOSAR就是在这个背景下出现的。它把ECU的软件按层次拆开制定标准接口让应用层和底层硬件隔离。这样换MCU时应用层几乎不动换应用功能时底层驱动也几乎不动。我学习的时候最直观的感受是AUTOSAR本质上是在给ECU软件“划地盘、定规矩”。每个模块有明确的职责边界模块之间只能通过标准API通信不能像以前那样想调谁就调谁。1.2 分层、标准化、方法论三件事一起理解AUTOSAR标准其实包含三块东西分层架构把软件分成应用层、RTE、BSW三层每层再细分模块。接口标准化规定每个模块对外提供的服务函数比如NvM_WriteBlock、Com_SendSignal不同供应商实现不同但接口长一样。方法论定义了开发过程中的输入输出文件主要是arxml格式的模型文件以及从系统级到ECU级的下探流程。这三件事必须放在一起看。只学分层不理解接口你无法看懂模块之间的调用关系只看接口不理解方法论你又不知道为什么需要那么多arxml文件。大多数培训资料会把重点放在“分层”上但我个人经验是“分层”和“方法论”必须同步建立。没有方法论的概念你在DaVinci Configurator里导入导出arxml时会一头雾水搞不清楚为什么一个SWC的接口改了还要跑到ECU配置里重新做映射。1.3 我的学习主线不管什么模块先抓住“链路”学AUTOSAR最容易犯的错就是按模块一个一个去学。今天查一下Com模块的参数明天看一下PduR的路由表后天翻NvM的状态机。结果学完就忘因为模块之间是强耦合的单独背参数等于记零散的单词没有句子。后来我换了个思路先找链路再找模块。比如一个CAN报文发出去链路是什么一个标定值要存到Flash掉电不丢链路是什么整车休眠时所有ECU怎么协同进入低功耗链路是什么把一条链路走通了链路里涉及哪些模块自然就记住了。这也是这篇笔记后续几章的安排逻辑先讲架构分层再把通信、网络管理、存储、安全四条主线拆开最后回到配置工具实操。2. AutoSar架构分层拆解从SWC到MCAL的每层职责2.1 三层架构Application、RTE、BSWAUTOSAR把ECU软件分成三大层由下往上分别是BSWBasic Software基础软件层再往下细分MCAL驱动、ECU抽象、服务层。RTERuntime Environment运行时环境连接应用层和BSW的桥梁。Application Layer应用层由若干个SWCSoftware Component软件组件组成你的具体功能逻辑都在这层。BSW内部又分几层。直接接触寄存器的叫MCAL比如Can Driver、Lin Driver、Spi Driver、Gpt Driver。MCAL往上是ECU抽象层像CanIfCAN接口、WdgIf看门狗接口、Eep、Fee它们把MCAL的不同实现抽象成统一接口。再往上是服务层包括通信服务Com、PduR、CanSM、存储服务NvM、诊断服务Dcm、Dem、模式管理EcuM、BswM等。这三层的关系可以用盖楼来理解。应用层是住在楼里的人RTE是电梯和走廊BSW是水电、消防、网络管线。住户不需要知道水管具体怎么走只需要一个水龙头应用层也不需要知道CAN控制器的寄存器怎么配只需要调用RTE接口。2.2 RTE不是简单的“函数搬运工”很多人把RTE理解成“把接口映射到函数的一层”这样说对了一半。它确实承担了接口映射但更重要的是它实现了组件间通信模式。SWC和SWC之间不能直接调用对方代码必须通过RTE。RTE支持两种基本通信模式Sender-Receiver发送-接收一个组件发送数据一个或多个组件接收比如车速信号。Client-Server客户端-服务器一个组件调用另一个组件的服务比如请求诊断故障码。除了通信模式RTE还管理Runnable的触发。SWC内部的功能逻辑被打包成若干个Runnable这些Runnable由RTE按照配置的事件来调度比如周期事件、数据接收事件、操作调用事件。这里有个很重要的实操点RTE生成出来的代码是“工具产物”不是“项目资产”。你改SWC的内部行为要去改arxml模型然后在Configurator里重新生成RTE而不是直接编辑生成的rte_c.c。很多人第一次吃这个亏手工改了生成代码一重新生成全部被覆盖改了个寂寞。2.3 从“裸跑代码”到“标准ECU软件”BSW服务层的价值BSW的服务层是AUTOSAR里信息量最大的区域也是配置工具里参数最多的区域。每个服务模块都有自己的状态机、参数集和接口。以通信为例底层是Can Driver它只管把数据塞进CAN控制器寄存器、触发发送和接收中断。但一个应用要去发不同ID、不同周期的报文不能直接操作驱动层中间要经过CanIf做缓冲和回调再往上经过PduR做路由最后由Com模块把信号打包成PDU。服务层的存在本质上是为了解耦。比如PduR这个模块它是PDU的路由中心。诊断报文可以走Dcm到PduR应用报文可以走Com到PduR网络管理报文可以走CanSM到PduRPduR再统一分发到CanIf。没有PduR每个模块都得直接感知底层通道的细节整个软件就会变成一团乱麻。所以学习BSW服务层时不要按模块孤立理解要按数据流向去理解。后面几章的四条主线其实就是BSW服务层最核心的几套“流”。3. 通信、网络管理、存储、安全四条链路是架构的筋3.1 通信链路一个信号是如何走上总线的先看最常用的一条链路。应用层SWC里有一个Runnable周期执行比如每10ms读取某个传感器值想把它发到CAN总线上。从Runnable调用Rte_Write开始RTE会把值写进Com模块对应的信号缓存区。Com模块再按照配置的PDU结构把多个信号打包进一个CAN报文的数据场。打包好之后调用PduRPduR根据路由表找到这条PDU的底层通道调用CanIf。CanIf再往下交给Can DriverCan Driver把数据写入CAN控制器的发送邮箱设置发送请求寄存器最后硬件把帧发到总线上。收报文是反过来的链路Can Driver接收中断收到一帧CanIf收到数据PduR路由Com模块按照PDU布局拆出信号RTE把信号更新到SWC的接收端口最终Runnable读到最新值。这整条链路里有一个极容易出问题的地方是信号布局。在Com模块配置里每个信号的位置要给出起始位和长度并且要跟通信矩阵通常来自DBC或ARXML完全一致。起始位配错一位接收方解出来的值就是乱的。这类问题用总线分析仪抓包其实很好查看ID、周期都对就是数据跟预期完全对不上十有八九是信号起始位或字节序配置错了。链路位置模块主要职责应用层SWC Runnable产生/消费数据调用Rte接口基础设施RTE端口映射、数据缓存、Runnable调度通信服务Com信号打包/解包、PDU周期控制路由服务PduRPDU在模块之间路由分发接口抽象CanIf统一CAN收发接口管理硬件句柄驱动Can Driver操作CAN控制器寄存器中断收发3.2 网络管理链路ECU如何一起醒、一起睡整车上有几十个ECU如果每个ECU独立决定休眠就会出现一个问题一个节点想睡了但其他节点还在收发报文休眠和唤醒不同步总线状态就会混乱。AUTOSAR网络管理CanNM/NM解决的是这个问题。网络管理模块有一套状态机最核心的几个状态是Bus-Sleep Mode总线休眠节点不参与通信。Prepare Bus-Sleep Mode准备休眠的过渡状态重复发送NM报文请求大家都睡觉。Normal Mode正常运行收发常规应用报文。Ready Sleep Mode等待睡眠状态已经没有通信需求等待总线进入准备睡眠。节点有通信需求时进入Normal模式通过NM报文向整个网络宣告自己还活着。当所有节点都没有需求且持续一段时间没有收到其他节点的NM报文大家会协商一致进入休眠。实际项目中最常遇到的问题是节点睡不下去。排查思路一般是先看它是否还在持续请求通信比如某条周期报文没有停发再看网络管理状态机当前停在哪个状态抓到NM报文看看有没有节点在拉着总线不睡。这种情况常常不是软件缺陷而是某个应用层的“通信需求标志”没有被清除。3.3 NvM存储链路掉电之后数据为什么还在AUTOSAR里负责数据存储的是NvM模块。它的完整链路是应用层SWC通过RTE的NvData端口或者同步/异步接口发起对某块数据的读写请求RTE映射到NvM模块的API。NvM是存储服务层的总管家它管理多个数据块负责调度读写、校验、冗余存储。NvM下面通过MemIf接口层把读写请求分发到Fee或Eep。Fee叫Flash EEPROM Emulation意思是“用Flash模拟EEPROM”。因为Flash不能单字节擦写、有擦写寿命限制所以Fee要做扇区管理、写均衡、垃圾回收这一套逻辑。当MCU本身没挂外部EEPROM时多数项目走的就是NvM-MemIf-Fee-Flash底层驱动这条线。这条链路有一个非常经典的坑NvM块的大小、CRC、状态位配置不一致会导致调用NvM_WriteBlock之后数据看起来写进去了但掉电再上电读出来就变成默认值。我排查这种问题时会先确认NvM块在配置工具里的大小是否跟实际结构体一致再确认校验算法和校验位宽是否匹配。有时候应用层数组加了一个元素NvM块大小忘了同步就会出现读出来的数据被截断。3.4 诊断与安全28服务、SecOC的定位诊断这条链路跟通信、存储都有关联。最常见的一个诊断服务是28服务CommunicationControl它用来控制ECU的通信行为比如禁止发送、禁止接收、只收不发等。整车下线、产线测试、售后刷写时经常用这个服务。28服务本身不是一个独立模块它由Dcm模块诊断通信管理实现但执行效果要对接到Com、CanSM、PduR这些模块。比如Tester发送请求禁止某个节点发报文Dcm会调用CanSM的接口把对应通道的通信关掉。配置28服务时要特别注意Dcm里的服务使能以及它控制的通信类型范围没配好会出现“明明回复了响应但报文还是发不出去”的奇怪现象。SecOC则负责通信安全。它给特定的PDU加上认证信息发送方对PDU数据计算MAC消息认证码并附带新鲜度值接收方验证MAC。这样一来总线上的恶意节点想伪造报文就很困难。SecOC的配置链路涉及CSM加密服务管理、KeyM密钥管理和SecOC实体本身而且对硬件能力有要求如果MCU没有硬件加解密引擎纯软件算MAC会带来不小的时间开销实测中可能导致原有报文周期抖动这个在选型阶段就要考虑。4. DaVinci Configurator配置SWC接口的实操记录与RTE避坑4.1 配置前的准备区分Developer和Configurator的职责做AUTOSAR开发最常用的一套工具链就是Vector的DaVinci系列。DaVinci Developer负责应用层设计主要是SWC、端口、接口、Runnable这些内容输出的是应用层的arxml模型文件。DaVinci Configurator负责ECU基础软件配置也就是ECUC相关的参数比如Com、NvM、CanIf、RTE这些模块的配置。我之前一直把这两个工具混在一起用后来才搞明白Developer管的是“应用层的骨架”Configurator管的是“ECU整体怎么跑起来”。两者的交集点就是RTEDeveloper生成的接口信息导入Configurator之后Configurator才能生成对应的RTE代码。实际操作里最容易乱套的场景是同一个SWC既要输入又要输出接口改了属性比如从Data改成NvData但Configurator里对应的Data Mapping没有重新映射导致RTE生成时不知道这个端口到底要跟哪个NvM块绑定。4.2 从端口定义到RTE生成的五个步骤我在DaVinci Configurator里配置一个典型SWC接口大致走这五个步骤第一步在Developer里创建SWC并定义端口。先确定这个SWC是数据生产者还是消费者或者既是生产者又是消费者。根据数据类型创建Sender-Receiver接口或Client-Server接口。比如一个车速计算SWC它要发车速给仪表模块那就定义一个发送端口数据元素的数据类型选好长度和字节序。第二步定义内部行为添加Runnable。在SWC的内部行为里创建Runnable并绑定触发事件。周期型Runnable绑定TimingEvent数据接收型Runnable绑定DataReceivedEvent。这一步容易被忽略的是触发事件的周期单位配置成10ms还是10s差别巨大。第三步导出应用层arxml导入Configurator。在Developer中完成设计后把arxml文件导出来在Configurator中导入。Configurator会解析SWC的端口信息把RTE相关模块的配置项自动带出来。第四步做端口与模块的映射。这是最容易出问题的一步。发送端口要映射到Com模块的某个信号或PDUNvData端口要映射到NvM块Client端口要映射到对应服务模块的API。如果映射漏了RTE生成时不会报错但运行时数据根本不会走到目标模块。第五步生成RTE并编译验证。配置完成后在Configurator里触发RTE生成。生成的代码里会有rte_c.h等文件本地编译后烧录到板子上看数据流。这一步如果报错大部分原因都出在前两步的接口定义或类型不匹配上。4.3 我踩过的RTE坑与排查思路坑一生成的RTE代码被手工修改。有次调试我为了临时加一个打印直接在生成的RTE源文件里改了一行。后来重新生成RTE改的内容全部消失我还以为是工具bug折腾了半天才发现是自己动了不该动的文件。从那之后我定了个规矩生成的RTE代码永远只读所有逻辑改动全部回到arxml模型里改。坑二Exclusive Area用错了地方。AUTOSAR提供了Exclusive Area来解决数据竞争问题。两个Runnable如果共享同一个全局变量且可能被中断或不同任务打断RTE会通过调度机制来保证互斥访问。但Exclusive Area不是万能的它只能保证RTE层面调度的互斥不能解决所有并发问题。我遇到过一次一个Runnable里操作外部变量的时候被另一个Runnable改了值配置了Exclusive Area之后查代码才发现变量根本不是走RTE接口访问的Exclusive Area压根没生效。正确的做法是让共享数据通过RTE端口或专门的protection hook来访问。坑三跨核通信配置没确认。多核MCU上SWC可以运行在不同核RTE会用跨核通信机制IOC来搬运数据。但这个通信是异步的数据可能不是实时同步。我碰到过一次一个核写入数据另一个核读数据总是读到旧值最后发现跨核通信缓冲配置成了单缓冲需要改成多缓冲才拿到最新数据。多核场景下除了配置还要关注数据一致性问题这种问题在台架上往往复现不出来一上车就偶发。5. 给后来者的学习路线与自检清单5.1 学习顺序怎么安排比较顺我的建议是倒着学先从最上层的概念入手别碰工具也别碰参数。先搞懂SWC、RTE、BSW分别是什么然后选一条通信链路从应用层Runnable出发追踪再到Can Driver最后再打开工具动手配置。最忌讳的就是一开始就抱着SWS的PDF从头翻到尾或者在Configurator里无目的地点参数。AUTOSAR规范文档最适合当“字典”用出问题时再去查而不是当小说看。如果项目里有Simulink可以先看一下Simulink的AUTOSAR支持功能。它可以把Simulink模型导出成SWC的arxml描述间接让你理解模型和AUTOSAR元素之间的对应关系。5.2 排查问题的通用套路我在实际调试中总结了一套排查流程先把现象定位到链路层级是应用层没调用RTE接口还是RTE之后的数据没到Com还是总线上根本就没发出来。用调试器在RTE生成的代码里下断点确认SWC里调用的写接口确实执行了。抓总线看报文确认Com层确实在按周期发帧。对比配置工具里的信号布局和通信矩阵排除定义错误。最后才怀疑模块内部实现。这个顺序看着简单但实际情况中很容易跳过第二步直接怀疑配置。很多所谓“软件bug”最后发现是应用层根本没往RTE写或者已经写了但周期没跑起来。5.3 自检清单学习了一个阶段之后我建议拿这几个问题来自检一下能不能在纸上画出“CAN发送链路”和“CAN接收链路”的完整模块顺序。能不能讲清楚NvM为什么要通过Fee访问Flash直接写Flash行不行。能不能解释网络管理里“所有节点都不发NM报文”和“总线休眠成功”之间的关系。能不能说清RTE生成代码为什么要作为只读产物。能不能理解ECUC参数在工具里到底描述了什么而不是只会对着教程点下一步。这些问题如果都能答上来AutoSar架构的骨架基本就搭起来了。剩下的就是项目里反复踩坑把每个模块的细节点补全。我自己的体会是学AutoSar最佳的方式还是“带问题学”。不要追求把标准全覆盖而是抓住手头项目里那条最常用的链路往深处挖一遍。挖完一条再挖第二条。等几条主线都在脑子里成型了模块间的信息自然就织成网了。