LoopBack
This sample uses the loopback test mode of CAN to send and receive frame data.
Using CAN transmit message buffer, it sends standard data frames, extended data frames, standard remote frames, and extended remote frames. The frame data received by the CAN message buffer is printed on the Debug Analyzer tool.
Requirements
For requirements, please refer to the Requirements.
Building and Downloading
For building and downloading, please refer to the Building and Downloading.
Experimental Verification
Execute CAN initialization and read the bus status before and after initialization respectively.
[CAN] BUS state: 0, waiting... [CAN] BUS ON 1
Send Standard Data Frame, Extended Data Frame, Standard Remote Frame, Extended Remote Frame respectively, and print within the log tool.
[CAN] rx frame_type x [CAN] rx frame_id = xxx , ext_frame_id = xxx [CAN] rx_data [0] xxx ... [CAN] BUS RX done ...
Code Overview
This section introduces the code and process description for initialization and corresponding function implementation in the sample.
Source Code Directory
The directory for project file and source code are as follows:
Project directory:
sdk\samples\peripheral\can\loopback\proj
Source code directory:
sdk\samples\peripheral\can\loopback\src
Initialization
The initialization flow for peripherals can refer to Initialization Flow in General Introduction.
In the CAN loopback test, there is no need to configure PAD and PINMUX.
Call
RCC_PeriphClockCmd()
to enable the CAN clock.Initialize the CAN peripheral:
Define a
CAN_InitTypeDef
typeinit_struct
and callCAN_StructInit()
to pre-fillinit_struct
with default values.Modify the
init_struct
parameters as needed. The CAN initialization parameters are configured as shown in the table below.Call
CAN_Init()
to initialize the parameters and the CAN peripheral.
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 |
Call
CAN_Cmd()
to enable the corresponding CAN peripheral.Call
CAN_GetBusState()
to loop-check the CAN bus state and wait for the CAN bus to open.while (CAN_GetBusState() != CAN_BUS_STATE_ON) { __asm volatile ( "nop \n" ); }
Note
If the program is stuck at the point of waiting for the CAN bus to be on, please check if the CAN bus is connected correctly.
Functional Implementation
Send a standard data frame, an extended data frame, a standard remote frame, an extended remote frame in loopback mode.
Note
If sending several frames using the same message buffer ID, make sure to wait for the previous frame to be sent before sending the next frame.
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); ... }
Execute the
can_loopback
function to send and receive frames of the specified type in loopback mode.Call
CAN_SetMsgBufRxMode()
to set the receive message buffer frame type. Use message buffer 15 for reception, mask the reception frame rtr, ide, id filters, i.e., receive all frames, disable Rx GDMA, disable automatic reply, and configure the message buffer in receive mode using the set receive frame type.Call
CAN_GetRamState()
to wait for RAM to be idle.Call
CAN_SetMsgBufTxMode()
to set the transmit message buffer frame type. Use the passed parameter message buffer id, frame type, standard frame id, extended frame id, disable automatic reply, and configure the message buffer in transmit mode using the set transmit frame type. CallCAN_GetRamState()
to wait for RAM to be idle.Poll
CAN_GetMBnTxDoneFlag()
andCAN_GetMBnRxDoneFlag()
to wait for transmission and reception completion.Call
CAN_GetRamData()
andCAN_CheckFrameType()
to read the receive message buffer information, and through the receive message buffer information, read the frame data received in RAM and print it.
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); ...