先楫HPM6750/HPM6450 CAN-FD实战:从协议到采样点调优

发布时间:2026/9/16 14:25:44
先楫HPM6750/HPM6450 CAN-FD实战:从协议到采样点调优 简介面向上海先楫HPM6750与HPM6450高性能MCU的CAN/CAN-FD通信代码工程适合嵌入式开发者在汽车电子、工业自动化等场景快速落地高速可靠通信。资源共3个文件约6KB包含C源码、TXT说明与Markdown文档其中C文件提供CAN控制器初始化、波特率配置、滤波器设置及收发函数示例文档则讲解标准帧/扩展帧结构及FD模式的数据段与CRC段差异。压缩包以.c/.txt/.md为核心结构紧凑便于对照调试。目前已有546人学习下载。通过这份示例开发者可掌握HPM6750/HPM6450内建CAN控制器的寄存器配置方法理解5Mbps更高数据速率下的时钟调整与FD模式开启步骤并基于清晰函数接口和测试建议快速移植到自有项目中是构建CAN/CAN-FD通信节点的实用起点。资源容量虽小但覆盖了协议关键实现点适合作为入门参考或排错模板。1. 上海先楫HPM6750跑CAN-FD为什么这题值得做先楫HPM6750是国产MCU里少有的、把“高主频”和“硬实时总线”同时交到工程师手里的芯片双核RISC-V、主频600MHz起步片内带多路CAN控制器其中一路支持CAN-FD这本身就是个自然的组合。但在实际项目里很多人第一次接触HPM6750是从伺服驱动、车载网关或工业控制器的换芯开始的工作负载是存量CAN总线空闲时想往CAN-FD迁移于是会遇到两件事第一普通CAN例程能跑通标准帧却发不出FD帧第二配置FD时反复调采样点和SJW波形在BRS切换处出现毛刺或者对端节点直接进bus off。这个标题把HPM6750和HPM6450放在一起写核心是在同一份外设驱动上做复用两个型号的CAN-FD控制器寄存器布局一致工程里只需要用宏切换型号与引脚业务代码不必动。这篇文章按“协议差异—硬件接入—驱动实现—参数调优—验证与后向兼容”的顺序把从“能发帧”到“敢上总线”的路径讲透。适合正在做存量总线升级、CAN网关或伺服驱动的嵌入式工程师也适合刚拿到先楫开发板、想直接上手CAN-FD的入门者。2. CAN-FD协议差异与HPM6750的CAN硬件特征2.1 CAN-FD相对CAN 2.0的帧结构变化DLC、BRS与CRC很多人以为CAN-FD只是把速率提高了一档实际改动是结构性的。以下表格对比两代协议在关键字段上的差异这也是后面配置寄存器和解析报文时最容易出错的地方。字段CAN 2.0经典CANCAN-FD最高标称速率典型1Mbps仲裁段最高1-2Mbps数据段速率与仲裁段相同可达2Mbps、5Mbps、8Mbps由收发器决定最大载荷8字节64字节DLC编码0-8直接对应字节数0-8对应0-8字节9-15映射为12/16/20/24/32/48/64字节CRC多项式15位CRC17位CRC0-16字节、21位CRC17-64字节BRS位不存在存在控制帧内是否切换数据段速率位填充规则每5个电平均匀插入1个填充位每17位有至少4个显性位避免反相实际为每17位检查表中最后一行是数据段的位填充规则CAN-FD填充计数器最多到16位CRC段填充有固定规则所以抓波形时如果看到数据段长度与预期不一致先怀疑CRC段填充和DLC字节数映射而不是立即怀疑时钟精度。CAN-FD重新定义了DLC值9到15的字节含义。经典CAN里DLC必须小于等于8超过8会被当作8处理CAN-FD里DLC9表示12字节DLC10表示16字节DLC11表示20字节DLC12表示24字节DLC13表示32字节DLC14表示48字节DLC15表示64字节。写驱动时需要用一张静态映射表转换不能直接做位运算。2.2 一个控制帧内部的两段速率为什么采样点要放在两个寄存器里CAN-FD仲裁段负责ID、控制位和ACK数据段负责载荷。仲裁段要与线上的所有节点保持相同的位时序保证仲裁、应答等机制可靠数据段则在BRS位为显性之后切换到更高的位速率。因此控制器内部分别用标称位时序寄存器NBTP和数据位时序寄存器DBTP采样点必须分开计算。HPM6750的CAN外设采用博世M_CAN内核寄存器体系中CAN_NBTP配置标称段CAN_DBTP配置数据段两个寄存器结构几乎一致都包含DIV、TSEG1、TSEG2和SJW字段。这样设计的好处是仲裁段用在线的1Mbps数据段切到5Mbps升级旧节点时只需保证仲裁段参数一致数据段速率可以逐步放宽。下面用一段C语言结构体说明这两段位时序在配置层的形态只做寄存器映射示意具体偏移以芯片手册为准typedef struct { uint32_t div; /* 分频系数控制Tq粒度 */ uint32_t tseg1; /* 相位缓冲段1加传播段 */ uint32_t tseg2; /* 相位缓冲段2 */ uint32_t sjw; /* 同步跳跃宽度 */ } can_bit_time_t; can_bit_time_t nominal_time; /* 仲裁段参数填入CAN_NBTP */ can_bit_time_t data_time; /* 数据段参数填入CAN_DBTP */HPM6750的CAN时钟由芯片内部的PLL分频后产生计算位时序前要确认时钟树中CAN模块的实际频率。常见做法是把CAN时钟源固定在一个整数频率上例如40MHz这样1Mbps可以做到每个位时间均匀的整数个Tq采样点也更稳定。2.3 HPM6750与HPM6450的通用硬件接入HPM6750片内多个CAN控制器中至少有一路支持CAN-FD其余为经典CANHPM6450同样分出FD控制器和普通CAN控制器这也是标题里强调两款型号可共用驱动的原因。工程上我一般把支持FD的通道固定在CAN0用于高速数据链路CAN1做经典CAN慢速总线业务层再通过统一的发送接口选择通道。收发器是CAN-FD链路里最容易忽视的一环。经典CAN收发器最高一般只保证2Mbps跑5Mbps时上升沿变缓采样点附近可能采到不定态。要跑5Mbps以上应选用支持ISO 11898-2:2016的收发器这类芯片明确标注支持CAN-FDTXD/RXD环路延时要小于波特率位时间的50%。收发器特性是否能跑CAN-FD推荐场景经典CAN收发器仅支持最高1Mbps否存量低速CAN低速FD收发器支持2Mbps是短距离节点高速FD收发器支持5/8Mbps是网关、伺服、整车节点接线方面HPM6750的CAN控制器TXD/RXD信号经过收发器后接入CAN_H和CAN_L末端节点需要120Ω终端电阻两个端节点各一个。收发器的VIO参考电压要接与HPM6750 IO电源一致的电平否则TXD引脚的逻辑电平不匹配现象是帧能发出但总线上全是错误帧。时钟方面需要特别注意CAN模块工作频率并非固定值代码中应通过时钟接口获取当前CAN时钟频率再代入位时序计算器。如果直接用经验值40MHz而实际时钟树配置为25MHz波特率会整整偏出百分之六十总线上一帧都收不到且这个错误在示波器上很难直观看出。3. 初始化HPM6750 CAN-FD的最小代码与收发帧路径3.1 时钟使能与引脚复用初始化CAN-FD的第一步不是设置波特率而是打开时钟和配置引脚复用。先楫SDK里每个外设都有一个时钟门控开关CAN0对应一个时钟控制宏GPIO的复用功能需要把TXD/RXD引脚切换到CAN信号。#include hpm_soc.h #include hpm_can.h void can_fd_clock_io_init(void) { /* 使能CAN0外设时钟 */ clock_add_to_group(clock_can0, 0); /* 配置TXD引脚为CAN0_TXD复用功能 */ IOC-PAD[IOC_PAD_PD09].FUNC_CTL IOC_PAD_FUNC_CTL_ALT_SELECT_SET(1); IOC-PAD[IOC_PAD_PD10].FUNC_CTL IOC_PAD_FUNC_CTL_ALT_SELECT_SET(1); }代码逻辑说明第一步调用clock_add_to_group把CAN0挂到时钟组确保外设寄存器可访问第二步通过IOC引脚复用寄存器把PD09、PD10分别映射到CAN0_TXD和CAN0_RXD。不同板卡引脚不同HPM6450对应引脚编号可能不同实际工程中建议在板级头文件里定义宏不要直接写死引脚号。参数说明ALT_SELECT_SET后面的数字是由芯片引脚复用表决定的索引改成错误值不会报错但引脚上完全没有波形。调试时可通过读取IOC寄存器确认复用功能是否生效。3.2 用NBTP和DBTP计算采样点并填充寄存器采样点是在一个位时间内进行电平采样的时刻通常用百分比表示。CAN-FD仲裁段采样点推荐75%到80%数据段推荐75%左右太低容易采到前一位的边沿太高容易被后一位的相位段遮挡。M_CAN的位时间由同步段、传播段和相位缓冲区组成同步段固定为1个TqTSEG1对应传播段加相位缓冲段1TSEG2对应相位缓冲段2。#define CAN_CLK_HZ 40000000UL static void can_fd_calc_bit_time(can_bit_time_t *bt, uint32_t target_bps, uint8_t sample_point) { uint32_t tq_num CAN_CLK_HZ / target_bps; uint32_t seg1, seg2; /* TSEG2 (1 - sample_point) * tq_num */ seg2 tq_num * (100 - sample_point) / 100; seg1 tq_num - seg2 - 1; /* 减去固定同步段 */ bt-div 0; bt-tseg1 seg1 - 1; /* 寄存器值从0开始 */ bt-tseg2 seg2 - 1; bt-sjw 1; /* 默认1BRS切换场景可调大 */ }逻辑说明target_bps传500000或5000000sample_point传80表示80%。tq_num是一个位时间内Tq总数因为同步段占1个Tq所以采样点位置是(1 TSEG1) / (1 TSEG1 TSEG2)。寄存器值需要减1因为M_CAN中TSEG字段为0表示1个Tq。参数说明以40MHz时钟、目标2Mbps、80%采样点为例一个位时间共20TqTSEG1寄存器值应为14TSEG2寄存器值应为4。若目标波特率改为5Mbps位时间只有8Tq采样点计算会出现较大舍入误差因此数据段采样点一般给75%更合适否则舍入后实际值可能跳到71%或83%。得到两组位时序后分别写入CAN_NBTP和CAN_DBTP然后退出初始化模式void can_fd_mode_enable(CAN_Type *base, bool enable_fd) { uint32_t cccr base-CCCR; cccr ~CAN_CCCR_INIT_MASK; base-CCCR cccr; /* 请求离开初始化模式 */ if (enable_fd) { base-CCCR | CAN_CCCR_FDOE_MASK | CAN_CCCR_BRSE_MASK; } }逻辑说明FDOE位使能FD格式BRSE位使能BRS速率切换两个位必须同时置1才能跑FD且让数据段用DBTP。只置FDOE不置BRSE控制器能发FD帧但数据段仍用NBTP速率这是很多例程“能发出FD帧但数据段没提速”的原因。3.3 发送一帧CAN-FD从TX Buffer到发送请求M_CAN的发送路径上有多个发送缓冲可以安排多个待发帧控制器按优先级自动仲裁。发送前需要填充发送缓冲元素再置位对应的发送请求位。先楫SDK把这一步封装成了发送结构体用户只需要填充ID、DLC和数据部分。can_tx_frame_t tx_frame {0}; tx_frame.id 0x123; tx_frame.id_type CAN_ID_STD; tx_frame.dlc CAN_DLC_WORD_8; /* 8字节 */ tx_frame.fd_frame true; tx_frame.brs_enable true; memcpy(tx_frame.data, payload, payload_len); can_send_message(CAN0, tx_frame);逻辑说明fd_frametrue表示按FD帧格式发送brs_enabletrue表示在数据段切换高速率如果brs_enablefalse即使配置了FD模式数据段也保持与仲裁段相同速率。dlc字段直接用帧格式枚举不用手动做DLC映射SDK内部会完成映射。参数说明ID标准帧只有11位超过0x7FF会被截断扩展帧支持29位ID但要把id_type改成CAN_ID_EXT。payload_len与dlc不一致时常见做法是以dlc为准不足部分自动补0超过部分由库完成填充业务代码应保证payload_len 64。发送完成判断有两种轮询发送缓冲状态位或等发送完成中断。轮询方式在低负载时最直观高负载时建议使用发送中断释放缓冲避免阻塞主循环。3.4 接收过滤与中断处理接收侧的过滤规则决定哪些报文进入FIFO、哪些被丢弃。M_CAN有两种接收存储方式FIFO和专用接收缓冲。先楫SDK默认配置为FIFO模式中断服务程序里读取报文后需要做字节序处理。HPM_IRQ_HANDLER(irq_can0_handler) { can_rx_frame_t rx_frame; can_receive_message(CAN0, rx_frame); if (rx_frame.fd_frame) { /* 声明实际数据字节数 */ len can_fd_dlc_to_bytes(rx_frame.dlc); process_fd_payload(rx_frame.data, len); } }逻辑说明接收中断会逐个弹出FIFO中的报文fd_frame标志指示是否为CAN-FD帧。多字节payload在HPM6750内部是小端存储发送到总线时按字节顺序发出不存在控制器层面的字节序转换问题业务协议里定义多字节字段时建议统一采用小端排列接收端直接memcpy取出避免手工字节交换带来的隐患。参数说明can_fd_dlc_to_bytes负责把DLC映射到实际字节数这是FD报文解析最容易被忽略的一步。经典CAN里dlc15按8字节处理FD里却是64字节若沿用旧解析逻辑会漏数据。4. 采样点、SJW与bus off恢复的参数调优4.1 一组可以直接抄的CAN-FD参数表以下参数基于CAN时钟40MHz给出仲裁段和数据段分开配置。表格中的数值已经做过采样点舍入可直接填入NBTP和DBTP寄存器。用途仲裁段速率数据段速率TSEG1值TSEG2值SJW实际采样点FD低速调试500kbps2Mbps仲裁19数据14仲裁4数据41/180% / 75%FD常规伺服500kbps5Mbps仲裁19数据3仲裁4数据11/180% / 75%FD高速网关1Mbps5Mbps仲裁39数据3仲裁9数据12/180% / 75%纯经典CAN500kbps不适用194180%需要说明的是表格中的TSEG字段值已经是写入寄存器的值即已经减1。若目标板卡的CAN时钟不是40MHz必须重新计算并核对采样点不能直接套用否则帧间同步误差会在长时间运行后积累表现为偶发CRC错误。4.2 SJW、BRS切换与时钟源的三个坑第一个坑是SJW设置过小。SJW决定控制器在收到总线跳变时最多能把采样点挪动多少Tq仲裁段SJW设为1在很多总线长度较长的场景下会失去同步能力尤其当总线上混有不同容差的节点时建议仲裁段SJW设为2数据段保持1即可。注意SJW增大后TSEG2的有效范围会变小SJW不能超过TSEG2。第二个坑是BRS切换的毛刺。数据段速率越高位时间越短收发器环路延时对采样点的影响越明显。常见做法是数据段采样点从75%往回调到70%不要因为想提高时序余量而调到80%以上。数据段SJW保持1用来吸收相邻等幅位之间的抖动。第三个坑是时钟源选择。HPM6750的CAN时钟如果在运行中被动态调频比如DVFS改变CPU频率而CAN时钟来自同一PLL分支会导致实际波特率漂移。我一般会把CAN时钟固定到独立PLL输出并在初始化前打印CAN内核时钟频率做日志记录便于分析线上故障。4.3 bus off恢复策略与物理层排错总线off是CAN控制器检测到128次连续错误后进入的离线状态。HPM6750的M_CAN支持自动恢复和手动恢复两种方式自动恢复由硬件在检测到总线空闲后自动重新参与通信适合对中断不敏感的场景。void can_bus_off_recover(CAN_Type *base) { /* 检查bus off状态 */ if (base-PSR CAN_PSR_BO_MASK) { /* 进入初始化模式后重新退出完成复位恢复 */ base-CCCR | CAN_CCCR_INIT_MASK; base-CCCR ~CAN_CCCR_INIT_MASK; } }逻辑说明这段代码的核心是置位INIT再清除INIT让控制器内部错误状态机复位。CAN协议规定节点重新参与通信前需要等待128个连续空闲位硬件会在退出初始化模式后自动完成这个等待不需要软件延时。参数说明如果业务层要求快速恢复可以缩短错误计数器的攀升时间但不要滥用。频繁的bus off恢复会破坏总线分时影响其他节点。遇到总线错误时先区分是控制器错误还是物理层错误打开CAN分析仪抓波形看是否有连续的显性错误帧如果分析仪提示can not open com port多数是收发器未上电或USB分析仪的端口被占用而不是控制器配置问题。总线负载率也是排查重点。CAN-FD数据段虽然速率提升但仲裁段时间仍按标称速率计算当节点数超过10个且每帧都发64字节时仲裁段占用率会明显上升。建议在业务层统计每毫秒的发送帧数并预留20%的空闲带宽避免突发流量把总线挤满。5. 验证CAN-FD链路的三层手段与存量总线兼容5.1 控制器回环测试先楫SDK把M_CAN的测试模式封装为回环功能配置后不接外部收发器也能完成自测。回环模式适合在硬件尚未准备好时验证控制器初始化、DLC映射和中断逻辑void can_fd_loopback_test(void) { CAN0-CCCR | CAN_CCCR_TEST_MASK; CAN0-TEST | CAN_TEST_LBCK_MASK; }回环开启后发送的FD帧会直接进入接收FIFOfd_frame标志、brs_enable标志和负载数据都会原样回来可以借此验证发送数据与接收数据是否一致。注意回环模式不经过收发器因此无法测试物理层信号质量帧能回环成功不代表总线波形合格。5.2 用逻辑分析仪做波形级验证回环通过后把收发器接入测试网络用支持CAN-FD解码的逻辑分析仪观察波形。重点看BRS位之后的数据段位时间是否变短以及数据段最后一位到CRC定界符的转换过程是否平滑。如果数据段长度与DLC映射不一致波形上会看到多出来的填充位直接对拍报文的DLC字段即可定位。没有逻辑分析仪时可以用示波器测量CAN_TX引脚的波形宽度发送一帧已知波特率的FD帧计算一个显性位的宽度是否与数据段配置吻合。硬件波形验证后再接入CAN分析仪做双向互发确认两边帧ID、速率和采样点配置一致。5.3 与经典CAN节点共存并平滑迁移存量总线上升级CAN-FD最稳妥的做法是保持仲裁段参数与旧节点相同数据段速率先不启用BRS让FD节点按经典CAN速率发送FD帧。之后逐步升级对端节点再统一开启BRS这样能最大程度降低总线停摆风险。如果节点驱动支持自动识别可以在初始化后先发送经典CAN帧收到特定诊断请求再进入FD模式这也是主机厂网关常用的激活逻辑。最后一层技巧是验证FD链路的实际可用吞吐。对64字节payload、2Mbps数据段做一次1000帧的批量发送统计总耗时可以算出仲裁段和数据段各自占用的总线时间从而评估是否真的需要更高的数据段速率。用这个数据反向校准采样点和SJW比盲目调参数更可靠。本文还有配套的精品资源点击获取