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.
Requirements
For hardware requirements, please refer to the Requirements.
Configurations
The entry function is as follows, call this function in
main()
to run this sample code. For more details, please refer to the Initialization.can_loopback_demo();
Building and Downloading
For building and downloading, please refer to the Building and Downloading.
Experimental Verification
Press the Reset button on the EVB and the message will be displayed in the Debug Analyzer.
can_loopback_demo: start!
Execute CAN initialization and read the bus status before and after initialization respectively.
can_driver_init: BUS state: 0, waiting... can_driver_init: BUS ON 1
Send Standard Data Frame, Extended Data Frame, Standard Remote Frame, Extended Remote Frame respectively, and print within the Debug Analyzer.
can_loopback_demo: send xxx frame can_loopback: BUS TX done can_loopback: rx frame_type xxx can_loopback: rx frame_id = xxx, ext_frame_id = xxx can_loopback: rx_data [0] xxx ... can_loopback: 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.
For project directory, please refer to Source Code Directory.
Source code directory:
sdk\sample\io_demo\canbus\loopback\can_loopback.c
.
Initialization
The initialization flow for peripherals can refer to Initialization Flow.
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(CAN0) != CAN_BUS_STATE_ON) { __asm volatile ( "nop \n" ); }
Functional Implementation
Send a standard data frame, an extended data frame, a standard remote frame, an extended remote frame in loopback mode.
/* Send standard data frame. */ IO_PRINT_INFO0("can_loopback_demo: send standard data frame"); can_loopback(0, CAN_STD_DATA_FRAME, 0x123, 0, tx_data, 8); /* Send extend data frame. */ IO_PRINT_INFO0("can_loopback_demo: send extend data frame"); can_loopback(1, CAN_EXT_DATA_FRAME, 0x123, 0x4567, tx_data, 8); /* Send standard remote frame. */ IO_PRINT_INFO0("can_loopback_demo: send standard remote frame"); can_loopback(2, CAN_STD_REMOTE_FRAME, 0x7ff, 0, tx_data, 0); /* Send extend remote frame. */ IO_PRINT_INFO0("can_loopback_demo: send extend remote frame"); can_loopback(3, CAN_EXT_REMOTE_FRAME, 0x7ff, 0x3ffff, tx_data, 0); IO_PRINT_INFO0("can_loopback_demo: end of can loopback demo");
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.
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 = CAN_RX_FRAME_MASK_RTR; rx_frame_type.frame_ide_mask = CAN_RX_FRAME_MASK_IDE; rx_frame_type.frame_id_mask = CAN_RX_FRAME_MASK_ID; rx_frame_type.rx_dma_en = RESET; rx_frame_type.auto_reply_bit = RESET; rx_error = CAN_SetMsgBufRxMode(CAN0, &rx_frame_type); while (CAN_GetRamState(CAN0) != 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.auto_reply_bit = DISABLE; tx_error = CAN_SetMsgBufTxMode(CAN0, &tx_frame_type, tx_data, data_len); while (CAN_GetRamState(CAN0) != CAN_RAM_STATE_IDLE) ... /* Polling tx done. */ while (SET != CAN_GetMBnTxDoneFlag(CAN0, tx_frame_type.msg_buf_id)) ... /* Polling rx done. */ while (SET != CAN_GetMBnRxDoneFlag(CAN0, rx_frame_type.msg_buf_id)) ... /* Receive rx data. */ ... CAN_GetMsgBufInfo(CAN0, rx_frame_type.msg_buf_id, &mb_info); ... if (CAN_GetRamData(CAN0, mb_info.data_length, rx_data) != CAN_NO_ERR) CANDataFrameSel_TypeDef get_frame_type = CAN_CheckFrameType(mb_info.rtr_bit, mb_info.ide_bit, mb_info.edl_bit); ...