DSP28335 eCAN自发自收例程详解:邮箱机制与寄存器配置实战

📅 发布时间:2026/9/15 15:59:44
DSP28335 eCAN自发自收例程详解:邮箱机制与寄存器配置实战
简介面向DSP28335嵌入式开发者的eCAN通信实例资料适合需要掌握CAN总线自发自收配置与调试的汽车电子或工业自动化领域工程师。压缩包共13个文件以可编译的C源码、CCS工程文件.pjt、链接命令文件.lkf为核心辅以GEL初始化脚本、数据库文件.dbf/.fpt/.cdx、编译日志等总大小仅137KB便于快速搭建实验环境并定位关键代码。资料详细讲解eCAN模块的初始化、报文ID与接收滤波设置、标准/扩展帧传输模式并特别说明模块内含双物理接口与发送/接收FIFO可支持多节点通讯中的优先级调度同时给出通过验证的自发自收实现过程涵盖总线错误检测、离线恢复机制等帮助读者系统理解DSP28335的CAN通信机制。已有313人学习该包适合正在基于DSP28335开展CAN接口开发或调试的中级嵌入式工程师使用。1. DSP28335 eCAN 自发自收例程到底能验证什么很多人拿到 ecan.rar看到 Example_2833xECanBack2Back.c 就把它当成 DSP28335 的标准 CAN 双机通信例程烧进板子却发现总线上抓不到波形。其实这是 TI 为 F28335 eCAN 模块设计的自发自收Back2Back验证工程发送邮箱发出的报文在模块内部直接回环到接收邮箱不依赖外部 CAN 收发器和总线。这个特性最大的价值在于隔离故障——新板子 CAN 不通时先跑通它就能区分是 eCAN 寄存器位域配置错误还是硬件链路收发器、终端电阻、接线问题。适合刚接触 C2000 系列、被 CANBTC 位时序参数绕晕的工程师也适合做量产前单板自检脚本。下面从 eCAN 邮箱机制开始拆这个工程。2. eCAN 邮箱机制、自测模式与寄存器选型2.1 为什么 F28335 用邮箱式 eCAN 而不是传统收发缓冲普通单片机上的 CAN 控制器通常只有 2 到 3 个发送缓冲和少量接收缓冲报文多了就要 CPU 频繁介入搬数据。DSP28335 的 eCAN 模块走的是完全不同的邮箱Mailbox架构32 个独立邮箱每个邮箱由 MSGID消息 ID、MSGCTRL控制字、MDL/MDH8 字节数据组成可以独立配置为发送邮箱或接收邮箱。这种设计的直接收益是多节点组网时可以把不同 ID 的报文固定映射到不同邮箱由硬件完成 ID 匹配后再通知 CPUCPU 只需要在接收中断里把数据搬走。邮箱的仲裁规则也值得注意发送时邮箱号越大优先级越高MBOX31 最高、MBOX0 最低。自发自收例程用 MBOX0 发、MBOX1 收刻意选了最低优先级的邮箱就是为了验证在最不利的仲裁条件下数据也能完整回环。实际工程里给重要报文分配高号邮箱低频报文放低号邮箱是 eCAN 邮箱分配的常见做法。2.2 关键寄存器速查表eCAN 的寄存器是内存映射的操作邮箱前要先搞清楚每个寄存器的作用。下面这张表只列自发自收会碰到的寄存器32 位寄存器全部通过ECanaRegs结构体访问。寄存器关键位/字段作用CANMCCCR, STM, ABO模块控制CCR 进入配置模式STM 置自测模式ABO 自动恢复总线CANBTCBRP, TSEG1, TSEG2, SJW位时序配置直接决定波特率与采样点CANMEME0~ME31邮箱使能对应位写 1 使能对应邮箱CANMDMD0~MD31邮箱方向0 发送、1 接收CANTRSTRS0~TRS31发送请求写 1 触发对应邮箱发送CANTATA0~TA31发送确认帧发出后硬件置 1写 1 清除CANRMPRMP0~RMP31接收挂起邮箱收到帧后置 1写 1 清除CANESCCE, EW, EP, BO模块状态CCE 表示配置模式已进入BO 表示 Bus OffCANGAM / CANLAM屏蔽位全局/局部接收屏蔽配置哪些 ID 位必须匹配2.3 自测模式与配置模式的寄存器级实现自发自收能成立靠的是 CANMC 寄存器里的 STM 位。STM 置 1 后发送邮箱发出的帧不会经过 CAN 收发器上总线而是在 eCAN 模块内部直接绕回接收路径行为表现和正常接收完全一致CANTA 会置位、CANRMP 会置位、数据能读回来。区别只在 CANES 里跟总线错误相关的计数器不会变化因为帧根本没离开芯片。配置模式是改动 CANBTC、CANGAM 这类受保护寄存器的前提标准流程是先请求进入配置模式改完再退出EALLOW; ECanaRegs.CANMC.bit.CCR 1; // 请求进入配置模式 while (ECanaRegs.CANES.bit.CCE ! 1) {} // 等待硬件确认进入 ECanaRegs.CANBTC.bit.BRP 14; // 波特率预分频这里是举例 ECanaRegs.CANBTC.bit.TSEG1 14; ECanaRegs.CANBTC.bit.TSEG2 5; ECanaRegs.CANMC.bit.CCR 0; // 退出配置模式 while (ECanaRegs.CANES.bit.CCE ! 0) {} // 等待生效 EDIS;这里的重点是while等待循环。CCR 只是请求硬件真正进入配置模式后 CCE 才会置位不能写完 CCR 马上写 CANBTC否则配置被忽略。这也是新手最容易踩的坑——波特率怎么改都不对回头看是没等 CCE。3. Example_2833xECanBack2Back 工程文件与 CCS 3.3 环境复盘3.1 解压后每个文件干什么这个例子是 CCS 3.3 时代的工程文件结构和现在 CCS 的工程差别很大。解压后看到一堆扩展名奇怪的文本先别急着删逐个搞清楚文件类型作用Example_2833xECanBack2Back.pjtCCS 工程文件编译入口记录源文件列表、编译选项、链接配置Example_2833xECanBack2Back.cC 源码主程序包含 eCAN 初始化和 Back2Back 回环逻辑Debug.lkf链接命令文件等价于 .cmd定义 MEMORY/SECTION 布局CCS 3.3 里在 Linker 选项卡指定Example_2833xECanBack2Back.gelGEL 脚本CCS 连接目标板后执行的初始化脚本含时钟配置cc_build_Debug.log构建日志上次编译的输出排查报错先看它CS_SYMBOL.DBF / FILE.CDX / FILE.FPT 等符号索引CCS 3.3 调试会话生成的符号库删除后会自动重建不影响编译.paf2 / .sbl中间产物编译预处理输出和调试状态缓冲可删提示DBF、CDX、FPT 是 xBase 系数据库格式CCS 3.3 用它管理断点和符号不能放进版本控制但也不需要手工维护。3.2 从零构建这个例程的步骤把工程拉到自己环境里的操作顺序安装 CCS 3.3 并打上支持 C28x 的补丁然后通过 Project → Open 选择.pjt文件。在 Project → Build Options 里确认目标器件选的是 TMS320F28335编译器版本选 C2000 CodeGen。确认 Linker 选项卡里链接命令文件指向Debug.lkf如果自己建工程就换成.cmd文件。按 F7 构建打开cc_build_Debug.log看输出常见错误集中在头文件路径和链接段地址冲突。连接仿真器后先在 GEL 菜单里执行OnTargetConnect()初始化时钟再加载.out文件运行。最后一步很容易漏。F28335 上电后默认时钟不是 150MHz不执行 GEL 脚本CAN 波特率全部按错误时钟计算自发自收大概率收不到数据表现为 CANTA 正常但 CANRMP 永远不置位。3.3 GEL 初始化脚本与时钟链.gel文件里最核心的是 PLL 初始化F28335 典型配置是外部 30MHz 晶振、内部 PLL 倍频到 150MHz 系统时钟OnTargetConnect() { GEL_MapAdd(0x000000, 0x100000, 0x080000, 0); GEL_TextOut(Connect OK\n); *(int *)0x7021 0x0A; // PLLCR 1030MHz × 10 / 2 150MHz }0x7021是 PLLCR 寄存器地址写入 10 表示倍频系数。SYSCLKOUT OSCCLK × PLLCR / 230MHz 外部晶振乘 10 再除 2正好是 150MHz。eCAN 模块的时钟来自系统时钟域所以 GEL 里时钟配错后面 CANBTC 所有参数都失去意义。用grep快速看编译日志也是个习惯grep -iE error|warning cc_build_Debug.log | tail -20这条命令直接过滤出编译告警和错误不用在几百行日志里翻。4. eCAN 初始化、波特率计算与自发自收收发代码4.1 初始化函数逐行拆解基于 TI 例程风格完整初始化逻辑如下。注意 F28335 的 eCAN 寄存器受写保护操作前要加EALLOW结束后EDISvoid InitECan(void) { // 1. 邮箱使能与方向配置 ECanaRegs.CANME.all 0xFFFFFFFF; // 先全部使能便于修改属性 ECanaRegs.CANMD.all 0x0; // 全部设为发送方向 ECanaRegs.CANMD.bit.MD1 1; // 邮箱1改为接收方向 ECanaRegs.CANME.all 0x00000003; // 只保留邮箱0和1使能 // 2. 进入配置模式配置波特率 ECanaRegs.CANMC.bit.CCR 1; while (ECanaRegs.CANES.bit.CCE ! 1) {} ECanaRegs.CANBTC.bit.BRP 14; // TQ (141)/150MHz 100ns ECanaRegs.CANBTC.bit.TSEG1 14; // 传播段相位段1 14 TQ ECanaRegs.CANBTC.bit.TSEG2 5; // 相位段2 5 TQ ECanaRegs.CANBTC.bit.SJW 1; // 同步跳转宽度 ECanaRegs.CANGAM.all 0x0; // 全局接收屏蔽不屏蔽任何位 ECanaRegs.CANMC.bit.CCR 0; while (ECanaRegs.CANES.bit.CCE ! 0) {} // 3. 置自测模式帧在模块内部回环 ECanaRegs.CANMC.bit.STM 1; // 4. 清挂起标志进入干净状态 ECanaRegs.CANTA.all 0xFFFFFFFF; ECanaRegs.CANRMP.all 0xFFFFFFFF; EDIS; }这段代码里的关键在于CANME全部使能后改CANMD是因为部分器件版本在邮箱未使能时不允许修改属性位。改完只保留 0 和 1 两个邮箱避免其他空闲邮箱产生干扰。CANBTC配置必须在配置模式下进行出了配置模式再写无效。4.2 500kbps 位时序参数表与采样点eCAN 的位时间由三部分组成同步段 1 TQ、传播段加相位段 1TSEG1、相位段 2TSEG2。位时间 TQ 数 1 TSEG1 TSEG2而每个 TQ 的时间是 (BRP 1) / SYSCLKOUT。以 150MHz 系统时钟为例常用速率参数如下目标波特率BRPTSEG1TSEG2位时间 TQ实际波特率采样点500kbps1414520500kbps75%250kbps2914520250kbps75%125kbps5914520125kbps75%采样点位置 (1 TSEG1) / (1 TSEG1 TSEG2)上面的组合全部落在 75%这是 CAN 总线比较通用的采样点位置兼顾传输延迟和抗干扰。500kbps 时 TQ 100ns位时间 2us正好符合标准帧要求的位时序。提示1Mbps 在 150MHz 系统时钟下没有整数分频组合用 BRP 怎么凑都有偏差。需要 1Mbps 时常见做法是把 SYSCLKOUT 降到 100MHz 或改用外部 20MHz 晶振方案保证位时间能整除。4.3 发送与接收的回环代码发送端配置邮箱 0接收端用邮箱 1。先看发送这里把 ID、控制字、数据全部写入对应邮箱字段void SendBack2Back(void) { // 邮箱0发送邮箱标准帧 ECanaMboxes.MBOX0.MSGID.bit.IDE 0; // 标准帧标识符 ECanaMboxes.MBOX0.MSGID.bit.AME 0; // 不使用接收屏蔽比较 ECanaMboxes.MBOX0.MSGID.bit.STDMSGID 0x123; // 标准ID ECanaMboxes.MBOX0.MSGCTRL.bit.DLC 8; // 数据长度8字节 ECanaMboxes.MBOX0.MDL.all 0x11223344; // 低4字节数据 ECanaMboxes.MBOX0.MDH.all 0x55667788; // 高4字节数据 ECanaRegs.CANTRS.all 0x1; // 触发邮箱0发送 while (ECanaRegs.CANTA.all ! 0x1) {} // 等待发送确认 ECanaRegs.CANTA.all 0x1; // 写1清除确认位 }STDMSGID 字段存放的才是实际 ID直接对 MSGID.all 整体赋值会把 IDE、AME 这些控制位一起覆盖掉这是很隐蔽的写法错误。CANTRS.all 0x1只发送邮箱 0等待 CANTA 第 0 位置位确认后再用写 1 的方式清除。接收端对称只不过改成了查询 CANRMPvoid RecvBack2Back(void) { Uint32 rcvId; Uint32 rcvL, rcvH; while (ECanaRegs.CANRMP.all ! 0x2) {} // 邮箱1的挂起位置位 rcvL ECanaMboxes.MBOX1.MDL.all; rcvH ECanaMboxes.MBOX1.MDH.all; rcvId ECanaMboxes.MBOX1.MSGID.bit.STDMSGID; ECanaRegs.CANRMP.all 0x2; // 清除邮箱1接收挂起 // 校验回环数据 if (rcvId 0x123 rcvL 0x11223344 rcvH 0x55667788) { GpioDataRegs.GPCTOGGLE.bit.GPIO34 1; // 翻转IO指示成功 } }CANRMP.all ! 0x2判断的是邮箱 1 的挂起位因为 MBOX1 对应 bit1所以是 0x2 而不是 0x1。收到数据后必须写 1 清除挂起位否则下次接收永远不会触发。实际工程里更推荐把接收放到中断里做把 CANGIM 的 I1EN 打开服务程序里读 CANGIF1 确认中断源再走同样的读数据流程。5. 位时序实测、Bus-Off 恢复与多节点前的三个检查5.1 用示波器核对采样点自发自收跑通后接上外部收发器把 STM 位清 0就能在 CANH/CANL 上看到真实波形。用示波器抓一帧数据的显性电平对比测量实际位宽度和协议计算值能反推位时序配没配错。示波器现象可能原因处理方向CANH/CANL 静态都在 2.5V 附近无差分收发器没工作或 STM 仍为 1检查 3.3V 供电和 STM 位显性位比计算值偏宽TSEG2 过大导致位时间偏长按公式重算 TSEG 组合帧能收到但偶发错误帧采样点距离跳变沿太近把采样点调到 75% 附近5.2 Bus-Off 自动恢复配置多节点环境下节点出错累计会导致 Bus OffeCAN 的 CANES 寄存器里 BO 位会置位。合理做法是开启自动恢复总线功能同时在错误状态翻转时记录日志EALLOW; if (ECanaRegs.CANES.bit.BO 1) { // 进入 Bus Off读取错误计数后请求自动恢复 errCount ECanaRegs.CANTEC.all; ECanaRegs.CANMC.bit.ABO 1; // 自动恢复总线条件满足自动退出Bus Off } EDIS;ABO 置 1 后eCAN 在总线上检测到 128 次连续的隐性位后自动恢复不需要 CPU 介入。注意不要在 ISR 里做这件事Bus Off 恢复过程有延时放在主循环的低优先级任务里更稳妥。5.3 上多节点前的自检清单把自发自收工程改造成双机通信前我会依次过三个检查一是把 STM 清 0接上带 120 欧终端电阻的总线用另一个节点回发数据确认双向收发二是连续跑 10000 帧回环统计是否有丢帧或错误帧错误率超过十万分之一就要回头查位时序和终端电阻三是故意短路 CANH 和 CANL 触发错误确认 ABO 恢复逻辑能自动跳出 Bus Off 状态。把这些检查放到你的自检函数里连续回环一万帧无错再考虑上真实总线。本文还有配套的精品资源点击获取