LoopBack
该示例使用 CAN 的回环测试模式发送和接收帧数据。
使用 CAN 发送邮箱分别发送标准数据帧、扩展数据帧、标准远程帧、扩展远程帧。 在 Debug Analyzer 工具上打印 CAN 邮箱接收到的帧数据。
环境需求
该示例的环境需求,可参考 环境需求。
编译和下载
该示例的编译和下载流程,可参考 编译和下载。
测试验证
执行 CAN 初始化,初始化前后分别读取总线状态。
[CAN] BUS state: 0, waiting... [CAN] BUS ON 1
发送邮箱分别发送标准数据帧、扩展数据帧、标准远程帧、扩展远程帧,接收邮箱收到数据后打印数据帧信息 log。
[CAN] rx frame_type x [CAN] rx frame_id = xxx , ext_frame_id = xxx [CAN] rx_data [0] xxx ... [CAN] BUS RX done ...
代码介绍
该章节主要介绍示例中的初始化和相应功能实现的代码和流程说明。
源码路径
工程文件和源码路径如下:
工程路径:
sdk\samples\peripheral\can\loopback\proj
源码路径:
sdk\samples\peripheral\can\loopback\src
初始化
外设的初始化流程可参考 General Introduction 中的 初始化流程 部分。
在 CAN 回环测试下,无需配置 PAD 与 PINMUX。
调用
RCC_PeriphClockCmd()
,开启 CAN 时钟。对 CAN 外设进行初始化:
定义
CAN_InitTypeDef
类型init_struct
,调用CAN_StructInit()
将init_struct
预填默认值。根据需求修改
init_struct
参数,CAN 的初始化参数配置如下表。调用
CAN_Init()
,初始化 CAN 外设。
CAN Hardware Parameters |
Setting in the |
CAN |
---|---|---|
Auto Re-transmit Enable |
||
CAN speed parameter - brp |
3 |
|
CAN speed parameter - sjw |
3 |
|
CAN speed parameter - tseg1 |
13 |
|
CAN speed parameter - tseg2 |
4 |
|
Test Mode |
调用
CAN_Cmd()
,使能相应 CAN 外设。调用
CAN_GetBusState()
,循环检查 CAN 总线状态,等待 CAN 总线打开。while (CAN_GetBusState() != CAN_BUS_STATE_ON) { __asm volatile ( "nop \n" ); }
备注
注意:如果程序卡在等待 CAN 总线打开处,请检查 CAN bus 是否连接准确。
功能实现
依次以回环方式发送标准数据帧,扩展数据帧,标准远程帧,扩展远程帧。
备注
注意:如果使用同一个邮箱号连续发送多个帧,请务必保证前一帧发送完成后再发送下一帧。
void can_demo(void) { ... /* Send standard data frame. */ can_loopback(0, CAN_STD_DATA_FRAME, 0x123, 0, tx_data, 8); /* Send extend data frame. */ can_loopback(1, CAN_EXT_DATA_FRAME, 0x123, 0x4567, tx_data, 8); /* Send standard remote frame. */ can_loopback(2, CAN_STD_REMOTE_FRAME, 0x7ff, 0, tx_data, 0); /* Send extend remote frame. */ can_loopback(3, CAN_EXT_REMOTE_FRAME, 0x7ff, 0x3ffff, tx_data, 0); ... }
执行
can_loopback
函数,以回环方式发送和接收指定类型的帧。调用
CAN_SetMsgBufRxMode()
设置接收邮箱的接收帧类型。使用邮箱 15 进行接收,屏蔽接收帧 rtr,ide,id 过滤,即接收所有帧,失能 Rx GDMA,失能自动回复,使用设置的接收帧类型将邮箱配置为接收模式。调用
CAN_GetRamState()
等待 RAM 状态空闲。调用
CAN_SetMsgBufTxMode()
设置发送邮箱的发送帧类型。使用传入参数邮箱 id,帧类型,标准帧 id,扩展帧 id,失能自动回复,使用设置的发送帧类型将邮箱配置为发送模式。调用CAN_GetRamState()
等待 RAM 状态空闲。轮询
CAN_GetMBnTxDoneFlag()
和CAN_GetMBnRxDoneFlag()
等待发送与接收完成。调用
CAN_GetRamData()
和CAN_CheckFrameType()
读取接收邮箱信息,通过接收邮箱信息读取 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); ...