简介:针对英飞凌公司的TC265微控制器,提供了一套完整的控制器局域网与控制器局域网灵活数据速率通信例程,主要面向汽车电子、工业自动化领域的嵌入式开发人员,尤其适合希望借助官方集成分层软件开发库快速上手外设驱动与网络通信的初学者。压缩包内共有九百五十三个文件,既包含大量底层头文件和源文件,也包含编译生成的目标文件、依赖文件与构建脚本,同时还有集成开发环境的工程配置文件、调试配置文件以及链接脚本,整体压缩后大小约为六点八八兆字节。主程序文件负责完成系统时钟、硬件资源等初始化操作,专门的网关功能文件和接收功能文件分别演示了灵活数据速率网关、灵活数据速率接收与标准控制器局域网接收的实现,并附带发光二极管控制示例,覆盖了常用的输入输出操作。工程结构清晰,借助官方库的抽象层,有助于深入理解波特率配置、滤波器设置、中断服务函数编写以及消息接收和发送等关键环节。已有约一千七百九十一人学习下载,对于希望在TC265平台上开展相关通信协议开发的工程师来说,这是一个很有价值的起步参考。 这几年经常有人问我:TC265的CAN FD例程到底怎么跑起来?其实我也没少踩坑,正好最近在英飞凌AURIX TC265平台手上调完一版CAN FD通信,把例程从零到能发包收包完整走了一遍。TC265的CAN FD模块,配合一颗支持FD的收发器,实测在500kbps仲裁段、2Mbps数据段下连续跑一天,错误帧和总线关闭一次都没出现。这篇文章就把这个TC265 CAN FD例程背后的东西彻底拆开:从为什么选这个芯片、CAN FD为什么和经典CAN不一样,到位时序怎么算、缓冲怎么配、代码怎么写,最后把调试中最容易翻车的几个场景拿出来单独说。准备做AURIX网关、车载控制器,或者只是想把手头CAN网络平滑升级到CAN FD的嵌入式工程师,这份记录可以直接拿来当参考。
1. 例程整体设计:先想清楚它到底要解决什么问题
1.1 为什么拿TC265来做CAN FD验证
TC265是英飞凌AURIX TC2xx系列里性价比挺高的一颗MCU,双核TriCore架构,主频能到200MHz,自带MCMCAN模块。MCMCAN是AURIX 2G系列上负责CAN通信的外设,最多可以挂多个CAN节点,每个节点有独立的报文缓冲、FIFO和过滤器,可以灵活配置成经典CAN或者CAN FD模式。
选TC265做CAN FD例程,主要图三点:第一,它的MCMCAN模块原生支持CAN FD,不需要外挂独立控制器,BRS(波特率切换)和64字节数据场都支持;第二,AURIX生态成熟,官方有iLLD底层库,Hightec和AURIX Development Studio都能直接用,开发门槛比想象中低;第三,TC265本身定位经常出现在车身域控、网关、BMS这类对CAN通信要求比较高的场景,用它验证CAN FD,后面切到实际项目时基本不用换平台。
如果你手头是TC275、TC277甚至TC3xx系列,这套思路同样适用,只是外设基地址、中断号和部分寄存器位有差异,配置流程几乎一致。
1.2 CAN FD和经典CAN的本质区别
很多人把CAN FD简单理解成“CAN加长到64字节”,其实它和经典CAN的差异远比表面看到的深。
- 帧格式不同:CAN FD帧在经典CAN的保留位位置改成了FDF位,用来标识这是一个FD帧;新增BRS位表示数据段波特率是否切换;新增ESI位表示节点错误状态。
- 数据场长度不同:经典CAN最多8字节,CAN FD最多64字节,DLC编码规则也变了。
- 波特率不同:CAN FD允许仲裁段用一种波特率,数据段切换到更高波特率,这就是BRS。仲裁段通常保持500kbps以保证和经典CAN共存,数据段可以跑到2Mbps、5Mbps甚至更高。
- CRC校验不同:CAN FD的CRC算法和多项式都改了,数据场超过16字节时还会加一次额外的CRC填充位,所以单纯把经典CAN控制器挂到FD网络上是收不了FD帧的。
这些差异意味着,一个例程如果真的要把CAN FD跑稳,不能只是改改寄存器把帧发出去,必须把位时序、采样点、收发器延迟补偿、缓冲结构全部重新设计一遍。
1.3 例程整体架构的四个层次
我把这个TC265_CAN_FD_Example的代码拆成四层来看,这样便于定位问题:
- 时钟层:TC265的CAN模块时钟源来自SPB总线时钟,例程先要把锁相环和外设时钟配置好,确保CAN模块拿到一个干净、稳定的时钟。
- 驱动层:MCMCAN模块初始化,包括CAN节点使能、FIFO和TX队列配置、过滤器配置、中断配置。这一层决定了CAN模块能不能被上层正常调用。
- 协议层:CAN FD报文的封装与解析,包括DLC长度映射、BRS位控制、可变波特率下发送接收时序的处理。
- 应用层:周期性发送、接收回环验证、错误计数上报等。
实际调试时,每一层都可能单独出问题。我见过有人时钟没配好,CAN模块始终进不了正常状态,折腾一整天——先确认时钟,再调CAN,顺序不要反。
2. 核心细节解析:位时序、采样点和缓冲结构
2.1 位时序计算是CAN FD例程里最容易翻车的地方
CAN总线的位时序由四段组成:同步段、传播段、相位缓冲段1、相位缓冲段2。采样点落在相位缓冲段1和2之间。对经典的CAN控制器来说,采样点通常推荐在75%~80%附近,而CAN FD的仲裁段建议80%~87.5%,数据段可以稍低一些,75%~85%都可以。
以TC265的MCMCAN为例,假设CAN模块时钟是100MHz,仲裁段500kbps,数据段2Mbps。位时序和预分频的计算公式:
波特率 = 外设时钟 / (预分频值 * 位时间Tq个数)我实际例程里用的参数大致如下:
| 参数 | 仲裁段 | 数据段 |
|---|---|---|
| 目标波特率 | 500kbps | 2Mbps |
| 外设时钟 | 100MHz | 100MHz |
| 预分频值 | 10 | 5 |
| 位时间(Tq个数) | 20 | 10 |
| 同步段 | 1 | 1 |
| 传播段 | 0 | 0 |
| 相位缓冲段1 | 15 | 7 |
| 相位缓冲段2 | 4 | 2 |
| 重同步跳转宽度 | 4 | 2 |
| 采样点 | 80% | 80% |
这个配置下,仲裁段采样点正好落在80%,数据段也是80%,两边都比较居中,兼容性相对好。注意这里的“同步段、传播段、相位缓冲段”在很多iLLD库里是合并赋值给一个位时序结构体的,不同版本的库字段名略有差异,但底层对应的还是这套位段模型。
如果采样点选得太靠后,总线较长时信号反射和边沿抖动就会把采样点推到竞争窗口里,误码率直线上升。
2.2 数据段高速率下必须开启收发器延迟补偿
很多人把CAN FD从1Mbps数据段提升到2Mbps以上时,会遇到“对方明明发了帧,接收端就是收不到”的情况,而且百思不得其解。原因很可能是没有配置收发器延迟补偿(TDC,Transmitter Delay Compensation)。
CAN FD的数据段速率上去后,收发器本身会有环路延迟,从TXD到RXD的延迟可能达到几十纳秒甚至数百纳秒。在低速下这个延迟相对于一个位时间可以忽略,但在2Mbps下一个位时间只有500ns,收发器延迟已经占了一个可观的比例,如果不补偿,接收端的采样点位置会被实际信号延迟“推走”。
MCMCAN模块里有一个SSP(Secondary Sample Point)机制,使能TDC后,接收数据时先测量收发器延迟,然后在延迟值之后加上一个预定偏移作为二次采样点。TC265的例程里,需要把节点配置中的TDC使能打开,同时设定一个合理的SSP偏移。SSP的典型经验值取数据段半个位时间比较稳,例如数据段2Mbps时,位时间500ns,SSP偏移可以设成250ns左右,但要结合具体收发器的环路延迟微调。
2.3 报文缓冲和FIFO怎么选才能不丢帧
MCMCAN模块的报文存储结构比较灵活,主要分成三块:
- RX FIFO:接收报文按顺序进入FIFO,适合不知道对方什么时候发数据的场景。
- Dedicated RX Buffer:专门的接收缓冲区,每个buffer对应一个固定的CAN ID或一组ID,适合确定性很高的通信。
- TX Event FIFO:记录发送完成事件,可以回读发送成功的时间、消息标记、错误码。
例程里我推荐这么分配:接收用RX FIFO0,深度设16帧;发送用TX Queue,深度设8帧;再开一个TX Event FIFO,深度4帧。这个配置对大多数验证场景够用,内存占用也小。
FIFO深度不是越大越好。深度越大,每个FIFO占用的报文RAM越多,而TC265的MCMCAN总共只有一定大小的报文RAM,把RX FIFO配成64帧,留给发送和接收Event FIFO的空间就少了。设计时要先算总预算,再按通信压力分配。
/* iLLD库中CAN节点FIFO配置的大致框架 */ canNodeConfig.rxFifo0.bufferedRxFifoSize = IfxCan_RxFifo0_Size_16; canNodeConfig.rxFifo0.rxFifo0Interrupt = IfxCan_Interrupt_enable; canNodeConfig.txBuffering.queueSize = 8; canNodeConfig.txBuffering.txEventFifoSize = IfxCan_TxEventFifo_Size_4;3. 实操过程:从配置到把CAN FD帧真正发出去
3.1 工程模板与文件结构
我用的开发环境是AURIX Development Studio,配合GCC工具链和iLLD库。新建工程之后,例程目录大概长这样:
TC265_CAN_FD/ ├── Lcf_Gnuc_Tricore_Tc.lsl ├── Cpu0_Main.c ├── CanFD.c ├── CanFD.h ├── Configurations/ └── iLLD/Cpu0_Main.c里只做系统初始化和调用CAN_FD的初始化、循环收发,真正的CAN逻辑放在CanFD.c里。这样做的好处是,后面如果要把例程移植到自己的工程,只需要拖走两个文件,再改一下中断号和端口宏就行。
3.2 CAN模块和节点初始化流程
初始化顺序很关键:先初始化模块,再初始化节点,最后配置过滤器。以iLLD库为例,大致如下:
/* 初始化CAN模块 */ IfxCan_Can_initModuleConfig(&canModuleConfig, &MODULE_CAN0); IfxCan_Can_initModule(&canModule, &canModuleConfig); /* 初始化CAN节点 */ IfxCan_Can_initNodeConfig(&canNodeConfig, &canNode); canNodeConfig.baudRate.baudrate = 500000; canNodeConfig.baudRate.dataBaudrate = 2000000; canNodeConfig.baudRate.samplePoint = 80.0; canNodeConfig.baudRate.dataSamplePoint = 80.0; canNodeConfig.baudRate.prescaler = 10; canNodeConfig.baudRate.dataPrescaler = 5; /* 使能CAN FD和BRS */ canNodeConfig.brs.enabled = TRUE; canNodeConfig.fd.enabled = TRUE; /* 使能收发器延迟补偿 */ canNodeConfig.tdc.enabled = TRUE; canNodeConfig.tdc.value = 25; /* 根据收发器延迟换算后的SSP值 */ IfxCan_Can_initNode(&canNode, &canNodeConfig);很多初学者容易漏掉fd.enabled,只开了BRS,结果发送FD帧时始终报错。这两个开关要一起打开。
3.3 发送一帧64字节CAN FD报文
发送逻辑其实不复杂,但有几个细节经常错。先构造一个发送对象,把报文ID、DLC、BRS位、数据都填好,然后调用发送接口:
IfxCan_Can_sendMessage(&canNode, &txMsg, &txMsgObj); /* 发送对象结构体 */ txMsg.msgId = 0x123; txMsg.frameType = IfxCan_FrameType_transmit; txMsg.brs = IfxCan_Brs_enable; txMsg.idMode = IfxCan_IdMode_standard; txMsg.dlc = IfxCan_Dlc_64; txMsg.data[0] = 0xAA; /* ... 填充到data[63] */坑点来了:CAN FD的DLC编码和实际字节数不是简单的一一对应。当DLC=9时,实际数据场是12字节;DLC=10对应16字节;DLC=11对应20字节;DLC=12对应24字节;DLC=13对应32字节;DLC=14对应48字节;DLC=15对应64字节。如果只填8字节,却把DLC设置成15,未初始化的缓冲区数据会被一起发出去,接收端拿到一堆随机数据。所以发送前务必按实际长度初始化整个data数组,不要只填需要用到的部分。
| DLC | 实际数据长度(字节) | 说明 |
|---|---|---|
| 0-8 | 0-8 | 与经典CAN一致 |
| 9 | 12 | 编码跳变 |
| 10 | 16 | |
| 11 | 20 | |
| 12 | 24 | |
| 13 | 32 | |
| 14 | 48 | |
| 15 | 64 |
3.4 接收过滤器和中断处理
接收侧如果用中断方式,需要在节点配置里打开RX FIFO0中断,并注册中断服务函数。过滤器可以根据报文ID来放行或者丢弃,例程里为了简化,通常把过滤器设成接收全部报文:
canNodeConfig.filterConfig[0].type = IfxCan_FilterType_acceptAll; canNodeConfig.filterConfig[0].number = 0; canNodeConfig.rxFifo0.rxFifo0Interrupt = IfxCan_Interrupt_enable; canNodeConfig.rxFifo0.rxFifo0InterruptLine = IfxCan_InterruptLine_0;中断服务函数里,从RX FIFO里读出一帧并解析:
IFX_INTERRUPT(CanFD_RX_ISR, 0, CAN_RX_ISR_PRIORITY) { IfxCan_Can_readMessage(&canNode, &rxMsgObj, &rxMsg); /* 处理rxMsg.data */ IfxCan_Can_clearInterrupt(&canNode, IfxCan_Interrupt_rxFifo0NewMessage); }一个常见问题是中断处理时间过长,导致后续报文覆盖FIFO。CAN FD一帧最大64字节,如果应用层在这个中断里做复杂的拷贝或者打印,FIFO很容易被冲掉。建议中断里只做“读取到内存缓冲区”这件事,解析放在主循环或者任务里做。
4. 常见问题与排查技巧实录
4.1 两帧不发错、连续发就报BusOff
这是我调试时遇到最多的现象。前期单帧发送一切正常,用脚本循环发200帧,总线上就出现错误帧,最后节点直接BusOff。
排查顺序是这样的:
- 看采样点:先用示波器或者CAN分析工具量一下实际信号,如果数据段采样点低于70%,在长线上非常容易出错。把数据段采样点调到75%~80%再试。
- 看终端电阻:CAN FD跑2Mbps以上时,终端电阻和线束质量影响比经典CAN大得多。两个终端电阻必须是120欧姆,不能只在一端接。
- 看收发器:确认用的是支持CAN FD的收发器,比如TLE9251V,而不是老掉牙的TJA1040。老收发器在FD数据段的高波特率下驱动能力不足,信号边沿变缓,误码率急剧上升。
- 看TDC:高波特率下如果TDC没开,再怎么调采样点都救不回来。
4.2 数据段波特率上不去,始终只能跑1Mbps
有些收发器和隔离模块在2Mbps以上会明显衰减,这不是配置问题,是硬件瓶颈。常见的原因是PCB走线过长、连接器接触不良、线束使用了非屏蔽双绞线并且靠近干扰源。
我的判断技巧是:把数据段波特率从2M降到1M,如果问题消失,基本可以判定是物理层问题,先查硬件再查代码。千万不要一上来就折腾寄存器。
4.3 TX Event FIFO一直不触发,发送完成标志读不到
TX Event FIFO是异步记录发送事件的,不是在TX Queue发送完成后立即更新。如果配置了发送完成中断,一定要确认中断线和TX Event FIFO的关联设置正确。例程里经常出现的问题是把TX Event FIFO的中断配置成了RX中断线,导致接收正常但发送完成事件永远不触发。
检查思路:读错误计数器看节点是否正常,读TX Event FIFO的有效指针,如果FIFO状态一直为空,说明事件没有写入,多半是配置里TX Event FIFO的使能位置没有打开。
4.4 用CAN分析仪能看到帧,但数据全是0x00
这个坑很隐蔽。FD帧的DLC如果是8字节,接收端根据DLC判断数据长度;但如果发送端用了DLC=15表示64字节,却只给data[0]赋了值,其他字节可能默认是0,看起来就像数据全丢了一样。先确认DLC和实际数据长度一致,再看发送缓冲区有没有初始化干净。
另外,如果数据段波特率较高,CAN分析仪在接收FD帧时需要明确使能FD支持,否则它将无法解析64字节数据场,显示出来的数据也会异常。
4.5 中断里用延时函数导致系统崩溃
不要在CAN中断里调用阻塞延时,尤其不要调用需要等待全局中断的库函数。MCMCAN中断优先级较高,如果中断里长时间占用CPU,而且此时又来了更高优先级的异常,整个系统容易进入无法恢复的状态。
我习惯把中断服务函数控制在几微秒到十几微秒内,只做数据搬移和置标志位。CAN FD一帧最多64字节,从FIFO搬到一个全局二维数组里也只是几十次赋值操作,完全可以在中断里完成,但解析、打印、存储这类重活一定放到任务层。
5. 这个例程后续还能怎么扩展
5.1 把收发模式改成网关转发
例程跑通单节点收发后,最自然的扩展方向是做一个CAN FD网关。TC265的MCMCAN有多个节点,可以配置一个节点接收经典CAN报文,另一个节点以CAN FD格式转发出去,中间用全局数据区做桥接。注意DLC映射和字节序转换,不能直接把经典CAN的8字节塞到FD帧里就算完。
5.2 增加错误处理和诊断功能
把BusOff恢复、错误计数器上报、被动错误状态切换这些逻辑加进去,例程就直接有了产品雏形。MCMCAN模块支持错误状态中断,可以在错误被动和BusOff时通过中断记录时间戳,这些信息对后续故障定位非常有用。
5.3 用E2E校验保护关键报文
如果例程要用于实际项目,特别是车身安全相关通信,强烈建议加上E2E(End-to-End)保护,对数据CRC校验和滚动计数器。CAN FD虽然数据场大了,但通信仍然可能受到电磁干扰,E2E是在应用层增加一道保险。
个人体会,把例程跑顺只是第一步,真正有价值的是理解每一条配置背后的物理含义。CAN FD的高波特率不是单纯改寄存器就能跑出来的,它把原本被总线速率掩盖的问题全暴露了一遍——收发器质量、线束布局、采样点选择、延迟补偿,每一个环节都在“教做人”。希望这份TC265_CAN_FD例程的记录能帮你少走我走过的那些弯路。
本文还有配套的精品资源,点击获取