MCAN模块FIFO操作与Message RAM配置实战指南
1. MCAN模块FIFO操作与Message RAM配置详解
在汽车电子和工业控制领域,控制器局域网(CAN)总线是实时通信的基石,而CAN FD(灵活数据速率)的引入,更是将数据吞吐量提升到了新的高度。作为CAN FD协议的核心硬件实现,MCAN(CAN FD控制器)模块的性能直接决定了整个通信系统的效率和可靠性。我接触过不少项目,从简单的车身控制到复杂的域控制器,MCAN的配置和调试往往是嵌入式工程师的“必修课”,也是容易踩坑的重灾区。
很多工程师在初次接触MCAN时,往往只关注基本的收发功能,却忽略了其内部数据管理的精髓——Message RAM(消息RAM)的配置与FIFO(先进先出队列)的操作机制。这就像只学会了开车,却不懂发动机的保养,短期看似没问题,一旦系统负载上来或者遇到异常情况,数据丢失、通信延迟等问题就会接踵而至。特别是当CPU需要从Rx FIFO中“插队”读取高优先级消息时,如果对FIFO的确认索引(Acknowledge Index)操作不当,轻则导致数据错乱,重则让整个通信链路陷入混乱。
这篇文章,我将结合自己多年的实战经验,深入拆解MCAN模块中FIFO的操作逻辑和Message RAM的配置细节。我不会只停留在手册的翻译上,而是会重点解释那些手册里一笔带过、但在实际开发中至关重要的“为什么”,并分享一些从调试中总结出来的避坑技巧。无论你是正在评估MCAN方案,还是已经深陷调试泥潭,相信这些内容都能给你带来实质性的帮助。
2. MCAN Message RAM:通信系统的数据枢纽
2.1 Message RAM的架构与核心作用
你可以把MCAN的Message RAM想象成一个高度定制化的“共享内存区”,它专门为CAN消息的存储和管理而设计。与通用RAM不同,它的结构和访问方式与CAN协议的特性紧密耦合。MCAN模块通过这个RAM来存储所有待发送(Tx)、已接收(Rx)的消息,以及决定哪些消息能被接收的过滤器配置。
为什么需要这样一个专用的RAM?原因在于CAN通信的实时性和确定性。CAN总线是事件驱动的,消息可能在任何时刻到达。如果让CPU直接处理每一个比特的收发,其开销是不可接受的。因此,MCAN硬件模块承担了比特级的协议处理(如位定时、CRC校验、错误帧处理),而将整理好的“消息对象”存入Message RAM,再通过中断或DMA通知CPU。这种分工使得CPU可以专注于应用层逻辑,而通信的实时性由硬件保障。
Message RAM在物理上是一个32位宽的单端口或双端口存储器。在CC27xx这类集成MCAN的SoC中,它通常作为MCAN子系统的一部分,通过内部总线与CPU核心相连。其最大可配置大小为4352个32位字(即17KB)。这4352个字并非固定分配给某个功能,而是由软件开发者根据实际应用需求,动态划分为以下几个关键区域:
- Rx FIFO 0 / Rx FIFO 1:两个独立的接收FIFO,每个最多可配置64个消息元素。常用于区分不同优先级或类型的消息。
- Rx Buffers:最多64个专用的接收缓冲区。每个缓冲区对应一个特定的消息ID,适合用于必须确保被及时处理的周期性或关键消息。
- Tx Buffers / Tx FIFO/Queue:发送缓冲区区域。可以配置为多个独立的专用发送缓冲区(Dedicated Tx Buffers),也可以配置为一个发送FIFO或发送队列(Tx FIFO/Queue),或者两者混合。
- Tx Event FIFO:发送事件FIFO,用于记录已发送消息的状态(如时间戳、发送成功/失败),便于应用层进行确认和诊断。
- Standard ID Filter Elements:标准ID(11位)过滤器列表,最多128个元素。
- Extended ID Filter Elements:扩展ID(29位)过滤器列表,最多64个元素。
这些区域的起始地址和大小完全由软件通过一系列配置寄存器(如RXF0SA,RXF0S,TXBSA,TXBC等)来定义。这种灵活性带来了强大的配置能力,但也要求开发者必须清晰地规划内存布局,避免区域重叠导致数据损坏。
2.2 Message RAM的初始化与ECC/Parity处理
在系统上电或硬件复位后,对Message RAM进行正确的初始化是第一步,也是至关重要的一步。手册中特别提到,如果Message RAM支持奇偶校验(Parity)或纠错码(ECC)功能,强烈建议在初始化阶段向每个Message RAM字写入一个已知值(例如0x00000000)。
这么做的原因是什么?对于带有ECC/Parity的RAM,其校验位是在数据写入时根据数据内容计算并存储的。如果RAM在上电后内容随机(未初始化),那么其校验位就是无效或未知的。当MCAN硬件或CPU首次读取该内存位置时,内存控制器会计算当前数据的校验值,并与存储的校验位比较,很可能触发ECC错误中断(如IR.BEC或IR.BEU),甚至导致硬件进入错误状态。
实操心得:在我的一个量产项目中,曾遇到系统偶尔启动失败的问题,最终定位到就是MCAN的Message RAM未初始化。在冷启动时,RAM中的随机数据触发了ECC不可纠正错误,导致MCAN模块被锁定。解决方法就是在MCAN初始化序列中,在使能模块前,先通过CPU写操作遍历整个Message RAM区域,填充零值。代码示例如下:
// 假设 Message RAM 位于地址 0x40080000,大小为 4352 字 volatile uint32_t *msgRamPtr = (volatile uint32_t *)0x40080000; for(uint32_t i = 0; i < 4352; i++) { msgRamPtr[i] = 0x00000000U; } // 等待初始化完成,检查 MCANSS_STAT.MEM_INIT_DONE 位(如果存在) while((MCANSS_STAT & (1 << 1)) == 0); // 等待 MEM_INIT_DONE 置位务必参考具体芯片的数据手册,确认Message RAM的准确基地址和大小,以及硬件是否会在复位后自动初始化。对于CC27xx,需要轮询
MCANSS_STAT.MEM_INIT_DONE位,确保硬件初始化完成后再进行软件访问。
另一个关键点是地址对齐。MCAN模块以32位字(4字节)为单位寻址Message RAM。所有配置寄存器中指定的起始地址(如RXF0SA,TBSA)都是字地址,即实际字节地址右移2位。例如,如果你希望Rx FIFO 0从Message RAM的字节地址0x100开始,那么需要配置RXF0SA = 0x100 / 4 = 0x40。寄存器的低2位会被硬件忽略。规划内存布局时,必须确保每个区域的起始地址是4字节对齐的,并且区域之间留有足够的空间。
3. FIFO操作机制深度解析
3.1 FIFO状态机:Put Index, Get Index 与 Fill Level
MCAN的Rx FIFO和Tx Event FIFO都遵循经典的双指针循环缓冲区模型。理解这三个核心概念是正确操作FIFO的基础:
- Put Index (写入指针,F0PI/F1PI):由MCAN的Rx硬件处理器维护。当一个新的消息通过过滤器并被接受存储到FIFO时,硬件会自动将消息写入
Put Index指向的位置,然后将Put Index加1(如果到达FIFO末尾则回绕到0)。软件只能读取此指针,用于了解最新数据的位置。 - Get Index (读取指针,F0GI/F1GI):由软件维护,指示下一个待读取的FIFO元素位置。初始化时,软件应将其设置为0。当软件从FIFO中读取一个消息后,需要通过写入Acknowledge Index寄存器(
RXF0A/RXF1A)来更新Get Index。 - Fill Level (填充等级,F0FL/F1FL):表示当前FIFO中存储的有效消息数量,计算公式为
Fill Level = (Put Index - Get Index) mod FIFO Size。当Put Index赶上Get Index且Fill Level等于FIFO大小时,表示FIFO已满(RFxF标志置位)。
FIFO有两种工作模式,通过RXFxC.FxOM位配置:
- 阻塞模式 (Blocking Mode, FxOM=0):当FIFO已满时,新到达的消息会被丢弃,并且
IR.RFxL(消息丢失)中断标志会被置位。适用于不能容忍数据覆盖的场景。 - 覆盖模式 (Overwrite Mode, FxOM=1):当FIFO已满时,新消息会覆盖最旧的消息(即
Get Index指向的位置),然后Put Index和Get Index都加1。Fill Level保持不变,且不会触发消息丢失中断。适用于需要最新数据、可以丢弃历史数据的流式应用。
3.2 Acknowledge Index的正确使用与“高优先级读取”陷阱
这是手册中特别强调,也是实际开发中最容易出错的地方。通常,软件从FIFO中读取消息的流程是顺序的:
- 检查
RXFxS.FxFL(填充等级)是否大于0。 - 根据
RXFxS.FxGI(获取索引)计算出消息在Message RAM中的地址。 - 从该地址读取消息数据。
- 读取完成后,向
RXFxA.FxAI寄存器写入刚刚读取的那个元素的索引值。 - MCAN硬件会自动将
Get Index更新为FxAI + 1,并重新计算Fill Level。
关键点在于第4步:你只需要在读取一系列连续的消息后,写入最后一个被读取消息的索引。例如,你从索引2开始,连续读取了索引2、3、4的消息,那么只需要写入RXF0A = 4。硬件会理解你已经处理完了直到索引4的所有消息。
然而,问题出现在非顺序读取时。考虑这样一个场景:FIFO中有多条消息,但其中一条具有非常高优先级,需要被立即处理。软件可能通过中断或轮询IR.HPM(高优先级消息)标志,并结合HPMS寄存器,直接定位到这条高优先级消息在FIFO中的位置(BIDX),然后绕过Get Index,直接去Message RAM中读取该特定索引处的数据。
此时,绝对不能写入Acknowledge Index!为什么?因为Acknowledge Index的本意是告诉硬件:“我已经处理完了直到这个索引的所有消息,你可以回收这些缓冲区了”。如果你读取了索引5的消息(假设当前Get Index是2),然后写入RXF0A = 5,硬件会认为索引2、3、4、5的消息你都处理完了,于是将Get Index更新为6。但实际上,索引2、3、4的消息你根本没读!它们会被“跳过”,永远丢失了。同时,Fill Level也会被错误地减少。
正确的做法是:对于这种“插队”读取的高优先级消息,仅读取数据,不更新Acknowledge Index。Get Index仍然指向最早未读的消息(索引2)。高优先级消息所占用的FIFO槽位会一直被占用,直到Get Index按顺序推进到该位置并被正常确认。这可能会暂时减少FIFO的有效容量,但保证了数据的顺序性和完整性。
注意事项:这种高优先级读取模式需要应用层软件额外维护一个“已读但未确认”的消息列表,或者确保高优先级消息的处理逻辑不会长期阻塞,以免FIFO被未确认的消息占满。在设计系统时,需要权衡实时性和缓冲区利用率。
4. Message RAM的配置实战与计算
4.1 元素大小(Element Size)的配置与影响
CAN FD帧的数据场最大可达64字节,而经典CAN帧只有8字节。为了节省内存,MCAN允许为Rx Buffer、Rx FIFO和Tx Buffer分别配置数据场大小。这是通过RXESC和TXESC寄存器实现的。
RXESC.F0DS/F1DS/RBDS:分别配置Rx FIFO 0、Rx FIFO 1和Rx Buffer的数据场大小。可选8, 12, 16, 20, 24, 32, 48, 64字节。TXESC.TBDS:配置Tx Buffer的数据场大小。选项同上。
配置的黄金法则:配置的大小必须大于或等于你预期接收或发送的帧的最大数据长度。如果接收到的帧数据长度超过了配置的大小,超出的字节会被硬件静默丢弃。如果发送时配置的DLC(数据长度码)超过了TBDS,多出的字节在发送时会被填充为0xCC。
每个消息元素在Message RAM中占用的空间是“元数据”+“数据场”。元数据固定为2个32位字(8字节),包含ID、DLC、控制标志等。数据场则根据RXESC/TXESC的配置占用相应的32位字。因此,一个元素的总大小(单位:32位字)为:2 + ceil(Data Field Size / 4)。
例如,配置为64字节数据场:2 + ceil(64 / 4) = 2 + 16 = 18个字。 配置为8字节数据场:2 + ceil(8 / 4) = 2 + 2 = 4个字。
可以看到,使用64字节比8字节多占用14个字(56字节)的空间。在资源紧张的嵌入式系统中,需要根据实际通信需求精细配置,避免内存浪费。
4.2 内存布局规划与地址计算实战
假设我们需要为一个汽车车窗控制模块设计MCAN的Message RAM布局,需求如下:
- Rx FIFO 0:用于接收一般的车身状态信息,深度16,数据场8字节。
- Rx FIFO 1:用于接收高优先级的诊断命令,深度8,数据场64字节(用于传输诊断数据)。
- Tx Buffer:配置为4个专用发送缓冲区,用于发送车窗状态和诊断响应,数据场8字节。
- Standard ID Filter:需要20个过滤元素。
- Extended ID Filter:需要10个过滤元素。
首先,我们确定每个区域的大小(以32位字为单位):
- Rx FIFO 0:元素大小 = 4字。总大小 = 16 * 4 =64字。
- Rx FIFO 1:元素大小 = 18字。总大小 = 8 * 18 =144字。
- Tx Buffer:元素大小 = 4字。总大小 = 4 * 4 =16字。
- Standard Filter:每个元素占1字。总大小 = 20 * 1 =20字。
- Extended Filter:每个元素占2字。总大小 = 10 * 2 =20字。
- Tx Event FIFO:我们配置深度为8,每个事件元素占2字。总大小 = 8 * 2 =16字。(注意:Rx Buffer本示例未使用,如果需要,其元素大小由
RXESC.RBDS决定)
接下来,规划起始地址。通常从Message RAM的起始位置(地址0)开始分配。我们需要为每个区域定义一个起始字地址。
| 区域 | 大小(字) | 起始字地址 | 结束字地址(起始+大小-1) | 配置寄存器 |
|---|---|---|---|---|
| Standard Filter | 20 | 0x0000 | 0x0013 | SIDFC.FLSSA = 0x0000,SIDFC.LSS = 20 |
| Extended Filter | 20 | 0x0014 | 0x0027 | XIDFC.FLESA = 0x0014,XIDFC.LSE = 10 |
| Rx FIFO 0 | 64 | 0x0028 | 0x0067 | RXF0SA = 0x0028,RXF0C.F0S = 16 |
| Rx FIFO 1 | 144 | 0x0068 | 0x00F7 | RXF1SA = 0x0068,RXF1C.F1S = 8 |
| Tx Buffer | 16 | 0x00F8 | 0x0107 | TXBC.TBSA = 0x00F8,TXBC.NDTB = 4 |
| Tx Event FIFO | 16 | 0x0108 | 0x0117 | TXEFC.EFSA = 0x0108,TXEFC.EFS = 8 |
| 总计 | 280 | 0x0117 |
配置步骤:
- 进入初始化模式:设置
CCCR.INIT = 1和CCCR.CCE = 1,使能配置更改。- 配置元素大小:根据需求设置
RXESC和TXESC寄存器。- 配置过滤器:设置
SIDFC和XIDFC,定义过滤器列表的起始地址和数量。- 配置接收部分:设置
RXF0C,RXF0SA,RXF1C,RXF1SA。如果使用Rx Buffer,还需设置RXBC.RBSA。- 配置发送部分:设置
TXBC,定义Tx Buffer起始地址、专用缓冲区数量以及是否启用Tx FIFO/Queue及其大小。- 配置Tx Event FIFO:设置
TXEFC。- 退出初始化模式:清除
CCCR.CCE和CCCR.INIT,MCAN开始正常操作。
在计算地址时,务必使用字地址。所有配置寄存器中的地址字段(如FLSSA,FLESA,RXF0SA,TBSA等)都只使用[15:2]位,低2位被硬件忽略。确保你的计算工具或代码在分配地址时是4字节对齐的。
5. 过滤器配置:消息的交通指挥所
5.1 过滤器元素详解与匹配逻辑
过滤器是MCAN的“守门员”,决定哪些接收到的消息可以进入Message RAM的哪个区域。每个过滤器元素包含一个ID(或两个ID)、一个掩码(Mask)以及一个动作配置(Configuration)。
标准ID过滤器元素(SIDFC)和扩展ID过滤器元素(XIDFC)结构相似,但长度不同。我们以标准ID过滤器为例,其结构如下表所示:
| 位域 | 名称 | 描述 |
|---|---|---|
| 31:30 | SFT[1:0] | 过滤器类型:00=范围过滤,01=双ID过滤,10=经典过滤(ID+掩码),11=禁用 |
| 29:27 | SFEC[2:0] | 过滤器元素配置:决定匹配后执行的动作 |
| 26:16 | SFID1[10:0] | 第一个标准ID或过滤ID |
| 10:0 | SFID2[10:0] | 第二个标准ID或掩码ID |
过滤器类型 (SFT):
- 范围过滤 (00):
SFID1为下限,SFID2为上限。接收到的ID在此闭区间内即匹配。 - 双ID过滤 (01):接收到的ID等于
SFID1或SFID2即匹配。 - 经典过滤 (10):
SFID1为过滤ID,SFID2为掩码。掩码位为1表示必须匹配,为0表示不关心。匹配条件:(Received ID & SFID2) == (SFID1 & SFID2)。 - 禁用 (11):该过滤器元素无效。
过滤器元素配置 (SFEC):这是过滤器的“动作指令”。
000:禁用。001:匹配则存入Rx FIFO 0。010:匹配则存入Rx FIFO 1。011:匹配则拒绝(丢弃)该消息。100:匹配则设置高优先级消息状态(触发IR.HPM中断),但不存储消息。用于监控特定ID的出现。101:匹配则设置高优先级状态并存入Rx FIFO 0。110:匹配则设置高优先级状态并存入Rx FIFO 1。111:匹配则存入Rx Buffer或作为调试消息。此时SFT被忽略,SFID1为精确匹配的ID,SFID2的低6位指定了Rx Buffer的索引偏移。
过滤流程:MCAN硬件按顺序遍历过滤器列表。对于标准帧,只检查标准ID过滤器列表;对于扩展帧,只检查扩展ID过滤器列表。一旦找到第一个匹配的、使能的过滤器元素,就执行其配置的动作,并停止后续过滤。如果遍历完整个列表都没有匹配,则根据GFC.ANFS(标准帧)或GFC.ANFE(扩展帧)的全局配置,决定是存入默认FIFO(0或1)还是直接拒绝。
5.2 过滤器配置策略与避坑指南
- 优先级排序:由于采用“首次匹配即停止”的机制,必须将最具体、最需要特殊处理的过滤器放在列表前面。例如,某个需要存入Rx Buffer的关键ID,其过滤器必须放在所有可能匹配它的范围过滤器或掩码过滤器之前。
- 合理使用拒绝过滤器:可以在列表末尾放置一个
SFEC=011的过滤器,ID和掩码都设为0,来拒绝所有未匹配前面任何规则的消息。这是一种“白名单”策略。 - 利用全局过滤器配置(GFC):
GFC.ANFS和GFC.ANFE定义了未匹配任何过滤器时的默认行为。GFC.RRFS和GFC.RRFE可以全局拒绝所有远程帧,简化过滤器配置。 - 扩展ID掩码(XIDAM):这是一个全局的29位掩码,应用于所有扩展ID过滤器的匹配逻辑之前。常用于在SAE J1939等协议中,屏蔽掉ID中的优先级位等不需要参与过滤的部分。默认值为全1(0x1FFFFFFF),即不生效。
- 计算过滤器内存占用:标准过滤器每个占1字,扩展过滤器每个占2字。在规划Message RAM时,要预留足够的空间。如果配置的数量(
LSS,LSE)超过了实际定义的过滤器元素,多出的部分不会被使用。
常见问题排查:如果发现某些消息收不到,请按以下步骤检查:
- 确认消息是否到达MCAN:检查
PSR寄存器的ACT字段,确认MCAN处于接收状态。检查ECR寄存器,看错误计数是否增加。- 检查过滤器配置:确认过滤器列表的起始地址(
FLSSA/FLESA)和大小(LSS/LSE)设置正确。确认过滤器元素的ID、类型、掩码和动作配置符合预期。一个常见的错误是地址计算错误,导致过滤器列表指向了错误的Message RAM区域。- 检查FIFO/Buffer配置:确认目标FIFO或Buffer已启用(大小>0),且起始地址正确。检查FIFO是否已满(
RFxF位),导致新消息被丢弃或覆盖。- 检查中断或轮询状态:使能相应的新消息中断(
IE.RFxNE),或定期轮询IR.RFxN和RXFxS.FxFL。
6. 中断与DMA配置:解放CPU的利器
6.1 中断系统架构与配置
MCAN提供了丰富的中断源,可以分为几大类:
- 通信状态中断:
BO(总线关闭)、EW(错误警告)、EP(错误被动)、ELO(错误日志溢出)。 - 协议错误中断:
PEA(仲裁阶段错误)、PED(数据阶段错误)。 - FIFO状态中断:
RFxN(FIFO新消息)、RFxF(FIFO满)、RFxW(FIFO达到水位线)、RFxL(FIFO消息丢失)。对于Tx Event FIFO也有对应的TEFN,TEFF,TEFW,TEFL。 - 高优先级消息中断:
HPM。 - 消息存储中断:
DRX(消息存入专用Rx Buffer)。 - 发送相关中断:
TC(发送完成)、TCF(发送取消完成)、TFE(Tx FIFO空)。 - RAM访问失败中断:
MRAF。 - ECC/Parity错误中断:
BEU(不可纠正位错误)、BEC(可纠正位错误,在Wrapper寄存器中)。
为了高效管理,MCAN允许将每个中断源分配到两条中断线(Line 0 和 Line 1)中的一条。这是通过ILS(中断线选择)寄存器配置的。然后,通过ILE寄存器分别使能这两条中断线。最后,通过IE寄存器使能具体的中断源。
典型的中断配置流程:
- 在初始化阶段(
CCCR.INIT=1),配置ILS寄存器,将不同类别的中断分配到不同的中断线。例如,将错误类中断(BO,EW,EP,ELO,PEA,PED)分配到Line 0,将数据收发中断(RF0N,RF1N,TC,TEFN)分配到Line 1。这样可以在中断服务程序(ISR)中快速判断中断类型。 - 使能中断线:
ILE.EINT0 = 1,ILE.EINT1 = 1。 - 使能具体的中断源:例如,
IE.RF0NE = 1,IE.TCE = 1,IE.BOE = 1。 - 退出初始化模式。
- 在对应的中断服务程序中,读取
IR寄存器来判断具体是哪个中断标志置位。处理完中断后,必须通过向IR寄存器的相应位写1来清除中断标志。这是一个“写1清零”的寄存器。
6.2 DMA与直接内存访问优化
对于高带宽或低延迟应用,频繁的中断和CPU搬运数据可能成为瓶颈。MCAN支持通过DMA来搬运Message RAM中的数据。
DMA触发源:
- Rx FIFO新消息:当消息存入Rx FIFO时,可以触发DMA将数据从Message RAM搬运到系统内存。
- Tx Buffer请求挂起:当应用层将消息写入Message RAM中的Tx Buffer并置位
TXBAR相应位后,可以触发DMA(但这通常用于从外部内存加载数据到Tx Buffer,不如直接写Message RAM常见)。 - 专用Rx Buffer新数据:当消息存入某个专用Rx Buffer时,其对应的
NDATx位被置位,可以映射为DMA触发信号。
CC27xx的MCAN Wrapper提供了更灵活的DMA触发映射寄存器(如MCANSS_DMA0_CTL),可以将特定的Tx Buffer请求(TXBRP)或Rx Buffer事件映射到固定的DMA通道。例如,可以配置DMA通道0由Tx Buffer 0的请求触发,通道1由Rx FIFO 0的新消息触发。
使用DMA的优势:
- 降低CPU负载:CPU无需介入每个消息的搬运过程。
- 提高实时性:DMA传输与CPU执行并行,减少了中断响应和数据处理延迟。
- 简化软件:应用层只需要处理在系统内存中整理好的消息队列。
配置DMA的注意事项:
- 内存一致性:确保DMA源地址(Message RAM)和目的地址(系统内存)都已正确配置,并且目的缓冲区足够大。
- 数据长度:DMA传输需要知道消息的长度。这需要从Message RAM读取的元素头信息(DLC)中解析,或者如果所有消息长度固定,可以配置固定长度的传输。
- 中断协调:通常DMA传输完成会产生自己的中断。需要协调好MCAN中断(消息就绪)和DMA中断(传输完成),避免竞争条件或数据覆盖。
- Wrapper特定配置:如
MCANSS_DMA0_CTL寄存器中的DMA_TRIG_SEL、TX_BRP_OTO_SEL、RX_FE_OTO_SEL等,需要根据具体的DMA触发需求进行配置。例如,选择“Rx buffer two-to-one DMA trigger”模式,可以将两个特定的Rx Buffer事件映射到一个DMA通道。
对于不需要DMA的简单应用,CPU也可以直接访问Message RAM。但需要注意,在访问Rx FIFO时,要遵循前面提到的Acknowledge Index规则。在访问Tx Buffer时,需要先检查TXFQS.TFFL(Tx FIFO空闲等级)以确保有空闲缓冲区,然后根据TXFQS.TFQP(Tx FIFO Put Index)找到下一个可写的缓冲区地址,写入数据后,再通过置位TXBAR相应位来提交发送请求。
7. 时钟、低功耗与错误处理
7.1 时钟配置与低功耗模式
MCAN模块的时钟通常来自系统时钟,并可能经过分频。CCCR寄存器中的INIT、CCE、CSR、CSA位与时钟控制密切相关。
CCCR.INIT:置1使MCAN进入初始化模式,此时核心停止总线活动,但寄存器可配置。CCCR.CSR(时钟停止请求):软件置1请求进入低功耗模式。MCAN会在完成所有挂起的传输且总线空闲后,自行置位CCCR.CSA(时钟停止应答)。此时,主机可以安全地关闭MCAN的时钟。CCCR.CSA:硬件置1,表示MCAN已准备好进入时钟停止模式。
低功耗进入流程:
- 确保没有挂起的发送请求(
TXBRP全为0)。 - 可选:通过
GFC寄存器拒绝所有新消息,或关闭接收中断。 - 置位
CCCR.CSR。 - 轮询等待
CCCR.CSA置位。 CCCR.CSA置位后,软件可以关闭MCAN模块的时钟。
唤醒:MCAN通常可以通过总线活动(检测到CAN RX引脚上的边沿)从低功耗模式唤醒。在CC27xx中,需要通过MCANSS_CTRL.WAKEUPREQEN使能唤醒请求,并可能配置MCANSS_CLKCTL.WKUP_GLTFLT_EN来启用毛刺滤波器,防止噪声误触发唤醒。
7.2 错误处理与诊断
一个健壮的CAN节点必须具备完善的错误处理机制。
协议状态监控:
PSR寄存器提供了实时状态。LEC(最后错误代码):指示最后一次总线错误类型(位错误、格式错误、ACK错误等)。DLEC:数据相位错误代码(仅CAN FD)。ACT(节点活动):显示模块当前是同步、空闲、接收还是发送状态。BO(总线关闭)、EP(错误被动)、EW(错误警告)状态位。
错误计数器:
ECR寄存器包含TEC(发送错误计数器)和REC(接收错误计数器)。根据CAN协议,当TEC或REC超过128时,节点进入错误被动状态;当TEC超过255时,节点进入总线关闭状态。在总线关闭后,MCAN会自动进入初始化模式,并在CCCR.INIT被清除后,执行128次11个隐性位的总线空闲恢复序列。RAM访问失败与看门狗:
IR.MRAF标志指示Message RAM访问失败。这可能发生在CPU和MCAN核心同时访问RAM发生冲突,或RAM响应超时。MCAN_RWD寄存器可以配置RAM看门狗,如果RAM在指定时间内无响应,会触发IR.WDI中断。ECC/Parity错误:如果Message RAM支持ECC,则使能相关错误中断(
IE.BEUE,以及Wrapper中的SEC/DED中断使能)至关重要。单比特错误(SEC)可以被纠正,但双比特错误(DED)不可纠正,通常会导致MCAN进入初始化模式(CCCR.INIT被硬件置1),以防止传输损坏的数据。软件需要记录这些错误,并在可能的情况下进行系统恢复或安全降级。
调试技巧:在开发初期,强烈建议使能所有错误相关中断(BOE,EPE,EWE,ELOE,PEAE,PEDE,MRAFE,WDIE,BEUE),并在中断服务程序中详细记录错误信息。这能帮助快速定位物理层问题(如终端电阻缺失、布线问题)、配置错误或软件逻辑缺陷。