
简介针对TMS320F28335的CAN通讯配置与函数使用详解资源包提供ECan模块的底层驱动源码适合工业控制、电力电子领域的嵌入式工程师及学习者参考。压缩包共2个文件包含DSP2833x_ECan.c源文件和DSP2833x_ECan.h头文件整体大小约10KB代码精简却覆盖ECan初始化、邮箱配置、消息收发、中断与错误处理等核心功能。目前已有176人学习下载。将驱动加入CCS工程后可直接调用相关API完成CAN报文收发免去重复查阅寄存器手册的时间同时源码中的波特率计算、滤波器ID设置和工作模式切换逻辑也为深入理解TMS320F28335的CAN控制器机制提供了直观示例。无论是快速验证通信功能还是系统学习外设驱动这份轻量级资源都能带来实用帮助。1. 为什么TMS320F28335的CAN通讯要先啃ECan寄存器一条CAN总线上挂着驱动器、PLC和上位机现场反馈偶发通信超时上位机读到的数据一跳一跳示波器波形又看不出明显异常。排查下来问题十有八九出在邮箱过滤和错误状态没有处理干净上。TI的TMS320F28335内置eCAN模块配套的DSP2833x_ECan.c和DSP2833x_ECan.h是寄存器级驱动不是封装好的HAL库直接调用还不够必须知道每个位在干什么。这篇文章从初始化、波特率、邮箱到错误恢复把源码里几个关键函数逐层拆开适合做伺服驱动、电力电子、工业控制的人也适合正在读嵌入式内核源码的朋友对照寄存器手册看驱动。2. ECan模块初始化从ECANCTRL到邮箱分配的寄存器级实现2.1 时钟使能与外设复位释放在F28335系统里eCAN-A和eCAN-B的时钟由PCLKCR0寄存器控制。如果没使能时钟读寄存器可能返回全1写进去也没反应这是很多人卡住的第一步。官方源码的InitECan()也把时钟使能放在最前面。extern struct PCLKCR0_BITS PclkCr0; EALLOW; PclkCr0.bit.ECAENCLK 1; // eCAN-A 外设时钟 PclkCr0.bit.ECBENCLK 1; // eCAN-B 外设时钟 EDIS;PCLKCR0的ECAENCLK对应位15ECBENCLK对应位16。EALLOW打开系统写保护EDIS恢复保护。如果只使用eCAN-A第二行也可以不写但建议两个都使能避免后续切到B组时忘记开时钟。2.2 ECANCTRL 与工作模式切换ECANCTRL是eCAN模块的主控制寄存器重要位包括CCE、SCC、DBO和TEST。CCE是配置模式使能位置1后才能修改位定时参数、屏蔽寄存器和邮箱属性。正常发送接收时必须退出该状态否则节点不会参与总线仲裁。ECanRegs.ECANCTRL.all 0x00000001; // CCE1请求进入配置模式 while (ECanRegs.ECANSTS.bit.CCE ! 1) {} // 等待硬件确认这里用all整体赋值比按位操作更常见一个写周期能把DBO、SCC一并设好。DBO控制数据字节顺序通常保持0SCC控制SCC兼容模式使用完整eCAN功能时也保持0。while循环是必须的因为寄存器写入到状态切换有一个时钟周期延迟不等待容易在下一次配置时写入无效。2.3 EcanInit() 的完整配置流程官方DSP2833x_ECan.c中的EcanInit()把上述步骤串起来再加上邮箱初始化。整理后的常见写法如下void EcanInit(void) { EALLOW; PclkCr0.bit.ECAENCLK 1; // 开时钟 EDIS; // 进入配置模式 ECanRegs.ECANCTRL.all 0x00000001; while (ECanRegs.ECANSTS.bit.CCE ! 1) {} // 关闭全部邮箱防止配置过程中误触发收发 ECanRegs.CANME.all 0; // 位定时参数按 500kbps 预置具体见第3章 ECanRegs.ECANBTC.bit.BRP 14; ECanRegs.ECANBTC.bit.SJW 1; ECanRegs.ECANBTC.bit.TSEG1 13; ECanRegs.ECANBTC.bit.TSEG2 4; // 邮箱类型0-15 接收16-31 发送 ECanRegs.CANMD.all 0xFFFF0000; // 屏蔽寄存器清零不屏蔽任何ID ECanRegs.CANAM.all 0; // 退出配置模式 ECanRegs.ECANCTRL.all 0x00000000; while (ECanRegs.ECANSTS.bit.CCE 1) {} // 最后使能邮箱0 ECanRegs.CANME.all 1; }CANME.all0是把所有邮箱置为禁止防止旧配置在新配置写入过程中产生意外帧。CANMD的每1位对应一个邮箱0表示接收1表示发送。CANAM全写0表示不屏蔽任何ID生产环境里应当按需配置。代码里每一次状态切换都做了等待避免写寄存器时序错乱。寄存器初始化作用需关心的位ECANCTRL进入/退出配置模式CCE, SCC, DBOECANBTC设定位定时参数BRP, SJW, TSEG1, TSEG2CANME邮箱使能与禁止对应邮箱的bit位CANMD邮箱收发方向0接收1发送CANAM接收掩码1为屏蔽0为需匹配如果在while (ECanRegs.ECANSTS.bit.CCE ! 1)卡死优先检查时钟是否使能、地址是否被位域定义覆盖。还有一种常见误用是配置模式下就置位CANTRS发起发送这会在硬件状态机里留下悬挂请求退出配置模式后立刻发出去一帧错误数据。3. CAN波特率与位定时BRP、TSEG1/TSEG2的工程计算3.1 位时间模型和采样点理解波特率前要先接受CAN位时间不是一个纯方波周期而是由同步段、传播段、相位缓冲段1、相位缓冲段2组成。F28335的eCAN把传播段和相位缓冲段1合并成TSEG1相位缓冲段2作为TSEG2同步段固定为1个时间量子。位时间公式如下位时间(秒) (BRP1) * (TSEG1 TSEG2 3) / SYSCLKOUT其中BRP是波特率预分频值TSEG1和TSEG2是寄存器里的值公式里的3就是同步段的1个量子加上TSEG1和TSEG2各自默认的1个量子。例如SYSCLKOUT等于150MHz目标500kbps一个位需要300个时钟周期。取BRP14则分频后为15个时钟周期一个量子位时间量子数应为20因此TSEG113、TSEG24因为134320。采样点位于同步段加TSEG1之后具体位置是(1(TSEG11)) / (TSEG1TSEG23)这里的计算结果约为75%。3.2 常用波特率与寄存器取值工程上不会每次现场去算直接把常用配置固化在头文件里。以下配置基于SYSCLKOUT150MHz目标波特率BRPTSEG1TSEG2SJW采样点1 Mbps983166.7%500 kbps14134175%250 kbps29134175%100 kbps74125172.2%注意TSEG1和TSEG2都有限定范围TSEG1最大15TSEG2最大7SJW不能大于TSEG2。若使用外部晶振而非内部时钟需要按实际SYSCLKOUT重新推算。代码中配置250kbps的写法是ECanRegs.ECANBTC.bit.BRP 29; ECanRegs.ECANBTC.bit.SJW 1; ECanRegs.ECANBTC.bit.TSEG1 13; ECanRegs.ECANBTC.bit.TSEG2 4;BRP字段写29代表分频系数30TSEG1写13代表实际13个时间量子数。这几个位域在官方头文件里都有位域定义直接赋值即可不需要手工拼整个寄存器。改完参数后必须重新进入配置模式再写否则写不进。3.3 采样点偏低导致的长距离误码有次在一条120米总线上把500kbps的采样点调到65%以下节点分散时偶发CRC错误。CAN控制器一般建议采样点靠近80%左右这样能容忍线缆边沿延迟。比如500kbps总时间量子数保持20不变把TSEG1改成14、TSEG2改成3则采样点变为(115)/2080%位时间不变只是采样点后移。修改后代码ECanRegs.ECANBTC.bit.BRP 14; ECanRegs.ECANBTC.bit.SJW 1; ECanRegs.ECANBTC.bit.TSEG1 14; ECanRegs.ECANBTC.bit.TSEG2 3;调整采样点不会提高传输速率但会提高抗干扰能力。遇到总线长度超过50米时优先调采样点而不是直接降波特率现场验证成本更低。4. 邮箱收发过滤器ID设置、发送优先级与中断处理4.1 邮箱数据结构与配置顺序eCAN模块有32个邮箱每个邮箱对应ID寄存器、控制寄存器、两个数据寄存器。配置顺序有讲究先禁能用邮箱再改方向、ID和长度最后使能否则可能在配置过程中触发一次错误帧。以下把邮箱0配置为接收标准帧ID 0x123。ECanRegs.CANME.all 0; // 禁止所有邮箱 ECanRegs.CANMD.all ~(1 0); // 邮箱0设为接收 ECanRegs.CANMSGID0.bit.STDMSGID 0x123; // 标准帧ID ECanRegs.CANMSGCTRL0.bit.DLC 8; // 数据长度8字节 ECanRegs.CANME.all | 1; // 使能邮箱0CANMSGID0的STDMSGID位域存放标准帧IDCANMSGCTRL0的DLC指数据域字节数。先清CANME再把CANMD置0是为了防止旧方向还在生效时收到不相干报文。使能邮箱的| 1操作要放在最后所有配置写完后一次生效。4.2 接收过滤用AMR掩码命中一组ID有些场景要求一个邮箱接收多条ID比如地址0x100到0x107的状态帧。AMR寄存器的每一位0表示必须匹配1表示不关心。下例让邮箱1接收ID高6位为0x100的高6位、低7位任意的帧ECanRegs.CANME.all 0; ECanRegs.CANMD.all 0; // 全部接收方向 ECanRegs.CANMSGID1.bit.STDMSGID 0x100; // 期望ID ECanRegs.CANAM1.all 0x07F; // 低7位忽略 ECanRegs.CANME.all (1 1); // 使能邮箱1这里AMR值0x07F表示低7位是掩码写入后硬件会在接收比较时忽略这些位。很多人把AMR当成“匹配位”来写写反后会收进来一大批不该收的帧。掩码设置完成后建议不要再改邮箱的MSGID否则掩码上下文会变得很难维护。4.3 发送函数实现与发送优先级官方DSP2833x_ECan.c中的EcanSendMsg()负责填充ID、数据和请求发送。整理后常见逻辑如下int EcanSendMsg(int boxNo, unsigned long msgId, unsigned long *data) { ECanRegs.CANTRS.all ~(1 boxNo); // 等待前一次发送完成 ECanRegs.CANMSGID[boxNo].all msgId; ECanRegs.CANMDL[boxNo].all data[0]; ECanRegs.CANMDH[boxNo].all data[1]; ECanRegs.CANTRS.all | (1 boxNo); // 置位发送请求 return 0; }CANTRS是发送请求寄存器置1后硬件自动按优先级参与总线仲裁发送成功或失败后硬件会清掉对应位。所以发送前先清对应位防止上一帧还没结束就覆盖寄存器。eCAN仲裁规则中邮箱号越小优先级越高重要帧放在小邮箱号周期帧放在接近31的邮箱能明显降低负载重时的偶发超时。4.4 接收中断与PIE配置接收中断适合用在不能丢帧的节点上。F28335的eCAN-A中断映射到PIE第9组初始化常见写法如下EALLOW; PieVectTable.ECAN0INTA ECanaINT; // 中断向量绑定 EDIS; IER | M_INT9; // 使能第9组 PieCtrlRegs.PIEIER9.bit.INTx1 1; // 使能eCAN-A中断服务程序里先判断哪些邮箱置位了CANRMP确认后读取数据再写1清除挂起位。interrupt void ECanaINT(void) { if (ECanRegs.CANRMP.all 1) { ECanRegs.CANRMP.all 1; // 写1清除接收挂起 recvMsg.id ECanRegs.CANMSGID0.bit.STDMSGID; recvMsg.d0 ECanRegs.CANMDL0.all; recvMsg.d1 ECanRegs.CANMDH0.all; } ECanRegs.CANINT.all 0; // 清全局中断位 PieCtrlRegs.PIEACK.all 0x200; // 应答第9组 }CANRMP写1清零是外设中断的通用规则。如果不手动写1该位会一直置位中断会反复触发CPU卡死在ISR里。PIEACK写0x200对应第9组不写这一行的话后续中断无法继续响应。5. 错误状态管理从CANES到总线恢复的实战技巧5.1 读CANES判断总线异常CANES寄存器汇总了发送错误计数、接收错误计数和最近一次错误状态。其中CANTEC和CANREC分别记录收发错误数超过127进入主动错误超过255触发总线关闭。实际排查时可以用下面代码在关键节点记录错误状态Uint32 es ECanRegs.CANES.all; if (es 0x000000C0) { // EW或EP标志位置位 errorLog(es); }高位的EW和EP标志能提前预警不用等总线完全关闭。看到CANES里错误类型频繁为CRC错误时优先检查波特率匹配和终端电阻而不是改代码。5.2 总线关闭后的恢复流程总线关闭后eCAN会自动恢复但恢复前必须等待128个隐性位。很多现场问题是恢复期间没有清空接收邮箱导致上位机重启后算法用了旧数据。恢复代码放在定时器中断里比较稳if (ECanRegs.ECANSTS.bit.BO 1) { ECanRegs.ECANSTS.bit.BO 1; // 写1清除总线关闭状态 ECanRegs.CANTRS.all 0; // 取消未发送帧 ECanRegs.CANRMP.all 0xFFFFFFFF; // 清空全部接收挂起标志 }ECANSTS的BO位写1才可清除。清完标志后还要把上层协议的发送队列重置否则重发的旧报文会和新状态混在一起。总线关闭恢复属于物理层自动行为软件侧要做的就是别让旧数据继续污染逻辑。5.3 用时间戳降低丢帧排查成本最后一个技巧为每个接收帧打上CPU定时器时间戳。F28335有32位CPU定时器在ISR里把CNT存到接收结构体。排查偶发丢帧时比较相邻两条CAN帧的时间戳差值如果差值远大于周期问题就定位在软件接收路径而不是物理层。static Uint32 lastTs; recvMsg.ts CpuTimer0Regs.TIM.all; if (recvMsg.ts - lastTs 15000) { faultLog(gap too large); } lastTs recvMsg.ts;时间戳差值用无符号减法利用回绕特性即使计数器翻转也能正确判断。这个技巧在长时间记录测试里很实用能直接分离出波特率漂移、CAN控制器过载和邮箱优先级冲突三类问题。观察到的gap如果是周期性事件基本可以锁定是某个routine长时间关闭中断如果是随机突发才需要回到物理层查信号质量。本文还有配套的精品资源点击获取