资讯详情

资讯详情

DSP28335 eCAN CAN通信程序:邮箱配置与调试避坑

简介面向使用TI DSP28335进行CAN通信开发的嵌入式学习者与工程人员这套程序资料围绕eCAN模块的初始化、波特率与滤波器配置、消息收发、中断响应及错误检测恢复展开可用于课程实验、项目原型和代码参考。压缩包共74个文件、约480KB以C源文件与配套头文件为核心另有obj中间文件、asm启动与延时汇编、cmd链接命令文件以及pjt工程和map/log输出便于在CCS环境中直接查看工程结构并复用关键函数。已有4029人学习或下载说明其在28335 CAN入门与调试场景中具有一定参考价值。读者可据此理解CAN控制器寄存器操作、发送缓冲区与接收FIFO处理流程并借鉴示例程序组织发送、接收和中断服务代码减少从零搭建通信框架的时间。1. 从一块跑不起来的板子说起DSP28335 CAN 通信程序到底解决了什么手头这块 28335 CAN 通信程序最早是我从一个只跑通自收自发的小工程里扒出来的。板子上电、集成开发环境编译通过、下载也显示成功可 CAN 分析仪上一帧都没有收发器输出脚安静得像没上电。后来才发现问题不在 CAN 协议本身而在 eCAN 外设的时钟、GPIO 复用和邮箱使能顺序上。这份程序干的事很具体把 DSP28335 的 eCAN-A 配成标准帧收发通道完成 500 kbps 下的邮箱发送、接收中断和错误状态读取。适合手里已经有 28335 板子、需要把 CAN 通信接进电机控制或采集节点的开发者也适合刚接触 C2000 外设、想找一个能上板跑的 CAN 最小闭环的人。2. 工程骨架拆解从源码目录到 eCAN 外设的初始化顺序2.1 典型工程目录与文件职责拿到一个 28335 CAN 工程先别急着点编译。我一般先看目录里有没有把外设头文件、源文件和应用层分开。一个能上板的最小闭环常见目录长下面这样。不同工程的文件名会有差异但职责基本跑不出这张表。文件或目录职责二次开发时最常改的地方main.c系统初始化、外设初始化、主循环初始化顺序、任务调度DSP2833x_ECan.c/.heCAN 寄存器结构体与位定义一般不动确认头文件版本匹配DSP2833x_SysCtrl.c系统时钟、外设时钟使能PCLKCR0里的 eCAN 时钟位DSP2833x_Gpio.cGPIO 复用配置GPIO30/31 复用为 CAN 引脚CAN.c/CAN.h邮箱配置、发送、接收、错误处理邮箱号、标识符、波特率、中断DSP2833x_GlobalVariableDefs.c寄存器变量定义一般不动最小闭环不需要把 32 个邮箱全用上。我一般先留两个发送邮箱、两个接收邮箱发送邮箱负责周期状态帧和命令应答接收邮箱负责上位机命令和广播帧。邮箱号一旦定下来后面所有CANMD、CANME、CANMIM、CANRMP的位操作都要跟着改最怕只改了结构体里的MBOX16忘了改使能位结果代码看起来对总线就是没反应。工程里还要确认系统时钟。28335 常见主频是 150 MHz但有些板子为了降功耗或匹配外设会跑到 100 MHz 或 120 MHz。eCAN 的位定时直接依赖系统时钟主频改了而BRPREG没改波特率就会偏。下面所有代码都按 150 MHz 写换板子先看SysCtrlRegs.PLLSTS和时钟配置。2.2 时钟、GPIO 复用与 eCAN 模块上电eCAN 初始化最容易翻车的地方不是邮箱而是外设根本没被“叫醒”。28335 的外设时钟默认不是全开的GPIO 也要从普通 IO 切到外设功能。下面这段是我一般会先跑通的底层初始化。#include DSP2833x_Device.h #include DSP2833x_Examples.h void ECAN_GPIO_Init(void) { EALLOW; // 允许写保护寄存器 SysCtrlRegs.PCLKCR0.bit.ECANAENCLK 1; // 打开 eCAN-A 外设时钟 GpioCtrlRegs.GPAMUX2.bit.GPIO30 2; // GPIO30 复用为 CANTXA GpioCtrlRegs.GPAMUX2.bit.GPIO31 2; // GPIO31 复用为 CANRXA GpioCtrlRegs.GPADIR.bit.GPIO30 1; // 发送脚方向为输出 GpioCtrlRegs.GPADIR.bit.GPIO31 0; // 接收脚方向为输入 EDIS; // 恢复写保护 }逻辑说明EALLOW和EDIS是一对28335 里很多复用和时钟寄存器受保护不先解锁写进去也不报错读回来还是旧值这种“静默失败”最容易让人怀疑硬件。PCLKCR0.bit.ECANAENCLK置 1 之后eCAN-A 才有工作时钟GPIO30/31 的GPAMUX2设为 2才是 CAN 功能设为 0 就是普通 IO收发器那边自然没波形。方向位不是所有工程都写但写上更稳避免接收脚被误配成输出。参数说明GPIO30/31 是 28335 eCAN-A 的常见默认引脚但不同封装、不同板子可能把 CAN 引到别的脚上接线前一定对着原理图确认。GPAMUX2的字段名也要和头文件对上有的工程写GPIO30有的写GPIO30_BITS本质是同一个寄存器位。EALLOW只包住需要解锁的写操作不要把整段初始化都包进去后面查问题时分不清哪些是保护寄存器。eCAN 模块本身还要软复位一次。软复位不是必须每次都做但在线调试反复下载、外设状态残留时先复位能省很多事。下面这段放在ECAN_GPIO_Init()之后。void ECAN_ModuleReset(void) { ECanaRegs.CANMCR.bit.SOFTRESET 1; // 触发 eCAN 软复位 DELAY_US(100); // 等复位稳定 ECanaRegs.CANMCR.bit.SOFTRESET 0; // 释放软复位 while (ECanaRegs.CANMCR.bit.SOFTRESET ! 0) { // 等待复位完成正常很快 } }逻辑说明SOFTRESET置 1 后eCAN 的邮箱、错误计数、位定时都会回到默认状态释放后要等它自己清 0不能刚写 0 就往下配。DELAY_US(100)是经验值不是严格时序要求但给够时间能避开偶发配置不生效。参数说明如果工程里没有DELAY_US可以用一个简单的循环延时替代别用编译器优化掉的空循环。2.3 波特率与位定时参数怎么算CAN 不通时波特率对不上是高频原因。28335 的 eCAN 位定时由CANBTC决定核心是三个量BRP 分频、TSEG1、TSEG2。位时间由 1 个同步段、TSEG1 段、TSEG2 段组成采样点落在 TSEG1 结束的位置。下面按 150 MHz 系统时钟、500 kbps 给一组常用参数。void ECAN_BitTiming_500K(void) { ECanaRegs.CANMC.bit.CCR 1; // 请求进入配置模式 while (ECanaRegs.CANMC.bit.CCE ! 1) {} // 等配置模式使能 ECanaRegs.CANBTC.bit.BRPREG 9; // 分频值 BRPREG 1 10 ECanaRegs.CANBTC.bit.TSEG1REG 9; // TSEG1 9 1 10 个 tq ECanaRegs.CANBTC.bit.TSEG2REG 3; // TSEG2 3 1 4 个 tq ECanaRegs.CANBTC.bit.SJWREG 3; // 同步跳转宽度 ECanaRegs.CANMC.bit.CCR 0; // 退出配置模式 while (ECanaRegs.CANMC.bit.CCE ! 0) {} }逻辑说明eCAN 的 CAN 时钟常见是系统时钟的一半150 MHz 系统时钟对应 75 MHz CAN 时钟。BRPREG9表示分频 10得到 7.5 MHz 的 tq 时钟一个位时间由1 TSEG1 TSEG2 1 10 4 15个 tq 组成7.5 MHz / 15 500 kbps。采样点约(1 10) / 15 73.3%对大多数 500 kbps 总线够用。参数说明如果系统时钟不是 150 MHz先算 CAN 时钟再倒推BRPREGTSEG1REG和TSEG2REG写的是“值减一”不是直接写段长度。SJWREG一般取 1 到 4总线长、节点多时可以适当放大但不要超过 TSEG2。目标速率系统时钟BRPREGTSEG1REGTSEG2REG采样点500 kbps150 MHz99373.3%250 kbps150 MHz199373.3%125 kbps150 MHz399373.3%提示改波特率时不要只改BRPREGTSEG1REG、TSEG2REG和SJWREG要一起复核。改完先用回环模式看能不能收再上真实总线。3. 核心收发链路邮箱配置、发送触发与接收中断3.1 邮箱方向、标识符与验收屏蔽28335 的 eCAN 有 32 个邮箱每个邮箱可以配成发送或接收。方向由CANMD决定使能由CANME决定标识符写在MSGID里。标准帧和扩展帧的区别在MSGID.IDE位标准帧用 11 位标识符扩展帧用 29 位。下面这张表是我在一个采集节点里常用的分配读者可以按自己的协议改。邮箱方向用途标识符MBOX0发送周期状态帧0x101MBOX1发送命令应答0x102MBOX16接收上位机命令0x201MBOX17接收广播帧0x300配置接收邮箱时CANMD对应位要置 1CANME对应位也要置 1。发送邮箱反过来CANMD对应位清 0。下面以 MBOX16 为例。void CAN_SetupRxMbox16(Uint32 id) { EALLOW; ECanaRegs.CANME.bit.ME ~(1U 16); // 先关邮箱使能 EDIS; ECanaMboxes.MBOX16.MSGID.all id; // 标准帧标识符 ECanaMboxes.MBOX16.MSGCTRL.bit.DLC 8; // 接收长度按 8 配 ECanaRegs.CANMD.bit.MD | (1U 16); // 1 接收 ECanaRegs.CANME.bit.ME | (1U 16); // 再打开邮箱使能 }逻辑说明先关CANME再改MSGID和CANMD是为了避免配置到一半时邮箱已经参与收发。MSGID.all直接写标识符标准帧不要带IDE位如果写扩展帧要把0x80000000或头文件里的IDE位带上。DLC是数据长度接收邮箱可以配 8实际收到多少看MSGCTRL.DLC。参数说明1U 16里的 16 就是邮箱号换邮箱时这个数、MBOX16、CANMD位、CANME位要同步改少改一处就会出现“配置了但收不到”。验收屏蔽不是每个工程都配但总线节点多的时候最好配。CANLAM和CANMASK决定哪些位参与验收配得不对会把该收的帧滤掉。我一般先全接收确认链路通了再收紧屏蔽别一上来就把自己滤死。3.2 发送一帧的标准流程发送邮箱的流程比接收简单等上一次发送完成、清发送应答、填标识符和数据、置CANTRS触发。下面这段以 MBOX0 发标准帧为例数据长度支持 0 到 8。void CAN_SendStd_Mbox0(Uint16 id, const Uint8 *buf, Uint8 len) { Uint32 low 0, high 0; Uint8 i; if (len 8) len 8; for (i 0; i len i 4; i) { low | ((Uint32)buf[i] (8 * i)); } for (i 4; i len i 8; i) { high | ((Uint32)buf[i] (8 * (i - 4))); } while (ECanaRegs.CANTA.bit.TA0 0) { // 等 MBOX0 上一次发送完成 } ECanaRegs.CANTA.bit.TA0 1; // 写 1 清发送应答 ECanaMboxes.MBOX0.MSGID.all id; ECanaMboxes.MBOX0.MSGCTRL.bit.DLC len; ECanaMboxes.MBOX0.MDL.all low; ECanaMboxes.MBOX0.MDH.all high; ECanaRegs.CANTRS.bit.TRS0 1; // 触发 MBOX0 发送 }逻辑说明CANTA是发送应答寄存器发送成功对应位置 1清标志要写 1不是写 0。CANTRS是发送请求置 1 后 eCAN 自己找总线空闲时机发出去。数据按小端填MDL放第 0 到第 3 字节MDH放第 4 到第 7 字节。参数说明id是 11 位标准帧标识符不要超过 0x7FFlen超过 8 会被截断协议层最好自己先校验。等待TA0的while循环没有超时总线异常时可能卡死量产代码要加超时计数后面二次开发会讲。发送邮箱的CANMD位必须是 0CANME位必须是 1。有人只配了MSGID和CANTRS忘了CANME现象就是CANTRS置了CANTA永远不置位总线也没有帧。这个坑我踩过查了半天以为是收发器坏了。3.3 接收中断与环形缓冲接收有两种做法主循环轮询CANRMP或者用邮箱中断。实时性要求高时用中断中断里只做“取帧、清标志、入环形缓冲”协议解析放到主循环。下面是一个最小接收中断。__interrupt void can_rx_isr(void) { Uint16 miv ECanaRegs.CANGIF0.bit.MIV0; if (miv 16) { Uint32 id ECanaMboxes.MBOX16.MSGID.all 0x1FFFFFFF; Uint8 dlc ECanaMboxes.MBOX16.MSGCTRL.bit.DLC; Uint32 low ECanaMboxes.MBOX16.MDL.all; Uint32 high ECanaMboxes.MBOX16.MDH.all; // 这里把 id / dlc / low / high 写入环形缓冲 // 不要在中中断里做耗时解析 ECanaRegs.CANRMP.bit.RMP16 1; // 写 1 清接收挂起 } ECanaRegs.CANGIF0.all 0xFFFFFFFF; // 清全局中断标志 PieCtrlRegs.PIEACK.all PIEACK_GROUP9; }逻辑说明CANGIF0.MIV0给出当前最高优先级的中断邮箱号miv 16表示 MBOX16 触发。读取MSGID、MSGCTRL、MDL、MDH之后必须清CANRMP对应位否则中断会反复进来。最后清CANGIF0和 PIEACK少清一个都会卡在中断里。参数说明PIEACK_GROUP9是 eCAN 所在的 PIE 组具体中断通道号要在 PIE 向量表里对应好不同工程的向量表文件名可能不同别只改函数名不改注册。环形缓冲建议用“头尾指针 长度”的实现中断只写头主循环只读尾。缓冲大小按总线负载定500 kbps 下如果每帧 8 字节负载不低缓冲太小会丢帧。我一般先给 32 或 64 帧跑一段时间看溢出计数再决定加不加。4. 上板联调从编译下载到 CAN 分析仪抓包4.1 硬件连接与终端电阻软件配完上板第一件事不是看代码是看线。CAN_H 和 CAN_L 要接对收发器供电要量终端电阻要确认。总线两端各 120Ω中间节点不要随便加。板子上如果已经焊了 120Ω分析仪那边又并一个总线负载会偏重短距离可能还能跑长一点就偶发错误帧。我一般按下面顺序查硬件量收发器 VCC 和 GND确认不是 3.3V 供电却接了 5V 器件。量收发器的待机或使能脚有些器件拉低才工作悬空状态不确定。断电量 CAN_H 和 CAN_L 之间电阻两端各 120Ω 时约 60Ω只有一端时约 120Ω。确认 28335 的 GPIO30/31 和收发器 TXD/RXD 没有交叉接反。共地。CAN 是差分但调试时分析仪和板子不共地波形会很难看。注意不要带电插拔 CAN 线收发器差分脚被浪涌打坏的概率不低。调试台架上先断电接线再上电。4.2 编译下载与在线调试编译下载本身不复杂关键是下载后看什么。我一般先让程序停在初始化之后看三个地方PCLKCR0.ECANAENCLK是不是 1GPAMUX2.GPIO30/31是不是 2CANMC.CCE在配置阶段是不是 1。这三个有一个不对后面邮箱配得再漂亮也没用。在线调试时CANES寄存器很有用。它里面有错误计数、总线关闭标志、错误类型。发送一帧后如果CANTA不置位先看CANES.TXERR和CANES.BOFF。BOFF1说明总线关闭通常是错误计数累计到阈值常见原因是波特率不匹配、终端电阻不对、线接反。别急着重烧程序先把CANES读出来。还有一个小习惯下载后先跑回环再上真实总线。回环能排除外部接线和收发器问题把问题锁在芯片配置里。回环通了真实总线不通再去查收发器和线束排查范围小一半。4.3 用回环模式先自测eCAN 支持自测模式发送脚内部回环不需要外部节点应答。下面这段在配置模式里把STM置 1。void CAN_EnterSelfTest(void) { ECanaRegs.CANMC.bit.CCR 1; while (ECanaRegs.CANMC.bit.CCE ! 1) {} ECanaRegs.CANMC.bit.STM 1; // 自测模式内部回环 ECanaRegs.CANMC.bit.CCR 0; while (ECanaRegs.CANMC.bit.CCE ! 0) {} }逻辑说明STM1后发送邮箱发出的帧会在内部回到接收邮箱不依赖外部收发器。验证时先配好一个发送邮箱和一个接收邮箱发送一帧看CANRMP对应位是否置 1接收邮箱的MSGID和数据是否和发送一致。参数说明自测模式只适合验证芯片配置和邮箱逻辑不能验证收发器、终端电阻和线束验证完记得把STM清 0否则上真实总线时可能收不到外部帧。回环通过后再把板子接到分析仪上。先发一帧固定数据分析仪看标识符、DLC、数据对不对再让分析仪发一帧看接收中断能不能进。两边都通再上周期发送和协议解析。5. 避坑与排查CAN 不通时先看哪几个寄存器5.1 现象一上电后总线无任何波形现象程序下载成功发送函数也调了CAN 分析仪一帧没有示波器看 CANTXA 有短脉冲但 CAN_H/CAN_L 没有差分波形。原因常见有三类。第一收发器没供电或待机脚状态不对第二GPIO30/31 没复用成 CAN 功能芯片内部有发送动作但没送到引脚第三CANME没使能或发送邮箱方向配错CANTRS置了但 eCAN 没真正发。解决先量收发器 VCC 和待机脚再回读GPAMUX2和PCLKCR0确认 eCAN 时钟和引脚复用。然后看CANMD对应位是不是 0、CANME对应位是不是 1。最后看CANTA有没有置位CANTA不置位说明帧根本没发出去别在总线上找原因。5.2 现象二能发不能收现象发送正常分析仪能收到板子发的帧但分析仪发命令板子接收邮箱的CANRMP不置位中断也不进。原因接收邮箱CANMD位没置 1或者CANME没使能验收屏蔽配错把帧滤掉了接收中断掩码CANMIM没开CANGIM全局中断没开PIE 向量没注册。解决按“邮箱方向 → 邮箱使能 → 验收屏蔽 → 邮箱中断 → 全局中断 → PIE 向量”的顺序查。先关掉验收屏蔽全接收试一帧通了再收紧屏蔽。中断不进时先看CANRMP有没有置位置位了但中断不进问题在中断使能或 PIE不在 CAN 收发。5.3 现象三偶发丢帧或错误帧现象短时间跑正常跑几分钟后分析仪看到错误帧错误计数慢慢涨偶尔丢一帧。原因波特率有误差、采样点偏、终端电阻不匹配、线太长、共地不好、变频器干扰。28335 的位定时如果BRPREG算错误差可能不大短帧能过长帧或连续帧就翻车。解决先复核CANBTC四个参数用分析仪看实际波特率误差再量终端电阻两端各 120Ω线束用双绞线CAN_H/CAN_L 不要和电机动力线捆在一起必要时降速到 250 kbps 或 125 kbps 验证。采样点一般 75% 左右长总线可以适当提前。5.4 现象四总线关闭后不恢复现象跑一段时间后收发全停CANES.BOFF置 1错误计数很高复位才能恢复。原因总线错误累计到阈值eCAN 进入 bus-off。常见触发是波特率不匹配、线束短路、终端电阻严重不对、某个节点持续发错误帧。程序里没有 bus-off 恢复策略就一直停着。解决在错误处理里读CANES确认是 bus-off 后清BOFF位重新走一遍位定时和邮箱使能更稳的做法是记录错误计数连续多次 bus-off 就停机报警。不要只清标志不查原因否则会反复进 bus-off。5.5 现象五仿真器一停就断线现象在线调试时设断点CPU 停住eCAN 还在收恢复运行后接收缓冲溢出或者程序跑飞CAN 不工作。原因断点停 CPU 但外设不停邮箱继续收帧CANRMP累积中断里设断点更容易把中断状态打乱看门狗没喂也会复位。解决尽量不在 CAN 中断里设断点要停就先关全局中断恢复前清CANRMP和CANGIF调试阶段把看门狗先关掉量产再打开。这个问题没有代码可抄靠习惯。6. 二次开发改造把点灯式例程改成可复用的 CAN 通信层6.1 分层封装把寄存器操作收进驱动层最小例程里应用层直接写ECanaMboxes.MBOX0能跑但第二个项目就不想再抄一遍。我一般分成四层应用层、协议层、驱动层、硬件层。应用层只调Can_Send和Can_Recv协议层管标识符和打包驱动层管邮箱本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →