CAN寄存器操作
-
部分客户为了适配之前的软件结构,或是想要简化代码复杂度,需要采取纯寄存器操作。其中,由于RAM的寄存器定义在手册中并未体现,因此操作难点主要体现在RAM配置。
这里以HA01为对象做一个简单的示例。型号及版本
EVB: HA01 EVB
SDK: 1_4_0
YCT: 2_7_8配置
控制器初始化
初始化主要包括以下几个方面:
1. 选择CAN时钟源,在CTRL1.CLKSRC进行设置,设置时钟源时CAN需处于DISABLE状态;
2. 通过MCR.MDIS使能CAN模块;
3. 设置RXMGMASK、RX14MASK、RX15MASK和RXFGMASK,默认初始化为全F。以上四个寄存器只有在freeze模式下才配置生效(如果需要使用独立掩码,即MCR.IRMQ=1,则RXIMR也需要初始化为全F);
4. 初始化RAM,RAM寄存器数量为邮箱数*4,即如果有32个邮箱,则RAM[0]~RAM[127]需要被初始化为0,具体看使用邮箱数量。如果使用了enhance fifo,那么enhance fifo的RAM所在区域都需要初始化;
5. 如果是FD模式,还需要完成以下步骤:
1. 使能MCR.FDEN和CTRL2.BTE;
2. 通过ENCBT和EDCBT配置仲裁段和数据段速率;
3. 通过FDCTRL.MBDSRn配置payload;不同payload下每个邮箱占用的空间不同。
Classic CAN (8B): 仲裁字段(2字) + 数据(2字) = 4 words
CAN FD 16B: 仲裁字段(2字) + 数据(4字) = 6 words
CAN FD 32B: 仲裁字段(2字) + 数据(8字) = 10 words
CAN FD 64B: 仲裁字段(2字) + 数据(16字) = 18 words
4. 使能CTRL2.ISOCANFDEN;
5. 通过FDCTRL.FDRATE使能数据阶段高速率。
6. 设置波特率。通常情况下,可以在CTRL1中设置PRESDIV、PROPSEG、PSEG1、PSEG2和RJW,但当CTRL2.BTE=1或者FD模式下CTRL1中的配置失效,此时需要在CBT或者ENCBT中进行波特率配置,寄存器中的值实际计算时需要加1。
其中,同步跳转宽度设置规则为≤min(Phase_Seg1,4),如果太大会使采样点提前,进而影响通信时序;
7. 通过IMASKn开启对应邮箱的中断。
ps:如果使用了FD、FIFO、Enhance FIFO或DMA等功能时,还需要单独进行相应设置。RAM设置
邮箱在RAM中的布局如下:
RAM[offset + 0] = CS 字(控制/状态)
RAM[offset + 1] = ID 字(消息ID)
RAM[offset + 2 .. offset+1+(dataLen/4)] = 数据字
发送数据时,一般步骤如下:
- 先清 IFLAG1:base->IFLAG1 = 1UL << mb_idx
- 写数据字:32位大端对齐写入
- 写 ID 字(注意标准/扩展 ID 格式差异)
- 最后写 CS 字(写入 CS 即触发发送)
数据字大端格式:
数据排列: data[0]→[3] 合并为 word[31:0]uint32_t word = (data[i] << 24) | (data[i+1] << 16) | (data[i+2] << 8 ) | data[i+3]; [链接文本]([链接地址]([链接地址]([链接地址]([链接地址]([链接地址]([链接地址](链接地址)))))))base->RAM[offset + 2 + i/4] = word;CS 构造(按位组合):
bit[19:16] = DLC (4-bit编码)
bit[21] = IDE (1=扩展帧)
bit[22] = SRR (扩展帧必须置1)
bit[31] = EDL (1=CAN FD帧)
bit[30] = BRS (1=使能比特率切换)
bit[27:24] = CODE (0xC=TX数据帧)
注意:发送 CS 字必须最后写入,因为写入 CS 字即触发 FlexCAN 发送操作,数据字和 ID 字必须先准备好。发送配置
上面有提到,一个MB占用4个RAM寄存器空间(Normal 模式下),那么以MB1为例,必须进行的步骤如下:
1. 设置ID。
MB1所在区域为RAM[4]~RAM[7],因此ID需要在RAM[5]中进行设置,若ID为0x32,那么配置如下:base->RAM[5] &= ~CAN_ID_STD_MASK; base->RAM[5] |= (frame.msgId << CAN_ID_STD_SHIFT) & CAN_ID_STD_MASK;//STD ID base->RAM[5] |= frame.msgId & (CAN_ID_STD_MASK | CAN_ID_EXT_MASK);//EXT ID- 写入数据。
一个单位RAM寄存器为32bit,最多可以存储4byte数据,因此MB1的RAM[6]、RAM[7]都是用来存储数据的,配置如下:
base->RAM[6] = (((uint32_t) frame.data[0]) << 24) | (((uint32_t) frame.data[1]) << 16) | (((uint32_t) frame.data[2]) << 8 ) | frame.data[3]; base->RAM[7] = (((uint32_t) frame.data[4]) << 24) | (((uint32_t) frame.data[5]) << 16) | (((uint32_t) frame.data[6]) << 8)| frame.data[7];- 设置邮箱状态/激活邮箱
若数据长度为8,那么配置如下:
base->RAM[0] &= ~(CAN_CS_IDE_MASK | CAN_CS_SRR_MASK); base->RAM[0] |= ((uint32_t)8 << CAN_CS_DLC_SHIFT) & CAN_CS_DLC_MASK; base->RAM[0] |= (FLEXCAN_TX_DATA << CAN_CS_CODE_SHIFT) & CAN_CS_CODE_MASK;接收配置
- 清除待处理标志
base->IFLAG1 = 1UL << mb_idx;- 清除仲裁字段
base->RAM[offset+0] = 0; base->RAM[offset+1] = 0;- 写入 ID (标准/扩展格式同发送)
CODE = 0x4 (EMPTY) → 激活接收
base->RAM[offset+0] = cs; // 写入 CS 激活 MB base->IMASK1 |= 1UL << mb_idx; // 使能 MB 中断注意:必须先清除 CS 和 ID 寄存器再写新值,否则可能残留旧数据导致意外匹配。标准 ID 接收时 CS 中的 IDE 位必须为 0。
接收帧配置步骤
- 先轮询 IFLAG1,不要直接读 MB的CS
if (!(base->IFLAG1 & (1UL << mb_idx))) return ERROR;注意:如果 MB 处于 EMPTY 状态时去读 CS,RX MB 会被锁定(Lock),直到收到新帧或复位。必须先检查 IFLAG1 再读 MB。
2. 检查 CODE:必须是 FULL(0x2) 或 OVERRUN(0x6) 才表示有数据
3. 读取 DLC 并解码为实际数据长度(CAN FD 需要查表):
DLC 0-8 → 8/12/16/20/24/32/48/64 字节
DLC 实际数据长度
0-8 0-8
9 12
10 16
11 20
12 24
13 32
14 48
15 64
4. 读取数据字并拆分为大端字节序(与发送对应)
5. 读取 TIMER 解锁:(void)base->TIMER; // 读取 TIMER 寄存器解锁 MB注意:FlexCAN 硬件要求在读取接收到的 MB 后,必须读取 TIMER 寄存器来解锁,否则 MB 会保持锁定状态无法接收新帧。
6. 清除 IFLAG1:base->IFLAG1 = 1UL << mb_idx- 重新将CODE设为EMPTY(0x04),保留 IDE 位:
rearm_cs = (0x4 << 24) | (cs & CAN_CS_IDE_MASK); base->RAM[offset+0] = rearm_cs;常见问题
问题 现象 解决方法 未等 FRZACK 即配置 配置无效 每次修改 MCR 后等待 FRZACK 同步 未先设 MAXMB 就退出冻结 MB 数量错误 在清除 FRZ/HALT 前设置 MAXMB 发送时先写 CS 再写数据 发送空数据/错误数据 按清IFLAG→数据→ID→CS 顺序 接收时直接读 CS 不查 IFLAG MB 锁定,无法收新帧 先轮询 IFLAG,确认有数据再读 接收后未读 TIMER MB 锁定 读取数据后立即 (void)base->TIMER DLC 未解码为实际长度(CAN FD) 数据截断/读越界 使用 DLC→Length 查表转换 数据字节序不对 数据错乱 大端格式:[0]:MSB, [3]:LSB 标准 ID 未左移 18 位 ID 不匹配 RAM[ID] = msgId << 18 FDCTRL[MBDSR] 未全部设置 部分 MB 负载异常 MBDSR0~3 均需配置为相同值 SRXDIS=0 导致自收自发 总线出现自己发的帧 非回环模式建议置 SRXDIS=1 - 写入数据。
快速上手云途开发生态
发帖前请查看
帮助改进和优化YT CONFIG TOOL,有机会抽取YTM32B1ME0 EVB哦...