资讯动态

DSP28335 eCAN通信实战:从寄存器配置到总线排坑全解析

发布时间:2026/9/8 9:49:04 来源:尧图企业网站定制
简介面向DSP28335浮点数字信号处理器的CAN通信程序包适合嵌入式开发工程师、自动化及汽车电子方向学习者可解决eCAN模块初始化、消息收发、中断响应与错误处理等实际难题。压缩包共74个文件内含30个h头文件、12个c源程序、3个asm汇编代码另有cmd链接脚本、out可执行文件、map映射文件及log编译日志完整覆盖从工程配置、代码编写到链接调试的完整流程。程序示例以C语言实现涉及标准帧与扩展帧格式、总线波特率与滤波器配置、发送缓冲区写入与接收FIFO读取、中断服务例程设计以及位错误和CRC错误检测后的恢复策略同时包含DSP2833x标准外设库与eCAN驱动源码便于对照寄存器操作理解底层机制。已有4006人学习下载适合正在调试CAN总线、需要参考DSP2833x eCAN实现的中级开发者快速上手或移植到自有项目。 做DSP28335的CAN通信程序很多人第一反应就是去抄一份TI官方例程改改ID结果一上板就发现问题初始化卡死、帧发不出去、接收中断不触发、和STM32对不上波特率。我前前后后调过好几版28335的eCAN程序从寄存器裸写到中断收发再到和别的设备联调这里把整个过程按实际踩坑顺序整理出来。文章不是抄手册而是告诉你每个配置项为什么这样设、出了问题从哪查起适合正在用DSP28335做CAN通信、或者准备从其他平台转过来的同学参考。1. 动手前先盘一下DSP28335的CAN家底1.1 eCAN模块到底给了你什么DSP28335内部集成的是TI的eCAN模块兼容CAN 2.0B协议支持最高1Mbps的经典CAN速率也支持标准帧和扩展帧。和STM32的bxCAN不太一样28335的eCAN提供32个邮箱Mailbox每个邮箱可以独立配置成发送或者接收这一点在需要多路报文收发的场景里非常灵活比如一个邮箱收转速、一个邮箱收状态字、一个邮箱专门发控制命令互不干扰。需要特别说明的是28335本身只有CAN控制器芯片引脚上不存在所谓的CAN_H和CAN_LGPIO18和GPIO19复用为CANRXA和CANTXA输出的是数字电平必须外接CAN收发器才能挂到总线上去。很多人第一次调程序拿示波器点在CANTXA引脚上看不到差分波形以为程序有问题其实就是缺少收发器这一步。另外eCAN有一个很容易被忽略的点所有寄存器访问都被EALLOW/EDIS保护。在CCS里调试如果你直接打开寄存器窗口修改值改完会被保护机制挡回去看起来改了实际没写进去。程序里每次操作eCAN相关寄存器都要包在EALLOW和EDIS之间这是新手最常见的问题之一。1.2 外部收发器和保护电路怎么配收发器选型方面常见的有TI的SN65HVD230、NXP的TJA1050、PCA82C250。SN65HVD230是3.3V供电和28335电平匹配最方便适合短距离板间通信TJA1050和PCA82C250是5V供电抗干扰能力和驱动能力更强适合长距离或者工业现场但和28335连接时要注意TXD/RXD引脚电平必要时加电平转换或限流处理。总线两端各需要一个120欧终端电阻这个不是可选项。CAN总线是差分传输终端电阻用来匹配阻抗、消除反射。做过一致性测试或者用示波器看过波形的人应该深有体会没终端电阻时波形上升沿过冲明显显性电平平台变形长线场景下甚至会直接导致采样错误。如果现场环境干扰比较重比如电机驱动旁边走线、有变频器建议在CANH和CANL上对地加TVS管再串共模电感有条件的话用带屏蔽的双绞线。工业总线接口常讨论的“TVSTSS方案”在这里同样适用总线端口要做浪涌防护不然一次静电或者雷击感应就可能烧掉收发器和DSP的IO。2. 波特率计算SJW和位时间不是随便填的2.1 位时间结构和采样点CAN总线的波特率配置本质上是配置一个位时间被分成多少个时间量子TQ以及每个字段的占比。28335的位时间由同步段、TSEG1、TSEG2三部分组成同步段固定占1个TQTSEG1和TSEG2由CANBTC寄存器的TSEG1字段和TSEG2字段决定。寄存器里的值都要加1才是实际TQ数这个特别容易搞错。同步跳跃宽度SJW的作用是处理总线上的时钟偏差和信号抖动。当节点检测到总线边沿和本地时钟不同步时会通过SJW调整采样点。SJW设得太小重同步能力不够长线或强干扰下偶发错误帧概率变大设得太大采样点位置会跳来跳去反而得不偿失。工程上SJW一般取1到2个TQ就够用。波特率计算公式可以简单写成波特率 SYSCLKOUT / (BRP 1) / (1 (TSEG1 1) (TSEG2 1))28335的主频SYSCLKOUT一般是150MHz我实际调试时喜欢把总TQ数固定成15这样采样点稳定在80%左右和大多数CAN节点的采样点接近联调时兼容性最好。2.2 150MHz主频下的常用参数表波特率BRPTSEG1TSEG2SJW总TQ数采样点1Mbps910211580%500Kbps1910211580%250Kbps3910211580%125Kbps7910211580%这个表是我自己算过、也在板子上验证过的核心思路是保持位时间结构完全一致只改变分频系数。比如1Mbps时BRP9表示分频10倍TQ是66.7ns15个TQ正好是1us500Kbps时把BRP改成19分频20倍TQ变成133.3ns15个TQ就是2us。这样所有速率下的采样点位置都是80%不会因为切换波特率而需要重新评估采样点是否合适。如果用的不是150MHz主频把150替换成你的SYSCLKOUTBRP重新算一遍就行。这里要强调一点很多人喜欢把TSEG1设得很小比如3或者4总TQ数也少这样做波特率照样能对上但采样点会在70%以下。对单机和短总线没什么感觉一旦挂多节点、走线稍长错误帧就出来了而且不好排查。3. 收发程序实操从初始化到能跑3.1 时钟、引脚和eCAN初始化完整初始化分四步使能eCAN的外设时钟、配置GPIO复用为CAN功能、请求进入配置模式、写CANBTC波特率寄存器。进入配置模式是关键步骤必须先置CANMC的CCR位然后等待CANES的CCE位变成1确认芯片已经进入配置模式之后再写CANBTC否则寄存器写入无效。void InitECan(void) { struct ECAN_REGS ECanaShadow; // 1. 使能eCAN-A外设时钟 EALLOW; SysCtrlRegs.PCLKCR0.bit.ECANAENCLK 1; // 2. GPIO18 - CANRXA, GPIO19 - CANTXA GpioCtrlRegs.GPAMUX1.bit.GPIO18 1; GpioCtrlRegs.GPAMUX1.bit.GPIO19 1; EDIS; // 3. 请求进入配置模式 EALLOW; ECanaShadow.CANMC.all 0; ECanaShadow.CANMC.bit.CCR 1; ECanaRegs.CANMC.all ECanaShadow.CANMC.all; EDIS; // 等待CCE置位确认进入配置模式 do { ECanaShadow.CANES.all ECanaRegs.CANES.all; } while (ECanaShadow.CANES.bit.CCE ! 1); // 4. 配置波特率为1Mbps主频150MHz EALLOW; ECanaShadow.CANBTC.all ECanaRegs.CANBTC.all; ECanaShadow.CANBTC.bit.BRP 9; ECanaShadow.CANBTC.bit.TSEG1 10; ECanaShadow.CANBTC.bit.TSEG2 2; ECanaShadow.CANBTC.bit.SJW 1; ECanaRegs.CANBTC.all ECanaShadow.CANBTC.all; // 5. 退出配置模式回到正常模式 ECanaShadow.CANMC.bit.CCR 0; ECanaRegs.CANMC.all ECanaShadow.CANMC.all; EDIS; // 等待CCE清零 do { ECanaShadow.CANES.all ECanaRegs.CANES.all; } while (ECanaShadow.CANES.bit.CCE ! 0); }这套流程里最容易出问题的是第3步到第4步的衔接。有些代码把CCR置1之后马上写CANBTC没有等CCE确认这在某些芯片版本上可能碰巧成功但在28335上大概率寄存器没写进去导致实际波特率还是上电默认值。调试时如果发现波特率怎么配都不对先检查这一步有没有等待CCE。3.2 邮箱发送数据发送过程可以分解成三个动作配置邮箱为发送模式并写入ID和数据、使能邮箱、请求发送并等待应答。28335的每个邮箱都有一个TRS请求位和一个TA应答位请求发送后硬件会自动把数据移位输出发送成功之后TA位置1。Uint8 msgTx[8] {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0}; void CanSend_Box1(void) { // 邮箱1配置为发送 EALLOW; ECanaRegs.CANME.all 0; // 先关闭所有邮箱 ECanaRegs.CANMD.bit.MD(1) 0; // 0发送1接收 ECanaRegs.MBOX(1).CANMSGID.bit.MSGID 0x123; ECanaRegs.MBOX(1).CANMSGID.bit.IDE 0; // 标准帧 ECanaRegs.MBOX(1).CANMSGCTRL.bit.DLC 8; // 8字节数据 // 数据写入邮箱数据区 ECanaRegs.MBOX(1).CANMDL.all (msgTx[0] 24) | (msgTx[1] 16) | (msgTx[2] 8) | msgTx[3]; ECanaRegs.MBOX(1).CANMDH.all (msgTx[4] 24) | (msgTx[5] 16) | (msgTx[6] 8) | msgTx[7]; ECanaRegs.CANME.bit.ME(1) 1; // 使能邮箱1 ECanaRegs.CANTRS.bit.TRS(1) 1; // 请求发送 EDIS; // 等待发送完成 while (ECanaRegs.CANTA.bit.TA(1) 0) {} // 清除发送应答标志写1清除 EALLOW; ECanaRegs.CANTA.all 0xFFFFFFFF; EDIS; }这段代码里我故意把数据字节的拼接顺序写得很直观CANMDL寄存器的高24位到低8位对应Byte0到Byte3。这里有一个和STM32对比容易混淆的地方28335默认不保证CAN数据域字节序和MCU内存字节序一致如果总线上的对端设备拆包后发现数据顺序反了检查CANMC寄存器的DBO位设置同时看对端解析器的字节序约定。发送等待TA标志这一段正式项目中不建议用空轮询。如果总线处于bus-off或者没有其他节点应答ACKTA一直不置位程序就死等在这里。项目里一般加上超时处理或者配合中断来做调试阶段呢裸轮询其实反而方便因为代码路径简单出问题一眼能看出来。3.3 中断接收与验收滤波接收邮箱建议直接用中断方式。28335的eCAN中断在PIE中断控制器中挂在第9组eCAN0INTA对应PIEIER9的INTx5。接收中断的ISR里第一件事是读CANRMP寄存器判断是哪个邮箱收到了数据然后把数据从对应的CANMDL和CANMDH拷贝出来最后必须清除接收挂起标志RMP否则这个邮箱再也不会收下一帧数据。interrupt void eCAN0INTA_ISR(void) { Uint8 i; Uint16 rxLen; if (ECanaRegs.CANRMP.bit.RMP(0) 1) { rxLen ECanaRegs.MBOX(0).CANMSGCTRL.bit.DLC; if (rxLen 8) rxLen 8; rxData[0] (ECanaRegs.MBOX(0).CANMDL.all 24) 0xFF; rxData[1] (ECanaRegs.MBOX(0).CANMDL.all 16) 0xFF; rxData[2] (ECanaRegs.MBOX(0).CANMDL.all 8) 0xFF; rxData[3] ECanaRegs.MBOX(0).CANMDL.all 0xFF; rxData[4] (ECanaRegs.MBOX(0).CANMDH.all 24) 0xFF; rxData[5] (ECanaRegs.MBOX(0).CANMDH.all 16) 0xFF; rxData[6] (ECanaRegs.MBOX(0).CANMDH.all 8) 0xFF; rxData[7] ECanaRegs.MBOX(0).CANMDH.all 0xFF; rxDoneFlag 1; // 清接收挂起标志写1清除 ECanaRegs.CANRMP.all 0xFFFFFFFF; } // 清邮箱中断标志 ECanaRegs.CANINT.all 0xFFFFFFFF; // 应答PIE第9组 PieCtrlRegs.PIEACK.all PIEACK_GROUP9; }接收邮箱在初始化时要做几件事配置邮箱方向为接收、写入期望接收的报文ID、配置该邮箱的局部验收屏蔽寄存器LAM、使能邮箱、打开该邮箱的中断屏蔽MIM。这里我想单独说一下LAM因为网上很多资料会把SJA1000或者STM32的验收滤波概念直接搬过来说28335有ACCCode和AccMask寄存器这在eCAN上是不准确的。28335每个邮箱有一个独立的LAM寄存器置1的位表示不比较该ID位置0的位表示必须匹配。如果要把邮箱0设置成只收标准ID为0x100的帧MSGID填0x100LAM低11位全部置0如果不想过滤任何ID就把LAM相关位置成1。它的思路和STM32的屏蔽位模式类似但寄存器名和位定义完全不同查手册时认准“Local Acceptance Mask”即可。3.4 和VOFA等调试工具的配合热词里提到dsp28335和VOFA通讯这里补充一个常见误区VOFA这类上位机工具一般是走串口的示波器而28335的CAN走的完全是另一套协议栈DSP的CANTXA引脚输出不能直接接USB转TTL的串口工具。想用VOFA看CAN波形正确链路是DSP28335的CAN收发器 - 总线 - USB-CAN分析仪 - PC上的VOFA或CAN上位机USB-CAN分析仪在调试阶段几乎是必需品它能帮你抓总线上的原始报文确认DSP发出的帧格式对不对也能模拟一个节点回数据验证DSP的接收逻辑。很多设备同时支持CAN转串口功能这时候再把数据送到VOFA做波形显示是商业项目里很常见的调试组合。4. 实测排坑波形、总线错误和跨芯片对接4.1 用示波器判断通信好坏判断CAN通信好坏最直接的工具就是示波器。测差分波形要接在CANH和CANL之间不能只对地量一路信号。以PCA82C250这类5V供电的收发器为例隐性状态时CANH和CANL都接近2.5V差分电压接近0V显性状态时CANH被拉高到约3.5VCANL被拉到约1.5V差分电压约2V。如果测到的差分电压明显偏低比如只有0.5V先查收发器供电和终端电阻再看是不是线缆太长导致信号衰减。波形质量方面注意看上升沿和下降沿是否平滑。标准CAN波形会有明显的梯形边沿因为收发器内部有斜率控制或必须外接斜率电阻。边沿太陡会产生高频辐射边沿太缓或出现平台状台阶说明总线阻抗不匹配、分支线过长或节点数量过多。另外从波形上位时间的宽度反过来能算出实际波特率怀疑波特率配置不对时拿示波器量一个显性位的时间乘以总TQ数看是否和理论位时间一致。4.2 常见总线状态与错误计数器CAN控制器内部有两套错误计数器发送错误计数TEC和接收错误计数REC。28335的CANES寄存器里有错误状态位可以读出当前是否处于错误主动、错误被动或者bus-off状态。协议规定TEC或REC超过127就会进入错误被动超过255就会进入bus-off。实际调试中最常见的错误是ACK错误。发送节点发出帧后如果在应答槽没有检测到显性电平就说明总线上没有其他节点成功接收这一帧。原因是多方面的总线上只有一个节点、对端没有配置好、波特率不一致、没有终端电阻导致信号畸形。其次是位填充错误和CRC错误这类错误十有八九是波特率两边其实不同。注意CAN是CSMA/CRCACK的机制波特率不一致时不仅数据收不到发送端还会因为收不到ACK而反复重发最终进入bus-off。进入bus-off之后控制器会停止参与总线通信。恢复逻辑不能粗暴地整片DSP复位而是要让eCAN重新走一遍初始化流程进入配置模式、清空错误计数器、退出配置模式。中断处理函数里如果检测到BO位建议置一个标志位在主循环里做恢复操作不要在ISR里做耗时动作。4.3 和STM32对测时的几个坑DSP28335和STM32做CAN互联是特别常见的组合两边CAN控制器都是CAN 2.0兼容协议层面通信没问题但配置习惯不同会带来一些坑。第一是采样点不一致。STM32 bxCAN配置波特率时使用的是BS1和BS2分别对应28335的TSEG1和TSEG2。很多STM32例程默认BS1为9、BS2为2采样点在87.5%左右而28335如果TSEG1和TSEG2配成10和2采样点就是80%两边差距不算大短距离没问题。但如果两边参数差异大一个采样点70%、一个85%在总线负载高或者布线质量差时就会随机出现错误帧。所以联调时优先把两边的采样点配置到接近的值不要只看波特率数字一样就以为万事大吉。第二是帧格式和ID长度。28335的邮箱在配置MSGID时要显式设置IDE位标准帧IDE0扩展帧IDE1。STM32那边同样要区分标准ID和扩展ID。如果一边发标准帧、一边用扩展帧滤波报文永远进不了接收邮箱但发送端看着是成功的因为CAN应答只关心帧有没有被正确接收不关心接收方滤波是否通过。第三是两个节点也要考虑终端电阻。很多人在桌面上用两个开发板对测结果每块板子都自带120欧电阻连接在一起等效终端电阻变成60欧波形会变得非常难看。这时候要么去掉一块板的电阻要么改用外部电阻保证总线上只有两端各一个120欧。4.4 问题速查表现象可能原因排查顺序完全发不出去TA一直不置位总线无ACK单节点、收发器没接、终端电阻缺失示波器看TXD、CANTXA波形再接CAN分析仪确认总线电平能发送但对端收不到对端接收邮箱未使能、验收滤波不匹配、ID/帧格式不一致用USB-CAN分析仪抓包看报文ID和帧类型接收中断不触发邮箱未使能、MIM未打开、PIEIER9未使能、RMP标志未清检查邮箱状态寄存器单步看CANRMP和CANINT值偶发错误帧、总线故障率高波特率配置不对、SJW太小、终端电阻缺失、分支线过长示波器看波形边沿用CAN分析仪统计错误计数器一上电就bus-offGPIO复用配置错误、CANTXA引脚被其它外设抢占、总线电平被拉死检查GPAMUX配置断开总线单独看TXD波形和STM32通信走动时好时坏两侧采样点不一致、共地不良、波特率精度差异统一采样点配置测量两侧参考地压差必要时加共模电感这张表是我调试时实际对照过的排查顺序。遇到问题先不要急着改代码先确认物理层正常再查配置最后才是逻辑问题。CAN这种东西软件配置来回就那么几个寄存器真正的坑大多在接线、波形和采样点上。最后分享一个我自己的习惯每次初始化eCAN都会在CCR置1后加一个延时再等CCE不要把等待循环写得太紧这样虽然代码看起来多几行但在某些主频配置不稳定、调试器介入的场合可以有效避免CCE还没稳定就误判超时的问题。另外多邮箱项目里建议把邮箱号固定下来并写在注释里比如邮箱0接收心跳、邮箱1发送控制字、邮箱2接收状态反馈不然调试一段时间后自己都会忘记哪个邮箱在干什么。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价