跳转至内容
  • 版块
  • 最新
  • 标签
  • 热门
折叠
品牌标识

YunTu Forum

YTMicro.com
  1. 主页
  2. Blogs
  3. CAN寄存器操作

CAN寄存器操作

已定时 已固定 已锁定 已移动 Blogs
1 帖子 1 发布者 17 浏览
  • 从旧到新
  • 从新到旧
  • 最多赞同
登录后回复
此主题已被删除。只有拥有主题管理权限的用户可以查看。
  • swustS 离线
    swustS 离线
    swust YunTu
    编写于 最后由 编辑
    #1

    部分客户为了适配之前的软件结构,或是想要简化代码复杂度,需要采取纯寄存器操作。其中,由于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
    
    1. 写入数据。
      一个单位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];
    
    1. 设置邮箱状态/激活邮箱
      若数据长度为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;
    

    接收配置

    1. 清除待处理标志
    base->IFLAG1 = 1UL << mb_idx;
    
    1. 清除仲裁字段
    base->RAM[offset+0] = 0;                     
    base->RAM[offset+1] = 0;
    
    1. 写入 ID (标准/扩展格式同发送)
      CODE = 0x4 (EMPTY) → 激活接收
    base->RAM[offset+0] = cs;       // 写入 CS 激活 MB
    base->IMASK1 |= 1UL << mb_idx;  // 使能 MB 中断
    

    注意:必须先清除 CS 和 ID 寄存器再写新值,否则可能残留旧数据导致意外匹配。标准 ID 接收时 CS 中的 IDE 位必须为 0。

    接收帧配置步骤

    1. 先轮询 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
    
    1. 重新将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

    Flexcan_Demo_Register.zip

    1 条回复 最后回复
    0

  • 云途开发生态介绍

    快速上手云途开发生态

  • 云途论坛规则/Yuntu Forum Rules

    发帖前请查看

  • YT CONFIG TOOL调查问卷

    帮助改进和优化YT CONFIG TOOL,有机会抽取YTM32B1ME0 EVB哦...

  • can
    28
    demo
    23
    uds
    14
    lin stack
    13
    md14
    6
    yt-link
    6
    fbl
    5
    adc模块
    4
    Online Users
    • 登录

    • 登录或注册以进行搜索。
    • 第一个帖子
      最后一个帖子
    0
    • 版块
    • 最新
    • 标签
    • 热门