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

  1. Execute CAN initialization and read the bus status before and after initialization respectively.

    [CAN]  BUS state: 0, waiting...
    [CAN]  BUS ON 1
    
  2. 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.

  1. In the CAN loopback test, there is no need to configure PAD and PINMUX.

  2. Call RCC_PeriphClockCmd() to enable the CAN clock.

  3. Initialize the CAN peripheral:

    1. Define a CAN_InitTypeDef type init_struct and call CAN_StructInit() to pre-fill init_struct with default values.

    2. Modify the init_struct parameters as needed. The CAN initialization parameters are configured as shown in the table below.

    3. Call CAN_Init() to initialize the parameters and the CAN peripheral.

CAN Initialization Parameters

CAN Hardware Parameters

Setting in the init_struct

CAN

Auto Re-transmit Enable

CAN_InitTypeDef::CAN_AutoReTxEn

DISABLE

CAN speed parameter - brp

CAN_BIT_TIMING_TYPE_TypeDef::can_brp

3

CAN speed parameter - sjw

CAN_BIT_TIMING_TYPE_TypeDef::can_sjw

3

CAN speed parameter - tseg1

CAN_BIT_TIMING_TYPE_TypeDef::can_tseg1

13

CAN speed parameter - tseg2

CAN_BIT_TIMING_TYPE_TypeDef::can_tseg2

4

Test Mode

CAN_InitTypeDef::CAN_TestModeSel

CAN_TEST_MODE_INT_LOOPBACK

  1. Call CAN_Cmd() to enable the corresponding CAN peripheral.

  2. 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

  1. 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);
    ...
}
  1. Execute the can_loopback function to send and receive frames of the specified type in loopback mode.

    1. 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.

    2. Call CAN_GetRamState() to wait for RAM to be idle.

    3. 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. Call CAN_GetRamState() to wait for RAM to be idle.

    4. Poll CAN_GetMBnTxDoneFlag() and CAN_GetMBnRxDoneFlag() to wait for transmission and reception completion.

    5. Call CAN_GetRamData() and CAN_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);
    ...