ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AUTOSAR BSW开发实战指南:S32K312从启动到CAN通信贯通

AUTOSAR BSW开发实战指南:S32K312从启动到CAN通信贯通 1. 这不是一份普通笔记而是一份能让你在BSW开发现场站稳脚跟的实战地图“Autosar BSW 开发笔记目录”——看到这个标题别急着划走。如果你正坐在某家 Tier 1 的工位上面对 S32K312 芯片上密密麻麻的 ECUC 配置项发呆如果你刚从 MATLAB Simulink 生成完应用层代码却卡在 OS 任务调度不起来、CAN 报文死活发不出去、NVM 数据一重启就消失的环节如果你在达芬奇DaVinci配置工具里反复点击“Generate Code”生成的 .c 文件里全是看不懂的宏定义和嵌套结构体连 main() 函数都找不到在哪被调用……那么这份笔记的目录就是你此刻最需要的导航图。它不是教科书式的理论罗列也不是视频教程里“点这里→点那里→成功”的幻灯片式演示。它是我过去五年在三个量产项目一个车身域控制器、两个动力域 ECU中亲手踩过坑、改过 Bug、熬过夜、被客户现场拉出来背锅后把散落在 Jira 工单、内部 Wiki、调试日志、甚至手写草稿本上的碎片信息一条条捋顺、验证、归类后沉淀下来的结构化路径。关键词Autosar、BSW、开发笔记这三个词背后的真实含义是一套强制性的、高度抽象的、跨厂商的汽车软件架构标准一套由数百个模块组成的、必须严格遵循 AUTOSAR 规范的底层支撑软件以及一份只属于你自己的、带着温度与血泪的操作手记。这份目录之所以重要是因为它直接对应你在真实开发中每天要面对的“问题域”。比如“autosar j1939”不是单纯讲协议栈而是告诉你如何让 J1939 TP 层正确绑定到 CAN 通道、如何配置 PGN 的传输周期与优先级、为什么你的诊断请求总被网关丢弃“s32k312 autosar 基础软件包”不是罗列文件夹而是拆解 NXP 官方 BSP 中哪些是可裁剪的、哪些是强依赖的、哪些头文件必须在编译时显式包含“autosar nvm”更不是背诵 NvMManager 的状态机而是教你如何设计一个安全可靠的擦写策略避免 ECU 在写入过程中掉电导致整个 Flash 区域锁死。它面向的是已经具备 C 语言基础、了解基本 CAN/LIN 通信原理、但对 AUTOSAR 分层模型仍感模糊的工程师——可能是刚转岗的嵌入式开发也可能是被临时抽调支援 AUTOSAR 项目的测试或系统工程师。接下来的内容每一节都源自真实战场每一段配置都经过实车验证每一个避坑提示都来自凌晨三点的调试台。2. 内容整体设计与思路拆解为什么是这个结构而不是别的2.1 不按 AUTOSAR 标准文档顺序而按开发者实际工作流组织AUTOSAR 官方规范文档如 SWS_NvM、SWS_ComM动辄几百页按模块功能划分逻辑严密但极度反人类。一个新人拿到文档第一反应往往是“我该从哪一页开始看看完 ComM 模块下一步是看 PduR 还是 CanIf”这种线性阅读方式在真实项目中效率极低。我们真正的工作流是先确定芯片平台S32K312再选型基础软件包Vector DaVinci 或 ETAS ISOLAR接着配置操作系统Autosar OS然后打通通信链路CanIf → CanTp → Com → ComM最后处理数据持久化NvM → Fee → Fls。这是一个自底向上、由硬件驱动、以功能交付为目标的闭环过程。因此本笔记目录完全抛弃了标准文档的章节顺序转而采用“芯片→工具→OS→通信→存储→诊断→网络管理→集成验证”的工程主干道。例如“autosar os”模块不放在“基础软件服务”大类下泛泛而谈而是紧接在“S32K312 芯片启动流程解析”之后因为只有理解了 S32K312 的 BootROM 如何跳转到 Startup.s才能明白 OS 的 StartOS() 是如何被触发的也只有清楚芯片的中断向量表布局才能正确配置 OS 的 ISR 绑定。2.2 每个模块聚焦“三件事”配置入口、关键参数、实车验证现象很多资料讲 AUTOSAR容易陷入两种极端一种是堆砌术语比如“ComM 提供通信模式管理服务支持 NO_COMMUNICATION、FULL_COMMUNICATION 等状态”说完就结束另一种是过度深入源码逐行分析 Vector 的 ComM.c 实现。这两种对一线开发帮助都很小。本笔记坚持“三件事”原则第一明确告诉你这个模块的配置入口在哪——是在 DaVinci Configurator 的哪个树节点下ECUC 配置文件.arxml里对应哪个容器Container第二提炼出该模块最关键的 3~5 个参数并解释其物理意义与取值陷阱。例如 Autosar OS 的OSAPPLICATION配置很多人只填名字却忽略OSAPPLICATION_ACCESSING字段必须勾选TRUSTED否则所有系统调用都会返回E_OS_ACCESS错误又如 NvM 的NVM_BLOCK_DATASET若设置为1意味着该 Block 支持多副本备份但若未同步配置 Fee 的FEE_NUMBER_OF_SECTORS会导致擦写失败。第三记录该配置在实车环境中的可观测现象。比如将 CanIf 的CanIfPublicSetBaudrateApi设置为TRUE后你能在 CANoe 的 Trace 窗口中看到CanIf_SetBaudrateAPI 被调用的日志而将 ComM 的ComMChannelModeIndication回调函数里加一句DEBUG_LED_TOGGLE()就能用示波器抓到通信唤醒瞬间的 LED 闪烁波形。这种“配置→参数→现象”的三角验证是快速定位问题的核心能力。2.3 主动规避“理论正确但工程失效”的陷阱AUTOSAR 标准本身存在大量“可选实现”Optional Implementation和“厂商扩展”Vendor Extension。比如 AUTOSAR 4.3 规范中NvM 模块理论上支持异步写入NvMWriteBlock返回E_NOT_OK后由后台任务重试但 Vector 的实现默认关闭此功能必须手动开启NVM_JOB_END_NOTIFICATION并注册回调。再比如J1939 协议栈要求支持 Transport ProtocolTP分包但某些基础软件包对 TP 的最大帧数MaxFrames硬编码为 8当你的 PGN 数据长度超过 64 字节时发送必然失败而错误码却显示为J1939_E_TIMEOUT极易误导排查方向。本笔记目录中专门设置了“厂商差异与兼容性”子节不是泛泛而谈“不同厂商有差异”而是精确到Vector DaVinci 7.0.0 对 J1939 TP 的 MaxFrames 限制为 8ETAS ISOLAR-A 2022.0 对 S32K312 的 Flash 驱动不支持 Quad SPI 模式必须降级为 Dual SPINXP S32DS IDE 自带的 MCAL 驱动中Can_Ipw_Init()函数在初始化 CAN FD 时会自动关闭 CAN 传统模式若未在配置中显式启用CAN_FD_ENABLE则 CAN 通信完全静默。这些细节官方文档不会写培训课件不会讲只有在产线上被 Bug 追着打过的人才刻骨铭心。2.4 将“达芬奇配置autosar”转化为可复现的原子操作步骤“达芬奇配置autosar”是热搜词但搜索结果大多是界面截图和模糊描述。本笔记将其拆解为 12 个不可跳过的原子步骤每个步骤都附带“为什么必须这么做”的底层逻辑。例如第 4 步“导入 MCAL 配置包.arxml”很多人直接拖入 DaVinci点击 Generate结果报错ECUC-0001: Container Can not found in module Can。原因在于MCAL 配置包中的Can容器名必须与 DaVinci 工程中引用的Can模块名完全一致而 NXP 提供的 MCAL 包默认使用Can_0作为容器名但 DaVinci 新建工程时默认创建的是Can。解决方案不是改 MCAL 包违反供应商约定而是进入 DaVinci 的 “Project Settings → Module Configuration → Can” 中将 Module Name 手动修改为Can_0。再比如第 7 步“配置 OS Application 与 Trusted Function”必须确保OsApplication的OsApplicationAccessing字段勾选TRUSTED且OsApplicationAccessingFunction列表中必须包含StartOS、TerminateApplication等所有将被调用的 API。这是因为 S32K312 的 TrustZone 机制在运行时会校验 API 调用权限未授权的调用会被硬件拦截并触发 HardFault。这些步骤不是凭空而来而是我在 S32K312 上用 J-Link Debugger 抓取 HardFault 的 LR 寄存器值反向追踪到具体哪一行 OS API 调用触发的异常再逐层回溯配置源头得出的结论。3. 核心细节解析与实操要点从芯片启动到第一个 CAN 报文发出3.1 S32K312 芯片启动流程与 BSW 初始化时序S32K312 的启动不是简单的“上电→执行 Reset Handler”而是一个多阶段、多权限域的精密过程。理解它是读懂整个 BSW 初始化日志的前提。芯片上电后首先由 BootROM 执行硬件初始化PLL 锁频、Flash 控制器使能然后根据 BOOT_CFG 引脚状态决定启动模式FlexSPI、UART、CAN 等。在绝大多数 AUTOSAR 项目中我们使用 FlexSPI 模式BootROM 会从外部 QSPI Flash 的固定地址0x08000000加载用户程序的向量表。向量表的第一项是 Reset Handler 地址它指向 Startup.s 中的_start符号。这里的关键细节是_start函数并非直接跳转到main()而是先执行一系列 C 运行时初始化__libc_init_array其中就包含了 AUTOSAR BSW 的Init()函数注册表调用。NXP 的 MCAL 驱动包中Startup.s末尾会调用__iar_program_startIAR 编译器或Reset_HandlerGCC而后者内部会遍历.init_array段依次调用所有__attribute__((constructor))标记的函数包括Can_Ipw_Init()、Fee_Init()、Fls_Init()等。这意味着BSW 模块的初始化顺序是由链接脚本.icf 或 .ld中.init_array段的排列顺序决定的而非代码中#include的顺序。我曾遇到一个 BugFee 模块初始化失败日志显示FEE_E_UNINITIALIZED排查发现是Fls_Init()被放在了Fee_Init()之后调用导致 Fee 在初始化时无法访问 Flash 驱动。解决方案是修改链接脚本将Fls_Init对应的目标文件fls.o强制排在Fee_Init对应文件fee.o之前。这个细节任何 AUTOSAR 教程都不会提但它直接决定了你的 ECU 能否正常启动。提示在 IAR Embedded Workbench 中查看初始化顺序的最简单方法是打开 “Project → Options → Linker → Config” 页面勾选 “Generate link map file”然后在生成的 .map 文件中搜索 “.init_array”即可看到所有构造函数的排列顺序。3.2 DaVinci Configurator 中 ECUC 配置的核心逻辑与常见误操作DaVinci Configurator 是 Vector 提供的图形化配置工具其本质是将用户在 GUI 中的操作翻译成符合 AUTOSAR 标准的 ECUCECU ConfigurationXML 文件.arxml。很多人以为“点几下就完了”殊不知每一个勾选框背后都关联着复杂的依赖关系和代码生成规则。以最常被忽视的CanIf模块为例当你在 “CanIfGeneral” 页面勾选CanIfPublicSetBaudrateApi时DaVinci 不仅会在CanIf.h中生成CanIf_SetBaudrate()声明还会在CanIf_Cfg.c中生成一个全局数组CanIf_BaudrateConfig该数组的每个元素对应一个 CAN 通道的波特率配置。但如果你没有在 “CanIfController” 页面为该通道配置CanIfControllerBaudrateConfig则生成的数组将是空的调用CanIf_SetBaudrate()时会因访问空指针而崩溃。更隐蔽的陷阱是CanIfPublicCancelTransmitApi的配置它控制是否生成CanIf_CancelTransmit()API但该 API 的可用性还依赖于底层Can模块的CanPublicCancelTransmitApi是否启用。如果Can模块没开即使CanIf开了生成的代码中CanIf_CancelTransmit()函数体也是空的调用它毫无效果。这种跨模块的依赖在 DaVinci 的 GUI 中没有任何视觉提示只能通过仔细阅读生成的CanIf_Cfg.c和Can_Cfg.c源码来验证。我的经验是每次完成一轮配置后必须执行 “Generate Code”然后立即打开生成的*_Cfg.c文件搜索你刚刚配置的 API 名称确认其函数体非空、参数列表正确、且调用链完整。这是防止“配置看似成功实则无效”的黄金法则。3.3 Autosar OS 的任务调度与中断处理深度实践Autosar OS 的核心是静态配置的任务Task、中断服务例程ISR和调度表ScheduleTable。它的“静态”二字意味着所有任务的堆栈大小、优先级、激活数量Activation都在编译时确定无法动态创建。这与 FreeRTOS 等通用 RTOS 有本质区别。在 S32K312 上OS 的任务调度基于 Cortex-M7 的 SysTick 定时器但 SysTick 只是提供 tick 中断源真正的调度决策由 OS 内核在Os_Scheduler()函数中完成。一个典型误区是认为“高优先级任务一定会抢占低优先级任务”。实际上AUTOSAR OS 规范定义了四种任务类型BASIC无等待、EXTENDED可等待事件、BACKGROUND最低优先级仅在无其他任务就绪时运行和HOOK钩子任务。其中EXTENDED任务的抢占行为受OsTaskAutoStart和OsTaskSchedule参数影响。例如若一个EXTENDED任务的OsTaskSchedule设置为FULL则它可以在任何时刻被更高优先级任务抢占若设置为NON则它一旦开始执行将一直运行到TerminateTask()或Schedule()调用期间不会被抢占。我在一个车身控制器项目中曾将空调压缩机控制任务需严格周期性执行错误地配置为OsTaskSchedule FULL导致当 CAN 通信任务更高优先级频繁触发时压缩机任务被严重延迟最终引发整车热管理故障。修正方案是将其改为OsTaskSchedule NON并确保其执行时间远小于周期10ms从而保证确定性。注意S32K312 的 Cortex-M7 内核支持 MPUMemory Protection UnitAUTOSAR OS 可利用 MPU 为每个OSAPPLICATION分配独立的内存区域。但启用 MPU 后所有任务切换时都会触发 MPU 重载带来额外开销。实测数据显示在 120MHz 主频下MPU 启用后任务切换耗时增加约 15%。因此除非项目有强安全要求如 ISO 26262 ASIL-B否则建议关闭 MPU用TRUSTED/UNTRUSTED应用区分权限。3.4 CAN 通信链路CanIf → CanTp → Com → ComM的端到端贯通AUTOSAR 的 CAN 通信不是一条直线而是一个四层流水线CanIfCAN 接口负责与底层Can驱动交互收发原始 CAN 帧CanTpCAN 传输协议负责 J1939 或 ISO-TP 的分包/组包Com通信负责信号级的打包/解包Signal-to-PDU 映射ComM通信管理负责整个 CAN 通道的唤醒/休眠状态机。这四层之间通过 PDUProtocol Data UnitID 进行松耦合连接。一个经典问题是“为什么我用 CANoe 发送了一个诊断请求0x7DFECU 却没有响应”排查路径必须是端到端的首先确认Can驱动是否收到原始帧用Can_MainFunction_Read()的调试日志其次检查CanIf是否将该帧正确路由到CanTp查看CanIf_RxIndication()中的CanIfRxPduId然后验证CanTp是否成功解析出诊断请求的 SIDService ID这取决于CanTp的CanTpRxNSdu配置中CanTpRxNSduCanId是否匹配 0x7DF最后确认Com模块是否将该 PDU 正确映射到诊断应用层的接收缓冲区。我曾在一个项目中因CanTpRxNSdu的CanTpRxNSduCanId配置为0x7E8诊断响应 ID而非0x7DF诊断请求 ID导致所有诊断请求在CanTp层就被丢弃Com层根本收不到数据。这个配置项在 DaVinci 的树状菜单中深藏于 “CanTp → CanTpRxNSdu → CanTpRxNSduCanId”极易被忽略。因此我的实操心得是为每个 CAN 通道建立一张“PDU ID 映射表”表格中清晰列出CanIfRxPduId、CanTpRxNSdu、ComIPdu、ComSignal四级 ID 的对应关系并在每次修改任一环节配置后重新核对整张表。这张表就是你通信链路的“DNA 图谱”。4. 实操过程与核心环节实现从零开始搭建一个可运行的 BSW 工程4.1 环境准备S32K312 DaVinci S32DS 的最小可行组合搭建环境是第一步也是最容易卡住的一步。官方推荐的组合是NXP S32DS IDE基于 Eclipse、Vector DaVinci Configurator、NXP 提供的 S32K312 MCAL 驱动包。但三者版本兼容性极差。例如S32DS 3.5 无法正确识别 DaVinci 7.0.0 生成的.arxml文件中的新属性而 DaVinci 6.8 生成的代码在 S32DS 3.4 中编译会报undefined reference to Fls_GetVersionInfo错误原因是新版 MCAL 驱动中Fls模块的 API 版本号已升级但 DaVinci 6.8 未同步更新其代码生成模板。经过数十次组合测试我验证出最稳定的“黄金组合”是S32DS 3.4 DaVinci 6.8 MCAL Package for S32K312 v3.0.0。安装顺序必须严格先装 S32DS 3.4再装 DaVinci 6.8安装时指定 S32DS 的安装路径最后解压 MCAL v3.0.0 包到 S32DS 的plugins目录下。安装完成后必须执行一个关键动作在 S32DS 的 “Window → Preferences → AUTOSAR → MCAL” 页面中将 “MCAL Root Path” 指向 MCAL v3.0.0 的解压根目录并勾选 “Enable MCAL Support”。否则DaVinci 在生成代码时无法找到Can_Ipw.h等头文件路径导致编译失败。这个步骤Vector 的安装文档里一笔带过但它是整个工程能否跑起来的前提。4.2 创建第一个可运行的 BSW 工程点亮 LED 并发送 CAN 报文目标让 S32K312 开发板上的一个 LED 以 500ms 周期闪烁并通过 CAN 通道 0 发送一个 ID 为 0x100、数据为0x01,0x02,0x03,0x04的报文。这是检验 BSW 集成是否成功的“Hello World”。步骤 1芯片级初始化在 DaVinci 中新建工程选择芯片型号为S32K312。进入 “MCAL → Port” 配置页面为 LED 对应的 GPIO 引脚假设是 PTA0配置为OUTPUT模式并勾选PORT_SET_PIN_DIRECTION_API。同时在 “MCAL → Clock” 中使能PORT时钟门控。这一步生成的Port_Init()函数会在main()之前被调用完成 GPIO 方向设置。步骤 2OS 任务创建在 “OS → OsApplication” 中创建一个名为App_LedBlink的应用并在其下添加一个BASIC类型任务Task_LedBlink周期设为500ms堆栈大小512 bytes。在任务函数体中调用PORT_SetPinDirection()切换 PTA0 电平。注意PORT_SetPinDirection()是 MCAL 提供的 API其声明在Port.h中必须在Task_LedBlink.c中#include Port.h。步骤 3CAN 通道配置在 “MCAL → Can” 中为CanController_0配置波特率为500kbpsCanControllerBusOffProcessing设为ON。在 “BSW → CanIf” 中创建CanIfController_0并将其CanIfControllerId关联到CanController_0。最关键的是在 “BSW → Com” 中创建一个ComIPduID 设为0x100方向为TX并为其添加一个ComSignal起始位为0长度32 bits类型UINT32。然后在 “BSW → ComM” 中为CanChannel_0配置ComMChannelModeIndication回调并在回调函数中调用Com_SendIpdu(ComIPduId)。步骤 4代码生成与集成执行 “Generate Code”DaVinci 会生成CanIf_Cfg.c、Com_Cfg.c、ComM_Cfg.c等文件。将这些文件及src/bsw/下的所有.c文件全部添加到 S32DS 工程的Sources文件夹中。在main.c中按顺序调用Port_Init()、Can_Init()、CanIf_Init()、Com_Init()、ComM_Init()、StartOS(OSDEFAULTAPPL)。编译、下载、运行。此时LED 应开始闪烁CANoe 应能捕获到 ID 0x100 的报文。实操心得第一次运行失败90% 的概率是main()中初始化函数的调用顺序错了。AUTOSAR 规范强制要求MCAL 驱动Can_Init必须在 BSW 模块CanIf_Init之前初始化BSW 模块必须在 OS 启动StartOS之前初始化。这个顺序是硬性规定不能颠倒。4.3 NvM 模块的可靠数据存储实现从配置到掉电保护NvMNon-Volatile Memory模块的目标是让 ECU 在掉电后仍能保存关键参数如里程、故障码计数器。但在 S32K312 上它涉及NvM、FeeFlash EEPROM Emulation、FlsFlash Driver三层驱动任何一个环节出错数据都会丢失。配置要点Fls层在 DaVinci 的 “MCAL → Fls” 中必须为FlsJobEndNotification和FlsJobErrorNotification注册回调函数并确保Fls的FlsSectorSize与 S32K312 的实际 Flash 扇区大小4KB一致。Fee层在 “BSW → Fee” 中FEE_NUMBER_OF_SECTORS必须 ≥ 2一个主扇区一个备用扇区FEE_VIRTUAL_PAGE_SIZE建议设为256字节以平衡擦写寿命与管理开销。NvM层在 “BSW → NvM” 中为每个需要存储的 Block如NvMBlock_ODO配置NVM_BLOCK_DATASET为1启用多副本NVM_BLOCK_WRITE_VERIFICATION为TRUE写后校验NVM_BLOCK_REDUNDANT为TRUE冗余存储。掉电保护实操S32K312 本身不提供掉电检测Power Fail Detection硬件需外接电压监控芯片如 TPS3808。在软件层面我们采用“双缓冲校验码”策略每次写入前先将新数据写入 Buffer A计算 CRC16 校验码再写入 Buffer B待两次写入均成功后再将 Buffer A 的有效标志位置 1。读取时优先读取 Buffer A若其有效标志为 0 或 CRC 校验失败则读取 Buffer B。这个逻辑必须在NvM_ReadBlock()的回调函数中实现而非依赖 NvM 模块的默认行为。我曾在一个项目中因未实现此策略ECU 在写入过程中遭遇瞬时掉电导致 Flash 扇区处于半擦除状态整个 ECU 无法启动必须用 J-Link 强制擦除 Flash 才能恢复。因此我的经验是永远不要相信 NvM 模块的“自动保护”必须在应用层实现自己的掉电安全逻辑。4.4 J1939 协议栈的定制化开发超越标准配置的实战需求“autosar j1939” 热搜背后是大量 OEM 对 J1939 功能的定制化需求比如要求支持特定 PGNParameter Group Number的快速传输Fast Packet或要求在 J1939 TP 层之上再封装一层私有协议用于 OTA 升级。标准 AUTOSAR J1939 栈如 Vector 的 J1939Tp只提供基础 TP 分包不支持 Fast Packet。此时必须进行“混合开发”保留标准 J1939Tp 处理常规 PGN同时在CanTp层之上自己编写一个J1939_CustomTp模块专门处理 Fast Packet。该模块的输入是CanIf的原始 CAN 帧输出是Com模块可识别的 PDU。关键在于CanIf的 PDU 路由配置需为 Fast Packet 的 CAN ID如0x18EA0000单独配置一个CanIfRxPduId并将其路由到J1939_CustomTp的接收函数而非标准J1939Tp_RxIndication。这样标准栈和自定义栈就能共存互不干扰。这种“标准定制”的混合架构是应对 OEM 复杂需求的唯一可行路径也是高级 BSW 工程师的核心竞争力。5. 常见问题与排查技巧实录那些让你彻夜难眠的 Bug5.1 典型问题速查表症状、原因、验证方法、解决措施症状可能原因验证方法解决措施ECU 上电后无任何反应LED 不亮CAN 无报文Startup.s中Reset_Handler未正确跳转到_start或__libc_init_array调用失败用 J-Link 连接暂停运行查看 PC 寄存器是否停在Reset_Handler第一行或查看__libc_init_array地址处是否有有效函数指针检查 S32DS 的 Linker Script.icf中__vector_table和__text段的起始地址是否与 BootROM 加载地址0x08000000匹配确保Startup.s中IMPORT __iar_program_start语句存在CAN 报文能发送但无法接收CanIf的CanIfControllerId与Can的CanControllerId不匹配或CanIfRxPduId的CanIfRxPduCanId配置错误在CanIf_RxIndication()函数开头添加DEBUG_LOG(Rx PduId: %d, CanIfRxPduId)观察日志中打印的 ID 是否与配置一致在 DaVinci 的 “CanIf → CanIfController” 页面确认CanIfControllerId与 “MCAL → Can → CanController” 中的CanControllerId完全相同在 “CanIf → CanIfRxPdu” 页面确认CanIfRxPduCanId的值等于你期望接收的 CAN IDNvM_WriteBlock() 返回 E_NOT_OK但无具体错误码Fee模块未初始化或Fls驱动的FlsJobErrorNotification回调未注册导致错误被静默吞掉在Fee_Init()调用后立即调用Fee_GetStatus()检查返回值是否为FEE_BUSY或FEE_UNINIT在Fls配置中确认FlsJobErrorNotification已勾选并指向有效函数确保Fee_Init()在Fls_Init()之后、NvM_Init()之前调用在 DaVinci 的 “MCAL → Fls” 页面为FlsJobErrorNotification输入一个有效的回调函数名如Fls_ErrorCallback并在Fls_Cfg.c中实现该函数内含DEBUG_LOGOS 任务周期性执行但实际间隔远大于配置值OsCounter的OsCounterFrequency配置错误或SysTick的重装载值LOAD计算错误查看Os_Counter.c中OsCounter_0的OsCounterFrequency值用示波器测量SysTick中断的实际周期OsCounterFrequency必须等于SysTick的时钟源频率通常为CPU_CLK / 8。例如S32K312 CPU 为 120MHzSysTick时钟源为CPU_CLK / 8 15MHz则OsCounterFrequency应设为15000000。SysTick的 LOAD 值 OsCounterFrequency / OsCounterTickInterval5.2 我踩过的最深的三个坑血泪教训总结坑一DaVinci 生成的CanIf_Cfg.c中CanIf_ControllerToCanMapping数组为空现象CanIf_SetControllerMode(CANIF_CS_STARTED)总是返回E_NOT_OK。 原因在 DaVinci 的 “CanIf → CanIfController” 页面CanIfControllerId的值被误设为0而Can模块的CanControllerId是1。DaVinci 在生成CanIf_ControllerToCanMapping数组时会以CanIfControllerId为索引若索引越界如0则该位置留空。 教训CanIfControllerId必须从1开始连续编号且必须与CanControllerId一一对应。我后来养成了一个习惯在配置完所有Can控制器后立即在 “CanIf → CanIfController” 页面将CanIfControllerId手动设置为与CanControllerId相同的数字并用 Excel 表格交叉核对。坑二Com_SendIpdu()成功返回但 CANoe 捕获不到报文现象函数返回E_OK但物理层无信号。 原因ComIPdu的ComTxModeTrue配置中ComTxModeMode被设为DIRECT但ComTxModeMode的ComTxModeNumberOfRepetitions为0导致报文只发送一次后即停止。 教训DIRECT模式适用于事件触发型报文如故障码上报但必须确保ComTxModeNumberOfRepetitions 0否则发送一次后Com模块会认为任务已完成不再重发。
返回列表