LoopBack

该示例使用使用 CAN 的回环测试模式发送和接收帧数据。 使用CAN发送邮箱分别发送标准数据帧、扩展数据帧、标准远程帧、扩展远程帧、FD标准数据帧、FD扩展数据帧类型。 在DebugAnalyzer工具上打印CAN邮箱接收到的帧数据。

环境需求

该示例支持以下开发套件:

开发套件

Hardware Platforms

Board Name

RTL87x2G HDK

RTL87x2G EVB

更多信息请参考 快速入门

硬件连线

EVB上,连接P3_2和P3_4。

编译和下载

该示例的工程路径如下:

Project file: samples\peripheral\can\loopback\proj\rtl87x2g\mdk

Project file: samples\peripheral\can\loopback\proj\rtl87x2g\gcc

请按照以下步骤操作构建并运行该示例:

  1. 打开工程文件。

  2. 按照 快速入门编译APP Image 给出的步骤构建目标文件。

  3. 编译成功后,在路径 mdk\bingcc\bin 下会生成 app bin app_MP_xxx.bin 文件。

  4. 按照 快速入门MPTool 给出的步骤将app bin烧录至EVB内。

  5. 按下复位按键,开始运行。

测试验证

  1. 执行CAN初始化,初始化前后分别读取总线状态。

    [CAN]  BUS state: 0, waiting...
    [CAN]  BUS ON 1
    
  2. 发送邮箱分别发送标准数据帧、扩展数据帧、标准远程帧、扩展远程帧、FD标准数据帧、FD扩展数据帧,接收邮箱收到数据后打印数据帧信息LOG。

    [CAN]  rx frame_type x
    [CAN]  rx frame_id = xxx , ext_frame_id = xxx
    [CAN]  rx_data [0] xxx
    ...
    [CAN]  BUS RX done
    ...
    
这里应该是CAN LOG图片

CAN LOG

代码介绍

该章节分为以下几个部分:

  1. 源码路径

  2. 初始化函数将在 初始化 章节介绍。

  3. 初始化后的功能实现将在 功能实现 章节介绍。

源码路径

  • 工程路径: sdk\samples\peripheral\can\loopback\proj

  • 源码路径: sdk\samples\peripheral\can\loopback\src

该工程的工程文件代码结构如下:

└── Project: loopback
    └── secure_only_app
        └── Device                   includes startup code
            ├── startup_rtl.c
            └── system_rtl.c
        ├── CMSIS                    includes CMSIS header files
        ├── CMSE Library             Non-secure callable lib
        ├── Lib                      includes all binary symbol files that user application is built on
            └── rtl87x2g_io.lib
        ├── Peripheral               includes all peripheral drivers and module code used by the application
            ├── rtl_rcc.c
            ├── rtl_pinmux.c
            └── rtl_can.c
        └── APP                      includes the ble_peripheral user application implementation
            ├── main_ns.c
            └── io_can.c

初始化

初始化流程包括了 can_driver_init

can_driver_init 包含了对CAN外设的初始化。

  1. 使能PCC时钟源。

  2. 关闭CAN的自动重传模式。

  3. 设置CAN总线同步位时间,将CAN总线速度设置为500kHz。

  4. 使能CAN FD,设置CAN FD可变速率段位同步时间,将CAN FD可变速率段速度设置为5MHz,设置采样补偿SSP为自动计算模式。

  5. 设置CAN为回环测试模式。

  6. 使能CAN,等待CAN总线打开。

备注

注意:如果程序卡在等待CAN总线打开处,请检查CAN bus是否连接准确。

RCC_PeriphClockCmd(APBPeriph_CAN, APBPeriph_CAN_CLOCK, ENABLE);
...
init_struct.CAN_AutoReTxEn = DISABLE;

/* can speed = 40mhz / ((brp + 1)*(1 + tseg1 + 1 + tseg2 + 1)) */
/* Here config to 500khz. */

init_struct.CAN_BitTiming.b.can_brp = 3;
...
init_struct.CAN_FdEn = ENABLE;
init_struct.CAN_FdBitTiming.b.can_fd_brp = 0;
...
init_struct.CAN_TestModeSel = CAN_TEST_MODE_LOOP_BACK;
...
CAN_Cmd(ENABLE);
while (CAN_GetBusState() != CAN_BUS_STATE_ON)
...

功能实现

  1. 依次以回环方式发送标准数据帧,扩展数据帧,标准远程帧,扩展远程帧,FD标准数据帧,FD扩展数据帧。

备注

注意:如果使用同一个邮箱号连续发送多个帧,请务必保证前一帧发送完成后再发送下一帧。

  1. 执行loopback函数,以回环方式发送和接收指定类型的帧。

    1. 设置接收邮箱的接收帧类型。使用邮箱15进行接收,屏蔽接收帧rtr,ide,id过滤,即接收所有帧,失能Rx DMA,失能自动回复,使用设置的接收帧类型将邮箱配置为接收模式,等待RAM状态空闲。

    2. 设置发送邮箱的发送帧类型。使用传入参数邮箱id,帧类型,标准帧id,扩展帧id,设置帧,失能自动回复,使用设置的发送帧类型将邮箱配置为发送模式,等待RAM状态空闲。

    3. 等待发送与接收完成。

    4. 读取接收邮箱信息,通过接收邮箱信息读取RAM中接收到的帧数据并打印。

CANError_TypeDef rx_error;
CANRxFrame_TypeDef rx_frame_type;

rx_frame_type.msg_buf_id = 15;
/* Set 0 to filter related bit, and set 1 to mask related filter. */
rx_frame_type.frame_rtr_mask = SET;
rx_frame_type.frame_ide_mask = SET;
rx_frame_type.frame_id_mask = CAN_FRAME_ID_MASK_MAX_VALUE;
rx_frame_type.rx_dma_en = RESET;
rx_frame_type.auto_reply_bit = RESET;

rx_error = CAN_SetMsgBufRxMode(&rx_frame_type);

while (CAN_GetRamState() != CAN_RAM_STATE_IDLE)
...

/* Set tx message buffer. */
CANError_TypeDef tx_error = CAN_NO_ERR;
CANTxFrame_TypeDef tx_frame_type;

tx_frame_type.msg_buf_id = buf_id;
tx_frame_type.frame_type = frame_type;
tx_frame_type.standard_frame_id = frame_id;
tx_frame_type.extend_frame_id = 0;
tx_frame_type.frame_brs_bit = CAN_BRS_NO_SWITCH_BIT_TIMING;
tx_frame_type.auto_reply_bit = DISABLE;

tx_error = CAN_SetMsgBufTxMode(&tx_frame_type, tx_data, data_len);
while (CAN_GetRamState() != CAN_RAM_STATE_IDLE)
...

/* Polling tx done. */
while (SET != CAN_GetMBnTxDoneFlag(tx_frame_type.msg_buf_id))
...

/* Polling rx done. */
while (SET != CAN_GetMBnRxDoneFlag(rx_frame_type.msg_buf_id))
...

/* Receive rx data. */
...
get_error = CAN_GetMsgBufInfo(rx_frame_type.msg_buf_id, &mb_info);
...
CAN_GetRamData(mb_info.data_length, rx_data);
CANDataFrameSel_TypeDef get_frame_type = CAN_CheckFrameType(mb_info.rtr_bit, mb_info.ide_bit, mb_info.edl_bit);
...